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

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

Enforce options coherency
https://bugs.webkit.org/show_bug.cgi?id=144921

Reviewed by Mark Lam.

JavaScriptCore should be failing early when the options are set in such
a way that we don't have a meaningful way to execute JavaScript, rather
than failing for obscure reasons at some point during execution.

This patch adds a new function that checks whether the options are set
in a coherent way, and makes JSC::Options::initialize() crash when the
environment enforces incoherent options.
Client applications able to add or change additional options are
responsible to check for coherency again before starting to actually
execute JavaScript, if any additional options have been set. This is
implemented for the jsc executable in this patch.

  • jsc.cpp:

(CommandLine::parseArguments):

  • runtime/Options.cpp:

(JSC::Options::initialize):
(JSC::Options::ensureOptionsAreCoherent): Added.

  • runtime/Options.h:

(JSC::Options::ensureOptionsAreCoherent): Added.

  • Property svn:eol-style set to native
File size: 54.2 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 "Disassembler.h"
32#include "ExceptionHelpers.h"
33#include "HeapStatistics.h"
34#include "InitializeThreading.h"
35#include "Interpreter.h"
36#include "JSArray.h"
37#include "JSArrayBuffer.h"
38#include "JSCInlines.h"
39#include "JSFunction.h"
40#include "JSLock.h"
41#include "JSONObject.h"
42#include "JSProxy.h"
43#include "JSString.h"
44#include "ProfilerDatabase.h"
45#include "SamplingTool.h"
46#include "StackVisitor.h"
47#include "StructureInlines.h"
48#include "StructureRareDataInlines.h"
49#include "TestRunnerUtils.h"
50#include "TypeProfilerLog.h"
51#include <math.h>
52#include <stdio.h>
53#include <stdlib.h>
54#include <string.h>
55#include <thread>
56#include <wtf/CurrentTime.h>
57#include <wtf/MainThread.h>
58#include <wtf/StringPrintStream.h>
59#include <wtf/text/StringBuilder.h>
60
61#if !OS(WINDOWS)
62#include <unistd.h>
63#endif
64
65#if HAVE(READLINE)
66// readline/history.h has a Function typedef which conflicts with the WTF::Function template from WTF/Forward.h
67// We #define it to something else to avoid this conflict.
68#define Function ReadlineFunction
69#include <readline/history.h>
70#include <readline/readline.h>
71#undef Function
72#endif
73
74#if HAVE(SYS_TIME_H)
75#include <sys/time.h>
76#endif
77
78#if HAVE(SIGNAL_H)
79#include <signal.h>
80#endif
81
82#if COMPILER(MSVC)
83#include <crtdbg.h>
84#include <mmsystem.h>
85#include <windows.h>
86#endif
87
88#if PLATFORM(IOS) && CPU(ARM_THUMB2)
89#include <fenv.h>
90#include <arm/arch.h>
91#endif
92
93#if PLATFORM(EFL)
94#include <Ecore.h>
95#endif
96
97using namespace JSC;
98using namespace WTF;
99
100namespace JSC {
101WTF_IMPORT extern const struct HashTable globalObjectTable;
102}
103
104namespace {
105
106NO_RETURN_WITH_VALUE static void jscExit(int status)
107{
108 waitForAsynchronousDisassembly();
109
110#if ENABLE(DFG_JIT)
111 if (DFG::isCrashing()) {
112 for (;;) {
113#if OS(WINDOWS)
114 Sleep(1000);
115#else
116 pause();
117#endif
118 }
119 }
120#endif // ENABLE(DFG_JIT)
121 exit(status);
122}
123
124class Element;
125class ElementHandleOwner;
126class Masuqerader;
127class Root;
128class RuntimeArray;
129
130class Element : public JSNonFinalObject {
131public:
132 Element(VM& vm, Structure* structure, Root* root)
133 : Base(vm, structure)
134 , m_root(root)
135 {
136 }
137
138 typedef JSNonFinalObject Base;
139 static const bool needsDestruction = false;
140
141 Root* root() const { return m_root; }
142 void setRoot(Root* root) { m_root = root; }
143
144 static Element* create(VM& vm, JSGlobalObject* globalObject, Root* root)
145 {
146 Structure* structure = createStructure(vm, globalObject, jsNull());
147 Element* element = new (NotNull, allocateCell<Element>(vm.heap, sizeof(Element))) Element(vm, structure, root);
148 element->finishCreation(vm);
149 return element;
150 }
151
152 void finishCreation(VM&);
153
154 static ElementHandleOwner* handleOwner();
155
156 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
157 {
158 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
159 }
160
161 DECLARE_INFO;
162
163private:
164 Root* m_root;
165};
166
167class ElementHandleOwner : public WeakHandleOwner {
168public:
169 virtual bool isReachableFromOpaqueRoots(Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
170 {
171 Element* element = jsCast<Element*>(handle.slot()->asCell());
172 return visitor.containsOpaqueRoot(element->root());
173 }
174};
175
176class Masquerader : public JSNonFinalObject {
177public:
178 Masquerader(VM& vm, Structure* structure)
179 : Base(vm, structure)
180 {
181 }
182
183 typedef JSNonFinalObject Base;
184 static const unsigned StructureFlags = Base::StructureFlags | JSC::MasqueradesAsUndefined;
185
186 static Masquerader* create(VM& vm, JSGlobalObject* globalObject)
187 {
188 globalObject->masqueradesAsUndefinedWatchpoint()->fireAll("Masquerading object allocated");
189 Structure* structure = createStructure(vm, globalObject, jsNull());
190 Masquerader* result = new (NotNull, allocateCell<Masquerader>(vm.heap, sizeof(Masquerader))) Masquerader(vm, structure);
191 result->finishCreation(vm);
192 return result;
193 }
194
195 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
196 {
197 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
198 }
199
200 DECLARE_INFO;
201};
202
203class Root : public JSDestructibleObject {
204public:
205 Root(VM& vm, Structure* structure)
206 : Base(vm, structure)
207 {
208 }
209
210 Element* element()
211 {
212 return m_element.get();
213 }
214
215 void setElement(Element* element)
216 {
217 Weak<Element> newElement(element, Element::handleOwner());
218 m_element.swap(newElement);
219 }
220
221 static Root* create(VM& vm, JSGlobalObject* globalObject)
222 {
223 Structure* structure = createStructure(vm, globalObject, jsNull());
224 Root* root = new (NotNull, allocateCell<Root>(vm.heap, sizeof(Root))) Root(vm, structure);
225 root->finishCreation(vm);
226 return root;
227 }
228
229 typedef JSDestructibleObject Base;
230
231 DECLARE_INFO;
232 static const bool needsDestruction = true;
233
234 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
235 {
236 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
237 }
238
239 static void visitChildren(JSCell* thisObject, SlotVisitor& visitor)
240 {
241 Base::visitChildren(thisObject, visitor);
242 visitor.addOpaqueRoot(thisObject);
243 }
244
245private:
246 Weak<Element> m_element;
247};
248
249class ImpureGetter : public JSNonFinalObject {
250public:
251 ImpureGetter(VM& vm, Structure* structure)
252 : Base(vm, structure)
253 {
254 }
255
256 DECLARE_INFO;
257 typedef JSNonFinalObject Base;
258 static const unsigned StructureFlags = Base::StructureFlags | JSC::HasImpureGetOwnPropertySlot | JSC::OverridesGetOwnPropertySlot;
259
260 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
261 {
262 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
263 }
264
265 static ImpureGetter* create(VM& vm, Structure* structure, JSObject* delegate)
266 {
267 ImpureGetter* getter = new (NotNull, allocateCell<ImpureGetter>(vm.heap, sizeof(ImpureGetter))) ImpureGetter(vm, structure);
268 getter->finishCreation(vm, delegate);
269 return getter;
270 }
271
272 void finishCreation(VM& vm, JSObject* delegate)
273 {
274 Base::finishCreation(vm);
275 if (delegate)
276 m_delegate.set(vm, this, delegate);
277 }
278
279 static bool getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName name, PropertySlot& slot)
280 {
281 ImpureGetter* thisObject = jsCast<ImpureGetter*>(object);
282
283 if (thisObject->m_delegate && thisObject->m_delegate->getPropertySlot(exec, name, slot))
284 return true;
285
286 return Base::getOwnPropertySlot(object, exec, name, slot);
287 }
288
289 static void visitChildren(JSCell* cell, SlotVisitor& visitor)
290 {
291 Base::visitChildren(cell, visitor);
292 ImpureGetter* thisObject = jsCast<ImpureGetter*>(cell);
293 visitor.append(&thisObject->m_delegate);
294 }
295
296 void setDelegate(VM& vm, JSObject* delegate)
297 {
298 m_delegate.set(vm, this, delegate);
299 }
300
301private:
302 WriteBarrier<JSObject> m_delegate;
303};
304
305class RuntimeArray : public JSArray {
306public:
307 typedef JSArray Base;
308 static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesGetPropertyNames;
309
310 static RuntimeArray* create(ExecState* exec)
311 {
312 VM& vm = exec->vm();
313 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
314 Structure* structure = createStructure(vm, globalObject, createPrototype(vm, globalObject));
315 RuntimeArray* runtimeArray = new (NotNull, allocateCell<RuntimeArray>(*exec->heap())) RuntimeArray(exec, structure);
316 runtimeArray->finishCreation(exec);
317 vm.heap.addFinalizer(runtimeArray, destroy);
318 return runtimeArray;
319 }
320
321 ~RuntimeArray() { }
322
323 static void destroy(JSCell* cell)
324 {
325 static_cast<RuntimeArray*>(cell)->RuntimeArray::~RuntimeArray();
326 }
327
328 static const bool needsDestruction = false;
329
330 static bool getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
331 {
332 RuntimeArray* thisObject = jsCast<RuntimeArray*>(object);
333 if (propertyName == exec->propertyNames().length) {
334 slot.setCacheableCustom(thisObject, DontDelete | ReadOnly | DontEnum, thisObject->lengthGetter);
335 return true;
336 }
337
338 Optional<uint32_t> index = parseIndex(propertyName);
339 if (index && index.value() < thisObject->getLength()) {
340 slot.setValue(thisObject, DontDelete | DontEnum, jsNumber(thisObject->m_vector[index.value()]));
341 return true;
342 }
343
344 return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot);
345 }
346
347 static bool getOwnPropertySlotByIndex(JSObject* object, ExecState* exec, unsigned index, PropertySlot& slot)
348 {
349 RuntimeArray* thisObject = jsCast<RuntimeArray*>(object);
350 if (index < thisObject->getLength()) {
351 slot.setValue(thisObject, DontDelete | DontEnum, jsNumber(thisObject->m_vector[index]));
352 return true;
353 }
354
355 return JSObject::getOwnPropertySlotByIndex(thisObject, exec, index, slot);
356 }
357
358 static NO_RETURN_DUE_TO_CRASH void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&)
359 {
360 RELEASE_ASSERT_NOT_REACHED();
361 }
362
363 static NO_RETURN_DUE_TO_CRASH bool deleteProperty(JSCell*, ExecState*, PropertyName)
364 {
365 RELEASE_ASSERT_NOT_REACHED();
366 }
367
368 unsigned getLength() const { return m_vector.size(); }
369
370 DECLARE_INFO;
371
372 static ArrayPrototype* createPrototype(VM&, JSGlobalObject* globalObject)
373 {
374 return globalObject->arrayPrototype();
375 }
376
377 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
378 {
379 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info(), ArrayClass);
380 }
381
382protected:
383 void finishCreation(ExecState* exec)
384 {
385 Base::finishCreation(exec->vm());
386 ASSERT(inherits(info()));
387
388 for (size_t i = 0; i < exec->argumentCount(); i++)
389 m_vector.append(exec->argument(i).toInt32(exec));
390 }
391
392private:
393 RuntimeArray(ExecState* exec, Structure* structure)
394 : JSArray(exec->vm(), structure, 0)
395 {
396 }
397
398 static EncodedJSValue lengthGetter(ExecState* exec, JSObject*, EncodedJSValue thisValue, PropertyName)
399 {
400 RuntimeArray* thisObject = jsDynamicCast<RuntimeArray*>(JSValue::decode(thisValue));
401 if (!thisObject)
402 return throwVMTypeError(exec);
403 return JSValue::encode(jsNumber(thisObject->getLength()));
404 }
405
406 Vector<int> m_vector;
407};
408
409const ClassInfo Element::s_info = { "Element", &Base::s_info, 0, CREATE_METHOD_TABLE(Element) };
410const ClassInfo Masquerader::s_info = { "Masquerader", &Base::s_info, 0, CREATE_METHOD_TABLE(Masquerader) };
411const ClassInfo Root::s_info = { "Root", &Base::s_info, 0, CREATE_METHOD_TABLE(Root) };
412const ClassInfo ImpureGetter::s_info = { "ImpureGetter", &Base::s_info, 0, CREATE_METHOD_TABLE(ImpureGetter) };
413const ClassInfo RuntimeArray::s_info = { "RuntimeArray", &Base::s_info, 0, CREATE_METHOD_TABLE(RuntimeArray) };
414
415ElementHandleOwner* Element::handleOwner()
416{
417 static ElementHandleOwner* owner = 0;
418 if (!owner)
419 owner = new ElementHandleOwner();
420 return owner;
421}
422
423void Element::finishCreation(VM& vm)
424{
425 Base::finishCreation(vm);
426 m_root->setElement(this);
427}
428
429}
430
431static bool fillBufferWithContentsOfFile(const String& fileName, Vector<char>& buffer);
432
433static EncodedJSValue JSC_HOST_CALL functionCreateProxy(ExecState*);
434static EncodedJSValue JSC_HOST_CALL functionCreateRuntimeArray(ExecState*);
435static EncodedJSValue JSC_HOST_CALL functionCreateImpureGetter(ExecState*);
436static EncodedJSValue JSC_HOST_CALL functionSetImpureGetterDelegate(ExecState*);
437
438static EncodedJSValue JSC_HOST_CALL functionSetElementRoot(ExecState*);
439static EncodedJSValue JSC_HOST_CALL functionCreateRoot(ExecState*);
440static EncodedJSValue JSC_HOST_CALL functionCreateElement(ExecState*);
441static EncodedJSValue JSC_HOST_CALL functionGetElement(ExecState*);
442static EncodedJSValue JSC_HOST_CALL functionPrint(ExecState*);
443static EncodedJSValue JSC_HOST_CALL functionDebug(ExecState*);
444static EncodedJSValue JSC_HOST_CALL functionDescribe(ExecState*);
445static EncodedJSValue JSC_HOST_CALL functionDescribeArray(ExecState*);
446static EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState*);
447static EncodedJSValue JSC_HOST_CALL functionGCAndSweep(ExecState*);
448static EncodedJSValue JSC_HOST_CALL functionFullGC(ExecState*);
449static EncodedJSValue JSC_HOST_CALL functionEdenGC(ExecState*);
450static EncodedJSValue JSC_HOST_CALL functionHeapSize(ExecState*);
451static EncodedJSValue JSC_HOST_CALL functionDeleteAllCompiledCode(ExecState*);
452#ifndef NDEBUG
453static EncodedJSValue JSC_HOST_CALL functionReleaseExecutableMemory(ExecState*);
454static EncodedJSValue JSC_HOST_CALL functionDumpCallFrame(ExecState*);
455#endif
456static EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*);
457static EncodedJSValue JSC_HOST_CALL functionRun(ExecState*);
458static EncodedJSValue JSC_HOST_CALL functionLoad(ExecState*);
459static EncodedJSValue JSC_HOST_CALL functionReadFile(ExecState*);
460static EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState*);
461static EncodedJSValue JSC_HOST_CALL functionReadline(ExecState*);
462static EncodedJSValue JSC_HOST_CALL functionPreciseTime(ExecState*);
463static EncodedJSValue JSC_HOST_CALL functionNeverInlineFunction(ExecState*);
464static EncodedJSValue JSC_HOST_CALL functionOptimizeNextInvocation(ExecState*);
465static EncodedJSValue JSC_HOST_CALL functionNumberOfDFGCompiles(ExecState*);
466static EncodedJSValue JSC_HOST_CALL functionReoptimizationRetryCount(ExecState*);
467static EncodedJSValue JSC_HOST_CALL functionTransferArrayBuffer(ExecState*);
468static NO_RETURN_WITH_VALUE EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*);
469static EncodedJSValue JSC_HOST_CALL functionFalse1(ExecState*);
470static EncodedJSValue JSC_HOST_CALL functionFalse2(ExecState*);
471static EncodedJSValue JSC_HOST_CALL functionUndefined1(ExecState*);
472static EncodedJSValue JSC_HOST_CALL functionUndefined2(ExecState*);
473static EncodedJSValue JSC_HOST_CALL functionIsInt32(ExecState*);
474static EncodedJSValue JSC_HOST_CALL functionEffectful42(ExecState*);
475static EncodedJSValue JSC_HOST_CALL functionIdentity(ExecState*);
476static EncodedJSValue JSC_HOST_CALL functionMakeMasquerader(ExecState*);
477static EncodedJSValue JSC_HOST_CALL functionHasCustomProperties(ExecState*);
478static EncodedJSValue JSC_HOST_CALL functionDumpTypesForAllVariables(ExecState*);
479static EncodedJSValue JSC_HOST_CALL functionFindTypeForExpression(ExecState*);
480static EncodedJSValue JSC_HOST_CALL functionReturnTypeFor(ExecState*);
481static EncodedJSValue JSC_HOST_CALL functionDumpBasicBlockExecutionRanges(ExecState*);
482static EncodedJSValue JSC_HOST_CALL functionHasBasicBlockExecuted(ExecState*);
483static EncodedJSValue JSC_HOST_CALL functionEnableExceptionFuzz(ExecState*);
484
485#if ENABLE(SAMPLING_FLAGS)
486static EncodedJSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState*);
487static EncodedJSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState*);
488#endif
489
490struct Script {
491 bool isFile;
492 char* argument;
493
494 Script(bool isFile, char *argument)
495 : isFile(isFile)
496 , argument(argument)
497 {
498 }
499};
500
501class CommandLine {
502public:
503 CommandLine(int argc, char** argv)
504 : m_interactive(false)
505 , m_dump(false)
506 , m_exitCode(false)
507 , m_profile(false)
508 {
509 parseArguments(argc, argv);
510 }
511
512 bool m_interactive;
513 bool m_dump;
514 bool m_exitCode;
515 Vector<Script> m_scripts;
516 Vector<String> m_arguments;
517 bool m_profile;
518 String m_profilerOutput;
519
520 void parseArguments(int, char**);
521};
522
523static const char interactivePrompt[] = ">>> ";
524
525class StopWatch {
526public:
527 void start();
528 void stop();
529 long getElapsedMS(); // call stop() first
530
531private:
532 double m_startTime;
533 double m_stopTime;
534};
535
536void StopWatch::start()
537{
538 m_startTime = monotonicallyIncreasingTime();
539}
540
541void StopWatch::stop()
542{
543 m_stopTime = monotonicallyIncreasingTime();
544}
545
546long StopWatch::getElapsedMS()
547{
548 return static_cast<long>((m_stopTime - m_startTime) * 1000);
549}
550
551class GlobalObject : public JSGlobalObject {
552private:
553 GlobalObject(VM&, Structure*);
554
555public:
556 typedef JSGlobalObject Base;
557
558 static GlobalObject* create(VM& vm, Structure* structure, const Vector<String>& arguments)
559 {
560 GlobalObject* object = new (NotNull, allocateCell<GlobalObject>(vm.heap)) GlobalObject(vm, structure);
561 object->finishCreation(vm, arguments);
562 vm.heap.addFinalizer(object, destroy);
563 return object;
564 }
565
566 static const bool needsDestruction = false;
567
568 DECLARE_INFO;
569 static const GlobalObjectMethodTable s_globalObjectMethodTable;
570
571 static Structure* createStructure(VM& vm, JSValue prototype)
572 {
573 return Structure::create(vm, 0, prototype, TypeInfo(GlobalObjectType, StructureFlags), info());
574 }
575
576 static RuntimeFlags javaScriptRuntimeFlags(const JSGlobalObject*) { return RuntimeFlags::createAllEnabled(); }
577
578protected:
579 void finishCreation(VM& vm, const Vector<String>& arguments)
580 {
581 Base::finishCreation(vm);
582
583 addFunction(vm, "debug", functionDebug, 1);
584 addFunction(vm, "describe", functionDescribe, 1);
585 addFunction(vm, "describeArray", functionDescribeArray, 1);
586 addFunction(vm, "print", functionPrint, 1);
587 addFunction(vm, "quit", functionQuit, 0);
588 addFunction(vm, "gc", functionGCAndSweep, 0);
589 addFunction(vm, "fullGC", functionFullGC, 0);
590 addFunction(vm, "edenGC", functionEdenGC, 0);
591 addFunction(vm, "gcHeapSize", functionHeapSize, 0);
592 addFunction(vm, "deleteAllCompiledCode", functionDeleteAllCompiledCode, 0);
593#ifndef NDEBUG
594 addFunction(vm, "dumpCallFrame", functionDumpCallFrame, 0);
595 addFunction(vm, "releaseExecutableMemory", functionReleaseExecutableMemory, 0);
596#endif
597 addFunction(vm, "version", functionVersion, 1);
598 addFunction(vm, "run", functionRun, 1);
599 addFunction(vm, "load", functionLoad, 1);
600 addFunction(vm, "readFile", functionReadFile, 1);
601 addFunction(vm, "checkSyntax", functionCheckSyntax, 1);
602 addFunction(vm, "jscStack", functionJSCStack, 1);
603 addFunction(vm, "readline", functionReadline, 0);
604 addFunction(vm, "preciseTime", functionPreciseTime, 0);
605 addFunction(vm, "neverInlineFunction", functionNeverInlineFunction, 1);
606 addFunction(vm, "noInline", functionNeverInlineFunction, 1);
607 addFunction(vm, "numberOfDFGCompiles", functionNumberOfDFGCompiles, 1);
608 addFunction(vm, "optimizeNextInvocation", functionOptimizeNextInvocation, 1);
609 addFunction(vm, "reoptimizationRetryCount", functionReoptimizationRetryCount, 1);
610 addFunction(vm, "transferArrayBuffer", functionTransferArrayBuffer, 1);
611#if ENABLE(SAMPLING_FLAGS)
612 addFunction(vm, "setSamplingFlags", functionSetSamplingFlags, 1);
613 addFunction(vm, "clearSamplingFlags", functionClearSamplingFlags, 1);
614#endif
615 addConstructableFunction(vm, "Root", functionCreateRoot, 0);
616 addConstructableFunction(vm, "Element", functionCreateElement, 1);
617 addFunction(vm, "getElement", functionGetElement, 1);
618 addFunction(vm, "setElementRoot", functionSetElementRoot, 2);
619
620 putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "DFGTrue"), 0, functionFalse1, DFGTrueIntrinsic, DontEnum | JSC::Function);
621 putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "OSRExit"), 0, functionUndefined1, OSRExitIntrinsic, DontEnum | JSC::Function);
622 putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "isFinalTier"), 0, functionFalse2, IsFinalTierIntrinsic, DontEnum | JSC::Function);
623 putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "predictInt32"), 0, functionUndefined2, SetInt32HeapPredictionIntrinsic, DontEnum | JSC::Function);
624 putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "isInt32"), 0, functionIsInt32, CheckInt32Intrinsic, DontEnum | JSC::Function);
625 putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "fiatInt52"), 0, functionIdentity, FiatInt52Intrinsic, DontEnum | JSC::Function);
626
627 addFunction(vm, "effectful42", functionEffectful42, 0);
628 addFunction(vm, "makeMasquerader", functionMakeMasquerader, 0);
629 addFunction(vm, "hasCustomProperties", functionHasCustomProperties, 0);
630
631 addFunction(vm, "createProxy", functionCreateProxy, 1);
632 addFunction(vm, "createRuntimeArray", functionCreateRuntimeArray, 0);
633
634 addFunction(vm, "createImpureGetter", functionCreateImpureGetter, 1);
635 addFunction(vm, "setImpureGetterDelegate", functionSetImpureGetterDelegate, 2);
636
637 addFunction(vm, "dumpTypesForAllVariables", functionDumpTypesForAllVariables , 0);
638 addFunction(vm, "findTypeForExpression", functionFindTypeForExpression, 2);
639 addFunction(vm, "returnTypeFor", functionReturnTypeFor, 1);
640
641 addFunction(vm, "dumpBasicBlockExecutionRanges", functionDumpBasicBlockExecutionRanges , 0);
642 addFunction(vm, "hasBasicBlockExecuted", functionHasBasicBlockExecuted, 2);
643
644 addFunction(vm, "enableExceptionFuzz", functionEnableExceptionFuzz, 0);
645
646 JSArray* array = constructEmptyArray(globalExec(), 0);
647 for (size_t i = 0; i < arguments.size(); ++i)
648 array->putDirectIndex(globalExec(), i, jsString(globalExec(), arguments[i]));
649 putDirect(vm, Identifier::fromString(globalExec(), "arguments"), array);
650
651 putDirect(vm, Identifier::fromString(globalExec(), "console"), jsUndefined());
652 }
653
654 void addFunction(VM& vm, const char* name, NativeFunction function, unsigned arguments)
655 {
656 Identifier identifier = Identifier::fromString(&vm, name);
657 putDirect(vm, identifier, JSFunction::create(vm, this, arguments, identifier.string(), function));
658 }
659
660 void addConstructableFunction(VM& vm, const char* name, NativeFunction function, unsigned arguments)
661 {
662 Identifier identifier = Identifier::fromString(&vm, name);
663 putDirect(vm, identifier, JSFunction::create(vm, this, arguments, identifier.string(), function, NoIntrinsic, function));
664 }
665};
666
667const ClassInfo GlobalObject::s_info = { "global", &JSGlobalObject::s_info, &globalObjectTable, CREATE_METHOD_TABLE(GlobalObject) };
668const GlobalObjectMethodTable GlobalObject::s_globalObjectMethodTable = { &allowsAccessFrom, &supportsProfiling, &supportsRichSourceInfo, &shouldInterruptScript, &javaScriptRuntimeFlags, 0, &shouldInterruptScriptBeforeTimeout };
669
670
671GlobalObject::GlobalObject(VM& vm, Structure* structure)
672 : JSGlobalObject(vm, structure, &s_globalObjectMethodTable)
673{
674}
675
676static inline String stringFromUTF(const char* utf8)
677{
678 return String::fromUTF8WithLatin1Fallback(utf8, strlen(utf8));
679}
680
681static inline SourceCode jscSource(const char* utf8, const String& filename)
682{
683 String str = stringFromUTF(utf8);
684 return makeSource(str, filename);
685}
686
687EncodedJSValue JSC_HOST_CALL functionPrint(ExecState* exec)
688{
689 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
690 if (i)
691 putchar(' ');
692
693 printf("%s", exec->uncheckedArgument(i).toString(exec)->value(exec).utf8().data());
694 }
695
696 putchar('\n');
697 fflush(stdout);
698 return JSValue::encode(jsUndefined());
699}
700
701#ifndef NDEBUG
702EncodedJSValue JSC_HOST_CALL functionDumpCallFrame(ExecState* exec)
703{
704 VMEntryFrame* topVMEntryFrame = exec->vm().topVMEntryFrame;
705 ExecState* callerFrame = exec->callerFrame(topVMEntryFrame);
706 if (callerFrame)
707 exec->vm().interpreter->dumpCallFrame(callerFrame);
708 return JSValue::encode(jsUndefined());
709}
710#endif
711
712EncodedJSValue JSC_HOST_CALL functionDebug(ExecState* exec)
713{
714 fprintf(stderr, "--> %s\n", exec->argument(0).toString(exec)->value(exec).utf8().data());
715 return JSValue::encode(jsUndefined());
716}
717
718EncodedJSValue JSC_HOST_CALL functionDescribe(ExecState* exec)
719{
720 if (exec->argumentCount() < 1)
721 return JSValue::encode(jsUndefined());
722 return JSValue::encode(jsString(exec, toString(exec->argument(0))));
723}
724
725EncodedJSValue JSC_HOST_CALL functionDescribeArray(ExecState* exec)
726{
727 if (exec->argumentCount() < 1)
728 return JSValue::encode(jsUndefined());
729 JSObject* object = jsDynamicCast<JSObject*>(exec->argument(0));
730 if (!object)
731 return JSValue::encode(jsNontrivialString(exec, ASCIILiteral("<not object>")));
732 return JSValue::encode(jsNontrivialString(exec, toString("<Public length: ", object->getArrayLength(), "; vector length: ", object->getVectorLength(), ">")));
733}
734
735class FunctionJSCStackFunctor {
736public:
737 FunctionJSCStackFunctor(StringBuilder& trace)
738 : m_trace(trace)
739 {
740 }
741
742 StackVisitor::Status operator()(StackVisitor& visitor)
743 {
744 m_trace.append(String::format(" %zu %s\n", visitor->index(), visitor->toString().utf8().data()));
745 return StackVisitor::Continue;
746 }
747
748private:
749 StringBuilder& m_trace;
750};
751
752EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState* exec)
753{
754 StringBuilder trace;
755 trace.appendLiteral("--> Stack trace:\n");
756
757 FunctionJSCStackFunctor functor(trace);
758 exec->iterate(functor);
759 fprintf(stderr, "%s", trace.toString().utf8().data());
760 return JSValue::encode(jsUndefined());
761}
762
763EncodedJSValue JSC_HOST_CALL functionCreateRoot(ExecState* exec)
764{
765 JSLockHolder lock(exec);
766 return JSValue::encode(Root::create(exec->vm(), exec->lexicalGlobalObject()));
767}
768
769EncodedJSValue JSC_HOST_CALL functionCreateElement(ExecState* exec)
770{
771 JSLockHolder lock(exec);
772 JSValue arg = exec->argument(0);
773 return JSValue::encode(Element::create(exec->vm(), exec->lexicalGlobalObject(), arg.isNull() ? nullptr : jsCast<Root*>(exec->argument(0))));
774}
775
776EncodedJSValue JSC_HOST_CALL functionGetElement(ExecState* exec)
777{
778 JSLockHolder lock(exec);
779 Element* result = jsCast<Root*>(exec->argument(0).asCell())->element();
780 return JSValue::encode(result ? result : jsUndefined());
781}
782
783EncodedJSValue JSC_HOST_CALL functionSetElementRoot(ExecState* exec)
784{
785 JSLockHolder lock(exec);
786 Element* element = jsCast<Element*>(exec->argument(0));
787 Root* root = jsCast<Root*>(exec->argument(1));
788 element->setRoot(root);
789 return JSValue::encode(jsUndefined());
790}
791
792EncodedJSValue JSC_HOST_CALL functionCreateProxy(ExecState* exec)
793{
794 JSLockHolder lock(exec);
795 JSValue target = exec->argument(0);
796 if (!target.isObject())
797 return JSValue::encode(jsUndefined());
798 JSObject* jsTarget = asObject(target.asCell());
799 Structure* structure = JSProxy::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsTarget->prototype());
800 JSProxy* proxy = JSProxy::create(exec->vm(), structure, jsTarget);
801 return JSValue::encode(proxy);
802}
803
804EncodedJSValue JSC_HOST_CALL functionCreateRuntimeArray(ExecState* exec)
805{
806 JSLockHolder lock(exec);
807 RuntimeArray* array = RuntimeArray::create(exec);
808 return JSValue::encode(array);
809}
810
811EncodedJSValue JSC_HOST_CALL functionCreateImpureGetter(ExecState* exec)
812{
813 JSLockHolder lock(exec);
814 JSValue target = exec->argument(0);
815 JSObject* delegate = nullptr;
816 if (target.isObject())
817 delegate = asObject(target.asCell());
818 Structure* structure = ImpureGetter::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsNull());
819 ImpureGetter* result = ImpureGetter::create(exec->vm(), structure, delegate);
820 return JSValue::encode(result);
821}
822
823EncodedJSValue JSC_HOST_CALL functionSetImpureGetterDelegate(ExecState* exec)
824{
825 JSLockHolder lock(exec);
826 JSValue base = exec->argument(0);
827 if (!base.isObject())
828 return JSValue::encode(jsUndefined());
829 JSValue delegate = exec->argument(1);
830 if (!delegate.isObject())
831 return JSValue::encode(jsUndefined());
832 ImpureGetter* impureGetter = jsCast<ImpureGetter*>(asObject(base.asCell()));
833 impureGetter->setDelegate(exec->vm(), asObject(delegate.asCell()));
834 return JSValue::encode(jsUndefined());
835}
836
837EncodedJSValue JSC_HOST_CALL functionGCAndSweep(ExecState* exec)
838{
839 JSLockHolder lock(exec);
840 exec->heap()->collectAllGarbage();
841 return JSValue::encode(jsNumber(exec->heap()->sizeAfterLastFullCollection()));
842}
843
844EncodedJSValue JSC_HOST_CALL functionFullGC(ExecState* exec)
845{
846 JSLockHolder lock(exec);
847 exec->heap()->collect(FullCollection);
848 return JSValue::encode(jsNumber(exec->heap()->sizeAfterLastFullCollection()));
849}
850
851EncodedJSValue JSC_HOST_CALL functionEdenGC(ExecState* exec)
852{
853 JSLockHolder lock(exec);
854 exec->heap()->collect(EdenCollection);
855 return JSValue::encode(jsNumber(exec->heap()->sizeAfterLastEdenCollection()));
856}
857
858EncodedJSValue JSC_HOST_CALL functionHeapSize(ExecState* exec)
859{
860 JSLockHolder lock(exec);
861 return JSValue::encode(jsNumber(exec->heap()->size()));
862}
863
864EncodedJSValue JSC_HOST_CALL functionDeleteAllCompiledCode(ExecState* exec)
865{
866 JSLockHolder lock(exec);
867 exec->heap()->deleteAllCompiledCode();
868 return JSValue::encode(jsUndefined());
869}
870
871#ifndef NDEBUG
872EncodedJSValue JSC_HOST_CALL functionReleaseExecutableMemory(ExecState* exec)
873{
874 JSLockHolder lock(exec);
875 exec->vm().releaseExecutableMemory();
876 return JSValue::encode(jsUndefined());
877}
878#endif
879
880EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*)
881{
882 // We need this function for compatibility with the Mozilla JS tests but for now
883 // we don't actually do any version-specific handling
884 return JSValue::encode(jsUndefined());
885}
886
887EncodedJSValue JSC_HOST_CALL functionRun(ExecState* exec)
888{
889 String fileName = exec->argument(0).toString(exec)->value(exec);
890 Vector<char> script;
891 if (!fillBufferWithContentsOfFile(fileName, script))
892 return JSValue::encode(exec->vm().throwException(exec, createError(exec, ASCIILiteral("Could not open file."))));
893
894 GlobalObject* globalObject = GlobalObject::create(exec->vm(), GlobalObject::createStructure(exec->vm(), jsNull()), Vector<String>());
895
896 JSArray* array = constructEmptyArray(globalObject->globalExec(), 0);
897 for (unsigned i = 1; i < exec->argumentCount(); ++i)
898 array->putDirectIndex(globalObject->globalExec(), i - 1, exec->uncheckedArgument(i));
899 globalObject->putDirect(
900 exec->vm(), Identifier::fromString(globalObject->globalExec(), "arguments"), array);
901
902 JSValue exception;
903 StopWatch stopWatch;
904 stopWatch.start();
905 evaluate(globalObject->globalExec(), jscSource(script.data(), fileName), JSValue(), &exception);
906 stopWatch.stop();
907
908 if (!!exception) {
909 exec->vm().throwException(globalObject->globalExec(), exception);
910 return JSValue::encode(jsUndefined());
911 }
912
913 return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
914}
915
916EncodedJSValue JSC_HOST_CALL functionLoad(ExecState* exec)
917{
918 String fileName = exec->argument(0).toString(exec)->value(exec);
919 Vector<char> script;
920 if (!fillBufferWithContentsOfFile(fileName, script))
921 return JSValue::encode(exec->vm().throwException(exec, createError(exec, ASCIILiteral("Could not open file."))));
922
923 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
924
925 JSValue evaluationException;
926 JSValue result = evaluate(globalObject->globalExec(), jscSource(script.data(), fileName), JSValue(), &evaluationException);
927 if (evaluationException)
928 exec->vm().throwException(exec, evaluationException);
929 return JSValue::encode(result);
930}
931
932EncodedJSValue JSC_HOST_CALL functionReadFile(ExecState* exec)
933{
934 String fileName = exec->argument(0).toString(exec)->value(exec);
935 Vector<char> script;
936 if (!fillBufferWithContentsOfFile(fileName, script))
937 return JSValue::encode(exec->vm().throwException(exec, createError(exec, ASCIILiteral("Could not open file."))));
938
939 return JSValue::encode(jsString(exec, stringFromUTF(script.data())));
940}
941
942EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState* exec)
943{
944 String fileName = exec->argument(0).toString(exec)->value(exec);
945 Vector<char> script;
946 if (!fillBufferWithContentsOfFile(fileName, script))
947 return JSValue::encode(exec->vm().throwException(exec, createError(exec, ASCIILiteral("Could not open file."))));
948
949 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
950
951 StopWatch stopWatch;
952 stopWatch.start();
953
954 JSValue syntaxException;
955 bool validSyntax = checkSyntax(globalObject->globalExec(), jscSource(script.data(), fileName), &syntaxException);
956 stopWatch.stop();
957
958 if (!validSyntax)
959 exec->vm().throwException(exec, syntaxException);
960 return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
961}
962
963#if ENABLE(SAMPLING_FLAGS)
964EncodedJSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState* exec)
965{
966 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
967 unsigned flag = static_cast<unsigned>(exec->uncheckedArgument(i).toNumber(exec));
968 if ((flag >= 1) && (flag <= 32))
969 SamplingFlags::setFlag(flag);
970 }
971 return JSValue::encode(jsNull());
972}
973
974EncodedJSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState* exec)
975{
976 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
977 unsigned flag = static_cast<unsigned>(exec->uncheckedArgument(i).toNumber(exec));
978 if ((flag >= 1) && (flag <= 32))
979 SamplingFlags::clearFlag(flag);
980 }
981 return JSValue::encode(jsNull());
982}
983#endif
984
985EncodedJSValue JSC_HOST_CALL functionReadline(ExecState* exec)
986{
987 Vector<char, 256> line;
988 int c;
989 while ((c = getchar()) != EOF) {
990 // FIXME: Should we also break on \r?
991 if (c == '\n')
992 break;
993 line.append(c);
994 }
995 line.append('\0');
996 return JSValue::encode(jsString(exec, line.data()));
997}
998
999EncodedJSValue JSC_HOST_CALL functionPreciseTime(ExecState*)
1000{
1001 return JSValue::encode(jsNumber(currentTime()));
1002}
1003
1004EncodedJSValue JSC_HOST_CALL functionNeverInlineFunction(ExecState* exec)
1005{
1006 return JSValue::encode(setNeverInline(exec));
1007}
1008
1009EncodedJSValue JSC_HOST_CALL functionOptimizeNextInvocation(ExecState* exec)
1010{
1011 return JSValue::encode(optimizeNextInvocation(exec));
1012}
1013
1014EncodedJSValue JSC_HOST_CALL functionNumberOfDFGCompiles(ExecState* exec)
1015{
1016 return JSValue::encode(numberOfDFGCompiles(exec));
1017}
1018
1019EncodedJSValue JSC_HOST_CALL functionReoptimizationRetryCount(ExecState* exec)
1020{
1021 if (exec->argumentCount() < 1)
1022 return JSValue::encode(jsUndefined());
1023
1024 CodeBlock* block = getSomeBaselineCodeBlockForFunction(exec->argument(0));
1025 if (!block)
1026 return JSValue::encode(jsNumber(0));
1027
1028 return JSValue::encode(jsNumber(block->reoptimizationRetryCounter()));
1029}
1030
1031EncodedJSValue JSC_HOST_CALL functionTransferArrayBuffer(ExecState* exec)
1032{
1033 if (exec->argumentCount() < 1)
1034 return JSValue::encode(exec->vm().throwException(exec, createError(exec, ASCIILiteral("Not enough arguments"))));
1035
1036 JSArrayBuffer* buffer = jsDynamicCast<JSArrayBuffer*>(exec->argument(0));
1037 if (!buffer)
1038 return JSValue::encode(exec->vm().throwException(exec, createError(exec, ASCIILiteral("Expected an array buffer"))));
1039
1040 ArrayBufferContents dummyContents;
1041 buffer->impl()->transfer(dummyContents);
1042
1043 return JSValue::encode(jsUndefined());
1044}
1045
1046EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*)
1047{
1048 jscExit(EXIT_SUCCESS);
1049
1050#if COMPILER(MSVC)
1051 // Without this, Visual Studio will complain that this method does not return a value.
1052 return JSValue::encode(jsUndefined());
1053#endif
1054}
1055
1056EncodedJSValue JSC_HOST_CALL functionFalse1(ExecState*) { return JSValue::encode(jsBoolean(false)); }
1057EncodedJSValue JSC_HOST_CALL functionFalse2(ExecState*) { return JSValue::encode(jsBoolean(false)); }
1058
1059EncodedJSValue JSC_HOST_CALL functionUndefined1(ExecState*) { return JSValue::encode(jsUndefined()); }
1060EncodedJSValue JSC_HOST_CALL functionUndefined2(ExecState*) { return JSValue::encode(jsUndefined()); }
1061EncodedJSValue JSC_HOST_CALL functionIsInt32(ExecState* exec)
1062{
1063 for (size_t i = 0; i < exec->argumentCount(); ++i) {
1064 if (!exec->argument(i).isInt32())
1065 return JSValue::encode(jsBoolean(false));
1066 }
1067 return JSValue::encode(jsBoolean(true));
1068}
1069
1070EncodedJSValue JSC_HOST_CALL functionIdentity(ExecState* exec) { return JSValue::encode(exec->argument(0)); }
1071
1072EncodedJSValue JSC_HOST_CALL functionEffectful42(ExecState*)
1073{
1074 return JSValue::encode(jsNumber(42));
1075}
1076
1077EncodedJSValue JSC_HOST_CALL functionMakeMasquerader(ExecState* exec)
1078{
1079 return JSValue::encode(Masquerader::create(exec->vm(), exec->lexicalGlobalObject()));
1080}
1081
1082EncodedJSValue JSC_HOST_CALL functionHasCustomProperties(ExecState* exec)
1083{
1084 JSValue value = exec->argument(0);
1085 if (value.isObject())
1086 return JSValue::encode(jsBoolean(asObject(value)->hasCustomProperties()));
1087 return JSValue::encode(jsBoolean(false));
1088}
1089
1090EncodedJSValue JSC_HOST_CALL functionDumpTypesForAllVariables(ExecState* exec)
1091{
1092 exec->vm().dumpTypeProfilerData();
1093 return JSValue::encode(jsUndefined());
1094}
1095
1096EncodedJSValue JSC_HOST_CALL functionFindTypeForExpression(ExecState* exec)
1097{
1098 RELEASE_ASSERT(exec->vm().typeProfiler());
1099 exec->vm().typeProfilerLog()->processLogEntries(ASCIILiteral("jsc Testing API: functionFindTypeForExpression"));
1100
1101 JSValue functionValue = exec->argument(0);
1102 RELEASE_ASSERT(functionValue.isFunction());
1103 FunctionExecutable* executable = (jsDynamicCast<JSFunction*>(functionValue.asCell()->getObject()))->jsExecutable();
1104
1105 RELEASE_ASSERT(exec->argument(1).isString());
1106 String substring = exec->argument(1).getString(exec);
1107 String sourceCodeText = executable->source().toString();
1108 unsigned offset = static_cast<unsigned>(sourceCodeText.find(substring) + executable->source().startOffset());
1109
1110 String jsonString = exec->vm().typeProfiler()->typeInformationForExpressionAtOffset(TypeProfilerSearchDescriptorNormal, offset, executable->sourceID(), exec->vm());
1111 return JSValue::encode(JSONParse(exec, jsonString));
1112}
1113
1114EncodedJSValue JSC_HOST_CALL functionReturnTypeFor(ExecState* exec)
1115{
1116 RELEASE_ASSERT(exec->vm().typeProfiler());
1117 exec->vm().typeProfilerLog()->processLogEntries(ASCIILiteral("jsc Testing API: functionReturnTypeFor"));
1118
1119 JSValue functionValue = exec->argument(0);
1120 RELEASE_ASSERT(functionValue.isFunction());
1121 FunctionExecutable* executable = (jsDynamicCast<JSFunction*>(functionValue.asCell()->getObject()))->jsExecutable();
1122
1123 unsigned offset = executable->source().startOffset();
1124 String jsonString = exec->vm().typeProfiler()->typeInformationForExpressionAtOffset(TypeProfilerSearchDescriptorFunctionReturn, offset, executable->sourceID(), exec->vm());
1125 return JSValue::encode(JSONParse(exec, jsonString));
1126}
1127
1128EncodedJSValue JSC_HOST_CALL functionDumpBasicBlockExecutionRanges(ExecState* exec)
1129{
1130 RELEASE_ASSERT(exec->vm().controlFlowProfiler());
1131 exec->vm().controlFlowProfiler()->dumpData();
1132 return JSValue::encode(jsUndefined());
1133}
1134
1135EncodedJSValue JSC_HOST_CALL functionHasBasicBlockExecuted(ExecState* exec)
1136{
1137 RELEASE_ASSERT(exec->vm().controlFlowProfiler());
1138
1139 JSValue functionValue = exec->argument(0);
1140 RELEASE_ASSERT(functionValue.isFunction());
1141 FunctionExecutable* executable = (jsDynamicCast<JSFunction*>(functionValue.asCell()->getObject()))->jsExecutable();
1142
1143 RELEASE_ASSERT(exec->argument(1).isString());
1144 String substring = exec->argument(1).getString(exec);
1145 String sourceCodeText = executable->source().toString();
1146 RELEASE_ASSERT(sourceCodeText.contains(substring));
1147 int offset = sourceCodeText.find(substring) + executable->source().startOffset();
1148
1149 bool hasExecuted = exec->vm().controlFlowProfiler()->hasBasicBlockAtTextOffsetBeenExecuted(offset, executable->sourceID(), exec->vm());
1150 return JSValue::encode(jsBoolean(hasExecuted));
1151}
1152
1153EncodedJSValue JSC_HOST_CALL functionEnableExceptionFuzz(ExecState*)
1154{
1155 Options::enableExceptionFuzz() = true;
1156 return JSValue::encode(jsUndefined());
1157}
1158
1159// Use SEH for Release builds only to get rid of the crash report dialog
1160// (luckily the same tests fail in Release and Debug builds so far). Need to
1161// be in a separate main function because the jscmain function requires object
1162// unwinding.
1163
1164#if COMPILER(MSVC) && !defined(_DEBUG)
1165#define TRY __try {
1166#define EXCEPT(x) } __except (EXCEPTION_EXECUTE_HANDLER) { x; }
1167#else
1168#define TRY
1169#define EXCEPT(x)
1170#endif
1171
1172int jscmain(int argc, char** argv);
1173
1174static double s_desiredTimeout;
1175
1176static NO_RETURN_DUE_TO_CRASH void timeoutThreadMain(void*)
1177{
1178 auto timeout = std::chrono::microseconds(static_cast<std::chrono::microseconds::rep>(s_desiredTimeout * 1000000));
1179 std::this_thread::sleep_for(timeout);
1180
1181 dataLog("Timed out after ", s_desiredTimeout, " seconds!\n");
1182 CRASH();
1183}
1184
1185int main(int argc, char** argv)
1186{
1187#if PLATFORM(IOS) && CPU(ARM_THUMB2)
1188 // Enabled IEEE754 denormal support.
1189 fenv_t env;
1190 fegetenv( &env );
1191 env.__fpscr &= ~0x01000000u;
1192 fesetenv( &env );
1193#endif
1194
1195#if OS(WINDOWS) && (defined(_M_X64) || defined(__x86_64__))
1196 // The VS2013 runtime has a bug where it mis-detects AVX-capable processors
1197 // if the feature has been disabled in firmware. This causes us to crash
1198 // in some of the math functions. For now, we disable those optimizations
1199 // because Microsoft is not going to fix the problem in VS2013.
1200 // FIXME: http://webkit.org/b/141449: Remove this workaround when we switch to VS2015+.
1201 _set_FMA3_enable(0);
1202
1203 // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for
1204 // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the
1205 // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>.
1206 ::SetErrorMode(0);
1207
1208#if defined(_DEBUG)
1209 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
1210 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
1211 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
1212 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
1213 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
1214 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
1215#endif
1216
1217 timeBeginPeriod(1);
1218#endif
1219
1220#if PLATFORM(EFL)
1221 ecore_init();
1222#endif
1223
1224 // Initialize JSC before getting VM.
1225#if ENABLE(SAMPLING_REGIONS)
1226 WTF::initializeMainThread();
1227#endif
1228 JSC::initializeThreading();
1229
1230 if (char* timeoutString = getenv("JSC_timeout")) {
1231 if (sscanf(timeoutString, "%lf", &s_desiredTimeout) != 1) {
1232 dataLog(
1233 "WARNING: timeout string is malformed, got ", timeoutString,
1234 " but expected a number. Not using a timeout.\n");
1235 } else
1236 createThread(timeoutThreadMain, 0, "jsc Timeout Thread");
1237 }
1238
1239#if PLATFORM(IOS)
1240 Options::crashIfCantAllocateJITMemory() = true;
1241#endif
1242
1243 // We can't use destructors in the following code because it uses Windows
1244 // Structured Exception Handling
1245 int res = 0;
1246 TRY
1247 res = jscmain(argc, argv);
1248 EXCEPT(res = 3)
1249 if (Options::logHeapStatisticsAtExit())
1250 HeapStatistics::reportSuccess();
1251
1252#if PLATFORM(EFL)
1253 ecore_shutdown();
1254#endif
1255
1256 jscExit(res);
1257}
1258
1259static bool runWithScripts(GlobalObject* globalObject, const Vector<Script>& scripts, bool dump)
1260{
1261 const char* script;
1262 String fileName;
1263 Vector<char> scriptBuffer;
1264
1265 if (dump)
1266 JSC::Options::dumpGeneratedBytecodes() = true;
1267
1268 VM& vm = globalObject->vm();
1269
1270#if ENABLE(SAMPLING_FLAGS)
1271 SamplingFlags::start();
1272#endif
1273
1274 bool success = true;
1275 for (size_t i = 0; i < scripts.size(); i++) {
1276 if (scripts[i].isFile) {
1277 fileName = scripts[i].argument;
1278 if (!fillBufferWithContentsOfFile(fileName, scriptBuffer))
1279 return false; // fail early so we can catch missing files
1280 script = scriptBuffer.data();
1281 } else {
1282 script = scripts[i].argument;
1283 fileName = ASCIILiteral("[Command Line]");
1284 }
1285
1286 vm.startSampling();
1287
1288 JSValue evaluationException;
1289 JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(script, fileName), JSValue(), &evaluationException);
1290 success = success && !evaluationException;
1291 if (dump && !evaluationException)
1292 printf("End: %s\n", returnValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
1293 if (evaluationException) {
1294 printf("Exception: %s\n", evaluationException.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
1295 Identifier stackID = Identifier::fromString(globalObject->globalExec(), "stack");
1296 JSValue stackValue = evaluationException.get(globalObject->globalExec(), stackID);
1297 if (!stackValue.isUndefinedOrNull())
1298 printf("%s\n", stackValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
1299 }
1300
1301 vm.stopSampling();
1302 globalObject->globalExec()->clearException();
1303 }
1304
1305#if ENABLE(SAMPLING_FLAGS)
1306 SamplingFlags::stop();
1307#endif
1308#if ENABLE(SAMPLING_REGIONS)
1309 SamplingRegion::dump();
1310#endif
1311 vm.dumpSampleData(globalObject->globalExec());
1312#if ENABLE(SAMPLING_COUNTERS)
1313 AbstractSamplingCounter::dump();
1314#endif
1315#if ENABLE(REGEXP_TRACING)
1316 vm.dumpRegExpTrace();
1317#endif
1318 return success;
1319}
1320
1321#define RUNNING_FROM_XCODE 0
1322
1323static void runInteractive(GlobalObject* globalObject)
1324{
1325 String interpreterName(ASCIILiteral("Interpreter"));
1326
1327 bool shouldQuit = false;
1328 while (!shouldQuit) {
1329#if HAVE(READLINE) && !RUNNING_FROM_XCODE
1330 ParserError error;
1331 String source;
1332 do {
1333 error = ParserError();
1334 char* line = readline(source.isEmpty() ? interactivePrompt : "... ");
1335 shouldQuit = !line;
1336 if (!line)
1337 break;
1338 source = source + line;
1339 source = source + '\n';
1340 checkSyntax(globalObject->vm(), makeSource(source, interpreterName), error);
1341 if (!line[0])
1342 break;
1343 add_history(line);
1344 } while (error.syntaxErrorType() == ParserError::SyntaxErrorRecoverable);
1345
1346 if (error.isValid()) {
1347 printf("%s:%d\n", error.message().utf8().data(), error.line());
1348 continue;
1349 }
1350
1351
1352 JSValue evaluationException;
1353 JSValue returnValue = evaluate(globalObject->globalExec(), makeSource(source, interpreterName), JSValue(), &evaluationException);
1354#else
1355 printf("%s", interactivePrompt);
1356 Vector<char, 256> line;
1357 int c;
1358 while ((c = getchar()) != EOF) {
1359 // FIXME: Should we also break on \r?
1360 if (c == '\n')
1361 break;
1362 line.append(c);
1363 }
1364 if (line.isEmpty())
1365 break;
1366 line.append('\0');
1367
1368 JSValue evaluationException;
1369 JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(line.data(), interpreterName), JSValue(), &evaluationException);
1370#endif
1371 if (evaluationException)
1372 printf("Exception: %s\n", evaluationException.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
1373 else
1374 printf("%s\n", returnValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
1375
1376 globalObject->globalExec()->clearException();
1377 }
1378 printf("\n");
1379}
1380
1381static NO_RETURN void printUsageStatement(bool help = false)
1382{
1383 fprintf(stderr, "Usage: jsc [options] [files] [-- arguments]\n");
1384 fprintf(stderr, " -d Dumps bytecode (debug builds only)\n");
1385 fprintf(stderr, " -e Evaluate argument as script code\n");
1386 fprintf(stderr, " -f Specifies a source file (deprecated)\n");
1387 fprintf(stderr, " -h|--help Prints this help message\n");
1388 fprintf(stderr, " -i Enables interactive mode (default if no files are specified)\n");
1389#if HAVE(SIGNAL_H)
1390 fprintf(stderr, " -s Installs signal handlers that exit on a crash (Unix platforms only)\n");
1391#endif
1392 fprintf(stderr, " -p <file> Outputs profiling data to a file\n");
1393 fprintf(stderr, " -x Output exit code before terminating\n");
1394 fprintf(stderr, "\n");
1395 fprintf(stderr, " --options Dumps all JSC VM options and exits\n");
1396 fprintf(stderr, " --dumpOptions Dumps all JSC VM options before continuing\n");
1397 fprintf(stderr, " --<jsc VM option>=<value> Sets the specified JSC VM option\n");
1398 fprintf(stderr, "\n");
1399
1400 jscExit(help ? EXIT_SUCCESS : EXIT_FAILURE);
1401}
1402
1403void CommandLine::parseArguments(int argc, char** argv)
1404{
1405 int i = 1;
1406 bool needToDumpOptions = false;
1407 bool needToExit = false;
1408
1409 for (; i < argc; ++i) {
1410 const char* arg = argv[i];
1411 if (!strcmp(arg, "-f")) {
1412 if (++i == argc)
1413 printUsageStatement();
1414 m_scripts.append(Script(true, argv[i]));
1415 continue;
1416 }
1417 if (!strcmp(arg, "-e")) {
1418 if (++i == argc)
1419 printUsageStatement();
1420 m_scripts.append(Script(false, argv[i]));
1421 continue;
1422 }
1423 if (!strcmp(arg, "-i")) {
1424 m_interactive = true;
1425 continue;
1426 }
1427 if (!strcmp(arg, "-d")) {
1428 m_dump = true;
1429 continue;
1430 }
1431 if (!strcmp(arg, "-p")) {
1432 if (++i == argc)
1433 printUsageStatement();
1434 m_profile = true;
1435 m_profilerOutput = argv[i];
1436 continue;
1437 }
1438 if (!strcmp(arg, "-s")) {
1439#if HAVE(SIGNAL_H)
1440 signal(SIGILL, _exit);
1441 signal(SIGFPE, _exit);
1442 signal(SIGBUS, _exit);
1443 signal(SIGSEGV, _exit);
1444#endif
1445 continue;
1446 }
1447 if (!strcmp(arg, "-x")) {
1448 m_exitCode = true;
1449 continue;
1450 }
1451 if (!strcmp(arg, "--")) {
1452 ++i;
1453 break;
1454 }
1455 if (!strcmp(arg, "-h") || !strcmp(arg, "--help"))
1456 printUsageStatement(true);
1457
1458 if (!strcmp(arg, "--options")) {
1459 needToDumpOptions = true;
1460 needToExit = true;
1461 continue;
1462 }
1463 if (!strcmp(arg, "--dumpOptions")) {
1464 needToDumpOptions = true;
1465 continue;
1466 }
1467
1468 // See if the -- option is a JSC VM option.
1469 // NOTE: At this point, we know that the arg starts with "--". Skip it.
1470 if (JSC::Options::setOption(&arg[2])) {
1471 // The arg was recognized as a VM option and has been parsed.
1472 continue; // Just continue with the next arg.
1473 }
1474
1475 // This arg is not recognized by the VM nor by jsc. Pass it on to the
1476 // script.
1477 m_scripts.append(Script(true, argv[i]));
1478 }
1479
1480 if (m_scripts.isEmpty())
1481 m_interactive = true;
1482
1483 for (; i < argc; ++i)
1484 m_arguments.append(argv[i]);
1485
1486 if (needToDumpOptions)
1487 JSC::Options::dumpAllOptions(JSC::Options::DumpLevel::Verbose, "All JSC runtime options:", stderr);
1488 JSC::Options::ensureOptionsAreCoherent();
1489 if (needToExit)
1490 jscExit(EXIT_SUCCESS);
1491}
1492
1493int jscmain(int argc, char** argv)
1494{
1495 // Note that the options parsing can affect VM creation, and thus
1496 // comes first.
1497 CommandLine options(argc, argv);
1498 VM* vm = VM::create(LargeHeap).leakRef();
1499 int result;
1500 {
1501 JSLockHolder locker(vm);
1502
1503 if (options.m_profile && !vm->m_perBytecodeProfiler)
1504 vm->m_perBytecodeProfiler = std::make_unique<Profiler::Database>(*vm);
1505
1506 GlobalObject* globalObject = GlobalObject::create(*vm, GlobalObject::createStructure(*vm, jsNull()), options.m_arguments);
1507 bool success = runWithScripts(globalObject, options.m_scripts, options.m_dump);
1508 if (options.m_interactive && success)
1509 runInteractive(globalObject);
1510
1511 result = success ? 0 : 3;
1512
1513 if (options.m_exitCode)
1514 printf("jsc exiting %d\n", result);
1515
1516 if (options.m_profile) {
1517 if (!vm->m_perBytecodeProfiler->save(options.m_profilerOutput.utf8().data()))
1518 fprintf(stderr, "could not save profiler output.\n");
1519 }
1520
1521#if ENABLE(JIT)
1522 if (Options::enableExceptionFuzz())
1523 printf("JSC EXCEPTION FUZZ: encountered %u checks.\n", numberOfExceptionFuzzChecks());
1524 bool fireAtEnabled =
1525 Options::fireExecutableAllocationFuzzAt() || Options::fireExecutableAllocationFuzzAtOrAfter();
1526 if (Options::enableExecutableAllocationFuzz() && (!fireAtEnabled || Options::verboseExecutableAllocationFuzz()))
1527 printf("JSC EXECUTABLE ALLOCATION FUZZ: encountered %u checks.\n", numberOfExecutableAllocationFuzzChecks());
1528#endif
1529 }
1530
1531 return result;
1532}
1533
1534static bool fillBufferWithContentsOfFile(const String& fileName, Vector<char>& buffer)
1535{
1536 FILE* f = fopen(fileName.utf8().data(), "r");
1537 if (!f) {
1538 fprintf(stderr, "Could not open file: %s\n", fileName.utf8().data());
1539 return false;
1540 }
1541
1542 size_t bufferSize = 0;
1543 size_t bufferCapacity = 1024;
1544
1545 buffer.resize(bufferCapacity);
1546
1547 while (!feof(f) && !ferror(f)) {
1548 bufferSize += fread(buffer.data() + bufferSize, 1, bufferCapacity - bufferSize, f);
1549 if (bufferSize == bufferCapacity) { // guarantees space for trailing '\0'
1550 bufferCapacity *= 2;
1551 buffer.resize(bufferCapacity);
1552 }
1553 }
1554 fclose(f);
1555 buffer[bufferSize] = '\0';
1556
1557 if (buffer[0] == '#' && buffer[1] == '!')
1558 buffer[0] = buffer[1] = '/';
1559
1560 return true;
1561}
1562
1563#if OS(WINDOWS)
1564extern "C" __declspec(dllexport) int WINAPI dllLauncherEntryPoint(int argc, const char* argv[])
1565{
1566 return main(argc, const_cast<char**>(argv));
1567}
1568#endif
Note: See TracBrowser for help on using the repository browser.