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