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

Last change on this file since 156240 was 156240, checked in by Darin Adler, 12 years ago

Add ExecState::uncheckedArgument and use where possible to shrink a bit
https://bugs.webkit.org/show_bug.cgi?id=121750

Reviewed by Andreas Kling.

Source/JavaScriptCore:

  • interpreter/CallFrame.h:

(JSC::ExecState::uncheckedArgument): Added. Like argument, but with an
assertion rather than a runtime check.

  • API/APICallbackFunction.h:

(JSC::APICallbackFunction::call): Use uncheckedArgument because we are
already in a loop over arguments, so don't need a range check.

  • API/JSCallbackConstructor.cpp:

(JSC::constructJSCallback): Ditto.

  • API/JSCallbackObjectFunctions.h:

(JSC::JSCallbackObject::construct): Ditto.
(JSC::JSCallbackObject::call): Ditto.

  • jsc.cpp:

(functionPrint): Ditto.
(functionRun): Ditto.
(functionSetSamplingFlags): Ditto.
(functionClearSamplingFlags): Ditto.

  • runtime/ArrayPrototype.cpp:

(JSC::arrayProtoFuncConcat): Ditto.
(JSC::arrayProtoFuncPush): Use uncheckedArgument because there is already
code that explicitly checks argumentCount.
(JSC::arrayProtoFuncSplice): Ditto.
(JSC::arrayProtoFuncUnShift): Ditto.
(JSC::arrayProtoFuncReduce): Ditto.
(JSC::arrayProtoFuncReduceRight): Ditto.
(JSC::arrayProtoFuncLastIndexOf): Ditto.

  • runtime/DatePrototype.cpp:

(JSC::fillStructuresUsingTimeArgs): Ditto.
(JSC::fillStructuresUsingDateArgs): Ditto.

  • runtime/JSArrayBufferConstructor.cpp:

(JSC::constructArrayBuffer): Ditto.

  • runtime/JSArrayBufferPrototype.cpp:

(JSC::arrayBufferProtoFuncSlice): Ditto.

  • runtime/JSBoundFunction.cpp:

(JSC::boundFunctionCall): Ditto.
(JSC::boundFunctionConstruct): Ditto.

  • runtime/JSDataViewPrototype.cpp:

(JSC::getData): Ditto.
(JSC::setData): Ditto.

  • runtime/JSGenericTypedArrayViewConstructorInlines.h:

(JSC::constructGenericTypedArrayView): Ditto.

  • runtime/JSGenericTypedArrayViewPrototypeInlines.h:

(JSC::genericTypedArrayViewProtoFuncSet): Ditto.
(JSC::genericTypedArrayViewProtoFuncSubarray): Ditto.

  • runtime/JSONObject.cpp:

(JSC::JSONProtoFuncParse): Ditto.
(JSC::JSONProtoFuncStringify): Ditto.

  • runtime/JSPromiseConstructor.cpp:

(JSC::constructPromise): Ditto.
(JSC::JSPromiseConstructorFuncFulfill): Ditto.
(JSC::JSPromiseConstructorFuncResolve): Ditto.
(JSC::JSPromiseConstructorFuncReject): Ditto.

  • runtime/MathObject.cpp:

(JSC::mathProtoFuncMax): Ditto.
(JSC::mathProtoFuncMin): Ditto.

  • runtime/NameConstructor.cpp:

(JSC::constructPrivateName): Removed unneeded check of argumentCout
that simply repeats what argument already does.

  • runtime/NativeErrorConstructor.cpp:

(JSC::Interpreter::constructWithNativeErrorConstructor): Ditto.
(JSC::Interpreter::callNativeErrorConstructor): Ditto.

  • runtime/NumberConstructor.cpp:

(JSC::constructWithNumberConstructor): Use uncheckedArgument since
there is already code that explicitly checks argument count.
(JSC::callNumberConstructor): Ditto.

  • runtime/ObjectConstructor.cpp:

(JSC::objectConstructorCreate): Small refactoring to not call argument(0)
three times.

  • runtime/SetConstructor.cpp:

(JSC::constructSet): Use uncheckedArgument since we are already in a loop
over arguments.

  • runtime/StringConstructor.cpp:

(JSC::stringFromCharCodeSlowCase): In a loop.
(JSC::stringFromCharCode): Already checked count.
(JSC::constructWithStringConstructor): Ditto.
(JSC::callStringConstructor): Ditto.

  • runtime/StringPrototype.cpp:

(JSC::stringProtoFuncConcat): Already checked count.

  • runtime/TestRunnerUtils.cpp:

(JSC::numberOfDFGCompiles): Ditto.
(JSC::setNeverInline): Ditto.

Source/WebCore:

  • bindings/js/JSHTMLCanvasElementCustom.cpp:

(WebCore::JSHTMLCanvasElement::probablySupportsContext): Already checked count.
(WebCore::JSHTMLCanvasElement::toDataURL): Ditto.

  • bindings/js/JSHTMLDocumentCustom.cpp:

(WebCore::documentWrite): In a loop.

  • bindings/js/JSInjectedScriptHostCustom.cpp:

(WebCore::JSInjectedScriptHost::inspectedObject): Already checked count.
(WebCore::JSInjectedScriptHost::internalConstructorName): Ditto.
(WebCore::JSInjectedScriptHost::isHTMLAllCollection): Ditto.
(WebCore::JSInjectedScriptHost::type): Ditto.
(WebCore::JSInjectedScriptHost::functionDetails): Ditto.
(WebCore::JSInjectedScriptHost::getEventListeners): Ditto.
(WebCore::JSInjectedScriptHost::inspect): Ditto.
(WebCore::JSInjectedScriptHost::databaseId): Ditto.
(WebCore::JSInjectedScriptHost::storageId): Ditto.

  • bindings/js/JSSQLTransactionSyncCustom.cpp:

(WebCore::JSSQLTransactionSync::executeSql): Ditto.

  • bindings/js/JSSVGLengthCustom.cpp:

(WebCore::JSSVGLength::convertToSpecifiedUnits): Ditto.

  • bindings/js/JSSharedWorkerCustom.cpp:

(WebCore::JSSharedWorkerConstructor::constructJSSharedWorker): Ditto.

  • bindings/js/JSWebGLRenderingContextCustom.cpp:

(WebCore::getObjectParameter): Already checked count.
(WebCore::JSWebGLRenderingContext::getAttachedShaders): Removed tortured code
to triply do the checking that the toWebGLProgram function already does, including
spurious exception checking in code that can't create an exception. Also count is
already checked.
(WebCore::JSWebGLRenderingContext::getExtension): More of the same.
(WebCore::JSWebGLRenderingContext::getFramebufferAttachmentParameter): Ditto.
(WebCore::JSWebGLRenderingContext::getParameter): Ditto.
(WebCore::JSWebGLRenderingContext::getProgramParameter): Ditto.
(WebCore::JSWebGLRenderingContext::getShaderParameter): Ditto.
(WebCore::JSWebGLRenderingContext::getUniform): Ditto.
(WebCore::dataFunctionf): Ditto.
(WebCore::dataFunctioni): Ditto.
(WebCore::dataFunctionMatrix): Ditto.

  • bindings/js/JSWorkerGlobalScopeCustom.cpp:

(WebCore::JSWorkerGlobalScope::importScripts): In a loop.

  • bindings/js/JSXMLHttpRequestCustom.cpp:

(WebCore::JSXMLHttpRequest::open): Already checked. Also removed some unneeded
argument count checks.
(WebCore::JSXMLHttpRequest::send): Removed unneeded special case for 0 argument
count that does the same thing as the undefined case, since asking for an
argument past the count yields undefined.

  • bindings/js/JSXSLTProcessorCustom.cpp:

(WebCore::JSXSLTProcessor::setParameter): Already checked.
(WebCore::JSXSLTProcessor::getParameter): Already checked.
(WebCore::JSXSLTProcessor::removeParameter): Already checked.

  • bindings/js/ScheduledAction.cpp:

(WebCore::ScheduledAction::ScheduledAction): In a loop.

  • bindings/js/ScriptCallStackFactory.cpp:

(WebCore::createScriptArguments): Ditto.

  • bindings/scripts/CodeGeneratorJS.pm:

(GenerateParametersCheck): Removed some excess argumentCount checks.
Used uncheckedArgument in a few places. More needs to be done, especially for
overloaded functions.

  • bridge/c/c_instance.cpp:

(JSC::Bindings::CInstance::invokeMethod): In a loop.
(JSC::Bindings::CInstance::invokeDefaultMethod): Ditto.

  • bridge/objc/objc_instance.mm:

(ObjcInstance::invokeObjcMethod): Ditto.
(ObjcInstance::invokeDefaultMethod): Ditto.

  • bindings/scripts/test/JS/JSTestMediaQueryListListener.cpp:
  • bindings/scripts/test/JS/JSTestObj.cpp:
  • bindings/scripts/test/JS/JSTestTypedefs.cpp:

Updated.

Source/WebKit2:

  • WebProcess/Plugins/Netscape/JSNPObject.cpp:

(WebKit::JSNPObject::callMethod): In a loop.
(WebKit::JSNPObject::callObject): Ditto.
(WebKit::JSNPObject::callConstructor): Ditto.

  • Property svn:eol-style set to native
File size: 28.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 "APIShims.h"
26#include "ButterflyInlines.h"
27#include "BytecodeGenerator.h"
28#include "CallFrameInlines.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 "JSFunction.h"
37#include "JSLock.h"
38#include "JSProxy.h"
39#include "JSString.h"
40#include "Operations.h"
41#include "SamplingTool.h"
42#include "StackVisitor.h"
43#include "StructureRareDataInlines.h"
44#include "TestRunnerUtils.h"
45#include <math.h>
46#include <stdio.h>
47#include <stdlib.h>
48#include <string.h>
49#include <wtf/CurrentTime.h>
50#include <wtf/MainThread.h>
51#include <wtf/StringPrintStream.h>
52#include <wtf/text/StringBuilder.h>
53
54#if !OS(WINDOWS)
55#include <unistd.h>
56#endif
57
58#if HAVE(READLINE)
59// readline/history.h has a Function typedef which conflicts with the WTF::Function template from WTF/Forward.h
60// We #define it to something else to avoid this conflict.
61#define Function ReadlineFunction
62#include <readline/history.h>
63#include <readline/readline.h>
64#undef Function
65#endif
66
67#if HAVE(SYS_TIME_H)
68#include <sys/time.h>
69#endif
70
71#if HAVE(SIGNAL_H)
72#include <signal.h>
73#endif
74
75#if COMPILER(MSVC) && !OS(WINCE)
76#include <crtdbg.h>
77#include <mmsystem.h>
78#include <windows.h>
79#endif
80
81#if PLATFORM(QT)
82#include <QCoreApplication>
83#include <QDateTime>
84#endif
85
86#if PLATFORM(IOS)
87#include <fenv.h>
88#include <arm/arch.h>
89#endif
90
91#if PLATFORM(BLACKBERRY)
92#include <BlackBerryPlatformLog.h>
93#endif
94
95#if PLATFORM(EFL)
96#include <Ecore.h>
97#endif
98
99using namespace JSC;
100using namespace WTF;
101
102static bool fillBufferWithContentsOfFile(const String& fileName, Vector<char>& buffer);
103
104static EncodedJSValue JSC_HOST_CALL functionPrint(ExecState*);
105static EncodedJSValue JSC_HOST_CALL functionDebug(ExecState*);
106static EncodedJSValue JSC_HOST_CALL functionDescribe(ExecState*);
107static EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState*);
108static EncodedJSValue JSC_HOST_CALL functionGC(ExecState*);
109#ifndef NDEBUG
110static EncodedJSValue JSC_HOST_CALL functionReleaseExecutableMemory(ExecState*);
111static EncodedJSValue JSC_HOST_CALL functionDumpCallFrame(ExecState*);
112#endif
113static EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*);
114static EncodedJSValue JSC_HOST_CALL functionRun(ExecState*);
115static EncodedJSValue JSC_HOST_CALL functionLoad(ExecState*);
116static EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState*);
117static EncodedJSValue JSC_HOST_CALL functionReadline(ExecState*);
118static EncodedJSValue JSC_HOST_CALL functionPreciseTime(ExecState*);
119static EncodedJSValue JSC_HOST_CALL functionNeverInlineFunction(ExecState*);
120static EncodedJSValue JSC_HOST_CALL functionNumberOfDFGCompiles(ExecState*);
121static NO_RETURN_WITH_VALUE EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*);
122
123#if ENABLE(SAMPLING_FLAGS)
124static EncodedJSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState*);
125static EncodedJSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState*);
126#endif
127
128struct Script {
129 bool isFile;
130 char* argument;
131
132 Script(bool isFile, char *argument)
133 : isFile(isFile)
134 , argument(argument)
135 {
136 }
137};
138
139class CommandLine {
140public:
141 CommandLine(int argc, char** argv)
142 : m_interactive(false)
143 , m_dump(false)
144 , m_exitCode(false)
145 , m_profile(false)
146 {
147 parseArguments(argc, argv);
148 }
149
150 bool m_interactive;
151 bool m_dump;
152 bool m_exitCode;
153 Vector<Script> m_scripts;
154 Vector<String> m_arguments;
155 bool m_profile;
156 String m_profilerOutput;
157
158 void parseArguments(int, char**);
159};
160
161static const char interactivePrompt[] = ">>> ";
162
163class StopWatch {
164public:
165 void start();
166 void stop();
167 long getElapsedMS(); // call stop() first
168
169private:
170 double m_startTime;
171 double m_stopTime;
172};
173
174void StopWatch::start()
175{
176 m_startTime = monotonicallyIncreasingTime();
177}
178
179void StopWatch::stop()
180{
181 m_stopTime = monotonicallyIncreasingTime();
182}
183
184long StopWatch::getElapsedMS()
185{
186 return static_cast<long>((m_stopTime - m_startTime) * 1000);
187}
188
189class GlobalObject : public JSGlobalObject {
190private:
191 GlobalObject(VM&, Structure*);
192
193public:
194 typedef JSGlobalObject Base;
195
196 static GlobalObject* create(VM& vm, Structure* structure, const Vector<String>& arguments)
197 {
198 GlobalObject* object = new (NotNull, allocateCell<GlobalObject>(vm.heap)) GlobalObject(vm, structure);
199 object->finishCreation(vm, arguments);
200 vm.heap.addFinalizer(object, destroy);
201 object->setGlobalThis(vm, JSProxy::create(vm, JSProxy::createStructure(vm, object, object->prototype()), object));
202 return object;
203 }
204
205 static const bool needsDestruction = false;
206
207 DECLARE_INFO;
208 static const GlobalObjectMethodTable s_globalObjectMethodTable;
209
210 static Structure* createStructure(VM& vm, JSValue prototype)
211 {
212 return Structure::create(vm, 0, prototype, TypeInfo(GlobalObjectType, StructureFlags), info());
213 }
214
215 static bool javaScriptExperimentsEnabled(const JSGlobalObject*) { return true; }
216
217protected:
218 void finishCreation(VM& vm, const Vector<String>& arguments)
219 {
220 Base::finishCreation(vm);
221
222 addFunction(vm, "debug", functionDebug, 1);
223 addFunction(vm, "describe", functionDescribe, 1);
224 addFunction(vm, "print", functionPrint, 1);
225 addFunction(vm, "quit", functionQuit, 0);
226 addFunction(vm, "gc", functionGC, 0);
227#ifndef NDEBUG
228 addFunction(vm, "dumpCallFrame", functionDumpCallFrame, 0);
229 addFunction(vm, "releaseExecutableMemory", functionReleaseExecutableMemory, 0);
230#endif
231 addFunction(vm, "version", functionVersion, 1);
232 addFunction(vm, "run", functionRun, 1);
233 addFunction(vm, "load", functionLoad, 1);
234 addFunction(vm, "checkSyntax", functionCheckSyntax, 1);
235 addFunction(vm, "jscStack", functionJSCStack, 1);
236 addFunction(vm, "readline", functionReadline, 0);
237 addFunction(vm, "preciseTime", functionPreciseTime, 0);
238 addFunction(vm, "neverInlineFunction", functionNeverInlineFunction, 1);
239 addFunction(vm, "numberOfDFGCompiles", functionNumberOfDFGCompiles, 1);
240#if ENABLE(SAMPLING_FLAGS)
241 addFunction(vm, "setSamplingFlags", functionSetSamplingFlags, 1);
242 addFunction(vm, "clearSamplingFlags", functionClearSamplingFlags, 1);
243#endif
244
245 JSArray* array = constructEmptyArray(globalExec(), 0);
246 for (size_t i = 0; i < arguments.size(); ++i)
247 array->putDirectIndex(globalExec(), i, jsString(globalExec(), arguments[i]));
248 putDirect(vm, Identifier(globalExec(), "arguments"), array);
249 }
250
251 void addFunction(VM& vm, const char* name, NativeFunction function, unsigned arguments)
252 {
253 Identifier identifier(globalExec(), name);
254 putDirect(vm, identifier, JSFunction::create(globalExec(), this, arguments, identifier.string(), function));
255 }
256
257 void addConstructableFunction(VM& vm, const char* name, NativeFunction function, unsigned arguments)
258 {
259 Identifier identifier(globalExec(), name);
260 putDirect(vm, identifier, JSFunction::create(globalExec(), this, arguments, identifier.string(), function, NoIntrinsic, function));
261 }
262};
263
264const ClassInfo GlobalObject::s_info = { "global", &JSGlobalObject::s_info, 0, ExecState::globalObjectTable, CREATE_METHOD_TABLE(GlobalObject) };
265const GlobalObjectMethodTable GlobalObject::s_globalObjectMethodTable = { &allowsAccessFrom, &supportsProfiling, &supportsRichSourceInfo, &shouldInterruptScript, &javaScriptExperimentsEnabled, 0 };
266
267
268GlobalObject::GlobalObject(VM& vm, Structure* structure)
269 : JSGlobalObject(vm, structure, &s_globalObjectMethodTable)
270{
271}
272
273static inline String stringFromUTF(const char* utf8)
274{
275 // Find the the first non-ascii character, or nul.
276 const char* pos = utf8;
277 while (*pos > 0)
278 pos++;
279 size_t asciiLength = pos - utf8;
280
281 // Fast case - string is all ascii.
282 if (!*pos)
283 return String(utf8, asciiLength);
284
285 // Slow case - contains non-ascii characters, use fromUTF8WithLatin1Fallback.
286 ASSERT(*pos < 0);
287 ASSERT(strlen(utf8) == asciiLength + strlen(pos));
288 return String::fromUTF8WithLatin1Fallback(utf8, asciiLength + strlen(pos));
289}
290
291static inline SourceCode jscSource(const char* utf8, const String& filename)
292{
293 String str = stringFromUTF(utf8);
294 return makeSource(str, filename);
295}
296
297EncodedJSValue JSC_HOST_CALL functionPrint(ExecState* exec)
298{
299 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
300 if (i)
301 putchar(' ');
302
303 printf("%s", exec->uncheckedArgument(i).toString(exec)->value(exec).utf8().data());
304 }
305
306 putchar('\n');
307 fflush(stdout);
308 return JSValue::encode(jsUndefined());
309}
310
311#ifndef NDEBUG
312EncodedJSValue JSC_HOST_CALL functionDumpCallFrame(ExecState* exec)
313{
314 if (!exec->callerFrame()->hasHostCallFrameFlag())
315 exec->vm().interpreter->dumpCallFrame(exec->callerFrame());
316 return JSValue::encode(jsUndefined());
317}
318#endif
319
320EncodedJSValue JSC_HOST_CALL functionDebug(ExecState* exec)
321{
322 fprintf(stderr, "--> %s\n", exec->argument(0).toString(exec)->value(exec).utf8().data());
323 return JSValue::encode(jsUndefined());
324}
325
326EncodedJSValue JSC_HOST_CALL functionDescribe(ExecState* exec)
327{
328 fprintf(stderr, "--> %s\n", toCString(exec->argument(0)).data());
329 return JSValue::encode(jsUndefined());
330}
331
332class FunctionJSCStackFunctor {
333public:
334 FunctionJSCStackFunctor(StringBuilder& trace)
335 : m_trace(trace)
336 {
337 }
338
339 StackVisitor::Status operator()(StackVisitor& visitor)
340 {
341 m_trace.append(String::format(" %zu %s\n", visitor->index(), visitor->toString().utf8().data()));
342 return StackVisitor::Continue;
343 }
344
345private:
346 StringBuilder& m_trace;
347};
348
349EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState* exec)
350{
351 StringBuilder trace;
352 trace.appendLiteral("--> Stack trace:\n");
353
354 FunctionJSCStackFunctor functor(trace);
355 exec->iterate(functor);
356 fprintf(stderr, "%s", trace.toString().utf8().data());
357 return JSValue::encode(jsUndefined());
358}
359
360EncodedJSValue JSC_HOST_CALL functionGC(ExecState* exec)
361{
362 JSLockHolder lock(exec);
363 exec->heap()->collectAllGarbage();
364 return JSValue::encode(jsUndefined());
365}
366
367#ifndef NDEBUG
368EncodedJSValue JSC_HOST_CALL functionReleaseExecutableMemory(ExecState* exec)
369{
370 JSLockHolder lock(exec);
371 exec->vm().releaseExecutableMemory();
372 return JSValue::encode(jsUndefined());
373}
374#endif
375
376EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*)
377{
378 // We need this function for compatibility with the Mozilla JS tests but for now
379 // we don't actually do any version-specific handling
380 return JSValue::encode(jsUndefined());
381}
382
383EncodedJSValue JSC_HOST_CALL functionRun(ExecState* exec)
384{
385 String fileName = exec->argument(0).toString(exec)->value(exec);
386 Vector<char> script;
387 if (!fillBufferWithContentsOfFile(fileName, script))
388 return JSValue::encode(exec->vm().throwException(exec, createError(exec, "Could not open file.")));
389
390 GlobalObject* globalObject = GlobalObject::create(exec->vm(), GlobalObject::createStructure(exec->vm(), jsNull()), Vector<String>());
391
392 JSArray* array = constructEmptyArray(globalObject->globalExec(), 0);
393 for (unsigned i = 1; i < exec->argumentCount(); ++i)
394 array->putDirectIndex(globalObject->globalExec(), i - 1, exec->uncheckedArgument(i));
395 globalObject->putDirect(
396 exec->vm(), Identifier(globalObject->globalExec(), "arguments"), array);
397
398 JSValue exception;
399 StopWatch stopWatch;
400 stopWatch.start();
401 evaluate(globalObject->globalExec(), jscSource(script.data(), fileName), JSValue(), &exception);
402 stopWatch.stop();
403
404 if (!!exception) {
405 exec->vm().throwException(globalObject->globalExec(), exception);
406 return JSValue::encode(jsUndefined());
407 }
408
409 return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
410}
411
412EncodedJSValue JSC_HOST_CALL functionLoad(ExecState* exec)
413{
414 String fileName = exec->argument(0).toString(exec)->value(exec);
415 Vector<char> script;
416 if (!fillBufferWithContentsOfFile(fileName, script))
417 return JSValue::encode(exec->vm().throwException(exec, createError(exec, "Could not open file.")));
418
419 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
420
421 JSValue evaluationException;
422 JSValue result = evaluate(globalObject->globalExec(), jscSource(script.data(), fileName), JSValue(), &evaluationException);
423 if (evaluationException)
424 exec->vm().throwException(exec, evaluationException);
425 return JSValue::encode(result);
426}
427
428EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState* exec)
429{
430 String fileName = exec->argument(0).toString(exec)->value(exec);
431 Vector<char> script;
432 if (!fillBufferWithContentsOfFile(fileName, script))
433 return JSValue::encode(exec->vm().throwException(exec, createError(exec, "Could not open file.")));
434
435 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
436
437 StopWatch stopWatch;
438 stopWatch.start();
439
440 JSValue syntaxException;
441 bool validSyntax = checkSyntax(globalObject->globalExec(), jscSource(script.data(), fileName), &syntaxException);
442 stopWatch.stop();
443
444 if (!validSyntax)
445 exec->vm().throwException(exec, syntaxException);
446 return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
447}
448
449#if ENABLE(SAMPLING_FLAGS)
450EncodedJSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState* exec)
451{
452 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
453 unsigned flag = static_cast<unsigned>(exec->uncheckedArgument(i).toNumber(exec));
454 if ((flag >= 1) && (flag <= 32))
455 SamplingFlags::setFlag(flag);
456 }
457 return JSValue::encode(jsNull());
458}
459
460EncodedJSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState* exec)
461{
462 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
463 unsigned flag = static_cast<unsigned>(exec->uncheckedArgument(i).toNumber(exec));
464 if ((flag >= 1) && (flag <= 32))
465 SamplingFlags::clearFlag(flag);
466 }
467 return JSValue::encode(jsNull());
468}
469#endif
470
471EncodedJSValue JSC_HOST_CALL functionReadline(ExecState* exec)
472{
473 Vector<char, 256> line;
474 int c;
475 while ((c = getchar()) != EOF) {
476 // FIXME: Should we also break on \r?
477 if (c == '\n')
478 break;
479 line.append(c);
480 }
481 line.append('\0');
482 return JSValue::encode(jsString(exec, line.data()));
483}
484
485EncodedJSValue JSC_HOST_CALL functionPreciseTime(ExecState*)
486{
487 return JSValue::encode(jsNumber(currentTime()));
488}
489
490EncodedJSValue JSC_HOST_CALL functionNeverInlineFunction(ExecState* exec)
491{
492 return JSValue::encode(setNeverInline(exec));
493}
494
495EncodedJSValue JSC_HOST_CALL functionNumberOfDFGCompiles(ExecState* exec)
496{
497 return JSValue::encode(numberOfDFGCompiles(exec));
498}
499
500EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*)
501{
502 exit(EXIT_SUCCESS);
503
504#if COMPILER(MSVC) && OS(WINCE)
505 // Without this, Visual Studio will complain that this method does not return a value.
506 return JSValue::encode(jsUndefined());
507#endif
508}
509
510// Use SEH for Release builds only to get rid of the crash report dialog
511// (luckily the same tests fail in Release and Debug builds so far). Need to
512// be in a separate main function because the jscmain function requires object
513// unwinding.
514
515#if COMPILER(MSVC) && !COMPILER(INTEL) && !defined(_DEBUG) && !OS(WINCE)
516#define TRY __try {
517#define EXCEPT(x) } __except (EXCEPTION_EXECUTE_HANDLER) { x; }
518#else
519#define TRY
520#define EXCEPT(x)
521#endif
522
523int jscmain(int argc, char** argv);
524
525static double s_desiredTimeout;
526static double s_timeToWake;
527
528static NO_RETURN_DUE_TO_CRASH void timeoutThreadMain(void*)
529{
530 // WTF doesn't provide for a portable sleep(), so we use the ThreadCondition, which
531 // is close enough.
532 Mutex mutex;
533 ThreadCondition condition;
534 mutex.lock();
535 while (currentTime() < s_timeToWake)
536 condition.timedWait(mutex, s_timeToWake);
537
538 dataLog("Timed out after ", s_desiredTimeout, " seconds!\n");
539 CRASH();
540}
541
542int main(int argc, char** argv)
543{
544#if PLATFORM(IOS)
545 // Enabled IEEE754 denormal support.
546 fenv_t env;
547 fegetenv( &env );
548 env.__fpscr &= ~0x01000000u;
549 fesetenv( &env );
550#endif
551
552#if OS(WINDOWS)
553#if !OS(WINCE)
554 // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for
555 // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the
556 // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>.
557 ::SetErrorMode(0);
558#endif
559
560#if defined(_DEBUG)
561 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
562 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
563 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
564 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
565 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
566 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
567#endif
568
569 timeBeginPeriod(1);
570#endif
571
572#if PLATFORM(BLACKBERRY)
573 // Write all WTF logs to the system log
574 BlackBerry::Platform::setupApplicationLogging("jsc");
575#endif
576
577#if PLATFORM(QT)
578 QCoreApplication app(argc, argv);
579#endif
580
581#if PLATFORM(EFL)
582 ecore_init();
583#endif
584
585 // Initialize JSC before getting VM.
586#if ENABLE(SAMPLING_REGIONS)
587 WTF::initializeMainThread();
588#endif
589 JSC::initializeThreading();
590
591 if (char* timeoutString = getenv("JSC_timeout")) {
592 if (sscanf(timeoutString, "%lf", &s_desiredTimeout) != 1) {
593 dataLog(
594 "WARNING: timeout string is malformed, got ", timeoutString,
595 " but expected a number. Not using a timeout.\n");
596 } else {
597 s_timeToWake = currentTime() + s_desiredTimeout;
598 createThread(timeoutThreadMain, 0, "jsc Timeout Thread");
599 }
600 }
601
602 // We can't use destructors in the following code because it uses Windows
603 // Structured Exception Handling
604 int res = 0;
605 TRY
606 res = jscmain(argc, argv);
607 EXCEPT(res = 3)
608 if (Options::logHeapStatisticsAtExit())
609 HeapStatistics::reportSuccess();
610
611#if PLATFORM(EFL)
612 ecore_shutdown();
613#endif
614
615 return res;
616}
617
618static bool runWithScripts(GlobalObject* globalObject, const Vector<Script>& scripts, bool dump)
619{
620 const char* script;
621 String fileName;
622 Vector<char> scriptBuffer;
623
624 if (dump)
625 JSC::Options::dumpGeneratedBytecodes() = true;
626
627 VM& vm = globalObject->vm();
628
629#if ENABLE(SAMPLING_FLAGS)
630 SamplingFlags::start();
631#endif
632
633 bool success = true;
634 for (size_t i = 0; i < scripts.size(); i++) {
635 if (scripts[i].isFile) {
636 fileName = scripts[i].argument;
637 if (!fillBufferWithContentsOfFile(fileName, scriptBuffer))
638 return false; // fail early so we can catch missing files
639 script = scriptBuffer.data();
640 } else {
641 script = scripts[i].argument;
642 fileName = "[Command Line]";
643 }
644
645 vm.startSampling();
646
647 JSValue evaluationException;
648 JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(script, fileName), JSValue(), &evaluationException);
649 success = success && !evaluationException;
650 if (dump && !evaluationException)
651 printf("End: %s\n", returnValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
652 if (evaluationException) {
653 printf("Exception: %s\n", evaluationException.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
654 Identifier stackID(globalObject->globalExec(), "stack");
655 JSValue stackValue = evaluationException.get(globalObject->globalExec(), stackID);
656 if (!stackValue.isUndefinedOrNull())
657 printf("%s\n", stackValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
658 }
659
660 vm.stopSampling();
661 globalObject->globalExec()->clearException();
662 }
663
664#if ENABLE(SAMPLING_FLAGS)
665 SamplingFlags::stop();
666#endif
667#if ENABLE(SAMPLING_REGIONS)
668 SamplingRegion::dump();
669#endif
670 vm.dumpSampleData(globalObject->globalExec());
671#if ENABLE(SAMPLING_COUNTERS)
672 AbstractSamplingCounter::dump();
673#endif
674#if ENABLE(REGEXP_TRACING)
675 vm.dumpRegExpTrace();
676#endif
677 return success;
678}
679
680#define RUNNING_FROM_XCODE 0
681
682static void runInteractive(GlobalObject* globalObject)
683{
684 String interpreterName("Interpreter");
685
686 bool shouldQuit = false;
687 while (!shouldQuit) {
688#if HAVE(READLINE) && !RUNNING_FROM_XCODE
689 ParserError error;
690 String source;
691 do {
692 error = ParserError();
693 char* line = readline(source.isEmpty() ? interactivePrompt : "... ");
694 shouldQuit = !line;
695 if (!line)
696 break;
697 source = source + line;
698 source = source + '\n';
699 checkSyntax(globalObject->vm(), makeSource(source, interpreterName), error);
700 if (!line[0])
701 break;
702 add_history(line);
703 } while (error.m_syntaxErrorType == ParserError::SyntaxErrorRecoverable);
704
705 if (error.m_type != ParserError::ErrorNone) {
706 printf("%s:%d\n", error.m_message.utf8().data(), error.m_line);
707 continue;
708 }
709
710
711 JSValue evaluationException;
712 JSValue returnValue = evaluate(globalObject->globalExec(), makeSource(source, interpreterName), JSValue(), &evaluationException);
713#else
714 printf("%s", interactivePrompt);
715 Vector<char, 256> line;
716 int c;
717 while ((c = getchar()) != EOF) {
718 // FIXME: Should we also break on \r?
719 if (c == '\n')
720 break;
721 line.append(c);
722 }
723 if (line.isEmpty())
724 break;
725 line.append('\0');
726
727 JSValue evaluationException;
728 JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(line.data(), interpreterName), JSValue(), &evaluationException);
729#endif
730 if (evaluationException)
731 printf("Exception: %s\n", evaluationException.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
732 else
733 printf("%s\n", returnValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
734
735 globalObject->globalExec()->clearException();
736 }
737 printf("\n");
738}
739
740static NO_RETURN void printUsageStatement(bool help = false)
741{
742 fprintf(stderr, "Usage: jsc [options] [files] [-- arguments]\n");
743 fprintf(stderr, " -d Dumps bytecode (debug builds only)\n");
744 fprintf(stderr, " -e Evaluate argument as script code\n");
745 fprintf(stderr, " -f Specifies a source file (deprecated)\n");
746 fprintf(stderr, " -h|--help Prints this help message\n");
747 fprintf(stderr, " -i Enables interactive mode (default if no files are specified)\n");
748#if HAVE(SIGNAL_H)
749 fprintf(stderr, " -s Installs signal handlers that exit on a crash (Unix platforms only)\n");
750#endif
751 fprintf(stderr, " -p <file> Outputs profiling data to a file\n");
752 fprintf(stderr, " -x Output exit code before terminating\n");
753 fprintf(stderr, "\n");
754 fprintf(stderr, " --options Dumps all JSC VM options and exits\n");
755 fprintf(stderr, " --dumpOptions Dumps all JSC VM options before continuing\n");
756 fprintf(stderr, " --<jsc VM option>=<value> Sets the specified JSC VM option\n");
757 fprintf(stderr, "\n");
758
759 exit(help ? EXIT_SUCCESS : EXIT_FAILURE);
760}
761
762void CommandLine::parseArguments(int argc, char** argv)
763{
764 int i = 1;
765 bool needToDumpOptions = false;
766 bool needToExit = false;
767
768 for (; i < argc; ++i) {
769 const char* arg = argv[i];
770 if (!strcmp(arg, "-f")) {
771 if (++i == argc)
772 printUsageStatement();
773 m_scripts.append(Script(true, argv[i]));
774 continue;
775 }
776 if (!strcmp(arg, "-e")) {
777 if (++i == argc)
778 printUsageStatement();
779 m_scripts.append(Script(false, argv[i]));
780 continue;
781 }
782 if (!strcmp(arg, "-i")) {
783 m_interactive = true;
784 continue;
785 }
786 if (!strcmp(arg, "-d")) {
787 m_dump = true;
788 continue;
789 }
790 if (!strcmp(arg, "-p")) {
791 if (++i == argc)
792 printUsageStatement();
793 m_profile = true;
794 m_profilerOutput = argv[i];
795 continue;
796 }
797 if (!strcmp(arg, "-s")) {
798#if HAVE(SIGNAL_H)
799 signal(SIGILL, _exit);
800 signal(SIGFPE, _exit);
801 signal(SIGBUS, _exit);
802 signal(SIGSEGV, _exit);
803#endif
804 continue;
805 }
806 if (!strcmp(arg, "-x")) {
807 m_exitCode = true;
808 continue;
809 }
810 if (!strcmp(arg, "--")) {
811 ++i;
812 break;
813 }
814 if (!strcmp(arg, "-h") || !strcmp(arg, "--help"))
815 printUsageStatement(true);
816
817 if (!strcmp(arg, "--options")) {
818 needToDumpOptions = true;
819 needToExit = true;
820 continue;
821 }
822 if (!strcmp(arg, "--dumpOptions")) {
823 needToDumpOptions = true;
824 continue;
825 }
826
827 // See if the -- option is a JSC VM option.
828 // NOTE: At this point, we know that the arg starts with "--". Skip it.
829 if (JSC::Options::setOption(&arg[2])) {
830 // The arg was recognized as a VM option and has been parsed.
831 continue; // Just continue with the next arg.
832 }
833
834 // This arg is not recognized by the VM nor by jsc. Pass it on to the
835 // script.
836 m_scripts.append(Script(true, argv[i]));
837 }
838
839 if (m_scripts.isEmpty())
840 m_interactive = true;
841
842 for (; i < argc; ++i)
843 m_arguments.append(argv[i]);
844
845 if (needToDumpOptions)
846 JSC::Options::dumpAllOptions(stderr);
847 if (needToExit)
848 exit(EXIT_SUCCESS);
849}
850
851int jscmain(int argc, char** argv)
852{
853 // Note that the options parsing can affect VM creation, and thus
854 // comes first.
855 CommandLine options(argc, argv);
856 RefPtr<VM> vm = VM::create(LargeHeap);
857 int result;
858 {
859 APIEntryShim shim(vm.get());
860
861 if (options.m_profile && !vm->m_perBytecodeProfiler)
862 vm->m_perBytecodeProfiler = adoptPtr(new Profiler::Database(*vm));
863
864 GlobalObject* globalObject = GlobalObject::create(*vm, GlobalObject::createStructure(*vm, jsNull()), options.m_arguments);
865 bool success = runWithScripts(globalObject, options.m_scripts, options.m_dump);
866 if (options.m_interactive && success)
867 runInteractive(globalObject);
868
869 result = success ? 0 : 3;
870
871 if (options.m_exitCode)
872 printf("jsc exiting %d\n", result);
873
874 if (options.m_profile) {
875 if (!vm->m_perBytecodeProfiler->save(options.m_profilerOutput.utf8().data()))
876 fprintf(stderr, "could not save profiler output.\n");
877 }
878 }
879
880 if (Options::neverDeleteVMInCommandLine()) {
881 JSC::VM* temp = vm.release().leakRef();
882 UNUSED_PARAM(temp);
883 } else {
884 JSLockHolder lock(*vm);
885 vm.clear();
886 }
887
888 return result;
889}
890
891static bool fillBufferWithContentsOfFile(const String& fileName, Vector<char>& buffer)
892{
893 FILE* f = fopen(fileName.utf8().data(), "r");
894 if (!f) {
895 fprintf(stderr, "Could not open file: %s\n", fileName.utf8().data());
896 return false;
897 }
898
899 size_t bufferSize = 0;
900 size_t bufferCapacity = 1024;
901
902 buffer.resize(bufferCapacity);
903
904 while (!feof(f) && !ferror(f)) {
905 bufferSize += fread(buffer.data() + bufferSize, 1, bufferCapacity - bufferSize, f);
906 if (bufferSize == bufferCapacity) { // guarantees space for trailing '\0'
907 bufferCapacity *= 2;
908 buffer.resize(bufferCapacity);
909 }
910 }
911 fclose(f);
912 buffer[bufferSize] = '\0';
913
914 if (buffer[0] == '#' && buffer[1] == '!')
915 buffer[0] = buffer[1] = '/';
916
917 return true;
918}
Note: See TracBrowser for help on using the repository browser.