/*
* Copyright (C) 1999-2000 Harri Porten ([email protected])
* Copyright (C) 2004, 2005, 2006, 2007, 2008, 2012, 2013 Apple Inc. All rights reserved.
* Copyright (C) 2006 Bjoern Graf ([email protected])
*
* 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<:unknown> 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