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

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

Structure should have a StructureRareData field to save space
https://bugs.webkit.org/show_bug.cgi?id=108659

Reviewed by Oliver Hunt.

Many of the fields in Structure are used in a subset of all total Structures; however, all Structures must
pay the memory cost of those fields, regardless of whether they use them or not. Since we can have potentially
many Structures on a single page (e.g. bing.com creates ~1500 Structures), it would be profitable to
refactor Structure so that not every Structure has to pay the memory costs for these infrequently used fields.

To accomplish this, we can create a new StructureRareData class to house these seldom used fields which we
can allocate on demand whenever a Structure requires it. This StructureRareData can itself be a JSCell, and
can do all the marking of the fields for the Structure. The StructureRareData field will be part of a union
with m_previous to minimize overhead. We'll add a new field to JSTypeInfo to indicate that the Structure has
a StructureRareData field. During transitions, a Structure will clone its previous Structure's StructureRareData
if it has one. There could be some potential for optimizing this process, but the initial implementation will
be dumb since we'd be paying these overhead costs for each Structure anyways.

Initially we'll only put two fields in the StructureRareData to avoid a memory regression. Over time we'll
continue to move fields from Structure to StructureRareData. Optimistically, this could potentially reduce our
Structure memory footprint by up to around 75%. It could also clear the way for removing destructors from
Structures (and into StructureRareData).

  • CMakeLists.txt:
  • GNUmakefile.list.am:
  • JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • Target.pri:
  • dfg/DFGRepatch.cpp: Includes for linking purposes.
  • jit/JITStubs.cpp:
  • jsc.cpp:
  • llint/LLIntSlowPaths.cpp:
  • runtime/JSCellInlines.h: Added ifdef guards.
  • runtime/JSGlobalData.cpp: New Structure for StructureRareData class.

(JSC::JSGlobalData::JSGlobalData):

  • runtime/JSGlobalData.h:

(JSGlobalData):

  • runtime/JSGlobalObject.h:
  • runtime/JSTypeInfo.h: New flag to indicate whether or not a Structure has a StructureRareData field.

(JSC::TypeInfo::flags):
(JSC::TypeInfo::structureHasRareData):

  • runtime/ObjectPrototype.cpp:
  • runtime/Structure.cpp: We use a combined WriteBarrier<JSCell> field m_previousOrRareData to avoid compiler issues.

(JSC::Structure::dumpStatistics):
(JSC::Structure::Structure):
(JSC::Structure::materializePropertyMap):
(JSC::Structure::addPropertyTransition):
(JSC::Structure::nonPropertyTransition):
(JSC::Structure::pin):
(JSC::Structure::allocateRareData): Handles allocating a brand new StructureRareData field.
(JSC::Structure::cloneRareDataFrom): Handles cloning a StructureRareData field from another. Used during Structure
transitions.
(JSC::Structure::visitChildren): We no longer have to worry about marking m_objectToStringValue.

  • runtime/Structure.h:

(JSC::Structure::previousID): Checks the structureHasRareData flag to see where it should get the previous Structure.
(JSC::Structure::objectToStringValue): Reads the value from the StructureRareData. If it doesn't exist, returns 0.
(JSC::Structure::setObjectToStringValue): Ensures that we have a StructureRareData field, then forwards the function
call to it.
(JSC::Structure::materializePropertyMapIfNecessary):
(JSC::Structure::setPreviousID): Checks for StructureRareData and forwards if necessary.
(Structure):
(JSC::Structure::clearPreviousID): Ditto.
(JSC::Structure::create):

  • runtime/StructureRareData.cpp: Added. All of the basic functionality of a JSCell with the fields that we've moved

from Structure and the functions required to access/modify those fields as Structure would have done.
(JSC):
(JSC::StructureRareData::createStructure):
(JSC::StructureRareData::create):
(JSC::StructureRareData::clone):
(JSC::StructureRareData::StructureRareData):
(JSC::StructureRareData::visitChildren):

  • runtime/StructureRareData.h: Added.

(JSC):
(StructureRareData):

  • runtime/StructureRareDataInlines.h: Added.

(JSC):
(JSC::StructureRareData::previousID):
(JSC::StructureRareData::setPreviousID):
(JSC::StructureRareData::clearPreviousID):
(JSC::Structure::previous): Handles the ugly casting to get the value of the right type of m_previousOrRareData.
(JSC::Structure::rareData): Ditto.
(JSC::StructureRareData::objectToStringValue):
(JSC::StructureRareData::setObjectToStringValue):

  • CMakeLists.txt:
  • GNUmakefile.list.am:
  • JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • Target.pri:
  • dfg/DFGRepatch.cpp:
  • jit/JITStubs.cpp:
  • jsc.cpp:
  • llint/LLIntSlowPaths.cpp:
  • runtime/JSCellInlines.h:
  • runtime/JSGlobalData.cpp:

(JSC::JSGlobalData::JSGlobalData):

  • runtime/JSGlobalData.h:

(JSGlobalData):

  • runtime/JSGlobalObject.h:
  • runtime/JSTypeInfo.h:

(JSC):
(JSC::TypeInfo::flags):
(JSC::TypeInfo::structureHasRareData):

  • runtime/ObjectPrototype.cpp:
  • runtime/Structure.cpp:

(JSC::Structure::dumpStatistics):
(JSC::Structure::Structure):
(JSC::Structure::materializePropertyMap):
(JSC::Structure::addPropertyTransition):
(JSC::Structure::nonPropertyTransition):
(JSC::Structure::pin):
(JSC::Structure::allocateRareData):
(JSC):
(JSC::Structure::cloneRareDataFrom):
(JSC::Structure::visitChildren):

  • runtime/Structure.h:

(JSC::Structure::previousID):
(JSC::Structure::objectToStringValue):
(JSC::Structure::setObjectToStringValue):
(JSC::Structure::materializePropertyMapIfNecessary):
(JSC::Structure::setPreviousID):
(Structure):
(JSC::Structure::clearPreviousID):
(JSC::Structure::previous):
(JSC::Structure::rareData):
(JSC::Structure::create):

  • runtime/StructureRareData.cpp: Added.

(JSC):
(JSC::StructureRareData::createStructure):
(JSC::StructureRareData::create):
(JSC::StructureRareData::clone):
(JSC::StructureRareData::StructureRareData):
(JSC::StructureRareData::visitChildren):

  • runtime/StructureRareData.h: Added.

(JSC):
(StructureRareData):

  • runtime/StructureRareDataInlines.h: Added.

(JSC):
(JSC::StructureRareData::previousID):
(JSC::StructureRareData::setPreviousID):
(JSC::StructureRareData::clearPreviousID):
(JSC::StructureRareData::objectToStringValue):
(JSC::StructureRareData::setObjectToStringValue):

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