/* * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2012, 2013 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 "Completion.h" #include "CopiedSpaceInlines.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 "JSLock.h" #include "JSProxy.h" #include "JSString.h" #include "ProfilerDatabase.h" #include "SamplingTool.h" #include "StackVisitor.h" #include "StructureInlines.h" #include "StructureRareDataInlines.h" #include "TestRunnerUtils.h" #include #include #include #include #include #include #include #include #include #if !OS(WINDOWS) #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) && !OS(WINCE) #include #include #include #endif #if PLATFORM(IOS) && CPU(ARM_THUMB2) #include #include #endif #if PLATFORM(EFL) #include #endif using namespace JSC; using namespace WTF; namespace { class Element; class ElementHandleOwner; class Masuqerader; class Root; class RuntimeArray; class Element : public JSNonFinalObject { public: Element(VM& vm, Structure* structure, Root* root) : Base(vm, structure) , m_root(root) { } typedef JSNonFinalObject Base; static const bool needsDestruction = false; Root* root() const { return m_root; } void setRoot(Root* root) { m_root = 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, root); element->finishCreation(vm); return element; } void finishCreation(VM&); 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: Root* m_root; }; class ElementHandleOwner : public WeakHandleOwner { public: virtual bool isReachableFromOpaqueRoots(Handle handle, void*, SlotVisitor& visitor) { 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 Masquerader* create(VM& vm, JSGlobalObject* globalObject) { globalObject->masqueradesAsUndefinedWatchpoint()->fireAll(); 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; protected: static const unsigned StructureFlags = JSC::MasqueradesAsUndefined | Base::StructureFlags; }; 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 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 const unsigned StructureFlags = JSC::HasImpureGetOwnPropertySlot | JSC::OverridesGetOwnPropertySlot | JSC::OverridesVisitChildren | Base::StructureFlags; 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 RuntimeArray : public JSArray { public: typedef JSArray Base; 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; } unsigned index = propertyName.asIndex(); if (index < thisObject->getLength()) { ASSERT(index != PropertyName::NotAnIndex); slot.setValue(thisObject, DontDelete | DontEnum, jsNumber(thisObject->m_vector[index])); 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(); #if !COMPILER(CLANG) return true; #endif } 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)); } static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesGetPropertyNames | JSArray::StructureFlags; private: RuntimeArray(ExecState* exec, Structure* structure) : JSArray(exec->vm(), structure, 0) { } static EncodedJSValue lengthGetter(ExecState* exec, JSObject*, 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, 0, CREATE_METHOD_TABLE(Element) }; const ClassInfo Masquerader::s_info = { "Masquerader", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(Masquerader) }; const ClassInfo Root::s_info = { "Root", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(Root) }; const ClassInfo ImpureGetter::s_info = { "ImpureGetter", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(ImpureGetter) }; const ClassInfo RuntimeArray::s_info = { "RuntimeArray", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(RuntimeArray) }; ElementHandleOwner* Element::handleOwner() { static ElementHandleOwner* owner = 0; if (!owner) owner = new ElementHandleOwner(); return owner; } void Element::finishCreation(VM& vm) { Base::finishCreation(vm); 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 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 functionDeleteAllCompiledCode(ExecState*); #ifndef NDEBUG static EncodedJSValue JSC_HOST_CALL functionReleaseExecutableMemory(ExecState*); 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 functionOptimizeNextInvocation(ExecState*); static EncodedJSValue JSC_HOST_CALL functionNumberOfDFGCompiles(ExecState*); static EncodedJSValue JSC_HOST_CALL functionReoptimizationRetryCount(ExecState*); static EncodedJSValue JSC_HOST_CALL functionTransferArrayBuffer(ExecState*); static NO_RETURN_WITH_VALUE EncodedJSValue JSC_HOST_CALL functionQuit(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 functionEffectful42(ExecState*); static EncodedJSValue JSC_HOST_CALL functionIdentity(ExecState*); static EncodedJSValue JSC_HOST_CALL functionMakeMasquerader(ExecState*); #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) : m_interactive(false) , m_dump(false) , m_exitCode(false) , m_profile(false) { parseArguments(argc, argv); } bool m_interactive; bool m_dump; bool m_exitCode; Vector