/* * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) * Copyright (C) 2004-2008, 2012-2013, 2015 Apple Inc. All rights reserved. * Copyright (C) 2006 Bjoern Graf (bjoern.graf@gmail.com) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */ #include "config.h" #include "ArrayPrototype.h" #include "ButterflyInlines.h" #include "BytecodeGenerator.h" #include "CodeBlock.h" #include "Completion.h" #include "CopiedSpaceInlines.h" #include "DFGPlan.h" #include "Disassembler.h" #include "Exception.h" #include "ExceptionHelpers.h" #include "HeapStatistics.h" #include "InitializeThreading.h" #include "Interpreter.h" #include "JSArray.h" #include "JSArrayBuffer.h" #include "JSCInlines.h" #include "JSFunction.h" #include "JSInternalPromise.h" #include "JSInternalPromiseDeferred.h" #include "JSLock.h" #include "JSNativeStdFunction.h" #include "JSONObject.h" #include "JSProxy.h" #include "JSString.h" #include "JSWASMModule.h" #include "ProfilerDatabase.h" #include "SamplingProfiler.h" #include "SamplingTool.h" #include "StackVisitor.h" #include "StructureInlines.h" #include "StructureRareDataInlines.h" #include "TestRunnerUtils.h" #include "TypeProfilerLog.h" #include "WASMModuleParser.h" #include #include #include #include #include #include #include #include #include #if OS(WINDOWS) #include #include #else #include #endif #if HAVE(READLINE) // readline/history.h has a Function typedef which conflicts with the WTF::Function template from WTF/Forward.h // We #define it to something else to avoid this conflict. #define Function ReadlineFunction #include #include #undef Function #endif #if HAVE(SYS_TIME_H) #include #endif #if HAVE(SIGNAL_H) #include #endif #if COMPILER(MSVC) #include #include #include #endif #if PLATFORM(IOS) && CPU(ARM_THUMB2) #include #include #endif #if PLATFORM(QT) #include #include #endif #if PLATFORM(EFL) #include #endif #if !defined(PATH_MAX) #define PATH_MAX 4096 #endif using namespace JSC; using namespace WTF; namespace { NO_RETURN_WITH_VALUE static void jscExit(int status) { waitForAsynchronousDisassembly(); #if ENABLE(DFG_JIT) if (DFG::isCrashing()) { for (;;) { #if OS(WINDOWS) Sleep(1000); #else pause(); #endif } } #endif // ENABLE(DFG_JIT) exit(status); } class Element; class ElementHandleOwner; class Masuqerader; class Root; class RuntimeArray; class Element : public JSNonFinalObject { public: Element(VM& vm, Structure* structure) : Base(vm, structure) { } typedef JSNonFinalObject Base; static const bool needsDestruction = false; Root* root() const { return m_root.get(); } void setRoot(VM& vm, Root* root) { m_root.set(vm, this, root); } static Element* create(VM& vm, JSGlobalObject* globalObject, Root* root) { Structure* structure = createStructure(vm, globalObject, jsNull()); Element* element = new (NotNull, allocateCell(vm.heap, sizeof(Element))) Element(vm, structure); element->finishCreation(vm, root); return element; } void finishCreation(VM&, Root*); static void visitChildren(JSCell* cell, SlotVisitor& visitor) { Element* thisObject = jsCast(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); Base::visitChildren(thisObject, visitor); visitor.append(&thisObject->m_root); } static ElementHandleOwner* handleOwner(); static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); } DECLARE_INFO; private: WriteBarrier m_root; }; class ElementHandleOwner : public WeakHandleOwner { public: bool isReachableFromOpaqueRoots(Handle handle, void*, SlotVisitor& visitor) override { Element* element = jsCast(handle.slot()->asCell()); return visitor.containsOpaqueRoot(element->root()); } }; class Masquerader : public JSNonFinalObject { public: Masquerader(VM& vm, Structure* structure) : Base(vm, structure) { } typedef JSNonFinalObject Base; static const unsigned StructureFlags = Base::StructureFlags | JSC::MasqueradesAsUndefined; static Masquerader* create(VM& vm, JSGlobalObject* globalObject) { globalObject->masqueradesAsUndefinedWatchpoint()->fireAll("Masquerading object allocated"); Structure* structure = createStructure(vm, globalObject, jsNull()); Masquerader* result = new (NotNull, allocateCell(vm.heap, sizeof(Masquerader))) Masquerader(vm, structure); result->finishCreation(vm); return result; } static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); } DECLARE_INFO; }; class Root : public JSDestructibleObject { public: Root(VM& vm, Structure* structure) : Base(vm, structure) { } Element* element() { return m_element.get(); } void setElement(Element* element) { Weak newElement(element, Element::handleOwner()); m_element.swap(newElement); } static Root* create(VM& vm, JSGlobalObject* globalObject) { Structure* structure = createStructure(vm, globalObject, jsNull()); Root* root = new (NotNull, allocateCell(vm.heap, sizeof(Root))) Root(vm, structure); root->finishCreation(vm); return root; } typedef JSDestructibleObject Base; DECLARE_INFO; static const bool needsDestruction = true; static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); } static void visitChildren(JSCell* thisObject, SlotVisitor& visitor) { Base::visitChildren(thisObject, visitor); visitor.addOpaqueRoot(thisObject); } private: Weak m_element; }; class ImpureGetter : public JSNonFinalObject { public: ImpureGetter(VM& vm, Structure* structure) : Base(vm, structure) { } DECLARE_INFO; typedef JSNonFinalObject Base; static const unsigned StructureFlags = Base::StructureFlags | JSC::GetOwnPropertySlotIsImpure | JSC::OverridesGetOwnPropertySlot; static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); } static ImpureGetter* create(VM& vm, Structure* structure, JSObject* delegate) { ImpureGetter* getter = new (NotNull, allocateCell(vm.heap, sizeof(ImpureGetter))) ImpureGetter(vm, structure); getter->finishCreation(vm, delegate); return getter; } void finishCreation(VM& vm, JSObject* delegate) { Base::finishCreation(vm); if (delegate) m_delegate.set(vm, this, delegate); } static bool getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName name, PropertySlot& slot) { ImpureGetter* thisObject = jsCast(object); if (thisObject->m_delegate && thisObject->m_delegate->getPropertySlot(exec, name, slot)) return true; return Base::getOwnPropertySlot(object, exec, name, slot); } static void visitChildren(JSCell* cell, SlotVisitor& visitor) { Base::visitChildren(cell, visitor); ImpureGetter* thisObject = jsCast(cell); visitor.append(&thisObject->m_delegate); } void setDelegate(VM& vm, JSObject* delegate) { m_delegate.set(vm, this, delegate); } private: WriteBarrier m_delegate; }; class CustomGetter : public JSNonFinalObject { public: CustomGetter(VM& vm, Structure* structure) : Base(vm, structure) { } DECLARE_INFO; typedef JSNonFinalObject Base; static const unsigned StructureFlags = Base::StructureFlags | JSC::OverridesGetOwnPropertySlot; static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); } static CustomGetter* create(VM& vm, Structure* structure) { CustomGetter* getter = new (NotNull, allocateCell(vm.heap, sizeof(CustomGetter))) CustomGetter(vm, structure); getter->finishCreation(vm); return getter; } static bool getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) { CustomGetter* thisObject = jsCast(object); if (propertyName == PropertyName(Identifier::fromString(exec, "customGetter"))) { slot.setCacheableCustom(thisObject, DontDelete | ReadOnly | DontEnum, thisObject->customGetter); return true; } return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot); } private: static EncodedJSValue customGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName) { CustomGetter* thisObject = jsDynamicCast(JSValue::decode(thisValue)); if (!thisObject) return throwVMTypeError(exec); bool shouldThrow = thisObject->get(exec, PropertyName(Identifier::fromString(exec, "shouldThrow"))).toBoolean(exec); if (shouldThrow) return throwVMTypeError(exec); return JSValue::encode(jsNumber(100)); } }; class RuntimeArray : public JSArray { public: typedef JSArray Base; static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesGetPropertyNames; static RuntimeArray* create(ExecState* exec) { VM& vm = exec->vm(); JSGlobalObject* globalObject = exec->lexicalGlobalObject(); Structure* structure = createStructure(vm, globalObject, createPrototype(vm, globalObject)); RuntimeArray* runtimeArray = new (NotNull, allocateCell(*exec->heap())) RuntimeArray(exec, structure); runtimeArray->finishCreation(exec); vm.heap.addFinalizer(runtimeArray, destroy); return runtimeArray; } ~RuntimeArray() { } static void destroy(JSCell* cell) { static_cast(cell)->RuntimeArray::~RuntimeArray(); } static const bool needsDestruction = false; static bool getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) { RuntimeArray* thisObject = jsCast(object); if (propertyName == exec->propertyNames().length) { slot.setCacheableCustom(thisObject, DontDelete | ReadOnly | DontEnum, thisObject->lengthGetter); return true; } Optional index = parseIndex(propertyName); if (index && index.value() < thisObject->getLength()) { slot.setValue(thisObject, DontDelete | DontEnum, jsNumber(thisObject->m_vector[index.value()])); return true; } return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot); } static bool getOwnPropertySlotByIndex(JSObject* object, ExecState* exec, unsigned index, PropertySlot& slot) { RuntimeArray* thisObject = jsCast(object); if (index < thisObject->getLength()) { slot.setValue(thisObject, DontDelete | DontEnum, jsNumber(thisObject->m_vector[index])); return true; } return JSObject::getOwnPropertySlotByIndex(thisObject, exec, index, slot); } static NO_RETURN_DUE_TO_CRASH void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&) { RELEASE_ASSERT_NOT_REACHED(); } static NO_RETURN_DUE_TO_CRASH bool deleteProperty(JSCell*, ExecState*, PropertyName) { RELEASE_ASSERT_NOT_REACHED(); } unsigned getLength() const { return m_vector.size(); } DECLARE_INFO; static ArrayPrototype* createPrototype(VM&, JSGlobalObject* globalObject) { return globalObject->arrayPrototype(); } static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info(), ArrayClass); } protected: void finishCreation(ExecState* exec) { Base::finishCreation(exec->vm()); ASSERT(inherits(info())); for (size_t i = 0; i < exec->argumentCount(); i++) m_vector.append(exec->argument(i).toInt32(exec)); } private: RuntimeArray(ExecState* exec, Structure* structure) : JSArray(exec->vm(), structure, 0) { } static EncodedJSValue lengthGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName) { RuntimeArray* thisObject = jsDynamicCast(JSValue::decode(thisValue)); if (!thisObject) return throwVMTypeError(exec); return JSValue::encode(jsNumber(thisObject->getLength())); } Vector m_vector; }; const ClassInfo Element::s_info = { "Element", &Base::s_info, 0, CREATE_METHOD_TABLE(Element) }; const ClassInfo Masquerader::s_info = { "Masquerader", &Base::s_info, 0, CREATE_METHOD_TABLE(Masquerader) }; const ClassInfo Root::s_info = { "Root", &Base::s_info, 0, CREATE_METHOD_TABLE(Root) }; const ClassInfo ImpureGetter::s_info = { "ImpureGetter", &Base::s_info, 0, CREATE_METHOD_TABLE(ImpureGetter) }; const ClassInfo CustomGetter::s_info = { "CustomGetter", &Base::s_info, 0, CREATE_METHOD_TABLE(CustomGetter) }; const ClassInfo RuntimeArray::s_info = { "RuntimeArray", &Base::s_info, 0, CREATE_METHOD_TABLE(RuntimeArray) }; ElementHandleOwner* Element::handleOwner() { static ElementHandleOwner* owner = 0; if (!owner) owner = new ElementHandleOwner(); return owner; } void Element::finishCreation(VM& vm, Root* root) { Base::finishCreation(vm); setRoot(vm, root); m_root->setElement(this); } } static bool fillBufferWithContentsOfFile(const String& fileName, Vector& buffer); static EncodedJSValue JSC_HOST_CALL functionCreateProxy(ExecState*); static EncodedJSValue JSC_HOST_CALL functionCreateRuntimeArray(ExecState*); static EncodedJSValue JSC_HOST_CALL functionCreateImpureGetter(ExecState*); static EncodedJSValue JSC_HOST_CALL functionCreateCustomGetterObject(ExecState*); static EncodedJSValue JSC_HOST_CALL functionSetImpureGetterDelegate(ExecState*); static EncodedJSValue JSC_HOST_CALL functionSetElementRoot(ExecState*); static EncodedJSValue JSC_HOST_CALL functionCreateRoot(ExecState*); static EncodedJSValue JSC_HOST_CALL functionCreateElement(ExecState*); static EncodedJSValue JSC_HOST_CALL functionGetElement(ExecState*); static EncodedJSValue JSC_HOST_CALL functionPrint(ExecState*); static EncodedJSValue JSC_HOST_CALL functionDebug(ExecState*); static EncodedJSValue JSC_HOST_CALL functionDescribe(ExecState*); static EncodedJSValue JSC_HOST_CALL functionDescribeArray(ExecState*); static EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState*); static EncodedJSValue JSC_HOST_CALL functionGCAndSweep(ExecState*); static EncodedJSValue JSC_HOST_CALL functionFullGC(ExecState*); static EncodedJSValue JSC_HOST_CALL functionEdenGC(ExecState*); static EncodedJSValue JSC_HOST_CALL functionForceGCSlowPaths(ExecState*); static EncodedJSValue JSC_HOST_CALL functionHeapSize(ExecState*); static EncodedJSValue JSC_HOST_CALL functionAddressOf(ExecState*); #ifndef NDEBUG static EncodedJSValue JSC_HOST_CALL functionDumpCallFrame(ExecState*); #endif static EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*); static EncodedJSValue JSC_HOST_CALL functionRun(ExecState*); static EncodedJSValue JSC_HOST_CALL functionLoad(ExecState*); static EncodedJSValue JSC_HOST_CALL functionReadFile(ExecState*); static EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState*); static EncodedJSValue JSC_HOST_CALL functionReadline(ExecState*); static EncodedJSValue JSC_HOST_CALL functionPreciseTime(ExecState*); static EncodedJSValue JSC_HOST_CALL functionNeverInlineFunction(ExecState*); static EncodedJSValue JSC_HOST_CALL functionNoDFG(ExecState*); static EncodedJSValue JSC_HOST_CALL functionOptimizeNextInvocation(ExecState*); static EncodedJSValue JSC_HOST_CALL functionNumberOfDFGCompiles(ExecState*); static EncodedJSValue JSC_HOST_CALL functionReoptimizationRetryCount(ExecState*); static EncodedJSValue JSC_HOST_CALL functionTransferArrayBuffer(ExecState*); static EncodedJSValue JSC_HOST_CALL functionFailNextNewCodeBlock(ExecState*); static NO_RETURN_WITH_VALUE EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*); static NO_RETURN_DUE_TO_CRASH EncodedJSValue JSC_HOST_CALL functionAbort(ExecState*); static EncodedJSValue JSC_HOST_CALL functionFalse1(ExecState*); static EncodedJSValue JSC_HOST_CALL functionFalse2(ExecState*); static EncodedJSValue JSC_HOST_CALL functionUndefined1(ExecState*); static EncodedJSValue JSC_HOST_CALL functionUndefined2(ExecState*); static EncodedJSValue JSC_HOST_CALL functionIsInt32(ExecState*); static EncodedJSValue JSC_HOST_CALL functionEffectful42(ExecState*); static EncodedJSValue JSC_HOST_CALL functionIdentity(ExecState*); static EncodedJSValue JSC_HOST_CALL functionMakeMasquerader(ExecState*); static EncodedJSValue JSC_HOST_CALL functionHasCustomProperties(ExecState*); static EncodedJSValue JSC_HOST_CALL functionDumpTypesForAllVariables(ExecState*); static EncodedJSValue JSC_HOST_CALL functionFindTypeForExpression(ExecState*); static EncodedJSValue JSC_HOST_CALL functionReturnTypeFor(ExecState*); static EncodedJSValue JSC_HOST_CALL functionDumpBasicBlockExecutionRanges(ExecState*); static EncodedJSValue JSC_HOST_CALL functionHasBasicBlockExecuted(ExecState*); static EncodedJSValue JSC_HOST_CALL functionBasicBlockExecutionCount(ExecState*); static EncodedJSValue JSC_HOST_CALL functionEnableExceptionFuzz(ExecState*); static EncodedJSValue JSC_HOST_CALL functionDrainMicrotasks(ExecState*); static EncodedJSValue JSC_HOST_CALL functionIs32BitPlatform(ExecState*); #if ENABLE(WEBASSEMBLY) static EncodedJSValue JSC_HOST_CALL functionLoadWebAssembly(ExecState*); #endif static EncodedJSValue JSC_HOST_CALL functionLoadModule(ExecState*); static EncodedJSValue JSC_HOST_CALL functionCheckModuleSyntax(ExecState*); static EncodedJSValue JSC_HOST_CALL functionPlatformSupportsSamplingProfiler(ExecState*); #if ENABLE(SAMPLING_PROFILER) static EncodedJSValue JSC_HOST_CALL functionStartSamplingProfiler(ExecState*); static EncodedJSValue JSC_HOST_CALL functionSamplingProfilerStackTraces(ExecState*); #endif #if ENABLE(SAMPLING_FLAGS) static EncodedJSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState*); static EncodedJSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState*); #endif struct Script { bool isFile; char* argument; Script(bool isFile, char *argument) : isFile(isFile) , argument(argument) { } }; class CommandLine { public: CommandLine(int argc, char** argv) { parseArguments(argc, argv); } bool m_interactive { false }; bool m_dump { false }; bool m_module { false }; bool m_exitCode { false }; Vector