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

Last change on this file since 178894 was 178894, checked in by Yusuke Suzuki, 10 years ago

put_by_val_direct need to check the property is index or not for using putDirect / putDirectIndex
https://bugs.webkit.org/show_bug.cgi?id=140426

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

In the put_by_val_direct operation, we use JSObject::putDirect.
However, it only accepts non-index property. For index property, we need to use JSObject::putDirectIndex.
This patch changes Identifier::asIndex() to return Optional<uint32_t>.
It forces callers to check the value is index or not explicitly.
Additionally, it checks toString-ed Identifier is index or not to choose putDirect / putDirectIndex.

  • bytecode/GetByIdStatus.cpp:

(JSC::GetByIdStatus::computeFor):

  • bytecode/PutByIdStatus.cpp:

(JSC::PutByIdStatus::computeFor):

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::emitDirectPutById):

  • dfg/DFGOperations.cpp:

(JSC::DFG::operationPutByValInternal):

  • jit/JITOperations.cpp:
  • jit/Repatch.cpp:

(JSC::emitPutTransitionStubAndGetOldStructure):

  • jsc.cpp:
  • llint/LLIntSlowPaths.cpp:

(JSC::LLInt::LLINT_SLOW_PATH_DECL):

  • runtime/Arguments.cpp:

(JSC::Arguments::getOwnPropertySlot):
(JSC::Arguments::put):
(JSC::Arguments::deleteProperty):
(JSC::Arguments::defineOwnProperty):

  • runtime/ArrayPrototype.cpp:

(JSC::arrayProtoFuncSort):

  • runtime/JSArray.cpp:

(JSC::JSArray::defineOwnProperty):

  • runtime/JSCJSValue.cpp:

(JSC::JSValue::putToPrimitive):

  • runtime/JSGenericTypedArrayViewInlines.h:

(JSC::JSGenericTypedArrayView<Adaptor>::getOwnPropertySlot):
(JSC::JSGenericTypedArrayView<Adaptor>::put):
(JSC::JSGenericTypedArrayView<Adaptor>::defineOwnProperty):
(JSC::JSGenericTypedArrayView<Adaptor>::deleteProperty):

  • runtime/JSObject.cpp:

(JSC::JSObject::put):
(JSC::JSObject::putDirectAccessor):
(JSC::JSObject::putDirectCustomAccessor):
(JSC::JSObject::deleteProperty):
(JSC::JSObject::putDirectMayBeIndex):
(JSC::JSObject::defineOwnProperty):

  • runtime/JSObject.h:

(JSC::JSObject::getOwnPropertySlot):
(JSC::JSObject::getPropertySlot):
(JSC::JSObject::putDirectInternal):

  • runtime/JSString.cpp:

(JSC::JSString::getStringPropertyDescriptor):

  • runtime/JSString.h:

(JSC::JSString::getStringPropertySlot):

  • runtime/LiteralParser.cpp:

(JSC::LiteralParser<CharType>::parse):

  • runtime/PropertyName.h:

(JSC::toUInt32FromCharacters):
(JSC::toUInt32FromStringImpl):
(JSC::PropertyName::asIndex):

  • runtime/PropertyNameArray.cpp:

(JSC::PropertyNameArray::add):

  • runtime/StringObject.cpp:

(JSC::StringObject::deleteProperty):

  • runtime/Structure.cpp:

(JSC::Structure::prototypeChainMayInterceptStoreTo):

Source/WebCore:

Test: js/dfg-put-by-val-direct-with-edge-numbers.html

  • bindings/js/JSDOMWindowCustom.cpp:

(WebCore::JSDOMWindow::getOwnPropertySlot):

  • bindings/js/JSHTMLAllCollectionCustom.cpp:

(WebCore::callHTMLAllCollection):
(WebCore::JSHTMLAllCollection::item):

  • bindings/scripts/CodeGeneratorJS.pm:

(GenerateGetOwnPropertySlotBody):
(GenerateImplementation):

  • bindings/scripts/test/JS/JSFloat64Array.cpp:

(WebCore::JSFloat64Array::getOwnPropertySlot):
(WebCore::JSFloat64Array::getOwnPropertyDescriptor):
(WebCore::JSFloat64Array::put):

  • bindings/scripts/test/JS/JSTestEventTarget.cpp:

(WebCore::JSTestEventTarget::getOwnPropertySlot):

  • bridge/runtime_array.cpp:

(JSC::RuntimeArray::getOwnPropertySlot):
(JSC::RuntimeArray::put):

LayoutTests:

  • js/dfg-put-by-val-direct-with-edge-numbers-expected.txt: Added.
  • js/dfg-put-by-val-direct-with-edge-numbers.html: Added.
  • js/script-tests/dfg-put-by-val-direct-with-edge-numbers.js: Added.

(lookupWithKey):
(dfgShouldThrow):
(lookupWithKey2):
(toStringThrowsError.toString):

  • Property svn:eol-style set to native
File size: 50.9 KB
Line 
1/*
2 * Copyright (C) 1999-2000 Harri Porten ([email protected])
3 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2012, 2013 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 "ExceptionHelpers.h"
32#include "HeapStatistics.h"
33#include "InitializeThreading.h"
34#include "Interpreter.h"
35#include "JSArray.h"
36#include "JSArrayBuffer.h"
37#include "JSCInlines.h"
38#include "JSFunction.h"
39#include "JSLock.h"
40#include "JSONObject.h"
41#include "JSProxy.h"
42#include "JSString.h"
43#include "ProfilerDatabase.h"
44#include "SamplingTool.h"
45#include "StackVisitor.h"
46#include "StructureInlines.h"
47#include "StructureRareDataInlines.h"
48#include "TestRunnerUtils.h"
49#include "TypeProfilerLog.h"
50#include <math.h>
51#include <stdio.h>
52#include <stdlib.h>
53#include <string.h>
54#include <thread>
55#include <wtf/CurrentTime.h>
56#include <wtf/MainThread.h>
57#include <wtf/StringPrintStream.h>
58#include <wtf/text/StringBuilder.h>
59
60#if !OS(WINDOWS)
61#include <unistd.h>
62#endif
63
64#if HAVE(READLINE)
65// readline/history.h has a Function typedef which conflicts with the WTF::Function template from WTF/Forward.h
66// We #define it to something else to avoid this conflict.
67#define Function ReadlineFunction
68#include <readline/history.h>
69#include <readline/readline.h>
70#undef Function
71#endif
72
73#if HAVE(SYS_TIME_H)
74#include <sys/time.h>
75#endif
76
77#if HAVE(SIGNAL_H)
78#include <signal.h>
79#endif
80
81#if COMPILER(MSVC)
82#include <crtdbg.h>
83#include <mmsystem.h>
84#include <windows.h>
85#endif
86
87#if PLATFORM(IOS) && CPU(ARM_THUMB2)
88#include <fenv.h>
89#include <arm/arch.h>
90#endif
91
92#if PLATFORM(EFL)
93#include <Ecore.h>
94#endif
95
96using namespace JSC;
97using namespace WTF;
98
99namespace JSC {
100WTF_IMPORT extern const struct HashTable globalObjectTable;
101}
102
103namespace {
104
105NO_RETURN_WITH_VALUE static void jscExit(int status)
106{
107#if ENABLE(DFG_JIT)
108 if (DFG::isCrashing()) {
109 for (;;) {
110#if OS(WINDOWS)
111 Sleep(1000);
112#else
113 pause();
114#endif
115 }
116 }
117#endif // ENABLE(DFG_JIT)
118 exit(status);
119}
120
121class Element;
122class ElementHandleOwner;
123class Masuqerader;
124class Root;
125class RuntimeArray;
126
127class Element : public JSNonFinalObject {
128public:
129 Element(VM& vm, Structure* structure, Root* root)
130 : Base(vm, structure)
131 , m_root(root)
132 {
133 }
134
135 typedef JSNonFinalObject Base;
136 static const bool needsDestruction = false;
137
138 Root* root() const { return m_root; }
139 void setRoot(Root* root) { m_root = root; }
140
141 static Element* create(VM& vm, JSGlobalObject* globalObject, Root* root)
142 {
143 Structure* structure = createStructure(vm, globalObject, jsNull());
144 Element* element = new (NotNull, allocateCell<Element>(vm.heap, sizeof(Element))) Element(vm, structure, root);
145 element->finishCreation(vm);
146 return element;
147 }
148
149 void finishCreation(VM&);
150
151 static ElementHandleOwner* handleOwner();
152
153 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
154 {
155 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
156 }
157
158 DECLARE_INFO;
159
160private:
161 Root* m_root;
162};
163
164class ElementHandleOwner : public WeakHandleOwner {
165public:
166 virtual bool isReachableFromOpaqueRoots(Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
167 {
168 Element* element = jsCast<Element*>(handle.slot()->asCell());
169 return visitor.containsOpaqueRoot(element->root());
170 }
171};
172
173class Masquerader : public JSNonFinalObject {
174public:
175 Masquerader(VM& vm, Structure* structure)
176 : Base(vm, structure)
177 {
178 }
179
180 typedef JSNonFinalObject Base;
181
182 static Masquerader* create(VM& vm, JSGlobalObject* globalObject)
183 {
184 globalObject->masqueradesAsUndefinedWatchpoint()->fireAll("Masquerading object allocated");
185 Structure* structure = createStructure(vm, globalObject, jsNull());
186 Masquerader* result = new (NotNull, allocateCell<Masquerader>(vm.heap, sizeof(Masquerader))) Masquerader(vm, structure);
187 result->finishCreation(vm);
188 return result;
189 }
190
191 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
192 {
193 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
194 }
195
196 DECLARE_INFO;
197
198protected:
199 static const unsigned StructureFlags = JSC::MasqueradesAsUndefined | Base::StructureFlags;
200};
201
202class Root : public JSDestructibleObject {
203public:
204 Root(VM& vm, Structure* structure)
205 : Base(vm, structure)
206 {
207 }
208
209 Element* element()
210 {
211 return m_element.get();
212 }
213
214 void setElement(Element* element)
215 {
216 Weak<Element> newElement(element, Element::handleOwner());
217 m_element.swap(newElement);
218 }
219
220 static Root* create(VM& vm, JSGlobalObject* globalObject)
221 {
222 Structure* structure = createStructure(vm, globalObject, jsNull());
223 Root* root = new (NotNull, allocateCell<Root>(vm.heap, sizeof(Root))) Root(vm, structure);
224 root->finishCreation(vm);
225 return root;
226 }
227
228 typedef JSDestructibleObject Base;
229
230 DECLARE_INFO;
231 static const bool needsDestruction = true;
232
233 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
234 {
235 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
236 }
237
238 static void visitChildren(JSCell* thisObject, SlotVisitor& visitor)
239 {
240 Base::visitChildren(thisObject, visitor);
241 visitor.addOpaqueRoot(thisObject);
242 }
243
244private:
245 Weak<Element> m_element;
246};
247
248class ImpureGetter : public JSNonFinalObject {
249public:
250 ImpureGetter(VM& vm, Structure* structure)
251 : Base(vm, structure)
252 {
253 }
254
255 DECLARE_INFO;
256 typedef JSNonFinalObject Base;
257
258 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
259 {
260 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
261 }
262
263 static ImpureGetter* create(VM& vm, Structure* structure, JSObject* delegate)
264 {
265 ImpureGetter* getter = new (NotNull, allocateCell<ImpureGetter>(vm.heap, sizeof(ImpureGetter))) ImpureGetter(vm, structure);
266 getter->finishCreation(vm, delegate);
267 return getter;
268 }
269
270 void finishCreation(VM& vm, JSObject* delegate)
271 {
272 Base::finishCreation(vm);
273 if (delegate)
274 m_delegate.set(vm, this, delegate);
275 }
276
277 static const unsigned StructureFlags = JSC::HasImpureGetOwnPropertySlot | JSC::OverridesGetOwnPropertySlot | Base::StructureFlags;
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
309 static RuntimeArray* create(ExecState* exec)
310 {
311 VM& vm = exec->vm();
312 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
313 Structure* structure = createStructure(vm, globalObject, createPrototype(vm, globalObject));
314 RuntimeArray* runtimeArray = new (NotNull, allocateCell<RuntimeArray>(*exec->heap())) RuntimeArray(exec, structure);
315 runtimeArray->finishCreation(exec);
316 vm.heap.addFinalizer(runtimeArray, destroy);
317 return runtimeArray;
318 }
319
320 ~RuntimeArray() { }
321
322 static void destroy(JSCell* cell)
323 {
324 static_cast<RuntimeArray*>(cell)->RuntimeArray::~RuntimeArray();
325 }
326
327 static const bool needsDestruction = false;
328
329 static bool getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
330 {
331 RuntimeArray* thisObject = jsCast<RuntimeArray*>(object);
332 if (propertyName == exec->propertyNames().length) {
333 slot.setCacheableCustom(thisObject, DontDelete | ReadOnly | DontEnum, thisObject->lengthGetter);
334 return true;
335 }
336
337 Optional<uint32_t> index = propertyName.asIndex();
338 if (index && index.value() < thisObject->getLength()) {
339 slot.setValue(thisObject, DontDelete | DontEnum, jsNumber(thisObject->m_vector[index.value()]));
340 return true;
341 }
342
343 return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot);
344 }
345
346 static bool getOwnPropertySlotByIndex(JSObject* object, ExecState* exec, unsigned index, PropertySlot& slot)
347 {
348 RuntimeArray* thisObject = jsCast<RuntimeArray*>(object);
349 if (index < thisObject->getLength()) {
350 slot.setValue(thisObject, DontDelete | DontEnum, jsNumber(thisObject->m_vector[index]));
351 return true;
352 }
353
354 return JSObject::getOwnPropertySlotByIndex(thisObject, exec, index, slot);
355 }
356
357 static NO_RETURN_DUE_TO_CRASH void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&)
358 {
359 RELEASE_ASSERT_NOT_REACHED();
360 }
361
362 static NO_RETURN_DUE_TO_CRASH bool deleteProperty(JSCell*, ExecState*, PropertyName)
363 {
364 RELEASE_ASSERT_NOT_REACHED();
365#if COMPILER_QUIRK(CONSIDERS_UNREACHABLE_CODE)
366 return true;
367#endif
368 }
369
370 unsigned getLength() const { return m_vector.size(); }
371
372 DECLARE_INFO;
373
374 static ArrayPrototype* createPrototype(VM&, JSGlobalObject* globalObject)
375 {
376 return globalObject->arrayPrototype();
377 }
378
379 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
380 {
381 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info(), ArrayClass);
382 }
383
384protected:
385 void finishCreation(ExecState* exec)
386 {
387 Base::finishCreation(exec->vm());
388 ASSERT(inherits(info()));
389
390 for (size_t i = 0; i < exec->argumentCount(); i++)
391 m_vector.append(exec->argument(i).toInt32(exec));
392 }
393
394 static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesGetPropertyNames | JSArray::StructureFlags;
395
396private:
397 RuntimeArray(ExecState* exec, Structure* structure)
398 : JSArray(exec->vm(), structure, 0)
399 {
400 }
401
402 static EncodedJSValue lengthGetter(ExecState* exec, JSObject*, EncodedJSValue thisValue, PropertyName)
403 {
404 RuntimeArray* thisObject = jsDynamicCast<RuntimeArray*>(JSValue::decode(thisValue));
405 if (!thisObject)
406 return throwVMTypeError(exec);
407 return JSValue::encode(jsNumber(thisObject->getLength()));
408 }
409
410 Vector<int> m_vector;
411};
412
413const ClassInfo Element::s_info = { "Element", &Base::s_info, 0, CREATE_METHOD_TABLE(Element) };
414const ClassInfo Masquerader::s_info = { "Masquerader", &Base::s_info, 0, CREATE_METHOD_TABLE(Masquerader) };
415const ClassInfo Root::s_info = { "Root", &Base::s_info, 0, CREATE_METHOD_TABLE(Root) };
416const ClassInfo ImpureGetter::s_info = { "ImpureGetter", &Base::s_info, 0, CREATE_METHOD_TABLE(ImpureGetter) };
417const ClassInfo RuntimeArray::s_info = { "RuntimeArray", &Base::s_info, 0, CREATE_METHOD_TABLE(RuntimeArray) };
418
419ElementHandleOwner* Element::handleOwner()
420{
421 static ElementHandleOwner* owner = 0;
422 if (!owner)
423 owner = new ElementHandleOwner();
424 return owner;
425}
426
427void Element::finishCreation(VM& vm)
428{
429 Base::finishCreation(vm);
430 m_root->setElement(this);
431}
432
433}
434
435static bool fillBufferWithContentsOfFile(const String& fileName, Vector<char>& buffer);
436
437static EncodedJSValue JSC_HOST_CALL functionCreateProxy(ExecState*);
438static EncodedJSValue JSC_HOST_CALL functionCreateRuntimeArray(ExecState*);
439static EncodedJSValue JSC_HOST_CALL functionCreateImpureGetter(ExecState*);
440static EncodedJSValue JSC_HOST_CALL functionSetImpureGetterDelegate(ExecState*);
441
442static EncodedJSValue JSC_HOST_CALL functionSetElementRoot(ExecState*);
443static EncodedJSValue JSC_HOST_CALL functionCreateRoot(ExecState*);
444static EncodedJSValue JSC_HOST_CALL functionCreateElement(ExecState*);
445static EncodedJSValue JSC_HOST_CALL functionGetElement(ExecState*);
446static EncodedJSValue JSC_HOST_CALL functionPrint(ExecState*);
447static EncodedJSValue JSC_HOST_CALL functionDebug(ExecState*);
448static EncodedJSValue JSC_HOST_CALL functionDescribe(ExecState*);
449static EncodedJSValue JSC_HOST_CALL functionDescribeArray(ExecState*);
450static EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState*);
451static EncodedJSValue JSC_HOST_CALL functionGCAndSweep(ExecState*);
452static EncodedJSValue JSC_HOST_CALL functionFullGC(ExecState*);
453static EncodedJSValue JSC_HOST_CALL functionEdenGC(ExecState*);
454static EncodedJSValue JSC_HOST_CALL functionDeleteAllCompiledCode(ExecState*);
455#ifndef NDEBUG
456static EncodedJSValue JSC_HOST_CALL functionReleaseExecutableMemory(ExecState*);
457static EncodedJSValue JSC_HOST_CALL functionDumpCallFrame(ExecState*);
458#endif
459static EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*);
460static EncodedJSValue JSC_HOST_CALL functionRun(ExecState*);
461static EncodedJSValue JSC_HOST_CALL functionLoad(ExecState*);
462static EncodedJSValue JSC_HOST_CALL functionReadFile(ExecState*);
463static EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState*);
464static EncodedJSValue JSC_HOST_CALL functionReadline(ExecState*);
465static EncodedJSValue JSC_HOST_CALL functionPreciseTime(ExecState*);
466static EncodedJSValue JSC_HOST_CALL functionNeverInlineFunction(ExecState*);
467static EncodedJSValue JSC_HOST_CALL functionOptimizeNextInvocation(ExecState*);
468static EncodedJSValue JSC_HOST_CALL functionNumberOfDFGCompiles(ExecState*);
469static EncodedJSValue JSC_HOST_CALL functionReoptimizationRetryCount(ExecState*);
470static EncodedJSValue JSC_HOST_CALL functionTransferArrayBuffer(ExecState*);
471static NO_RETURN_WITH_VALUE EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*);
472static EncodedJSValue JSC_HOST_CALL functionFalse1(ExecState*);
473static EncodedJSValue JSC_HOST_CALL functionFalse2(ExecState*);
474static EncodedJSValue JSC_HOST_CALL functionUndefined1(ExecState*);
475static EncodedJSValue JSC_HOST_CALL functionUndefined2(ExecState*);
476static EncodedJSValue JSC_HOST_CALL functionEffectful42(ExecState*);
477static EncodedJSValue JSC_HOST_CALL functionIdentity(ExecState*);
478static EncodedJSValue JSC_HOST_CALL functionMakeMasquerader(ExecState*);
479static EncodedJSValue JSC_HOST_CALL functionHasCustomProperties(ExecState*);
480static EncodedJSValue JSC_HOST_CALL functionDumpTypesForAllVariables(ExecState*);
481static EncodedJSValue JSC_HOST_CALL functionFindTypeForExpression(ExecState*);
482static EncodedJSValue JSC_HOST_CALL functionReturnTypeFor(ExecState*);
483static EncodedJSValue JSC_HOST_CALL functionDumpBasicBlockExecutionRanges(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 bool javaScriptExperimentsEnabled(const JSGlobalObject*) { return true; }
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, "deleteAllCompiledCode", functionDeleteAllCompiledCode, 0);
592#ifndef NDEBUG
593 addFunction(vm, "dumpCallFrame", functionDumpCallFrame, 0);
594 addFunction(vm, "releaseExecutableMemory", functionReleaseExecutableMemory, 0);
595#endif
596 addFunction(vm, "version", functionVersion, 1);
597 addFunction(vm, "run", functionRun, 1);
598 addFunction(vm, "load", functionLoad, 1);
599 addFunction(vm, "readFile", functionReadFile, 1);
600 addFunction(vm, "checkSyntax", functionCheckSyntax, 1);
601 addFunction(vm, "jscStack", functionJSCStack, 1);
602 addFunction(vm, "readline", functionReadline, 0);
603 addFunction(vm, "preciseTime", functionPreciseTime, 0);
604 addFunction(vm, "neverInlineFunction", functionNeverInlineFunction, 1);
605 addFunction(vm, "noInline", functionNeverInlineFunction, 1);
606 addFunction(vm, "numberOfDFGCompiles", functionNumberOfDFGCompiles, 1);
607 addFunction(vm, "optimizeNextInvocation", functionOptimizeNextInvocation, 1);
608 addFunction(vm, "reoptimizationRetryCount", functionReoptimizationRetryCount, 1);
609 addFunction(vm, "transferArrayBuffer", functionTransferArrayBuffer, 1);
610#if ENABLE(SAMPLING_FLAGS)
611 addFunction(vm, "setSamplingFlags", functionSetSamplingFlags, 1);
612 addFunction(vm, "clearSamplingFlags", functionClearSamplingFlags, 1);
613#endif
614 addConstructableFunction(vm, "Root", functionCreateRoot, 0);
615 addConstructableFunction(vm, "Element", functionCreateElement, 1);
616 addFunction(vm, "getElement", functionGetElement, 1);
617 addFunction(vm, "setElementRoot", functionSetElementRoot, 2);
618
619 putDirectNativeFunction(vm, this, Identifier(&vm, "DFGTrue"), 0, functionFalse1, DFGTrueIntrinsic, DontEnum | JSC::Function);
620 putDirectNativeFunction(vm, this, Identifier(&vm, "OSRExit"), 0, functionUndefined1, OSRExitIntrinsic, DontEnum | JSC::Function);
621 putDirectNativeFunction(vm, this, Identifier(&vm, "isFinalTier"), 0, functionFalse2, IsFinalTierIntrinsic, DontEnum | JSC::Function);
622 putDirectNativeFunction(vm, this, Identifier(&vm, "predictInt32"), 0, functionUndefined2, SetInt32HeapPredictionIntrinsic, DontEnum | JSC::Function);
623 putDirectNativeFunction(vm, this, Identifier(&vm, "fiatInt52"), 0, functionIdentity, FiatInt52Intrinsic, DontEnum | JSC::Function);
624
625 addFunction(vm, "effectful42", functionEffectful42, 0);
626 addFunction(vm, "makeMasquerader", functionMakeMasquerader, 0);
627 addFunction(vm, "hasCustomProperties", functionHasCustomProperties, 0);
628
629 addFunction(vm, "createProxy", functionCreateProxy, 1);
630 addFunction(vm, "createRuntimeArray", functionCreateRuntimeArray, 0);
631
632 addFunction(vm, "createImpureGetter", functionCreateImpureGetter, 1);
633 addFunction(vm, "setImpureGetterDelegate", functionSetImpureGetterDelegate, 2);
634
635 addFunction(vm, "dumpTypesForAllVariables", functionDumpTypesForAllVariables , 0);
636 addFunction(vm, "findTypeForExpression", functionFindTypeForExpression, 2);
637 addFunction(vm, "returnTypeFor", functionReturnTypeFor, 1);
638
639 addFunction(vm, "dumpBasicBlockExecutionRanges", functionDumpBasicBlockExecutionRanges , 0);
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(globalExec(), "arguments"), array);
645
646 putDirect(vm, Identifier(globalExec(), "console"), jsUndefined());
647 }
648
649 void addFunction(VM& vm, const char* name, NativeFunction function, unsigned arguments)
650 {
651 Identifier identifier(&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(&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, &javaScriptExperimentsEnabled, 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(jsUndefined());
837}
838
839EncodedJSValue JSC_HOST_CALL functionFullGC(ExecState* exec)
840{
841 JSLockHolder lock(exec);
842 exec->heap()->collect(FullCollection);
843 return JSValue::encode(jsUndefined());
844}
845
846EncodedJSValue JSC_HOST_CALL functionEdenGC(ExecState* exec)
847{
848 JSLockHolder lock(exec);
849 exec->heap()->collect(EdenCollection);
850 return JSValue::encode(jsUndefined());
851}
852
853EncodedJSValue JSC_HOST_CALL functionDeleteAllCompiledCode(ExecState* exec)
854{
855 JSLockHolder lock(exec);
856 exec->heap()->deleteAllCompiledCode();
857 return JSValue::encode(jsUndefined());
858}
859
860#ifndef NDEBUG
861EncodedJSValue JSC_HOST_CALL functionReleaseExecutableMemory(ExecState* exec)
862{
863 JSLockHolder lock(exec);
864 exec->vm().releaseExecutableMemory();
865 return JSValue::encode(jsUndefined());
866}
867#endif
868
869EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*)
870{
871 // We need this function for compatibility with the Mozilla JS tests but for now
872 // we don't actually do any version-specific handling
873 return JSValue::encode(jsUndefined());
874}
875
876EncodedJSValue JSC_HOST_CALL functionRun(ExecState* exec)
877{
878 String fileName = exec->argument(0).toString(exec)->value(exec);
879 Vector<char> script;
880 if (!fillBufferWithContentsOfFile(fileName, script))
881 return JSValue::encode(exec->vm().throwException(exec, createError(exec, ASCIILiteral("Could not open file."))));
882
883 GlobalObject* globalObject = GlobalObject::create(exec->vm(), GlobalObject::createStructure(exec->vm(), jsNull()), Vector<String>());
884
885 JSArray* array = constructEmptyArray(globalObject->globalExec(), 0);
886 for (unsigned i = 1; i < exec->argumentCount(); ++i)
887 array->putDirectIndex(globalObject->globalExec(), i - 1, exec->uncheckedArgument(i));
888 globalObject->putDirect(
889 exec->vm(), Identifier(globalObject->globalExec(), "arguments"), array);
890
891 JSValue exception;
892 StopWatch stopWatch;
893 stopWatch.start();
894 evaluate(globalObject->globalExec(), jscSource(script.data(), fileName), JSValue(), &exception);
895 stopWatch.stop();
896
897 if (!!exception) {
898 exec->vm().throwException(globalObject->globalExec(), exception);
899 return JSValue::encode(jsUndefined());
900 }
901
902 return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
903}
904
905EncodedJSValue JSC_HOST_CALL functionLoad(ExecState* exec)
906{
907 String fileName = exec->argument(0).toString(exec)->value(exec);
908 Vector<char> script;
909 if (!fillBufferWithContentsOfFile(fileName, script))
910 return JSValue::encode(exec->vm().throwException(exec, createError(exec, ASCIILiteral("Could not open file."))));
911
912 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
913
914 JSValue evaluationException;
915 JSValue result = evaluate(globalObject->globalExec(), jscSource(script.data(), fileName), JSValue(), &evaluationException);
916 if (evaluationException)
917 exec->vm().throwException(exec, evaluationException);
918 return JSValue::encode(result);
919}
920
921EncodedJSValue JSC_HOST_CALL functionReadFile(ExecState* exec)
922{
923 String fileName = exec->argument(0).toString(exec)->value(exec);
924 Vector<char> script;
925 if (!fillBufferWithContentsOfFile(fileName, script))
926 return JSValue::encode(exec->vm().throwException(exec, createError(exec, ASCIILiteral("Could not open file."))));
927
928 return JSValue::encode(jsString(exec, stringFromUTF(script.data())));
929}
930
931EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState* exec)
932{
933 String fileName = exec->argument(0).toString(exec)->value(exec);
934 Vector<char> script;
935 if (!fillBufferWithContentsOfFile(fileName, script))
936 return JSValue::encode(exec->vm().throwException(exec, createError(exec, ASCIILiteral("Could not open file."))));
937
938 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
939
940 StopWatch stopWatch;
941 stopWatch.start();
942
943 JSValue syntaxException;
944 bool validSyntax = checkSyntax(globalObject->globalExec(), jscSource(script.data(), fileName), &syntaxException);
945 stopWatch.stop();
946
947 if (!validSyntax)
948 exec->vm().throwException(exec, syntaxException);
949 return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
950}
951
952#if ENABLE(SAMPLING_FLAGS)
953EncodedJSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState* exec)
954{
955 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
956 unsigned flag = static_cast<unsigned>(exec->uncheckedArgument(i).toNumber(exec));
957 if ((flag >= 1) && (flag <= 32))
958 SamplingFlags::setFlag(flag);
959 }
960 return JSValue::encode(jsNull());
961}
962
963EncodedJSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState* exec)
964{
965 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
966 unsigned flag = static_cast<unsigned>(exec->uncheckedArgument(i).toNumber(exec));
967 if ((flag >= 1) && (flag <= 32))
968 SamplingFlags::clearFlag(flag);
969 }
970 return JSValue::encode(jsNull());
971}
972#endif
973
974EncodedJSValue JSC_HOST_CALL functionReadline(ExecState* exec)
975{
976 Vector<char, 256> line;
977 int c;
978 while ((c = getchar()) != EOF) {
979 // FIXME: Should we also break on \r?
980 if (c == '\n')
981 break;
982 line.append(c);
983 }
984 line.append('\0');
985 return JSValue::encode(jsString(exec, line.data()));
986}
987
988EncodedJSValue JSC_HOST_CALL functionPreciseTime(ExecState*)
989{
990 return JSValue::encode(jsNumber(currentTime()));
991}
992
993EncodedJSValue JSC_HOST_CALL functionNeverInlineFunction(ExecState* exec)
994{
995 return JSValue::encode(setNeverInline(exec));
996}
997
998EncodedJSValue JSC_HOST_CALL functionOptimizeNextInvocation(ExecState* exec)
999{
1000 return JSValue::encode(optimizeNextInvocation(exec));
1001}
1002
1003EncodedJSValue JSC_HOST_CALL functionNumberOfDFGCompiles(ExecState* exec)
1004{
1005 return JSValue::encode(numberOfDFGCompiles(exec));
1006}
1007
1008EncodedJSValue JSC_HOST_CALL functionReoptimizationRetryCount(ExecState* exec)
1009{
1010 if (exec->argumentCount() < 1)
1011 return JSValue::encode(jsUndefined());
1012
1013 CodeBlock* block = getSomeBaselineCodeBlockForFunction(exec->argument(0));
1014 if (!block)
1015 return JSValue::encode(jsNumber(0));
1016
1017 return JSValue::encode(jsNumber(block->reoptimizationRetryCounter()));
1018}
1019
1020EncodedJSValue JSC_HOST_CALL functionTransferArrayBuffer(ExecState* exec)
1021{
1022 if (exec->argumentCount() < 1)
1023 return JSValue::encode(exec->vm().throwException(exec, createError(exec, ASCIILiteral("Not enough arguments"))));
1024
1025 JSArrayBuffer* buffer = jsDynamicCast<JSArrayBuffer*>(exec->argument(0));
1026 if (!buffer)
1027 return JSValue::encode(exec->vm().throwException(exec, createError(exec, ASCIILiteral("Expected an array buffer"))));
1028
1029 ArrayBufferContents dummyContents;
1030 buffer->impl()->transfer(dummyContents);
1031
1032 return JSValue::encode(jsUndefined());
1033}
1034
1035EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*)
1036{
1037 jscExit(EXIT_SUCCESS);
1038
1039#if COMPILER(MSVC)
1040 // Without this, Visual Studio will complain that this method does not return a value.
1041 return JSValue::encode(jsUndefined());
1042#endif
1043}
1044
1045EncodedJSValue JSC_HOST_CALL functionFalse1(ExecState*) { return JSValue::encode(jsBoolean(false)); }
1046EncodedJSValue JSC_HOST_CALL functionFalse2(ExecState*) { return JSValue::encode(jsBoolean(false)); }
1047
1048EncodedJSValue JSC_HOST_CALL functionUndefined1(ExecState*) { return JSValue::encode(jsUndefined()); }
1049EncodedJSValue JSC_HOST_CALL functionUndefined2(ExecState*) { return JSValue::encode(jsUndefined()); }
1050
1051EncodedJSValue JSC_HOST_CALL functionIdentity(ExecState* exec) { return JSValue::encode(exec->argument(0)); }
1052
1053EncodedJSValue JSC_HOST_CALL functionEffectful42(ExecState*)
1054{
1055 return JSValue::encode(jsNumber(42));
1056}
1057
1058EncodedJSValue JSC_HOST_CALL functionMakeMasquerader(ExecState* exec)
1059{
1060 return JSValue::encode(Masquerader::create(exec->vm(), exec->lexicalGlobalObject()));
1061}
1062
1063EncodedJSValue JSC_HOST_CALL functionHasCustomProperties(ExecState* exec)
1064{
1065 JSValue value = exec->argument(0);
1066 if (value.isObject())
1067 return JSValue::encode(jsBoolean(asObject(value)->hasCustomProperties()));
1068 return JSValue::encode(jsBoolean(false));
1069}
1070
1071EncodedJSValue JSC_HOST_CALL functionDumpTypesForAllVariables(ExecState* exec)
1072{
1073 exec->vm().dumpTypeProfilerData();
1074 return JSValue::encode(jsUndefined());
1075}
1076
1077EncodedJSValue JSC_HOST_CALL functionFindTypeForExpression(ExecState* exec)
1078{
1079 RELEASE_ASSERT(exec->vm().typeProfiler());
1080 exec->vm().typeProfilerLog()->processLogEntries(ASCIILiteral("jsc Testing API: functionFindTypeForExpression"));
1081
1082 JSValue functionValue = exec->argument(0);
1083 RELEASE_ASSERT(functionValue.isFunction());
1084 FunctionExecutable* executable = (jsDynamicCast<JSFunction*>(functionValue.asCell()->getObject()))->jsExecutable();
1085
1086 RELEASE_ASSERT(exec->argument(1).isString());
1087 String substring = exec->argument(1).getString(exec);
1088 String sourceCodeText = executable->source().toString();
1089 unsigned offset = static_cast<unsigned>(sourceCodeText.find(substring) + executable->source().startOffset());
1090
1091 String jsonString = exec->vm().typeProfiler()->typeInformationForExpressionAtOffset(TypeProfilerSearchDescriptorNormal, offset, executable->sourceID(), exec->vm());
1092 return JSValue::encode(JSONParse(exec, jsonString));
1093}
1094
1095EncodedJSValue JSC_HOST_CALL functionReturnTypeFor(ExecState* exec)
1096{
1097 RELEASE_ASSERT(exec->vm().typeProfiler());
1098 exec->vm().typeProfilerLog()->processLogEntries(ASCIILiteral("jsc Testing API: functionReturnTypeFor"));
1099
1100 JSValue functionValue = exec->argument(0);
1101 RELEASE_ASSERT(functionValue.isFunction());
1102 FunctionExecutable* executable = (jsDynamicCast<JSFunction*>(functionValue.asCell()->getObject()))->jsExecutable();
1103
1104 unsigned offset = executable->source().startOffset();
1105 String jsonString = exec->vm().typeProfiler()->typeInformationForExpressionAtOffset(TypeProfilerSearchDescriptorFunctionReturn, offset, executable->sourceID(), exec->vm());
1106 return JSValue::encode(JSONParse(exec, jsonString));
1107}
1108
1109EncodedJSValue JSC_HOST_CALL functionDumpBasicBlockExecutionRanges(ExecState* exec)
1110{
1111 RELEASE_ASSERT(exec->vm().controlFlowProfiler());
1112 exec->vm().controlFlowProfiler()->dumpData();
1113 return JSValue::encode(jsUndefined());
1114}
1115
1116// Use SEH for Release builds only to get rid of the crash report dialog
1117// (luckily the same tests fail in Release and Debug builds so far). Need to
1118// be in a separate main function because the jscmain function requires object
1119// unwinding.
1120
1121#if COMPILER(MSVC) && !defined(_DEBUG)
1122#define TRY __try {
1123#define EXCEPT(x) } __except (EXCEPTION_EXECUTE_HANDLER) { x; }
1124#else
1125#define TRY
1126#define EXCEPT(x)
1127#endif
1128
1129int jscmain(int argc, char** argv);
1130
1131static double s_desiredTimeout;
1132
1133static NO_RETURN_DUE_TO_CRASH void timeoutThreadMain(void*)
1134{
1135 auto timeout = std::chrono::microseconds(static_cast<std::chrono::microseconds::rep>(s_desiredTimeout * 1000000));
1136 std::this_thread::sleep_for(timeout);
1137
1138 dataLog("Timed out after ", s_desiredTimeout, " seconds!\n");
1139 CRASH();
1140}
1141
1142int main(int argc, char** argv)
1143{
1144#if PLATFORM(IOS) && CPU(ARM_THUMB2)
1145 // Enabled IEEE754 denormal support.
1146 fenv_t env;
1147 fegetenv( &env );
1148 env.__fpscr &= ~0x01000000u;
1149 fesetenv( &env );
1150#endif
1151
1152#if OS(WINDOWS)
1153 // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for
1154 // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the
1155 // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>.
1156 ::SetErrorMode(0);
1157
1158#if defined(_DEBUG)
1159 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
1160 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
1161 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
1162 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
1163 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
1164 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
1165#endif
1166
1167 timeBeginPeriod(1);
1168#endif
1169
1170#if PLATFORM(EFL)
1171 ecore_init();
1172#endif
1173
1174 // Initialize JSC before getting VM.
1175#if ENABLE(SAMPLING_REGIONS)
1176 WTF::initializeMainThread();
1177#endif
1178 JSC::initializeThreading();
1179
1180 if (char* timeoutString = getenv("JSC_timeout")) {
1181 if (sscanf(timeoutString, "%lf", &s_desiredTimeout) != 1) {
1182 dataLog(
1183 "WARNING: timeout string is malformed, got ", timeoutString,
1184 " but expected a number. Not using a timeout.\n");
1185 } else
1186 createThread(timeoutThreadMain, 0, "jsc Timeout Thread");
1187 }
1188
1189#if PLATFORM(IOS)
1190 Options::crashIfCantAllocateJITMemory() = true;
1191#endif
1192
1193 // We can't use destructors in the following code because it uses Windows
1194 // Structured Exception Handling
1195 int res = 0;
1196 TRY
1197 res = jscmain(argc, argv);
1198 EXCEPT(res = 3)
1199 if (Options::logHeapStatisticsAtExit())
1200 HeapStatistics::reportSuccess();
1201
1202#if PLATFORM(EFL)
1203 ecore_shutdown();
1204#endif
1205
1206 jscExit(res);
1207}
1208
1209static bool runWithScripts(GlobalObject* globalObject, const Vector<Script>& scripts, bool dump)
1210{
1211 const char* script;
1212 String fileName;
1213 Vector<char> scriptBuffer;
1214
1215 if (dump)
1216 JSC::Options::dumpGeneratedBytecodes() = true;
1217
1218 VM& vm = globalObject->vm();
1219
1220#if ENABLE(SAMPLING_FLAGS)
1221 SamplingFlags::start();
1222#endif
1223
1224 bool success = true;
1225 for (size_t i = 0; i < scripts.size(); i++) {
1226 if (scripts[i].isFile) {
1227 fileName = scripts[i].argument;
1228 if (!fillBufferWithContentsOfFile(fileName, scriptBuffer))
1229 return false; // fail early so we can catch missing files
1230 script = scriptBuffer.data();
1231 } else {
1232 script = scripts[i].argument;
1233 fileName = ASCIILiteral("[Command Line]");
1234 }
1235
1236 vm.startSampling();
1237
1238 JSValue evaluationException;
1239 JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(script, fileName), JSValue(), &evaluationException);
1240 success = success && !evaluationException;
1241 if (dump && !evaluationException)
1242 printf("End: %s\n", returnValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
1243 if (evaluationException) {
1244 printf("Exception: %s\n", evaluationException.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
1245 Identifier stackID(globalObject->globalExec(), "stack");
1246 JSValue stackValue = evaluationException.get(globalObject->globalExec(), stackID);
1247 if (!stackValue.isUndefinedOrNull())
1248 printf("%s\n", stackValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
1249 }
1250
1251 vm.stopSampling();
1252 globalObject->globalExec()->clearException();
1253 }
1254
1255#if ENABLE(SAMPLING_FLAGS)
1256 SamplingFlags::stop();
1257#endif
1258#if ENABLE(SAMPLING_REGIONS)
1259 SamplingRegion::dump();
1260#endif
1261 vm.dumpSampleData(globalObject->globalExec());
1262#if ENABLE(SAMPLING_COUNTERS)
1263 AbstractSamplingCounter::dump();
1264#endif
1265#if ENABLE(REGEXP_TRACING)
1266 vm.dumpRegExpTrace();
1267#endif
1268 return success;
1269}
1270
1271#define RUNNING_FROM_XCODE 0
1272
1273static void runInteractive(GlobalObject* globalObject)
1274{
1275 String interpreterName(ASCIILiteral("Interpreter"));
1276
1277 bool shouldQuit = false;
1278 while (!shouldQuit) {
1279#if HAVE(READLINE) && !RUNNING_FROM_XCODE
1280 ParserError error;
1281 String source;
1282 do {
1283 error = ParserError();
1284 char* line = readline(source.isEmpty() ? interactivePrompt : "... ");
1285 shouldQuit = !line;
1286 if (!line)
1287 break;
1288 source = source + line;
1289 source = source + '\n';
1290 checkSyntax(globalObject->vm(), makeSource(source, interpreterName), error);
1291 if (!line[0])
1292 break;
1293 add_history(line);
1294 } while (error.m_syntaxErrorType == ParserError::SyntaxErrorRecoverable);
1295
1296 if (error.m_type != ParserError::ErrorNone) {
1297 printf("%s:%d\n", error.m_message.utf8().data(), error.m_line);
1298 continue;
1299 }
1300
1301
1302 JSValue evaluationException;
1303 JSValue returnValue = evaluate(globalObject->globalExec(), makeSource(source, interpreterName), JSValue(), &evaluationException);
1304#else
1305 printf("%s", interactivePrompt);
1306 Vector<char, 256> line;
1307 int c;
1308 while ((c = getchar()) != EOF) {
1309 // FIXME: Should we also break on \r?
1310 if (c == '\n')
1311 break;
1312 line.append(c);
1313 }
1314 if (line.isEmpty())
1315 break;
1316 line.append('\0');
1317
1318 JSValue evaluationException;
1319 JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(line.data(), interpreterName), JSValue(), &evaluationException);
1320#endif
1321 if (evaluationException)
1322 printf("Exception: %s\n", evaluationException.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
1323 else
1324 printf("%s\n", returnValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
1325
1326 globalObject->globalExec()->clearException();
1327 }
1328 printf("\n");
1329}
1330
1331static NO_RETURN void printUsageStatement(bool help = false)
1332{
1333 fprintf(stderr, "Usage: jsc [options] [files] [-- arguments]\n");
1334 fprintf(stderr, " -d Dumps bytecode (debug builds only)\n");
1335 fprintf(stderr, " -e Evaluate argument as script code\n");
1336 fprintf(stderr, " -f Specifies a source file (deprecated)\n");
1337 fprintf(stderr, " -h|--help Prints this help message\n");
1338 fprintf(stderr, " -i Enables interactive mode (default if no files are specified)\n");
1339#if HAVE(SIGNAL_H)
1340 fprintf(stderr, " -s Installs signal handlers that exit on a crash (Unix platforms only)\n");
1341#endif
1342 fprintf(stderr, " -p <file> Outputs profiling data to a file\n");
1343 fprintf(stderr, " -x Output exit code before terminating\n");
1344 fprintf(stderr, "\n");
1345 fprintf(stderr, " --options Dumps all JSC VM options and exits\n");
1346 fprintf(stderr, " --dumpOptions Dumps all JSC VM options before continuing\n");
1347 fprintf(stderr, " --<jsc VM option>=<value> Sets the specified JSC VM option\n");
1348 fprintf(stderr, "\n");
1349
1350 jscExit(help ? EXIT_SUCCESS : EXIT_FAILURE);
1351}
1352
1353void CommandLine::parseArguments(int argc, char** argv)
1354{
1355 int i = 1;
1356 bool needToDumpOptions = false;
1357 bool needToExit = false;
1358
1359 for (; i < argc; ++i) {
1360 const char* arg = argv[i];
1361 if (!strcmp(arg, "-f")) {
1362 if (++i == argc)
1363 printUsageStatement();
1364 m_scripts.append(Script(true, argv[i]));
1365 continue;
1366 }
1367 if (!strcmp(arg, "-e")) {
1368 if (++i == argc)
1369 printUsageStatement();
1370 m_scripts.append(Script(false, argv[i]));
1371 continue;
1372 }
1373 if (!strcmp(arg, "-i")) {
1374 m_interactive = true;
1375 continue;
1376 }
1377 if (!strcmp(arg, "-d")) {
1378 m_dump = true;
1379 continue;
1380 }
1381 if (!strcmp(arg, "-p")) {
1382 if (++i == argc)
1383 printUsageStatement();
1384 m_profile = true;
1385 m_profilerOutput = argv[i];
1386 continue;
1387 }
1388 if (!strcmp(arg, "-s")) {
1389#if HAVE(SIGNAL_H)
1390 signal(SIGILL, _exit);
1391 signal(SIGFPE, _exit);
1392 signal(SIGBUS, _exit);
1393 signal(SIGSEGV, _exit);
1394#endif
1395 continue;
1396 }
1397 if (!strcmp(arg, "-x")) {
1398 m_exitCode = true;
1399 continue;
1400 }
1401 if (!strcmp(arg, "--")) {
1402 ++i;
1403 break;
1404 }
1405 if (!strcmp(arg, "-h") || !strcmp(arg, "--help"))
1406 printUsageStatement(true);
1407
1408 if (!strcmp(arg, "--options")) {
1409 needToDumpOptions = true;
1410 needToExit = true;
1411 continue;
1412 }
1413 if (!strcmp(arg, "--dumpOptions")) {
1414 needToDumpOptions = true;
1415 continue;
1416 }
1417
1418 // See if the -- option is a JSC VM option.
1419 // NOTE: At this point, we know that the arg starts with "--". Skip it.
1420 if (JSC::Options::setOption(&arg[2])) {
1421 // The arg was recognized as a VM option and has been parsed.
1422 continue; // Just continue with the next arg.
1423 }
1424
1425 // This arg is not recognized by the VM nor by jsc. Pass it on to the
1426 // script.
1427 m_scripts.append(Script(true, argv[i]));
1428 }
1429
1430 if (m_scripts.isEmpty())
1431 m_interactive = true;
1432
1433 for (; i < argc; ++i)
1434 m_arguments.append(argv[i]);
1435
1436 if (needToDumpOptions)
1437 JSC::Options::dumpAllOptions(stderr);
1438 if (needToExit)
1439 jscExit(EXIT_SUCCESS);
1440}
1441
1442int jscmain(int argc, char** argv)
1443{
1444 // Note that the options parsing can affect VM creation, and thus
1445 // comes first.
1446 CommandLine options(argc, argv);
1447 VM* vm = VM::create(LargeHeap).leakRef();
1448 int result;
1449 {
1450 JSLockHolder locker(vm);
1451
1452 if (options.m_profile && !vm->m_perBytecodeProfiler)
1453 vm->m_perBytecodeProfiler = std::make_unique<Profiler::Database>(*vm);
1454
1455 GlobalObject* globalObject = GlobalObject::create(*vm, GlobalObject::createStructure(*vm, jsNull()), options.m_arguments);
1456 bool success = runWithScripts(globalObject, options.m_scripts, options.m_dump);
1457 if (options.m_interactive && success)
1458 runInteractive(globalObject);
1459
1460 result = success ? 0 : 3;
1461
1462 if (options.m_exitCode)
1463 printf("jsc exiting %d\n", result);
1464
1465 if (options.m_profile) {
1466 if (!vm->m_perBytecodeProfiler->save(options.m_profilerOutput.utf8().data()))
1467 fprintf(stderr, "could not save profiler output.\n");
1468 }
1469
1470#if ENABLE(JIT)
1471 if (Options::enableExceptionFuzz())
1472 printf("JSC EXCEPTION FUZZ: encountered %u checks.\n", numberOfExceptionFuzzChecks());
1473#endif
1474 }
1475
1476 return result;
1477}
1478
1479static bool fillBufferWithContentsOfFile(const String& fileName, Vector<char>& buffer)
1480{
1481 FILE* f = fopen(fileName.utf8().data(), "r");
1482 if (!f) {
1483 fprintf(stderr, "Could not open file: %s\n", fileName.utf8().data());
1484 return false;
1485 }
1486
1487 size_t bufferSize = 0;
1488 size_t bufferCapacity = 1024;
1489
1490 buffer.resize(bufferCapacity);
1491
1492 while (!feof(f) && !ferror(f)) {
1493 bufferSize += fread(buffer.data() + bufferSize, 1, bufferCapacity - bufferSize, f);
1494 if (bufferSize == bufferCapacity) { // guarantees space for trailing '\0'
1495 bufferCapacity *= 2;
1496 buffer.resize(bufferCapacity);
1497 }
1498 }
1499 fclose(f);
1500 buffer[bufferSize] = '\0';
1501
1502 if (buffer[0] == '#' && buffer[1] == '!')
1503 buffer[0] = buffer[1] = '/';
1504
1505 return true;
1506}
1507
1508#if OS(WINDOWS)
1509extern "C" __declspec(dllexport) int WINAPI dllLauncherEntryPoint(int argc, const char* argv[])
1510{
1511 return main(argc, const_cast<char**>(argv));
1512}
1513#endif
Note: See TracBrowser for help on using the repository browser.