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

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

toThis() on a JSWorkerGlobalScope should return a JSProxy and not undefined
https://bugs.webkit.org/show_bug.cgi?id=130554

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

Fixed toThis() on WorkerGlobalScope to return a JSProxy instead of the JSGlobalObject.
Did some cleanup as well. Moved the setting of the thisObject in a JSGlobalObject to
happen in finishCreation() so that it will also happen for other derived classes including
JSWorkerGlobalScopeBase.

  • API/JSContextRef.cpp:

(JSGlobalContextCreateInGroup):

  • jsc.cpp:

(GlobalObject::create):

  • API/tests/testapi.c:

(globalObject_initialize): Eliminated ASSERT that the global object we are creating matches
the result from JSContextGetGlobalObject() as that will return the proxy.

  • runtime/JSGlobalObject.cpp:

(JSC::JSGlobalObject::init): Removed thisValue parameter and the call to setGlobalThis() since
we now call setGlobalThis in finishCreation().

  • runtime/JSGlobalObject.h:

(JSC::JSGlobalObject::finishCreation):
(JSC::JSGlobalObject::setGlobalThis): Made this a private method.

Source/WebCore:

Fixed toThis() on WorkerGlobalScope to return a JSProxy instead of the JSGlobalObject.
Added cast from JSProxy->target() if the jsCast<>() to the native object fails
in toJSDedicatedWorkerGlobalScope() and toJSSharedWorkerGlobalScope().
The original cast is needed for access to the local side of the worker, while the JSProxy
cast is used on the remote side of a worker.

Test: fast/workers/worker-strict.html

  • bindings/js/JSWorkerGlobalScopeBase.cpp:

(WebCore::toJSDedicatedWorkerGlobalScope):
(WebCore::toJSSharedWorkerGlobalScope):

  • bindings/js/WorkerScriptController.cpp:

(WebCore::WorkerScriptController::evaluate): Changed to pass in the JSProxy and not
the WorkerGlobalScope object as the this object to script evaluation.

  • workers/DedicatedWorkerGlobalScope.idl:
  • workers/SharedWorkerGlobalScope.idl:
  • workers/WorkerGlobalScope.idl:

Added the new CustomProxyToJSObject attribute so we'll call to<{nativeClass}>() for
getting the object to use for global evaluation.

LayoutTests:

Fixed toThis() on WorkerGlobalScope to return a JSProxy instead of the JSGlobalObject.
New regressions tests.

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