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

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

JSValue::toString() should return a JSString* instead of a UString
https://bugs.webkit.org/show_bug.cgi?id=76861

../JavaScriptCore:

Reviewed by Gavin Barraclough.

This makes the common case -- toString() on a string -- faster and
inline-able. (Not a measureable speedup, but we can now remove a bunch
of duplicate hand-rolled code for this optimization.)

This also clarifies the boundary between "C++ strings" and "JS strings".

In all cases other than true, false, null, undefined, and multi-digit
numbers, the JS runtime was just retrieving a UString from a JSString,
so returning a JSString* is strictly better. In the other cases, we can
optimize to avoid creating a new JSString if we care to, but it doesn't
seem to be a big deal.


  • jsc.cpp:

(functionPrint):
(functionDebug):
(functionRun):
(functionLoad):
(functionCheckSyntax):
(runWithScripts):
(runInteractive):

  • API/JSValueRef.cpp:

(JSValueToStringCopy):

  • bytecode/CodeBlock.cpp:

(JSC::valueToSourceString): Call value() after calling toString(), to
convert from "JS string" (JSString*) to "C++ string" (UString), since
toString() no longer returns a "C++ string".

  • dfg/DFGOperations.cpp:

(JSC::DFG::operationValueAddNotNumber):

  • jit/JITStubs.cpp:

(op_add): Updated for removal of toPrimitiveString():
all '+' operands can use toString(), except for object operands, which
need to take a slow path to call toPrimitive().

  • runtime/ArrayPrototype.cpp:

(JSC::arrayProtoFuncToString):
(JSC::arrayProtoFuncToLocaleString):
(JSC::arrayProtoFuncJoin):
(JSC::arrayProtoFuncPush):

  • runtime/CommonSlowPaths.h:

(JSC::CommonSlowPaths::opIn):

  • runtime/DateConstructor.cpp:

(JSC::dateParse):

  • runtime/DatePrototype.cpp:

(JSC::formatLocaleDate): Call value() after calling toString(), as above.

  • runtime/ErrorInstance.h:

(JSC::ErrorInstance::create): Simplified down to one canonical create()
function, to make string handling easier.

  • runtime/ErrorPrototype.cpp:

(JSC::errorProtoFuncToString):

  • runtime/ExceptionHelpers.cpp:

(JSC::createInvalidParamError):
(JSC::createNotAConstructorError):
(JSC::createNotAFunctionError):
(JSC::createNotAnObjectError):

  • runtime/FunctionConstructor.cpp:

(JSC::constructFunctionSkippingEvalEnabledCheck):

  • runtime/FunctionPrototype.cpp:

(JSC::functionProtoFuncBind):

  • runtime/JSArray.cpp:

(JSC::JSArray::sort): Call value() after calling toString(), as above.

  • runtime/JSCell.cpp:
  • runtime/JSCell.h: Removed JSCell::toString() because JSValue does this

job now. Doing it in JSCell is slower (requires extra type checking), and
creates the misimpression that language-defined toString() behavior is
an implementation detail of JSCell.

  • runtime/JSGlobalObjectFunctions.cpp:

(JSC::encode):
(JSC::decode):
(JSC::globalFuncEval):
(JSC::globalFuncParseInt):
(JSC::globalFuncParseFloat):
(JSC::globalFuncEscape):
(JSC::globalFuncUnescape): Call value() after calling toString(), as above.

  • runtime/JSONObject.cpp:

(JSC::unwrapBoxedPrimitive):
(JSC::Stringifier::Stringifier):
(JSC::JSONProtoFuncParse): Removed some manual optimization that toString()
takes care of.

  • runtime/JSObject.cpp:

(JSC::JSObject::toString):

  • runtime/JSObject.h: Updated to return JSString*.
  • runtime/JSString.cpp:
  • runtime/JSString.h:

(JSC::JSValue::toString): Removed, since I removed JSCell::toString().

  • runtime/JSValue.cpp:

(JSC::JSValue::toStringSlowCase): Removed toPrimitiveString(), and re-
spawned toStringSlowCase() from its zombie corpse, since toPrimitiveString()
basically did what we want all the time. (Note that the toPrimitive()
preference changes from NoPreference to PreferString, because that's
how ToString is defined in the language. op_add does not want this behavior.)

  • runtime/NumberPrototype.cpp:

(JSC::numberProtoFuncToString):
(JSC::numberProtoFuncToLocaleString): A little simpler, now that toString()
returns a JSString*.

  • runtime/ObjectConstructor.cpp:

(JSC::objectConstructorGetOwnPropertyDescriptor):
(JSC::objectConstructorDefineProperty):

  • runtime/ObjectPrototype.cpp:

(JSC::objectProtoFuncHasOwnProperty):
(JSC::objectProtoFuncDefineGetter):
(JSC::objectProtoFuncDefineSetter):
(JSC::objectProtoFuncLookupGetter):
(JSC::objectProtoFuncLookupSetter):
(JSC::objectProtoFuncPropertyIsEnumerable): More calls to value(), as above.

  • runtime/Operations.cpp:

(JSC::jsAddSlowCase): Need to check for object before taking the toString()
fast path becuase adding an object to a string requires calling toPrimitive()
on the object, not toString(). (They differ in their preferred conversion
type.)

  • runtime/Operations.h:

(JSC::jsString):
(JSC::jsStringFromArguments): This code gets simpler, now that toString()
does the right thing.

(JSC::jsAdd): Now checks for object, just like jsAddSlowCase().

  • runtime/RegExpConstructor.cpp:

(JSC::setRegExpConstructorInput):
(JSC::constructRegExp):

  • runtime/RegExpObject.cpp:

(JSC::RegExpObject::match):

  • runtime/RegExpPrototype.cpp:

(JSC::regExpProtoFuncCompile):
(JSC::regExpProtoFuncToString): More calls to value(), as above.

  • runtime/StringConstructor.cpp:

(JSC::constructWithStringConstructor):
(JSC::callStringConstructor): This code gets simpler, now that toString()
does the right thing.

  • runtime/StringPrototype.cpp:

(JSC::replaceUsingRegExpSearch):
(JSC::replaceUsingStringSearch):
(JSC::stringProtoFuncReplace):
(JSC::stringProtoFuncCharAt):
(JSC::stringProtoFuncCharCodeAt):
(JSC::stringProtoFuncConcat):
(JSC::stringProtoFuncIndexOf):
(JSC::stringProtoFuncLastIndexOf):
(JSC::stringProtoFuncMatch):
(JSC::stringProtoFuncSearch):
(JSC::stringProtoFuncSlice):
(JSC::stringProtoFuncSplit):
(JSC::stringProtoFuncSubstr):
(JSC::stringProtoFuncSubstring):
(JSC::stringProtoFuncToLowerCase):
(JSC::stringProtoFuncToUpperCase):
(JSC::stringProtoFuncLocaleCompare):
(JSC::stringProtoFuncBig):
(JSC::stringProtoFuncSmall):
(JSC::stringProtoFuncBlink):
(JSC::stringProtoFuncBold):
(JSC::stringProtoFuncFixed):
(JSC::stringProtoFuncItalics):
(JSC::stringProtoFuncStrike):
(JSC::stringProtoFuncSub):
(JSC::stringProtoFuncSup):
(JSC::stringProtoFuncFontcolor):
(JSC::stringProtoFuncFontsize):
(JSC::stringProtoFuncAnchor):
(JSC::stringProtoFuncLink):
(JSC::trimString): Some of this code gets simpler, now that toString()
does the right thing. More calls to value(), as above.

../JavaScriptGlue:

Reviewed by Gavin Barraclough.

  • JSUtils.cpp:

(KJSValueToCFTypeInternal):

../WebCore:

Reviewed by Gavin Barraclough.

Mechanical changes to call value() after calling toString(), to
convert from "JS string" (JSString*) to "C++ string" (UString), since
toString() no longer returns a "C++ string".

  • bindings/js/IDBBindingUtilities.cpp:

(WebCore::createIDBKeyFromValue):

  • bindings/js/JSCSSStyleDeclarationCustom.cpp:

(WebCore::JSCSSStyleDeclaration::getPropertyCSSValue):

  • bindings/js/JSClipboardCustom.cpp:

(WebCore::JSClipboard::clearData):
(WebCore::JSClipboard::getData):

  • bindings/js/JSCustomXPathNSResolver.cpp:

(WebCore::JSCustomXPathNSResolver::lookupNamespaceURI):

  • bindings/js/JSDOMBinding.cpp:

(WebCore::valueToStringWithNullCheck):
(WebCore::valueToStringWithUndefinedOrNullCheck):
(WebCore::reportException):

  • bindings/js/JSDOMFormDataCustom.cpp:

(WebCore::JSDOMFormData::append):

  • bindings/js/JSDOMStringMapCustom.cpp:

(WebCore::JSDOMStringMap::putDelegate):

  • bindings/js/JSDOMWindowCustom.cpp:

(WebCore::JSDOMWindow::setLocation):
(WebCore::JSDOMWindow::open):
(WebCore::JSDOMWindow::addEventListener):
(WebCore::JSDOMWindow::removeEventListener):

  • bindings/js/JSDeviceMotionEventCustom.cpp:

(WebCore::JSDeviceMotionEvent::initDeviceMotionEvent):

  • bindings/js/JSDeviceOrientationEventCustom.cpp:

(WebCore::JSDeviceOrientationEvent::initDeviceOrientationEvent):

  • bindings/js/JSDictionary.cpp:

(WebCore::JSDictionary::convertValue):

  • bindings/js/JSDocumentCustom.cpp:

(WebCore::JSDocument::setLocation):

  • bindings/js/JSEventListener.cpp:

(WebCore::JSEventListener::handleEvent):

  • bindings/js/JSHTMLAllCollectionCustom.cpp:

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

  • bindings/js/JSHTMLCanvasElementCustom.cpp:

(WebCore::JSHTMLCanvasElement::getContext):

  • bindings/js/JSHTMLCollectionCustom.cpp:

(WebCore::JSHTMLCollection::item):
(WebCore::JSHTMLCollection::namedItem):

  • bindings/js/JSHTMLDocumentCustom.cpp:

(WebCore::documentWrite):

  • bindings/js/JSHTMLInputElementCustom.cpp:

(WebCore::JSHTMLInputElement::setSelectionDirection):
(WebCore::JSHTMLInputElement::setSelectionRange):

  • bindings/js/JSInspectorFrontendHostCustom.cpp:

(WebCore::JSInspectorFrontendHost::showContextMenu):

  • bindings/js/JSJavaScriptCallFrameCustom.cpp:

(WebCore::JSJavaScriptCallFrame::evaluate):

  • bindings/js/JSLocationCustom.cpp:

(WebCore::JSLocation::setHref):
(WebCore::JSLocation::setProtocol):
(WebCore::JSLocation::setHost):
(WebCore::JSLocation::setHostname):
(WebCore::JSLocation::setPort):
(WebCore::JSLocation::setPathname):
(WebCore::JSLocation::setSearch):
(WebCore::JSLocation::setHash):
(WebCore::JSLocation::replace):
(WebCore::JSLocation::assign):

  • bindings/js/JSMessageEventCustom.cpp:

(WebCore::handleInitMessageEvent):

  • bindings/js/JSSQLTransactionCustom.cpp:

(WebCore::JSSQLTransaction::executeSql):

  • bindings/js/JSSQLTransactionSyncCustom.cpp:

(WebCore::JSSQLTransactionSync::executeSql):

  • bindings/js/JSSharedWorkerCustom.cpp:

(WebCore::JSSharedWorkerConstructor::constructJSSharedWorker):

  • bindings/js/JSStorageCustom.cpp:

(WebCore::JSStorage::putDelegate):

  • bindings/js/JSWebGLRenderingContextCustom.cpp:

(WebCore::JSWebGLRenderingContext::getExtension):

  • bindings/js/JSWebSocketCustom.cpp:

(WebCore::JSWebSocketConstructor::constructJSWebSocket):
(WebCore::JSWebSocket::send):
(WebCore::JSWebSocket::close):

  • bindings/js/JSWorkerContextCustom.cpp:

(WebCore::JSWorkerContext::importScripts):

  • bindings/js/JSWorkerCustom.cpp:

(WebCore::JSWorkerConstructor::constructJSWorker):

  • bindings/js/JSXMLHttpRequestCustom.cpp:

(WebCore::JSXMLHttpRequest::open):
(WebCore::JSXMLHttpRequest::send):

  • bindings/js/JSXSLTProcessorCustom.cpp:

(WebCore::JSXSLTProcessor::setParameter):
(WebCore::JSXSLTProcessor::getParameter):
(WebCore::JSXSLTProcessor::removeParameter):

  • bindings/js/ScheduledAction.cpp:

(WebCore::ScheduledAction::create):

  • bindings/js/ScriptEventListener.cpp:

(WebCore::eventListenerHandlerBody):

  • bindings/js/ScriptValue.cpp:

(WebCore::ScriptValue::toString):

  • bindings/scripts/CodeGeneratorJS.pm:

(GenerateEventListenerCall):
(JSValueToNative):
(GenerateConstructorDefinition):

  • bridge/c/c_utility.cpp:

(JSC::Bindings::convertValueToNPVariant):

  • bridge/jni/jni_jsobject.mm:

(JavaJSObject::convertValueToJObject):

  • bridge/jni/jsc/JNIUtilityPrivate.cpp:

(JSC::Bindings::convertArrayInstanceToJavaArray):
(JSC::Bindings::convertValueToJValue):

  • bridge/jni/jsc/JavaFieldJSC.cpp:

(JavaField::dispatchValueFromInstance):
(JavaField::valueFromInstance):
(JavaField::dispatchSetValueToInstance):
(JavaField::setValueToInstance):

  • bridge/jni/jsc/JavaInstanceJSC.cpp:

(JavaInstance::invokeMethod):

  • testing/js/JSInternalsCustom.cpp:

(WebCore::JSInternals::setUserPreferredLanguages):

../WebKit/mac:

Reviewed by Gavin Barraclough.

Mechanical changes to call value() after calling toString(), to
convert from "JS string" (JSString*) to "C++ string" (UString), since
toString() no longer returns a "C++ string".

  • Plugins/Hosted/NetscapePluginInstanceProxy.mm:

(WebKit::NetscapePluginInstanceProxy::addValueToArray):

  • WebView/WebFrame.mm:

(-[WebFrame _stringByEvaluatingJavaScriptFromString:forceUserGesture:]):
(-[WebFrame _stringByEvaluatingJavaScriptFromString:withGlobalObject:inScriptWorld:]):

../WebKit2:

Reviewed by Gavin Barraclough.

Mechanical changes to call value() after calling toString(), to
convert from "JS string" (JSString*) to "C++ string" (UString), since
toString() no longer returns a "C++ string".

  • WebProcess/Plugins/Netscape/NPRuntimeObjectMap.cpp:

(WebKit::NPRuntimeObjectMap::convertJSValueToNPVariant):

  • Property svn:eol-style set to native
File size: 21.0 KB
Line 
1/*
2 * Copyright (C) 1999-2000 Harri Porten ([email protected])
3 * Copyright (C) 2004, 2005, 2006, 2007, 2008 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 "BytecodeGenerator.h"
26#include "Completion.h"
27#include "CurrentTime.h"
28#include "ExceptionHelpers.h"
29#include "InitializeThreading.h"
30#include "JSArray.h"
31#include "JSFunction.h"
32#include "JSLock.h"
33#include "JSString.h"
34#include "MainThread.h"
35#include "SamplingTool.h"
36#include <math.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40
41#if !OS(WINDOWS)
42#include <unistd.h>
43#endif
44
45#if HAVE(READLINE)
46// readline/history.h has a Function typedef which conflicts with the WTF::Function template from WTF/Forward.h
47// We #define it to something else to avoid this conflict.
48#define Function ReadlineFunction
49#include <readline/history.h>
50#include <readline/readline.h>
51#undef Function
52#endif
53
54#if HAVE(SYS_TIME_H)
55#include <sys/time.h>
56#endif
57
58#if HAVE(SIGNAL_H)
59#include <signal.h>
60#endif
61
62#if COMPILER(MSVC) && !OS(WINCE)
63#include <crtdbg.h>
64#include <mmsystem.h>
65#include <windows.h>
66#endif
67
68#if PLATFORM(QT)
69#include <QCoreApplication>
70#include <QDateTime>
71#endif
72
73using namespace JSC;
74using namespace WTF;
75
76static void cleanupGlobalData(JSGlobalData*);
77static bool fillBufferWithContentsOfFile(const UString& fileName, Vector<char>& buffer);
78
79static EncodedJSValue JSC_HOST_CALL functionPrint(ExecState*);
80static EncodedJSValue JSC_HOST_CALL functionDebug(ExecState*);
81static EncodedJSValue JSC_HOST_CALL functionGC(ExecState*);
82#ifndef NDEBUG
83static EncodedJSValue JSC_HOST_CALL functionReleaseExecutableMemory(ExecState*);
84#endif
85static EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*);
86static EncodedJSValue JSC_HOST_CALL functionRun(ExecState*);
87static EncodedJSValue JSC_HOST_CALL functionLoad(ExecState*);
88static EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState*);
89static EncodedJSValue JSC_HOST_CALL functionReadline(ExecState*);
90static EncodedJSValue JSC_HOST_CALL functionPreciseTime(ExecState*);
91static NO_RETURN_WITH_VALUE EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*);
92
93#if ENABLE(SAMPLING_FLAGS)
94static EncodedJSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState*);
95static EncodedJSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState*);
96#endif
97
98struct Script {
99 bool isFile;
100 char* argument;
101
102 Script(bool isFile, char *argument)
103 : isFile(isFile)
104 , argument(argument)
105 {
106 }
107};
108
109struct CommandLine {
110 CommandLine()
111 : interactive(false)
112 , dump(false)
113 {
114 }
115
116 bool interactive;
117 bool dump;
118 Vector<Script> scripts;
119 Vector<UString> arguments;
120};
121
122static const char interactivePrompt[] = "> ";
123
124class StopWatch {
125public:
126 void start();
127 void stop();
128 long getElapsedMS(); // call stop() first
129
130private:
131 double m_startTime;
132 double m_stopTime;
133};
134
135void StopWatch::start()
136{
137 m_startTime = currentTime();
138}
139
140void StopWatch::stop()
141{
142 m_stopTime = currentTime();
143}
144
145long StopWatch::getElapsedMS()
146{
147 return static_cast<long>((m_stopTime - m_startTime) * 1000);
148}
149
150class GlobalObject : public JSGlobalObject {
151private:
152 GlobalObject(JSGlobalData&, Structure*);
153
154public:
155 typedef JSGlobalObject Base;
156
157 static GlobalObject* create(JSGlobalData& globalData, Structure* structure, const Vector<UString>& arguments)
158 {
159 GlobalObject* object = new (NotNull, allocateCell<GlobalObject>(globalData.heap)) GlobalObject(globalData, structure);
160 object->finishCreation(globalData, arguments);
161 return object;
162 }
163
164 static const ClassInfo s_info;
165
166 static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
167 {
168 return Structure::create(globalData, 0, prototype, TypeInfo(GlobalObjectType, StructureFlags), &s_info);
169 }
170
171protected:
172 void finishCreation(JSGlobalData& globalData, const Vector<UString>& arguments)
173 {
174 Base::finishCreation(globalData);
175
176 addFunction(globalData, "debug", functionDebug, 1);
177 addFunction(globalData, "print", functionPrint, 1);
178 addFunction(globalData, "quit", functionQuit, 0);
179 addFunction(globalData, "gc", functionGC, 0);
180#ifndef NDEBUG
181 addFunction(globalData, "releaseExecutableMemory", functionReleaseExecutableMemory, 0);
182#endif
183 addFunction(globalData, "version", functionVersion, 1);
184 addFunction(globalData, "run", functionRun, 1);
185 addFunction(globalData, "load", functionLoad, 1);
186 addFunction(globalData, "checkSyntax", functionCheckSyntax, 1);
187 addFunction(globalData, "readline", functionReadline, 0);
188 addFunction(globalData, "preciseTime", functionPreciseTime, 0);
189#if ENABLE(SAMPLING_FLAGS)
190 addFunction(globalData, "setSamplingFlags", functionSetSamplingFlags, 1);
191 addFunction(globalData, "clearSamplingFlags", functionClearSamplingFlags, 1);
192#endif
193
194 JSObject* array = constructEmptyArray(globalExec());
195 for (size_t i = 0; i < arguments.size(); ++i)
196 array->methodTable()->putByIndex(array, globalExec(), i, jsString(globalExec(), arguments[i]));
197 putDirect(globalData, Identifier(globalExec(), "arguments"), array);
198 }
199
200 void addFunction(JSGlobalData& globalData, const char* name, NativeFunction function, unsigned arguments)
201 {
202 Identifier identifier(globalExec(), name);
203 putDirect(globalData, identifier, JSFunction::create(globalExec(), this, arguments, identifier, function));
204 }
205};
206COMPILE_ASSERT(!IsInteger<GlobalObject>::value, WTF_IsInteger_GlobalObject_false);
207ASSERT_CLASS_FITS_IN_CELL(GlobalObject);
208
209const ClassInfo GlobalObject::s_info = { "global", &JSGlobalObject::s_info, 0, ExecState::globalObjectTable, CREATE_METHOD_TABLE(GlobalObject) };
210
211GlobalObject::GlobalObject(JSGlobalData& globalData, Structure* structure)
212 : JSGlobalObject(globalData, structure)
213{
214}
215
216static inline SourceCode jscSource(const char* utf8, const UString& filename)
217{
218 // Find the the first non-ascii character, or nul.
219 const char* pos = utf8;
220 while (*pos > 0)
221 pos++;
222 size_t asciiLength = pos - utf8;
223
224 // Fast case - string is all ascii.
225 if (!*pos)
226 return makeSource(UString(utf8, asciiLength), filename);
227
228 // Slow case - contains non-ascii characters, use fromUTF8WithLatin1Fallback.
229 ASSERT(*pos < 0);
230 ASSERT(strlen(utf8) == asciiLength + strlen(pos));
231 String source = String::fromUTF8WithLatin1Fallback(utf8, asciiLength + strlen(pos));
232 return makeSource(source.impl(), filename);
233}
234
235EncodedJSValue JSC_HOST_CALL functionPrint(ExecState* exec)
236{
237 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
238 if (i)
239 putchar(' ');
240
241 printf("%s", exec->argument(i).toString(exec)->value(exec).utf8().data());
242 }
243
244 putchar('\n');
245 fflush(stdout);
246 return JSValue::encode(jsUndefined());
247}
248
249EncodedJSValue JSC_HOST_CALL functionDebug(ExecState* exec)
250{
251 fprintf(stderr, "--> %s\n", exec->argument(0).toString(exec)->value(exec).utf8().data());
252 return JSValue::encode(jsUndefined());
253}
254
255EncodedJSValue JSC_HOST_CALL functionGC(ExecState* exec)
256{
257 JSLock lock(SilenceAssertionsOnly);
258 exec->heap()->collectAllGarbage();
259 return JSValue::encode(jsUndefined());
260}
261
262#ifndef NDEBUG
263EncodedJSValue JSC_HOST_CALL functionReleaseExecutableMemory(ExecState* exec)
264{
265 JSLock lock(SilenceAssertionsOnly);
266 exec->globalData().releaseExecutableMemory();
267 return JSValue::encode(jsUndefined());
268}
269#endif
270
271EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*)
272{
273 // We need this function for compatibility with the Mozilla JS tests but for now
274 // we don't actually do any version-specific handling
275 return JSValue::encode(jsUndefined());
276}
277
278EncodedJSValue JSC_HOST_CALL functionRun(ExecState* exec)
279{
280 UString fileName = exec->argument(0).toString(exec)->value(exec);
281 Vector<char> script;
282 if (!fillBufferWithContentsOfFile(fileName, script))
283 return JSValue::encode(throwError(exec, createError(exec, "Could not open file.")));
284
285 GlobalObject* globalObject = GlobalObject::create(exec->globalData(), GlobalObject::createStructure(exec->globalData(), jsNull()), Vector<UString>());
286
287 StopWatch stopWatch;
288 stopWatch.start();
289 evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), jscSource(script.data(), fileName));
290 stopWatch.stop();
291
292 return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
293}
294
295EncodedJSValue JSC_HOST_CALL functionLoad(ExecState* exec)
296{
297 UString fileName = exec->argument(0).toString(exec)->value(exec);
298 Vector<char> script;
299 if (!fillBufferWithContentsOfFile(fileName, script))
300 return JSValue::encode(throwError(exec, createError(exec, "Could not open file.")));
301
302 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
303
304 JSValue evaluationException;
305 JSValue result = evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), jscSource(script.data(), fileName), JSValue(), &evaluationException);
306 if (evaluationException)
307 throwError(exec, evaluationException);
308 return JSValue::encode(result);
309}
310
311EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState* exec)
312{
313 UString fileName = exec->argument(0).toString(exec)->value(exec);
314 Vector<char> script;
315 if (!fillBufferWithContentsOfFile(fileName, script))
316 return JSValue::encode(throwError(exec, createError(exec, "Could not open file.")));
317
318 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
319
320 StopWatch stopWatch;
321 stopWatch.start();
322
323 JSValue syntaxException;
324 bool validSyntax = checkSyntax(globalObject->globalExec(), jscSource(script.data(), fileName), &syntaxException);
325 stopWatch.stop();
326
327 if (!validSyntax)
328 throwError(exec, syntaxException);
329 return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
330}
331
332#if ENABLE(SAMPLING_FLAGS)
333EncodedJSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState* exec)
334{
335 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
336 unsigned flag = static_cast<unsigned>(exec->argument(i).toNumber(exec));
337 if ((flag >= 1) && (flag <= 32))
338 SamplingFlags::setFlag(flag);
339 }
340 return JSValue::encode(jsNull());
341}
342
343EncodedJSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState* exec)
344{
345 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
346 unsigned flag = static_cast<unsigned>(exec->argument(i).toNumber(exec));
347 if ((flag >= 1) && (flag <= 32))
348 SamplingFlags::clearFlag(flag);
349 }
350 return JSValue::encode(jsNull());
351}
352#endif
353
354EncodedJSValue JSC_HOST_CALL functionReadline(ExecState* exec)
355{
356 Vector<char, 256> line;
357 int c;
358 while ((c = getchar()) != EOF) {
359 // FIXME: Should we also break on \r?
360 if (c == '\n')
361 break;
362 line.append(c);
363 }
364 line.append('\0');
365 return JSValue::encode(jsString(exec, line.data()));
366}
367
368EncodedJSValue JSC_HOST_CALL functionPreciseTime(ExecState*)
369{
370 return JSValue::encode(jsNumber(currentTime()));
371}
372
373EncodedJSValue JSC_HOST_CALL functionQuit(ExecState* exec)
374{
375 // Technically, destroying the heap in the middle of JS execution is a no-no,
376 // but we want to maintain compatibility with the Mozilla test suite, so
377 // we pretend that execution has terminated to avoid ASSERTs, then tear down the heap.
378 exec->globalData().dynamicGlobalObject = 0;
379
380 cleanupGlobalData(&exec->globalData());
381 exit(EXIT_SUCCESS);
382
383#if COMPILER(MSVC) && OS(WINCE)
384 // Without this, Visual Studio will complain that this method does not return a value.
385 return JSValue::encode(jsUndefined());
386#endif
387}
388
389// Use SEH for Release builds only to get rid of the crash report dialog
390// (luckily the same tests fail in Release and Debug builds so far). Need to
391// be in a separate main function because the jscmain function requires object
392// unwinding.
393
394#if COMPILER(MSVC) && !COMPILER(INTEL) && !defined(_DEBUG) && !OS(WINCE)
395#define TRY __try {
396#define EXCEPT(x) } __except (EXCEPTION_EXECUTE_HANDLER) { x; }
397#else
398#define TRY
399#define EXCEPT(x)
400#endif
401
402int jscmain(int argc, char** argv, JSGlobalData*);
403
404int main(int argc, char** argv)
405{
406#if OS(WINDOWS)
407#if !OS(WINCE)
408 // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for
409 // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the
410 // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>.
411 ::SetErrorMode(0);
412#endif
413
414#if defined(_DEBUG)
415 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
416 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
417 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
418 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
419 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
420 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
421#endif
422
423 timeBeginPeriod(1);
424#endif
425
426#if PLATFORM(QT)
427 QCoreApplication app(argc, argv);
428#endif
429
430 // Initialize JSC before getting JSGlobalData.
431#if ENABLE(SAMPLING_REGIONS)
432 WTF::initializeMainThread();
433#endif
434 JSC::initializeThreading();
435
436 // We can't use destructors in the following code because it uses Windows
437 // Structured Exception Handling
438 int res = 0;
439 JSGlobalData* globalData = JSGlobalData::create(ThreadStackTypeLarge, LargeHeap).leakRef();
440 TRY
441 res = jscmain(argc, argv, globalData);
442 EXCEPT(res = 3)
443
444 cleanupGlobalData(globalData);
445 return res;
446}
447
448static void cleanupGlobalData(JSGlobalData* globalData)
449{
450 JSLock lock(SilenceAssertionsOnly);
451 globalData->clearBuiltinStructures();
452 globalData->heap.destroy();
453 globalData->deref();
454}
455
456static bool runWithScripts(GlobalObject* globalObject, const Vector<Script>& scripts, bool dump)
457{
458 const char* script;
459 UString fileName;
460 Vector<char> scriptBuffer;
461
462 if (dump)
463 BytecodeGenerator::setDumpsGeneratedCode(true);
464
465 JSGlobalData& globalData = globalObject->globalData();
466
467#if ENABLE(SAMPLING_FLAGS)
468 SamplingFlags::start();
469#endif
470
471 bool success = true;
472 for (size_t i = 0; i < scripts.size(); i++) {
473 if (scripts[i].isFile) {
474 fileName = scripts[i].argument;
475 if (!fillBufferWithContentsOfFile(fileName, scriptBuffer))
476 return false; // fail early so we can catch missing files
477 script = scriptBuffer.data();
478 } else {
479 script = scripts[i].argument;
480 fileName = "[Command Line]";
481 }
482
483 globalData.startSampling();
484
485 JSValue evaluationException;
486 JSValue returnValue = evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), jscSource(script, fileName), JSValue(), &evaluationException);
487 success = success && !evaluationException;
488 if (dump) {
489 if (evaluationException)
490 printf("Exception: %s\n", evaluationException.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
491 else
492 printf("End: %s\n", returnValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
493 }
494
495 globalData.stopSampling();
496 globalObject->globalExec()->clearException();
497 }
498
499#if ENABLE(SAMPLING_FLAGS)
500 SamplingFlags::stop();
501#endif
502#if ENABLE(SAMPLING_REGIONS)
503 SamplingRegion::dump();
504#endif
505 globalData.dumpSampleData(globalObject->globalExec());
506#if ENABLE(SAMPLING_COUNTERS)
507 AbstractSamplingCounter::dump();
508#endif
509#if ENABLE(REGEXP_TRACING)
510 globalData.dumpRegExpTrace();
511#endif
512 return success;
513}
514
515#define RUNNING_FROM_XCODE 0
516
517static void runInteractive(GlobalObject* globalObject)
518{
519 UString interpreterName("Interpreter");
520
521 while (true) {
522#if HAVE(READLINE) && !RUNNING_FROM_XCODE
523 char* line = readline(interactivePrompt);
524 if (!line)
525 break;
526 if (line[0])
527 add_history(line);
528 JSValue evaluationException;
529 JSValue returnValue = evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), jscSource(line, interpreterName), JSValue(), &evaluationException);
530 free(line);
531#else
532 printf("%s", interactivePrompt);
533 Vector<char, 256> line;
534 int c;
535 while ((c = getchar()) != EOF) {
536 // FIXME: Should we also break on \r?
537 if (c == '\n')
538 break;
539 line.append(c);
540 }
541 if (line.isEmpty())
542 break;
543 line.append('\0');
544
545 JSValue evaluationException;
546 JSValue returnValue = evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), jscSource(line.data(), interpreterName), JSValue(), &evaluationException);
547#endif
548 if (evaluationException)
549 printf("Exception: %s\n", evaluationException.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
550 else
551 printf("%s\n", returnValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
552
553 globalObject->globalExec()->clearException();
554 }
555 printf("\n");
556}
557
558static NO_RETURN void printUsageStatement(JSGlobalData* globalData, bool help = false)
559{
560 fprintf(stderr, "Usage: jsc [options] [files] [-- arguments]\n");
561 fprintf(stderr, " -d Dumps bytecode (debug builds only)\n");
562 fprintf(stderr, " -e Evaluate argument as script code\n");
563 fprintf(stderr, " -f Specifies a source file (deprecated)\n");
564 fprintf(stderr, " -h|--help Prints this help message\n");
565 fprintf(stderr, " -i Enables interactive mode (default if no files are specified)\n");
566#if HAVE(SIGNAL_H)
567 fprintf(stderr, " -s Installs signal handlers that exit on a crash (Unix platforms only)\n");
568#endif
569
570 cleanupGlobalData(globalData);
571 exit(help ? EXIT_SUCCESS : EXIT_FAILURE);
572}
573
574static void parseArguments(int argc, char** argv, CommandLine& options, JSGlobalData* globalData)
575{
576 int i = 1;
577 for (; i < argc; ++i) {
578 const char* arg = argv[i];
579 if (!strcmp(arg, "-f")) {
580 if (++i == argc)
581 printUsageStatement(globalData);
582 options.scripts.append(Script(true, argv[i]));
583 continue;
584 }
585 if (!strcmp(arg, "-e")) {
586 if (++i == argc)
587 printUsageStatement(globalData);
588 options.scripts.append(Script(false, argv[i]));
589 continue;
590 }
591 if (!strcmp(arg, "-i")) {
592 options.interactive = true;
593 continue;
594 }
595 if (!strcmp(arg, "-d")) {
596 options.dump = true;
597 continue;
598 }
599 if (!strcmp(arg, "-s")) {
600#if HAVE(SIGNAL_H)
601 signal(SIGILL, _exit);
602 signal(SIGFPE, _exit);
603 signal(SIGBUS, _exit);
604 signal(SIGSEGV, _exit);
605#endif
606 continue;
607 }
608 if (!strcmp(arg, "--")) {
609 ++i;
610 break;
611 }
612 if (!strcmp(arg, "-h") || !strcmp(arg, "--help"))
613 printUsageStatement(globalData, true);
614 options.scripts.append(Script(true, argv[i]));
615 }
616
617 if (options.scripts.isEmpty())
618 options.interactive = true;
619
620 for (; i < argc; ++i)
621 options.arguments.append(argv[i]);
622}
623
624int jscmain(int argc, char** argv, JSGlobalData* globalData)
625{
626 JSLock lock(SilenceAssertionsOnly);
627
628 CommandLine options;
629 parseArguments(argc, argv, options, globalData);
630
631 GlobalObject* globalObject = GlobalObject::create(*globalData, GlobalObject::createStructure(*globalData, jsNull()), options.arguments);
632 bool success = runWithScripts(globalObject, options.scripts, options.dump);
633 if (options.interactive && success)
634 runInteractive(globalObject);
635
636 return success ? 0 : 3;
637}
638
639static bool fillBufferWithContentsOfFile(const UString& fileName, Vector<char>& buffer)
640{
641 FILE* f = fopen(fileName.utf8().data(), "r");
642 if (!f) {
643 fprintf(stderr, "Could not open file: %s\n", fileName.utf8().data());
644 return false;
645 }
646
647 size_t bufferSize = 0;
648 size_t bufferCapacity = 1024;
649
650 buffer.resize(bufferCapacity);
651
652 while (!feof(f) && !ferror(f)) {
653 bufferSize += fread(buffer.data() + bufferSize, 1, bufferCapacity - bufferSize, f);
654 if (bufferSize == bufferCapacity) { // guarantees space for trailing '\0'
655 bufferCapacity *= 2;
656 buffer.resize(bufferCapacity);
657 }
658 }
659 fclose(f);
660 buffer[bufferSize] = '\0';
661
662 if (buffer[0] == '#' && buffer[1] == '!')
663 buffer[0] = buffer[1] = '/';
664
665 return true;
666}
Note: See TracBrowser for help on using the repository browser.