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

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

Static hash tables no longer need to be coupled with a VM.
<https://webkit.org/b/135421>

Source/JavaScriptCore:
Now that the static hash tables are using char instead of StringImpl,
it's no longer necessary to make them per-VM.

This patch removes the hook in ClassInfo for providing your own static
hash table getter. Everyone now uses ClassInfo::staticPropHashTable.
Most of this patch is tweaking ClassInfo construction sites to pass one
less null pointer.

Also simplified Lookup.h to stop requiring ExecState/VM to access the
static hash tables.

Reviewed by Geoffrey Garen.

  • API/JSAPIWrapperObject.mm:
  • API/JSCallbackConstructor.cpp:
  • API/JSCallbackFunction.cpp:
  • API/JSCallbackObject.cpp:
  • API/ObjCCallbackFunction.mm:
  • bytecode/UnlinkedCodeBlock.cpp:
  • create_hash_table:
  • debugger/DebuggerScope.cpp:
  • inspector/JSInjectedScriptHost.cpp:
  • inspector/JSInjectedScriptHostPrototype.cpp:
  • inspector/JSJavaScriptCallFrame.cpp:
  • inspector/JSJavaScriptCallFramePrototype.cpp:
  • interpreter/CallFrame.h:

(JSC::ExecState::arrayConstructorTable): Deleted.
(JSC::ExecState::arrayPrototypeTable): Deleted.
(JSC::ExecState::booleanPrototypeTable): Deleted.
(JSC::ExecState::dataViewTable): Deleted.
(JSC::ExecState::dateTable): Deleted.
(JSC::ExecState::dateConstructorTable): Deleted.
(JSC::ExecState::errorPrototypeTable): Deleted.
(JSC::ExecState::globalObjectTable): Deleted.
(JSC::ExecState::jsonTable): Deleted.
(JSC::ExecState::numberConstructorTable): Deleted.
(JSC::ExecState::numberPrototypeTable): Deleted.
(JSC::ExecState::objectConstructorTable): Deleted.
(JSC::ExecState::privateNamePrototypeTable): Deleted.
(JSC::ExecState::regExpTable): Deleted.
(JSC::ExecState::regExpConstructorTable): Deleted.
(JSC::ExecState::regExpPrototypeTable): Deleted.
(JSC::ExecState::stringConstructorTable): Deleted.
(JSC::ExecState::promisePrototypeTable): Deleted.
(JSC::ExecState::promiseConstructorTable): Deleted.

  • jsc.cpp:
  • parser/Lexer.h:

(JSC::Keywords::isKeyword):
(JSC::Keywords::getKeyword):

  • runtime/Arguments.cpp:
  • runtime/ArgumentsIteratorConstructor.cpp:
  • runtime/ArgumentsIteratorPrototype.cpp:
  • runtime/ArrayBufferNeuteringWatchpoint.cpp:
  • runtime/ArrayConstructor.cpp:

(JSC::ArrayConstructor::getOwnPropertySlot):

  • runtime/ArrayIteratorConstructor.cpp:
  • runtime/ArrayIteratorPrototype.cpp:
  • runtime/ArrayPrototype.cpp:

(JSC::ArrayPrototype::getOwnPropertySlot):

  • runtime/BooleanConstructor.cpp:
  • runtime/BooleanObject.cpp:
  • runtime/BooleanPrototype.cpp:

(JSC::BooleanPrototype::getOwnPropertySlot):

  • runtime/ClassInfo.h:

(JSC::ClassInfo::hasStaticProperties):
(JSC::ClassInfo::propHashTable): Deleted.

  • runtime/ConsolePrototype.cpp:
  • runtime/CustomGetterSetter.cpp:
  • runtime/DateConstructor.cpp:

(JSC::DateConstructor::getOwnPropertySlot):

  • runtime/DateInstance.cpp:
  • runtime/DatePrototype.cpp:

(JSC::DatePrototype::getOwnPropertySlot):

  • runtime/Error.cpp:
  • runtime/ErrorConstructor.cpp:
  • runtime/ErrorInstance.cpp:
  • runtime/ErrorPrototype.cpp:

(JSC::ErrorPrototype::getOwnPropertySlot):

  • runtime/ExceptionHelpers.cpp:
  • runtime/Executable.cpp:
  • runtime/FunctionConstructor.cpp:
  • runtime/FunctionPrototype.cpp:
  • runtime/GetterSetter.cpp:
  • runtime/InternalFunction.cpp:
  • runtime/JSAPIValueWrapper.cpp:
  • runtime/JSActivation.cpp:
  • runtime/JSArgumentsIterator.cpp:
  • runtime/JSArray.cpp:
  • runtime/JSArrayBuffer.cpp:
  • runtime/JSArrayBufferConstructor.cpp:
  • runtime/JSArrayBufferPrototype.cpp:
  • runtime/JSArrayBufferView.cpp:
  • runtime/JSArrayIterator.cpp:
  • runtime/JSBoundFunction.cpp:
  • runtime/JSConsole.cpp:
  • runtime/JSDataView.cpp:
  • runtime/JSDataViewPrototype.cpp:

(JSC::JSDataViewPrototype::getOwnPropertySlot):

  • runtime/JSFunction.cpp:
  • runtime/JSGlobalObject.cpp:

(JSC::JSGlobalObject::getOwnPropertySlot):

  • runtime/JSMap.cpp:
  • runtime/JSMapIterator.cpp:
  • runtime/JSNameScope.cpp:
  • runtime/JSNotAnObject.cpp:
  • runtime/JSONObject.cpp:

(JSC::JSONObject::getOwnPropertySlot):

  • runtime/JSObject.cpp:

(JSC::getClassPropertyNames):
(JSC::JSObject::put):
(JSC::JSObject::deleteProperty):
(JSC::JSObject::findPropertyHashEntry):
(JSC::JSObject::reifyStaticFunctionsForDelete):

  • runtime/JSObject.h:
  • runtime/JSPromise.cpp:
  • runtime/JSPromiseConstructor.cpp:

(JSC::JSPromiseConstructor::getOwnPropertySlot):

  • runtime/JSPromiseDeferred.cpp:
  • runtime/JSPromisePrototype.cpp:

(JSC::JSPromisePrototype::getOwnPropertySlot):

  • runtime/JSPromiseReaction.cpp:
  • runtime/JSPropertyNameIterator.cpp:
  • runtime/JSProxy.cpp:
  • runtime/JSSet.cpp:
  • runtime/JSSetIterator.cpp:
  • runtime/JSString.cpp:
  • runtime/JSTypedArrayConstructors.cpp:
  • runtime/JSTypedArrayPrototypes.cpp:
  • runtime/JSTypedArrays.cpp:
  • runtime/JSVariableObject.cpp:
  • runtime/JSWeakMap.cpp:
  • runtime/JSWithScope.cpp:
  • runtime/Lookup.cpp:

(JSC::HashTable::createTable):

  • runtime/Lookup.h:

(JSC::HashTable::initializeIfNeeded):
(JSC::HashTable::entry):
(JSC::HashTable::begin):
(JSC::HashTable::end):
(JSC::getStaticPropertySlot):
(JSC::getStaticFunctionSlot):
(JSC::getStaticValueSlot):
(JSC::lookupPut):

  • runtime/MapConstructor.cpp:
  • runtime/MapData.cpp:
  • runtime/MapIteratorConstructor.cpp:
  • runtime/MapIteratorPrototype.cpp:
  • runtime/MapPrototype.cpp:
  • runtime/MathObject.cpp:
  • runtime/NameConstructor.cpp:
  • runtime/NameInstance.cpp:
  • runtime/NamePrototype.cpp:

(JSC::NamePrototype::getOwnPropertySlot):

  • runtime/NativeErrorConstructor.cpp:
  • runtime/NumberConstructor.cpp:

(JSC::NumberConstructor::getOwnPropertySlot):

  • runtime/NumberObject.cpp:
  • runtime/NumberPrototype.cpp:

(JSC::NumberPrototype::getOwnPropertySlot):

  • runtime/ObjectConstructor.cpp:

(JSC::ObjectConstructor::getOwnPropertySlot):

  • runtime/ObjectPrototype.cpp:
  • runtime/PropertyTable.cpp:
  • runtime/RegExp.cpp:
  • runtime/RegExpConstructor.cpp:

(JSC::RegExpConstructor::getOwnPropertySlot):

  • runtime/RegExpMatchesArray.cpp:
  • runtime/RegExpObject.cpp:

(JSC::RegExpObject::getOwnPropertySlot):

  • runtime/RegExpPrototype.cpp:

(JSC::RegExpPrototype::getOwnPropertySlot):

  • runtime/SetConstructor.cpp:
  • runtime/SetIteratorConstructor.cpp:
  • runtime/SetIteratorPrototype.cpp:
  • runtime/SetPrototype.cpp:
  • runtime/SparseArrayValueMap.cpp:
  • runtime/StrictEvalActivation.cpp:
  • runtime/StringConstructor.cpp:

(JSC::StringConstructor::getOwnPropertySlot):

  • runtime/StringObject.cpp:
  • runtime/StringPrototype.cpp:
  • runtime/Structure.cpp:

(JSC::Structure::Structure):
(JSC::Structure::freezeTransition):
(JSC::ClassInfo::hasStaticSetterOrReadonlyProperties):

  • runtime/StructureChain.cpp:
  • runtime/StructureRareData.cpp:
  • runtime/SymbolTable.cpp:
  • runtime/VM.cpp:

(JSC::VM::VM):
(JSC::VM::~VM):

  • runtime/VM.h:
  • runtime/WeakMapConstructor.cpp:
  • runtime/WeakMapData.cpp:
  • runtime/WeakMapPrototype.cpp:
  • testRegExp.cpp:

Source/WebCore:
Update for JSC::ClassInfo changes.

Remove the JSNoStaticTables mode for IDL code generation, which was used to
ensure that each VM had its own unique copy of certain static tables.
This was used for interfaces that could be used in workers, and now there's
no need to manually annotate these things anymore.

Also remove the DOMObjectHashTableMap class that was only used for this.

Reviewed by Geoffrey Garen.

  • Modules/indexeddb/IDBAny.idl:
  • Modules/indexeddb/IDBCursor.idl:
  • Modules/indexeddb/IDBCursorWithValue.idl:
  • Modules/indexeddb/IDBDatabase.idl:
  • Modules/indexeddb/IDBFactory.idl:
  • Modules/indexeddb/IDBIndex.idl:
  • Modules/indexeddb/IDBKeyRange.idl:
  • Modules/indexeddb/IDBObjectStore.idl:
  • Modules/indexeddb/IDBOpenDBRequest.idl:
  • Modules/indexeddb/IDBRequest.idl:
  • Modules/indexeddb/IDBTransaction.idl:
  • Modules/indexeddb/IDBVersionChangeEvent.idl:
  • Modules/webdatabase/Database.idl:
  • Modules/webdatabase/DatabaseSync.idl:
  • Modules/webdatabase/SQLError.idl:
  • Modules/webdatabase/SQLException.idl:
  • Modules/webdatabase/SQLResultSet.idl:
  • Modules/webdatabase/SQLResultSetRowList.idl:
  • Modules/webdatabase/SQLTransaction.idl:
  • Modules/webdatabase/SQLTransactionSync.idl:
  • Modules/websockets/CloseEvent.idl:
  • Modules/websockets/WebSocket.idl:
  • WebCore.xcodeproj/project.pbxproj:
  • bindings/js/DOMObjectHashTableMap.cpp: Removed.
  • bindings/js/DOMObjectHashTableMap.h: Removed.
  • bindings/js/JSDOMBinding.cpp:

(WebCore::getHashTableForGlobalData): Deleted.

  • bindings/js/JSDOMBinding.h:

(WebCore::getStaticValueSlotEntryWithoutCaching):

  • bindings/js/JSDOMGlobalObject.cpp:
  • bindings/js/JSDOMWindowBase.cpp:
  • bindings/js/JSDOMWindowCustom.cpp:

(WebCore::JSDOMWindow::getOwnPropertySlot):
(WebCore::JSDOMWindow::put):

  • bindings/js/JSDOMWindowShell.cpp:
  • bindings/js/JSImageConstructor.cpp:
  • bindings/js/JSLocationCustom.cpp:

(WebCore::JSLocation::putDelegate):

  • bindings/js/JSStorageCustom.cpp:

(WebCore::JSStorage::deleteProperty):
(WebCore::JSStorage::putDelegate):

  • bindings/js/JSWorkerGlobalScopeBase.cpp:
  • bindings/js/WebCoreJSClientData.h:
  • bindings/scripts/CodeGeneratorJS.pm:

(GenerateGetOwnPropertySlotBody):
(GenerateImplementation):
(GenerateConstructorHelperMethods):
(hashTableAccessor): Deleted.
(prototypeHashTableAccessor): Deleted.
(constructorHashTableAccessor): Deleted.

  • bindings/scripts/IDLAttributes.txt:
  • bridge/c/CRuntimeObject.cpp:
  • bridge/c/c_instance.cpp:
  • bridge/objc/ObjCRuntimeObject.mm:
  • bridge/objc/objc_instance.mm:
  • bridge/objc/objc_runtime.mm:
  • bridge/runtime_array.cpp:
  • bridge/runtime_method.cpp:
  • bridge/runtime_object.cpp:
  • crypto/CryptoKey.idl:
  • css/CSSFontFaceLoadEvent.idl:
  • dom/DOMCoreException.idl:
  • dom/DOMStringList.idl:
  • dom/ErrorEvent.idl:
  • dom/Event.idl:
  • dom/EventException.idl:
  • dom/EventListener.idl:
  • dom/MessageChannel.idl:
  • dom/MessageEvent.idl:
  • dom/MessagePort.idl:
  • dom/ProgressEvent.idl:
  • fileapi/Blob.idl:
  • fileapi/File.idl:
  • fileapi/FileError.idl:
  • fileapi/FileException.idl:
  • fileapi/FileList.idl:
  • fileapi/FileReader.idl:
  • fileapi/FileReaderSync.idl:
  • html/DOMURL.idl:
  • page/EventSource.idl:
  • page/WorkerNavigator.idl:
  • workers/DedicatedWorkerGlobalScope.idl:
  • workers/SharedWorkerGlobalScope.idl:
  • workers/WorkerGlobalScope.idl:
  • workers/WorkerLocation.idl:
  • xml/XMLHttpRequest.idl:
  • xml/XMLHttpRequestException.idl:
  • xml/XMLHttpRequestProgressEvent.idl:
  • xml/XMLHttpRequestUpload.idl:

Source/WebKit/mac:
Reviewed by Geoffrey Garen.

  • Plugins/Hosted/ProxyInstance.mm:
  • Plugins/Hosted/ProxyRuntimeObject.mm:

Source/WebKit2:
Reviewed by Geoffrey Garen.

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