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

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

GC has trouble with pathologically large array allocations
https://bugs.webkit.org/show_bug.cgi?id=144609

Reviewed by Mark Lam.

  • heap/Heap.cpp:

(JSC::Heap::updateObjectCounts): Make this code less confusing.

  • heap/SlotVisitorInlines.h:

(JSC::SlotVisitor::copyLater): The early return for isOversize() was the bug. We still need to report these bytes as live. Otherwise the GC doesn't know that it owns this memory.

  • jsc.cpp: Add size measuring hooks to write the largeish test.

(GlobalObject::finishCreation):
(functionGCAndSweep):
(functionFullGC):
(functionEdenGC):
(functionHeapSize):

  • tests/stress/new-array-storage-array-with-size.js: Fix this so that it actually allocates ArrayStorage arrays and tests the thing it was supposed to test.
  • tests/stress/new-largeish-contiguous-array-with-size.js: Added. This tests what the other test accidentally started testing, but does so without running your system out of memory.

(foo):
(test):

  • Property svn:eol-style set to native
File size: 53.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 "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 functionEffectful42(ExecState*);
474static EncodedJSValue JSC_HOST_CALL functionIdentity(ExecState*);
475static EncodedJSValue JSC_HOST_CALL functionMakeMasquerader(ExecState*);
476static EncodedJSValue JSC_HOST_CALL functionHasCustomProperties(ExecState*);
477static EncodedJSValue JSC_HOST_CALL functionDumpTypesForAllVariables(ExecState*);
478static EncodedJSValue JSC_HOST_CALL functionFindTypeForExpression(ExecState*);
479static EncodedJSValue JSC_HOST_CALL functionReturnTypeFor(ExecState*);
480static EncodedJSValue JSC_HOST_CALL functionDumpBasicBlockExecutionRanges(ExecState*);
481static EncodedJSValue JSC_HOST_CALL functionHasBasicBlockExecuted(ExecState*);
482
483#if ENABLE(SAMPLING_FLAGS)
484static EncodedJSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState*);
485static EncodedJSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState*);
486#endif
487
488struct Script {
489 bool isFile;
490 char* argument;
491
492 Script(bool isFile, char *argument)
493 : isFile(isFile)
494 , argument(argument)
495 {
496 }
497};
498
499class CommandLine {
500public:
501 CommandLine(int argc, char** argv)
502 : m_interactive(false)
503 , m_dump(false)
504 , m_exitCode(false)
505 , m_profile(false)
506 {
507 parseArguments(argc, argv);
508 }
509
510 bool m_interactive;
511 bool m_dump;
512 bool m_exitCode;
513 Vector<Script> m_scripts;
514 Vector<String> m_arguments;
515 bool m_profile;
516 String m_profilerOutput;
517
518 void parseArguments(int, char**);
519};
520
521static const char interactivePrompt[] = ">>> ";
522
523class StopWatch {
524public:
525 void start();
526 void stop();
527 long getElapsedMS(); // call stop() first
528
529private:
530 double m_startTime;
531 double m_stopTime;
532};
533
534void StopWatch::start()
535{
536 m_startTime = monotonicallyIncreasingTime();
537}
538
539void StopWatch::stop()
540{
541 m_stopTime = monotonicallyIncreasingTime();
542}
543
544long StopWatch::getElapsedMS()
545{
546 return static_cast<long>((m_stopTime - m_startTime) * 1000);
547}
548
549class GlobalObject : public JSGlobalObject {
550private:
551 GlobalObject(VM&, Structure*);
552
553public:
554 typedef JSGlobalObject Base;
555
556 static GlobalObject* create(VM& vm, Structure* structure, const Vector<String>& arguments)
557 {
558 GlobalObject* object = new (NotNull, allocateCell<GlobalObject>(vm.heap)) GlobalObject(vm, structure);
559 object->finishCreation(vm, arguments);
560 vm.heap.addFinalizer(object, destroy);
561 return object;
562 }
563
564 static const bool needsDestruction = false;
565
566 DECLARE_INFO;
567 static const GlobalObjectMethodTable s_globalObjectMethodTable;
568
569 static Structure* createStructure(VM& vm, JSValue prototype)
570 {
571 return Structure::create(vm, 0, prototype, TypeInfo(GlobalObjectType, StructureFlags), info());
572 }
573
574 static RuntimeFlags javaScriptRuntimeFlags(const JSGlobalObject*) { return RuntimeFlags::createAllEnabled(); }
575
576protected:
577 void finishCreation(VM& vm, const Vector<String>& arguments)
578 {
579 Base::finishCreation(vm);
580
581 addFunction(vm, "debug", functionDebug, 1);
582 addFunction(vm, "describe", functionDescribe, 1);
583 addFunction(vm, "describeArray", functionDescribeArray, 1);
584 addFunction(vm, "print", functionPrint, 1);
585 addFunction(vm, "quit", functionQuit, 0);
586 addFunction(vm, "gc", functionGCAndSweep, 0);
587 addFunction(vm, "fullGC", functionFullGC, 0);
588 addFunction(vm, "edenGC", functionEdenGC, 0);
589 addFunction(vm, "gcHeapSize", functionHeapSize, 0);
590 addFunction(vm, "deleteAllCompiledCode", functionDeleteAllCompiledCode, 0);
591#ifndef NDEBUG
592 addFunction(vm, "dumpCallFrame", functionDumpCallFrame, 0);
593 addFunction(vm, "releaseExecutableMemory", functionReleaseExecutableMemory, 0);
594#endif
595 addFunction(vm, "version", functionVersion, 1);
596 addFunction(vm, "run", functionRun, 1);
597 addFunction(vm, "load", functionLoad, 1);
598 addFunction(vm, "readFile", functionReadFile, 1);
599 addFunction(vm, "checkSyntax", functionCheckSyntax, 1);
600 addFunction(vm, "jscStack", functionJSCStack, 1);
601 addFunction(vm, "readline", functionReadline, 0);
602 addFunction(vm, "preciseTime", functionPreciseTime, 0);
603 addFunction(vm, "neverInlineFunction", functionNeverInlineFunction, 1);
604 addFunction(vm, "noInline", functionNeverInlineFunction, 1);
605 addFunction(vm, "numberOfDFGCompiles", functionNumberOfDFGCompiles, 1);
606 addFunction(vm, "optimizeNextInvocation", functionOptimizeNextInvocation, 1);
607 addFunction(vm, "reoptimizationRetryCount", functionReoptimizationRetryCount, 1);
608 addFunction(vm, "transferArrayBuffer", functionTransferArrayBuffer, 1);
609#if ENABLE(SAMPLING_FLAGS)
610 addFunction(vm, "setSamplingFlags", functionSetSamplingFlags, 1);
611 addFunction(vm, "clearSamplingFlags", functionClearSamplingFlags, 1);
612#endif
613 addConstructableFunction(vm, "Root", functionCreateRoot, 0);
614 addConstructableFunction(vm, "Element", functionCreateElement, 1);
615 addFunction(vm, "getElement", functionGetElement, 1);
616 addFunction(vm, "setElementRoot", functionSetElementRoot, 2);
617
618 putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "DFGTrue"), 0, functionFalse1, DFGTrueIntrinsic, DontEnum | JSC::Function);
619 putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "OSRExit"), 0, functionUndefined1, OSRExitIntrinsic, DontEnum | JSC::Function);
620 putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "isFinalTier"), 0, functionFalse2, IsFinalTierIntrinsic, DontEnum | JSC::Function);
621 putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "predictInt32"), 0, functionUndefined2, SetInt32HeapPredictionIntrinsic, DontEnum | JSC::Function);
622 putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "fiatInt52"), 0, functionIdentity, FiatInt52Intrinsic, DontEnum | JSC::Function);
623
624 addFunction(vm, "effectful42", functionEffectful42, 0);
625 addFunction(vm, "makeMasquerader", functionMakeMasquerader, 0);
626 addFunction(vm, "hasCustomProperties", functionHasCustomProperties, 0);
627
628 addFunction(vm, "createProxy", functionCreateProxy, 1);
629 addFunction(vm, "createRuntimeArray", functionCreateRuntimeArray, 0);
630
631 addFunction(vm, "createImpureGetter", functionCreateImpureGetter, 1);
632 addFunction(vm, "setImpureGetterDelegate", functionSetImpureGetterDelegate, 2);
633
634 addFunction(vm, "dumpTypesForAllVariables", functionDumpTypesForAllVariables , 0);
635 addFunction(vm, "findTypeForExpression", functionFindTypeForExpression, 2);
636 addFunction(vm, "returnTypeFor", functionReturnTypeFor, 1);
637
638 addFunction(vm, "dumpBasicBlockExecutionRanges", functionDumpBasicBlockExecutionRanges , 0);
639 addFunction(vm, "hasBasicBlockExecuted", functionHasBasicBlockExecuted, 2);
640
641 JSArray* array = constructEmptyArray(globalExec(), 0);
642 for (size_t i = 0; i < arguments.size(); ++i)
643 array->putDirectIndex(globalExec(), i, jsString(globalExec(), arguments[i]));
644 putDirect(vm, Identifier::fromString(globalExec(), "arguments"), array);
645
646 putDirect(vm, Identifier::fromString(globalExec(), "console"), jsUndefined());
647 }
648
649 void addFunction(VM& vm, const char* name, NativeFunction function, unsigned arguments)
650 {
651 Identifier identifier = Identifier::fromString(&vm, name);
652 putDirect(vm, identifier, JSFunction::create(vm, this, arguments, identifier.string(), function));
653 }
654
655 void addConstructableFunction(VM& vm, const char* name, NativeFunction function, unsigned arguments)
656 {
657 Identifier identifier = Identifier::fromString(&vm, name);
658 putDirect(vm, identifier, JSFunction::create(vm, this, arguments, identifier.string(), function, NoIntrinsic, function));
659 }
660};
661
662const ClassInfo GlobalObject::s_info = { "global", &JSGlobalObject::s_info, &globalObjectTable, CREATE_METHOD_TABLE(GlobalObject) };
663const GlobalObjectMethodTable GlobalObject::s_globalObjectMethodTable = { &allowsAccessFrom, &supportsProfiling, &supportsRichSourceInfo, &shouldInterruptScript, &javaScriptRuntimeFlags, 0, &shouldInterruptScriptBeforeTimeout };
664
665
666GlobalObject::GlobalObject(VM& vm, Structure* structure)
667 : JSGlobalObject(vm, structure, &s_globalObjectMethodTable)
668{
669}
670
671static inline String stringFromUTF(const char* utf8)
672{
673 return String::fromUTF8WithLatin1Fallback(utf8, strlen(utf8));
674}
675
676static inline SourceCode jscSource(const char* utf8, const String& filename)
677{
678 String str = stringFromUTF(utf8);
679 return makeSource(str, filename);
680}
681
682EncodedJSValue JSC_HOST_CALL functionPrint(ExecState* exec)
683{
684 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
685 if (i)
686 putchar(' ');
687
688 printf("%s", exec->uncheckedArgument(i).toString(exec)->value(exec).utf8().data());
689 }
690
691 putchar('\n');
692 fflush(stdout);
693 return JSValue::encode(jsUndefined());
694}
695
696#ifndef NDEBUG
697EncodedJSValue JSC_HOST_CALL functionDumpCallFrame(ExecState* exec)
698{
699 VMEntryFrame* topVMEntryFrame = exec->vm().topVMEntryFrame;
700 ExecState* callerFrame = exec->callerFrame(topVMEntryFrame);
701 if (callerFrame)
702 exec->vm().interpreter->dumpCallFrame(callerFrame);
703 return JSValue::encode(jsUndefined());
704}
705#endif
706
707EncodedJSValue JSC_HOST_CALL functionDebug(ExecState* exec)
708{
709 fprintf(stderr, "--> %s\n", exec->argument(0).toString(exec)->value(exec).utf8().data());
710 return JSValue::encode(jsUndefined());
711}
712
713EncodedJSValue JSC_HOST_CALL functionDescribe(ExecState* exec)
714{
715 if (exec->argumentCount() < 1)
716 return JSValue::encode(jsUndefined());
717 return JSValue::encode(jsString(exec, toString(exec->argument(0))));
718}
719
720EncodedJSValue JSC_HOST_CALL functionDescribeArray(ExecState* exec)
721{
722 if (exec->argumentCount() < 1)
723 return JSValue::encode(jsUndefined());
724 JSObject* object = jsDynamicCast<JSObject*>(exec->argument(0));
725 if (!object)
726 return JSValue::encode(jsNontrivialString(exec, ASCIILiteral("<not object>")));
727 return JSValue::encode(jsNontrivialString(exec, toString("<Public length: ", object->getArrayLength(), "; vector length: ", object->getVectorLength(), ">")));
728}
729
730class FunctionJSCStackFunctor {
731public:
732 FunctionJSCStackFunctor(StringBuilder& trace)
733 : m_trace(trace)
734 {
735 }
736
737 StackVisitor::Status operator()(StackVisitor& visitor)
738 {
739 m_trace.append(String::format(" %zu %s\n", visitor->index(), visitor->toString().utf8().data()));
740 return StackVisitor::Continue;
741 }
742
743private:
744 StringBuilder& m_trace;
745};
746
747EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState* exec)
748{
749 StringBuilder trace;
750 trace.appendLiteral("--> Stack trace:\n");
751
752 FunctionJSCStackFunctor functor(trace);
753 exec->iterate(functor);
754 fprintf(stderr, "%s", trace.toString().utf8().data());
755 return JSValue::encode(jsUndefined());
756}
757
758EncodedJSValue JSC_HOST_CALL functionCreateRoot(ExecState* exec)
759{
760 JSLockHolder lock(exec);
761 return JSValue::encode(Root::create(exec->vm(), exec->lexicalGlobalObject()));
762}
763
764EncodedJSValue JSC_HOST_CALL functionCreateElement(ExecState* exec)
765{
766 JSLockHolder lock(exec);
767 JSValue arg = exec->argument(0);
768 return JSValue::encode(Element::create(exec->vm(), exec->lexicalGlobalObject(), arg.isNull() ? nullptr : jsCast<Root*>(exec->argument(0))));
769}
770
771EncodedJSValue JSC_HOST_CALL functionGetElement(ExecState* exec)
772{
773 JSLockHolder lock(exec);
774 Element* result = jsCast<Root*>(exec->argument(0).asCell())->element();
775 return JSValue::encode(result ? result : jsUndefined());
776}
777
778EncodedJSValue JSC_HOST_CALL functionSetElementRoot(ExecState* exec)
779{
780 JSLockHolder lock(exec);
781 Element* element = jsCast<Element*>(exec->argument(0));
782 Root* root = jsCast<Root*>(exec->argument(1));
783 element->setRoot(root);
784 return JSValue::encode(jsUndefined());
785}
786
787EncodedJSValue JSC_HOST_CALL functionCreateProxy(ExecState* exec)
788{
789 JSLockHolder lock(exec);
790 JSValue target = exec->argument(0);
791 if (!target.isObject())
792 return JSValue::encode(jsUndefined());
793 JSObject* jsTarget = asObject(target.asCell());
794 Structure* structure = JSProxy::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsTarget->prototype());
795 JSProxy* proxy = JSProxy::create(exec->vm(), structure, jsTarget);
796 return JSValue::encode(proxy);
797}
798
799EncodedJSValue JSC_HOST_CALL functionCreateRuntimeArray(ExecState* exec)
800{
801 JSLockHolder lock(exec);
802 RuntimeArray* array = RuntimeArray::create(exec);
803 return JSValue::encode(array);
804}
805
806EncodedJSValue JSC_HOST_CALL functionCreateImpureGetter(ExecState* exec)
807{
808 JSLockHolder lock(exec);
809 JSValue target = exec->argument(0);
810 JSObject* delegate = nullptr;
811 if (target.isObject())
812 delegate = asObject(target.asCell());
813 Structure* structure = ImpureGetter::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsNull());
814 ImpureGetter* result = ImpureGetter::create(exec->vm(), structure, delegate);
815 return JSValue::encode(result);
816}
817
818EncodedJSValue JSC_HOST_CALL functionSetImpureGetterDelegate(ExecState* exec)
819{
820 JSLockHolder lock(exec);
821 JSValue base = exec->argument(0);
822 if (!base.isObject())
823 return JSValue::encode(jsUndefined());
824 JSValue delegate = exec->argument(1);
825 if (!delegate.isObject())
826 return JSValue::encode(jsUndefined());
827 ImpureGetter* impureGetter = jsCast<ImpureGetter*>(asObject(base.asCell()));
828 impureGetter->setDelegate(exec->vm(), asObject(delegate.asCell()));
829 return JSValue::encode(jsUndefined());
830}
831
832EncodedJSValue JSC_HOST_CALL functionGCAndSweep(ExecState* exec)
833{
834 JSLockHolder lock(exec);
835 exec->heap()->collectAllGarbage();
836 return JSValue::encode(jsNumber(exec->heap()->sizeAfterLastFullCollection()));
837}
838
839EncodedJSValue JSC_HOST_CALL functionFullGC(ExecState* exec)
840{
841 JSLockHolder lock(exec);
842 exec->heap()->collect(FullCollection);
843 return JSValue::encode(jsNumber(exec->heap()->sizeAfterLastFullCollection()));
844}
845
846EncodedJSValue JSC_HOST_CALL functionEdenGC(ExecState* exec)
847{
848 JSLockHolder lock(exec);
849 exec->heap()->collect(EdenCollection);
850 return JSValue::encode(jsNumber(exec->heap()->sizeAfterLastEdenCollection()));
851}
852
853EncodedJSValue JSC_HOST_CALL functionHeapSize(ExecState* exec)
854{
855 JSLockHolder lock(exec);
856 return JSValue::encode(jsNumber(exec->heap()->size()));
857}
858
859EncodedJSValue JSC_HOST_CALL functionDeleteAllCompiledCode(ExecState* exec)
860{
861 JSLockHolder lock(exec);
862 exec->heap()->deleteAllCompiledCode();
863 return JSValue::encode(jsUndefined());
864}
865
866#ifndef NDEBUG
867EncodedJSValue JSC_HOST_CALL functionReleaseExecutableMemory(ExecState* exec)
868{
869 JSLockHolder lock(exec);
870 exec->vm().releaseExecutableMemory();
871 return JSValue::encode(jsUndefined());
872}
873#endif
874
875EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*)
876{
877 // We need this function for compatibility with the Mozilla JS tests but for now
878 // we don't actually do any version-specific handling
879 return JSValue::encode(jsUndefined());
880}
881
882EncodedJSValue JSC_HOST_CALL functionRun(ExecState* exec)
883{
884 String fileName = exec->argument(0).toString(exec)->value(exec);
885 Vector<char> script;
886 if (!fillBufferWithContentsOfFile(fileName, script))
887 return JSValue::encode(exec->vm().throwException(exec, createError(exec, ASCIILiteral("Could not open file."))));
888
889 GlobalObject* globalObject = GlobalObject::create(exec->vm(), GlobalObject::createStructure(exec->vm(), jsNull()), Vector<String>());
890
891 JSArray* array = constructEmptyArray(globalObject->globalExec(), 0);
892 for (unsigned i = 1; i < exec->argumentCount(); ++i)
893 array->putDirectIndex(globalObject->globalExec(), i - 1, exec->uncheckedArgument(i));
894 globalObject->putDirect(
895 exec->vm(), Identifier::fromString(globalObject->globalExec(), "arguments"), array);
896
897 JSValue exception;
898 StopWatch stopWatch;
899 stopWatch.start();
900 evaluate(globalObject->globalExec(), jscSource(script.data(), fileName), JSValue(), &exception);
901 stopWatch.stop();
902
903 if (!!exception) {
904 exec->vm().throwException(globalObject->globalExec(), exception);
905 return JSValue::encode(jsUndefined());
906 }
907
908 return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
909}
910
911EncodedJSValue JSC_HOST_CALL functionLoad(ExecState* exec)
912{
913 String fileName = exec->argument(0).toString(exec)->value(exec);
914 Vector<char> script;
915 if (!fillBufferWithContentsOfFile(fileName, script))
916 return JSValue::encode(exec->vm().throwException(exec, createError(exec, ASCIILiteral("Could not open file."))));
917
918 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
919
920 JSValue evaluationException;
921 JSValue result = evaluate(globalObject->globalExec(), jscSource(script.data(), fileName), JSValue(), &evaluationException);
922 if (evaluationException)
923 exec->vm().throwException(exec, evaluationException);
924 return JSValue::encode(result);
925}
926
927EncodedJSValue JSC_HOST_CALL functionReadFile(ExecState* exec)
928{
929 String fileName = exec->argument(0).toString(exec)->value(exec);
930 Vector<char> script;
931 if (!fillBufferWithContentsOfFile(fileName, script))
932 return JSValue::encode(exec->vm().throwException(exec, createError(exec, ASCIILiteral("Could not open file."))));
933
934 return JSValue::encode(jsString(exec, stringFromUTF(script.data())));
935}
936
937EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState* exec)
938{
939 String fileName = exec->argument(0).toString(exec)->value(exec);
940 Vector<char> script;
941 if (!fillBufferWithContentsOfFile(fileName, script))
942 return JSValue::encode(exec->vm().throwException(exec, createError(exec, ASCIILiteral("Could not open file."))));
943
944 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
945
946 StopWatch stopWatch;
947 stopWatch.start();
948
949 JSValue syntaxException;
950 bool validSyntax = checkSyntax(globalObject->globalExec(), jscSource(script.data(), fileName), &syntaxException);
951 stopWatch.stop();
952
953 if (!validSyntax)
954 exec->vm().throwException(exec, syntaxException);
955 return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
956}
957
958#if ENABLE(SAMPLING_FLAGS)
959EncodedJSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState* exec)
960{
961 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
962 unsigned flag = static_cast<unsigned>(exec->uncheckedArgument(i).toNumber(exec));
963 if ((flag >= 1) && (flag <= 32))
964 SamplingFlags::setFlag(flag);
965 }
966 return JSValue::encode(jsNull());
967}
968
969EncodedJSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState* exec)
970{
971 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
972 unsigned flag = static_cast<unsigned>(exec->uncheckedArgument(i).toNumber(exec));
973 if ((flag >= 1) && (flag <= 32))
974 SamplingFlags::clearFlag(flag);
975 }
976 return JSValue::encode(jsNull());
977}
978#endif
979
980EncodedJSValue JSC_HOST_CALL functionReadline(ExecState* exec)
981{
982 Vector<char, 256> line;
983 int c;
984 while ((c = getchar()) != EOF) {
985 // FIXME: Should we also break on \r?
986 if (c == '\n')
987 break;
988 line.append(c);
989 }
990 line.append('\0');
991 return JSValue::encode(jsString(exec, line.data()));
992}
993
994EncodedJSValue JSC_HOST_CALL functionPreciseTime(ExecState*)
995{
996 return JSValue::encode(jsNumber(currentTime()));
997}
998
999EncodedJSValue JSC_HOST_CALL functionNeverInlineFunction(ExecState* exec)
1000{
1001 return JSValue::encode(setNeverInline(exec));
1002}
1003
1004EncodedJSValue JSC_HOST_CALL functionOptimizeNextInvocation(ExecState* exec)
1005{
1006 return JSValue::encode(optimizeNextInvocation(exec));
1007}
1008
1009EncodedJSValue JSC_HOST_CALL functionNumberOfDFGCompiles(ExecState* exec)
1010{
1011 return JSValue::encode(numberOfDFGCompiles(exec));
1012}
1013
1014EncodedJSValue JSC_HOST_CALL functionReoptimizationRetryCount(ExecState* exec)
1015{
1016 if (exec->argumentCount() < 1)
1017 return JSValue::encode(jsUndefined());
1018
1019 CodeBlock* block = getSomeBaselineCodeBlockForFunction(exec->argument(0));
1020 if (!block)
1021 return JSValue::encode(jsNumber(0));
1022
1023 return JSValue::encode(jsNumber(block->reoptimizationRetryCounter()));
1024}
1025
1026EncodedJSValue JSC_HOST_CALL functionTransferArrayBuffer(ExecState* exec)
1027{
1028 if (exec->argumentCount() < 1)
1029 return JSValue::encode(exec->vm().throwException(exec, createError(exec, ASCIILiteral("Not enough arguments"))));
1030
1031 JSArrayBuffer* buffer = jsDynamicCast<JSArrayBuffer*>(exec->argument(0));
1032 if (!buffer)
1033 return JSValue::encode(exec->vm().throwException(exec, createError(exec, ASCIILiteral("Expected an array buffer"))));
1034
1035 ArrayBufferContents dummyContents;
1036 buffer->impl()->transfer(dummyContents);
1037
1038 return JSValue::encode(jsUndefined());
1039}
1040
1041EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*)
1042{
1043 jscExit(EXIT_SUCCESS);
1044
1045#if COMPILER(MSVC)
1046 // Without this, Visual Studio will complain that this method does not return a value.
1047 return JSValue::encode(jsUndefined());
1048#endif
1049}
1050
1051EncodedJSValue JSC_HOST_CALL functionFalse1(ExecState*) { return JSValue::encode(jsBoolean(false)); }
1052EncodedJSValue JSC_HOST_CALL functionFalse2(ExecState*) { return JSValue::encode(jsBoolean(false)); }
1053
1054EncodedJSValue JSC_HOST_CALL functionUndefined1(ExecState*) { return JSValue::encode(jsUndefined()); }
1055EncodedJSValue JSC_HOST_CALL functionUndefined2(ExecState*) { return JSValue::encode(jsUndefined()); }
1056
1057EncodedJSValue JSC_HOST_CALL functionIdentity(ExecState* exec) { return JSValue::encode(exec->argument(0)); }
1058
1059EncodedJSValue JSC_HOST_CALL functionEffectful42(ExecState*)
1060{
1061 return JSValue::encode(jsNumber(42));
1062}
1063
1064EncodedJSValue JSC_HOST_CALL functionMakeMasquerader(ExecState* exec)
1065{
1066 return JSValue::encode(Masquerader::create(exec->vm(), exec->lexicalGlobalObject()));
1067}
1068
1069EncodedJSValue JSC_HOST_CALL functionHasCustomProperties(ExecState* exec)
1070{
1071 JSValue value = exec->argument(0);
1072 if (value.isObject())
1073 return JSValue::encode(jsBoolean(asObject(value)->hasCustomProperties()));
1074 return JSValue::encode(jsBoolean(false));
1075}
1076
1077EncodedJSValue JSC_HOST_CALL functionDumpTypesForAllVariables(ExecState* exec)
1078{
1079 exec->vm().dumpTypeProfilerData();
1080 return JSValue::encode(jsUndefined());
1081}
1082
1083EncodedJSValue JSC_HOST_CALL functionFindTypeForExpression(ExecState* exec)
1084{
1085 RELEASE_ASSERT(exec->vm().typeProfiler());
1086 exec->vm().typeProfilerLog()->processLogEntries(ASCIILiteral("jsc Testing API: functionFindTypeForExpression"));
1087
1088 JSValue functionValue = exec->argument(0);
1089 RELEASE_ASSERT(functionValue.isFunction());
1090 FunctionExecutable* executable = (jsDynamicCast<JSFunction*>(functionValue.asCell()->getObject()))->jsExecutable();
1091
1092 RELEASE_ASSERT(exec->argument(1).isString());
1093 String substring = exec->argument(1).getString(exec);
1094 String sourceCodeText = executable->source().toString();
1095 unsigned offset = static_cast<unsigned>(sourceCodeText.find(substring) + executable->source().startOffset());
1096
1097 String jsonString = exec->vm().typeProfiler()->typeInformationForExpressionAtOffset(TypeProfilerSearchDescriptorNormal, offset, executable->sourceID(), exec->vm());
1098 return JSValue::encode(JSONParse(exec, jsonString));
1099}
1100
1101EncodedJSValue JSC_HOST_CALL functionReturnTypeFor(ExecState* exec)
1102{
1103 RELEASE_ASSERT(exec->vm().typeProfiler());
1104 exec->vm().typeProfilerLog()->processLogEntries(ASCIILiteral("jsc Testing API: functionReturnTypeFor"));
1105
1106 JSValue functionValue = exec->argument(0);
1107 RELEASE_ASSERT(functionValue.isFunction());
1108 FunctionExecutable* executable = (jsDynamicCast<JSFunction*>(functionValue.asCell()->getObject()))->jsExecutable();
1109
1110 unsigned offset = executable->source().startOffset();
1111 String jsonString = exec->vm().typeProfiler()->typeInformationForExpressionAtOffset(TypeProfilerSearchDescriptorFunctionReturn, offset, executable->sourceID(), exec->vm());
1112 return JSValue::encode(JSONParse(exec, jsonString));
1113}
1114
1115EncodedJSValue JSC_HOST_CALL functionDumpBasicBlockExecutionRanges(ExecState* exec)
1116{
1117 RELEASE_ASSERT(exec->vm().controlFlowProfiler());
1118 exec->vm().controlFlowProfiler()->dumpData();
1119 return JSValue::encode(jsUndefined());
1120}
1121
1122EncodedJSValue JSC_HOST_CALL functionHasBasicBlockExecuted(ExecState* exec)
1123{
1124 RELEASE_ASSERT(exec->vm().controlFlowProfiler());
1125
1126 JSValue functionValue = exec->argument(0);
1127 RELEASE_ASSERT(functionValue.isFunction());
1128 FunctionExecutable* executable = (jsDynamicCast<JSFunction*>(functionValue.asCell()->getObject()))->jsExecutable();
1129
1130 RELEASE_ASSERT(exec->argument(1).isString());
1131 String substring = exec->argument(1).getString(exec);
1132 String sourceCodeText = executable->source().toString();
1133 RELEASE_ASSERT(sourceCodeText.contains(substring));
1134 int offset = sourceCodeText.find(substring) + executable->source().startOffset();
1135
1136 bool hasExecuted = exec->vm().controlFlowProfiler()->hasBasicBlockAtTextOffsetBeenExecuted(offset, executable->sourceID(), exec->vm());
1137 return JSValue::encode(jsBoolean(hasExecuted));
1138}
1139
1140// Use SEH for Release builds only to get rid of the crash report dialog
1141// (luckily the same tests fail in Release and Debug builds so far). Need to
1142// be in a separate main function because the jscmain function requires object
1143// unwinding.
1144
1145#if COMPILER(MSVC) && !defined(_DEBUG)
1146#define TRY __try {
1147#define EXCEPT(x) } __except (EXCEPTION_EXECUTE_HANDLER) { x; }
1148#else
1149#define TRY
1150#define EXCEPT(x)
1151#endif
1152
1153int jscmain(int argc, char** argv);
1154
1155static double s_desiredTimeout;
1156
1157static NO_RETURN_DUE_TO_CRASH void timeoutThreadMain(void*)
1158{
1159 auto timeout = std::chrono::microseconds(static_cast<std::chrono::microseconds::rep>(s_desiredTimeout * 1000000));
1160 std::this_thread::sleep_for(timeout);
1161
1162 dataLog("Timed out after ", s_desiredTimeout, " seconds!\n");
1163 CRASH();
1164}
1165
1166int main(int argc, char** argv)
1167{
1168#if PLATFORM(IOS) && CPU(ARM_THUMB2)
1169 // Enabled IEEE754 denormal support.
1170 fenv_t env;
1171 fegetenv( &env );
1172 env.__fpscr &= ~0x01000000u;
1173 fesetenv( &env );
1174#endif
1175
1176#if OS(WINDOWS) && (defined(_M_X64) || defined(__x86_64__))
1177 // The VS2013 runtime has a bug where it mis-detects AVX-capable processors
1178 // if the feature has been disabled in firmware. This causes us to crash
1179 // in some of the math functions. For now, we disable those optimizations
1180 // because Microsoft is not going to fix the problem in VS2013.
1181 // FIXME: http://webkit.org/b/141449: Remove this workaround when we switch to VS2015+.
1182 _set_FMA3_enable(0);
1183
1184 // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for
1185 // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the
1186 // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>.
1187 ::SetErrorMode(0);
1188
1189#if defined(_DEBUG)
1190 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
1191 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
1192 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
1193 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
1194 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
1195 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
1196#endif
1197
1198 timeBeginPeriod(1);
1199#endif
1200
1201#if PLATFORM(EFL)
1202 ecore_init();
1203#endif
1204
1205 // Initialize JSC before getting VM.
1206#if ENABLE(SAMPLING_REGIONS)
1207 WTF::initializeMainThread();
1208#endif
1209 JSC::initializeThreading();
1210
1211 if (char* timeoutString = getenv("JSC_timeout")) {
1212 if (sscanf(timeoutString, "%lf", &s_desiredTimeout) != 1) {
1213 dataLog(
1214 "WARNING: timeout string is malformed, got ", timeoutString,
1215 " but expected a number. Not using a timeout.\n");
1216 } else
1217 createThread(timeoutThreadMain, 0, "jsc Timeout Thread");
1218 }
1219
1220#if PLATFORM(IOS)
1221 Options::crashIfCantAllocateJITMemory() = true;
1222#endif
1223
1224 // We can't use destructors in the following code because it uses Windows
1225 // Structured Exception Handling
1226 int res = 0;
1227 TRY
1228 res = jscmain(argc, argv);
1229 EXCEPT(res = 3)
1230 if (Options::logHeapStatisticsAtExit())
1231 HeapStatistics::reportSuccess();
1232
1233#if PLATFORM(EFL)
1234 ecore_shutdown();
1235#endif
1236
1237 jscExit(res);
1238}
1239
1240static bool runWithScripts(GlobalObject* globalObject, const Vector<Script>& scripts, bool dump)
1241{
1242 const char* script;
1243 String fileName;
1244 Vector<char> scriptBuffer;
1245
1246 if (dump)
1247 JSC::Options::dumpGeneratedBytecodes() = true;
1248
1249 VM& vm = globalObject->vm();
1250
1251#if ENABLE(SAMPLING_FLAGS)
1252 SamplingFlags::start();
1253#endif
1254
1255 bool success = true;
1256 for (size_t i = 0; i < scripts.size(); i++) {
1257 if (scripts[i].isFile) {
1258 fileName = scripts[i].argument;
1259 if (!fillBufferWithContentsOfFile(fileName, scriptBuffer))
1260 return false; // fail early so we can catch missing files
1261 script = scriptBuffer.data();
1262 } else {
1263 script = scripts[i].argument;
1264 fileName = ASCIILiteral("[Command Line]");
1265 }
1266
1267 vm.startSampling();
1268
1269 JSValue evaluationException;
1270 JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(script, fileName), JSValue(), &evaluationException);
1271 success = success && !evaluationException;
1272 if (dump && !evaluationException)
1273 printf("End: %s\n", returnValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
1274 if (evaluationException) {
1275 printf("Exception: %s\n", evaluationException.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
1276 Identifier stackID = Identifier::fromString(globalObject->globalExec(), "stack");
1277 JSValue stackValue = evaluationException.get(globalObject->globalExec(), stackID);
1278 if (!stackValue.isUndefinedOrNull())
1279 printf("%s\n", stackValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
1280 }
1281
1282 vm.stopSampling();
1283 globalObject->globalExec()->clearException();
1284 }
1285
1286#if ENABLE(SAMPLING_FLAGS)
1287 SamplingFlags::stop();
1288#endif
1289#if ENABLE(SAMPLING_REGIONS)
1290 SamplingRegion::dump();
1291#endif
1292 vm.dumpSampleData(globalObject->globalExec());
1293#if ENABLE(SAMPLING_COUNTERS)
1294 AbstractSamplingCounter::dump();
1295#endif
1296#if ENABLE(REGEXP_TRACING)
1297 vm.dumpRegExpTrace();
1298#endif
1299 return success;
1300}
1301
1302#define RUNNING_FROM_XCODE 0
1303
1304static void runInteractive(GlobalObject* globalObject)
1305{
1306 String interpreterName(ASCIILiteral("Interpreter"));
1307
1308 bool shouldQuit = false;
1309 while (!shouldQuit) {
1310#if HAVE(READLINE) && !RUNNING_FROM_XCODE
1311 ParserError error;
1312 String source;
1313 do {
1314 error = ParserError();
1315 char* line = readline(source.isEmpty() ? interactivePrompt : "... ");
1316 shouldQuit = !line;
1317 if (!line)
1318 break;
1319 source = source + line;
1320 source = source + '\n';
1321 checkSyntax(globalObject->vm(), makeSource(source, interpreterName), error);
1322 if (!line[0])
1323 break;
1324 add_history(line);
1325 } while (error.syntaxErrorType() == ParserError::SyntaxErrorRecoverable);
1326
1327 if (error.isValid()) {
1328 printf("%s:%d\n", error.message().utf8().data(), error.line());
1329 continue;
1330 }
1331
1332
1333 JSValue evaluationException;
1334 JSValue returnValue = evaluate(globalObject->globalExec(), makeSource(source, interpreterName), JSValue(), &evaluationException);
1335#else
1336 printf("%s", interactivePrompt);
1337 Vector<char, 256> line;
1338 int c;
1339 while ((c = getchar()) != EOF) {
1340 // FIXME: Should we also break on \r?
1341 if (c == '\n')
1342 break;
1343 line.append(c);
1344 }
1345 if (line.isEmpty())
1346 break;
1347 line.append('\0');
1348
1349 JSValue evaluationException;
1350 JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(line.data(), interpreterName), JSValue(), &evaluationException);
1351#endif
1352 if (evaluationException)
1353 printf("Exception: %s\n", evaluationException.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
1354 else
1355 printf("%s\n", returnValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
1356
1357 globalObject->globalExec()->clearException();
1358 }
1359 printf("\n");
1360}
1361
1362static NO_RETURN void printUsageStatement(bool help = false)
1363{
1364 fprintf(stderr, "Usage: jsc [options] [files] [-- arguments]\n");
1365 fprintf(stderr, " -d Dumps bytecode (debug builds only)\n");
1366 fprintf(stderr, " -e Evaluate argument as script code\n");
1367 fprintf(stderr, " -f Specifies a source file (deprecated)\n");
1368 fprintf(stderr, " -h|--help Prints this help message\n");
1369 fprintf(stderr, " -i Enables interactive mode (default if no files are specified)\n");
1370#if HAVE(SIGNAL_H)
1371 fprintf(stderr, " -s Installs signal handlers that exit on a crash (Unix platforms only)\n");
1372#endif
1373 fprintf(stderr, " -p <file> Outputs profiling data to a file\n");
1374 fprintf(stderr, " -x Output exit code before terminating\n");
1375 fprintf(stderr, "\n");
1376 fprintf(stderr, " --options Dumps all JSC VM options and exits\n");
1377 fprintf(stderr, " --dumpOptions Dumps all JSC VM options before continuing\n");
1378 fprintf(stderr, " --<jsc VM option>=<value> Sets the specified JSC VM option\n");
1379 fprintf(stderr, "\n");
1380
1381 jscExit(help ? EXIT_SUCCESS : EXIT_FAILURE);
1382}
1383
1384void CommandLine::parseArguments(int argc, char** argv)
1385{
1386 int i = 1;
1387 bool needToDumpOptions = false;
1388 bool needToExit = false;
1389
1390 for (; i < argc; ++i) {
1391 const char* arg = argv[i];
1392 if (!strcmp(arg, "-f")) {
1393 if (++i == argc)
1394 printUsageStatement();
1395 m_scripts.append(Script(true, argv[i]));
1396 continue;
1397 }
1398 if (!strcmp(arg, "-e")) {
1399 if (++i == argc)
1400 printUsageStatement();
1401 m_scripts.append(Script(false, argv[i]));
1402 continue;
1403 }
1404 if (!strcmp(arg, "-i")) {
1405 m_interactive = true;
1406 continue;
1407 }
1408 if (!strcmp(arg, "-d")) {
1409 m_dump = true;
1410 continue;
1411 }
1412 if (!strcmp(arg, "-p")) {
1413 if (++i == argc)
1414 printUsageStatement();
1415 m_profile = true;
1416 m_profilerOutput = argv[i];
1417 continue;
1418 }
1419 if (!strcmp(arg, "-s")) {
1420#if HAVE(SIGNAL_H)
1421 signal(SIGILL, _exit);
1422 signal(SIGFPE, _exit);
1423 signal(SIGBUS, _exit);
1424 signal(SIGSEGV, _exit);
1425#endif
1426 continue;
1427 }
1428 if (!strcmp(arg, "-x")) {
1429 m_exitCode = true;
1430 continue;
1431 }
1432 if (!strcmp(arg, "--")) {
1433 ++i;
1434 break;
1435 }
1436 if (!strcmp(arg, "-h") || !strcmp(arg, "--help"))
1437 printUsageStatement(true);
1438
1439 if (!strcmp(arg, "--options")) {
1440 needToDumpOptions = true;
1441 needToExit = true;
1442 continue;
1443 }
1444 if (!strcmp(arg, "--dumpOptions")) {
1445 needToDumpOptions = true;
1446 continue;
1447 }
1448
1449 // See if the -- option is a JSC VM option.
1450 // NOTE: At this point, we know that the arg starts with "--". Skip it.
1451 if (JSC::Options::setOption(&arg[2])) {
1452 // The arg was recognized as a VM option and has been parsed.
1453 continue; // Just continue with the next arg.
1454 }
1455
1456 // This arg is not recognized by the VM nor by jsc. Pass it on to the
1457 // script.
1458 m_scripts.append(Script(true, argv[i]));
1459 }
1460
1461 if (m_scripts.isEmpty())
1462 m_interactive = true;
1463
1464 for (; i < argc; ++i)
1465 m_arguments.append(argv[i]);
1466
1467 if (needToDumpOptions)
1468 JSC::Options::dumpAllOptions(JSC::Options::DumpLevel::Verbose, "All JSC runtime options:", stderr);
1469 if (needToExit)
1470 jscExit(EXIT_SUCCESS);
1471}
1472
1473int jscmain(int argc, char** argv)
1474{
1475 // Note that the options parsing can affect VM creation, and thus
1476 // comes first.
1477 CommandLine options(argc, argv);
1478 VM* vm = VM::create(LargeHeap).leakRef();
1479 int result;
1480 {
1481 JSLockHolder locker(vm);
1482
1483 if (options.m_profile && !vm->m_perBytecodeProfiler)
1484 vm->m_perBytecodeProfiler = std::make_unique<Profiler::Database>(*vm);
1485
1486 GlobalObject* globalObject = GlobalObject::create(*vm, GlobalObject::createStructure(*vm, jsNull()), options.m_arguments);
1487 bool success = runWithScripts(globalObject, options.m_scripts, options.m_dump);
1488 if (options.m_interactive && success)
1489 runInteractive(globalObject);
1490
1491 result = success ? 0 : 3;
1492
1493 if (options.m_exitCode)
1494 printf("jsc exiting %d\n", result);
1495
1496 if (options.m_profile) {
1497 if (!vm->m_perBytecodeProfiler->save(options.m_profilerOutput.utf8().data()))
1498 fprintf(stderr, "could not save profiler output.\n");
1499 }
1500
1501#if ENABLE(JIT)
1502 if (Options::enableExceptionFuzz())
1503 printf("JSC EXCEPTION FUZZ: encountered %u checks.\n", numberOfExceptionFuzzChecks());
1504 bool fireAtEnabled =
1505 Options::fireExecutableAllocationFuzzAt() || Options::fireExecutableAllocationFuzzAtOrAfter();
1506 if (Options::enableExecutableAllocationFuzz() && (!fireAtEnabled || Options::verboseExecutableAllocationFuzz()))
1507 printf("JSC EXECUTABLE ALLOCATION FUZZ: encountered %u checks.\n", numberOfExecutableAllocationFuzzChecks());
1508#endif
1509 }
1510
1511 return result;
1512}
1513
1514static bool fillBufferWithContentsOfFile(const String& fileName, Vector<char>& buffer)
1515{
1516 FILE* f = fopen(fileName.utf8().data(), "r");
1517 if (!f) {
1518 fprintf(stderr, "Could not open file: %s\n", fileName.utf8().data());
1519 return false;
1520 }
1521
1522 size_t bufferSize = 0;
1523 size_t bufferCapacity = 1024;
1524
1525 buffer.resize(bufferCapacity);
1526
1527 while (!feof(f) && !ferror(f)) {
1528 bufferSize += fread(buffer.data() + bufferSize, 1, bufferCapacity - bufferSize, f);
1529 if (bufferSize == bufferCapacity) { // guarantees space for trailing '\0'
1530 bufferCapacity *= 2;
1531 buffer.resize(bufferCapacity);
1532 }
1533 }
1534 fclose(f);
1535 buffer[bufferSize] = '\0';
1536
1537 if (buffer[0] == '#' && buffer[1] == '!')
1538 buffer[0] = buffer[1] = '/';
1539
1540 return true;
1541}
1542
1543#if OS(WINDOWS)
1544extern "C" __declspec(dllexport) int WINAPI dllLauncherEntryPoint(int argc, const char* argv[])
1545{
1546 return main(argc, const_cast<char**>(argv));
1547}
1548#endif
Note: See TracBrowser for help on using the repository browser.