if (!v)
return 0;
if (!v.isCell())
- return reinterpret_cast<JSValueRef>(asCell(JSC::jsAPIValueWrapper(exec, v)));
- return reinterpret_cast<JSValueRef>(asCell(v));
+ return reinterpret_cast<JSValueRef>(JSC::jsAPIValueWrapper(exec, v).asCell());
+ return reinterpret_cast<JSValueRef>(v.asCell());
#else
UNUSED_PARAM(exec);
return reinterpret_cast<JSValueRef>(JSC::JSValue::encode(v));
#define APIShims_h
#include "CallFrame.h"
+#include "GCActivityCallback.h"
#include "JSLock.h"
#include <wtf/WTFThreadData.h>
: m_globalData(globalData)
, m_entryIdentifierTable(wtfThreadData().setCurrentIdentifierTable(globalData->identifierTable))
{
+ UNUSED_PARAM(registerThread);
+#if ENABLE(JSC_MULTIPLE_THREADS)
if (registerThread)
- globalData->heap.registerThread();
+ globalData->heap.machineThreads().addCurrentThread();
+#endif
+ m_globalData->heap.activityCallback()->synchronize();
m_globalData->timeoutChecker.start();
}
~APICallbackShim()
{
+ m_globalData->heap.activityCallback()->synchronize();
wtfThreadData().setCurrentIdentifierTable(m_globalData->identifierTable);
}
typedef struct OpaqueJSValue* JSObjectRef;
/* JavaScript symbol exports */
+/* These rules should stay the same as in WebKit2/Shared/API/c/WKBase.h */
#undef JS_EXPORT
#if defined(JS_NO_EXPORT)
- #define JS_EXPORT
+#define JS_EXPORT
#elif defined(__GNUC__) && !defined(__CC_ARM) && !defined(__ARMCC__)
- #define JS_EXPORT __attribute__((visibility("default")))
-#elif defined(WIN32) || defined(_WIN32) || defined(_WIN32_WCE)
- #if defined(BUILDING_JavaScriptCore) || defined(BUILDING_WTF)
- #define JS_EXPORT __declspec(dllexport)
- #else
- #define JS_EXPORT __declspec(dllimport)
- #endif
+#define JS_EXPORT __attribute__((visibility("default")))
+#elif defined(WIN32) || defined(_WIN32) || defined(_WIN32_WCE) || defined(__CC_ARM) || defined(__ARMCC__)
+#if defined(BUILDING_JavaScriptCore) || defined(BUILDING_WTF)
+#define JS_EXPORT __declspec(dllexport)
#else
- #define JS_EXPORT
+#define JS_EXPORT __declspec(dllimport)
+#endif
+#else /* !defined(JS_NO_EXPORT) */
+#define JS_EXPORT
+#endif /* defined(JS_NO_EXPORT) */
+
+/* JS tests uses WTF but has no config.h, so we need to set the export defines here. */
+#ifndef WTF_EXPORT_PRIVATE
+#define WTF_EXPORT_PRIVATE JS_EXPORT
#endif
#ifdef __cplusplus
#include "APIShims.h"
#include "APICast.h"
+#include <runtime/Error.h>
#include <runtime/JSGlobalObject.h>
#include <runtime/JSLock.h>
#include <runtime/ObjectPrototype.h>
namespace JSC {
-const ClassInfo JSCallbackConstructor::info = { "CallbackConstructor", 0, 0, 0 };
+const ClassInfo JSCallbackConstructor::s_info = { "CallbackConstructor", &JSObjectWithGlobalObject::s_info, 0, 0 };
-JSCallbackConstructor::JSCallbackConstructor(NonNullPassRefPtr<Structure> structure, JSClassRef jsClass, JSObjectCallAsConstructorCallback callback)
- : JSObject(structure)
+JSCallbackConstructor::JSCallbackConstructor(JSGlobalObject* globalObject, Structure* structure, JSClassRef jsClass, JSObjectCallAsConstructorCallback callback)
+ : JSObjectWithGlobalObject(globalObject, structure)
, m_class(jsClass)
, m_callback(callback)
{
+ ASSERT(inherits(&s_info));
if (m_class)
JSClassRetain(jsClass);
}
JSClassRelease(m_class);
}
-static JSObject* constructJSCallback(ExecState* exec, JSObject* constructor, const ArgList& args)
+static EncodedJSValue JSC_HOST_CALL constructJSCallback(ExecState* exec)
{
+ JSObject* constructor = exec->callee();
JSContextRef ctx = toRef(exec);
JSObjectRef constructorRef = toRef(constructor);
JSObjectCallAsConstructorCallback callback = static_cast<JSCallbackConstructor*>(constructor)->callback();
if (callback) {
- int argumentCount = static_cast<int>(args.size());
+ int argumentCount = static_cast<int>(exec->argumentCount());
Vector<JSValueRef, 16> arguments(argumentCount);
for (int i = 0; i < argumentCount; i++)
- arguments[i] = toRef(exec, args.at(i));
+ arguments[i] = toRef(exec, exec->argument(i));
JSValueRef exception = 0;
JSObjectRef result;
result = callback(ctx, constructorRef, argumentCount, arguments.data(), &exception);
}
if (exception)
- exec->setException(toJS(exec, exception));
- return toJS(result);
+ throwError(exec, toJS(exec, exception));
+ return JSValue::encode(toJS(result));
}
- return toJS(JSObjectMake(ctx, static_cast<JSCallbackConstructor*>(constructor)->classRef(), 0));
+ return JSValue::encode(toJS(JSObjectMake(ctx, static_cast<JSCallbackConstructor*>(constructor)->classRef(), 0)));
}
ConstructType JSCallbackConstructor::getConstructData(ConstructData& constructData)
#define JSCallbackConstructor_h
#include "JSObjectRef.h"
-#include <runtime/JSObject.h>
+#include <runtime/JSObjectWithGlobalObject.h>
namespace JSC {
-class JSCallbackConstructor : public JSObject {
+class JSCallbackConstructor : public JSObjectWithGlobalObject {
public:
- JSCallbackConstructor(NonNullPassRefPtr<Structure>, JSClassRef, JSObjectCallAsConstructorCallback);
+ JSCallbackConstructor(JSGlobalObject*, Structure*, JSClassRef, JSObjectCallAsConstructorCallback);
virtual ~JSCallbackConstructor();
JSClassRef classRef() const { return m_class; }
JSObjectCallAsConstructorCallback callback() const { return m_callback; }
- static const ClassInfo info;
-
- static PassRefPtr<Structure> createStructure(JSValue proto)
- {
- return Structure::create(proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
+ static const ClassInfo s_info;
+
+ static Structure* createStructure(JSGlobalData& globalData, JSValue proto)
+ {
+ return Structure::create(globalData, proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
}
protected:
private:
virtual ConstructType getConstructData(ConstructData&);
- virtual const ClassInfo* classInfo() const { return &info; }
JSClassRef m_class;
JSObjectCallAsConstructorCallback m_callback;
#include "APIShims.h"
#include "APICast.h"
#include "CodeBlock.h"
+#include "ExceptionHelpers.h"
#include "JSFunction.h"
#include "FunctionPrototype.h"
#include <runtime/JSGlobalObject.h>
ASSERT_CLASS_FITS_IN_CELL(JSCallbackFunction);
-const ClassInfo JSCallbackFunction::info = { "CallbackFunction", &InternalFunction::info, 0, 0 };
+const ClassInfo JSCallbackFunction::s_info = { "CallbackFunction", &InternalFunction::s_info, 0, 0 };
-JSCallbackFunction::JSCallbackFunction(ExecState* exec, JSObjectCallAsFunctionCallback callback, const Identifier& name)
- : InternalFunction(&exec->globalData(), exec->lexicalGlobalObject()->callbackFunctionStructure(), name)
+JSCallbackFunction::JSCallbackFunction(ExecState* exec, JSGlobalObject* globalObject, JSObjectCallAsFunctionCallback callback, const Identifier& name)
+ : InternalFunction(&exec->globalData(), globalObject, globalObject->callbackFunctionStructure(), name)
, m_callback(callback)
{
+ ASSERT(inherits(&s_info));
}
-JSValue JSCallbackFunction::call(ExecState* exec, JSObject* functionObject, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSCallbackFunction::call(ExecState* exec)
{
JSContextRef execRef = toRef(exec);
- JSObjectRef functionRef = toRef(functionObject);
- JSObjectRef thisObjRef = toRef(thisValue.toThisObject(exec));
+ JSObjectRef functionRef = toRef(exec->callee());
+ JSObjectRef thisObjRef = toRef(exec->hostThisValue().toThisObject(exec));
- int argumentCount = static_cast<int>(args.size());
+ int argumentCount = static_cast<int>(exec->argumentCount());
Vector<JSValueRef, 16> arguments(argumentCount);
for (int i = 0; i < argumentCount; i++)
- arguments[i] = toRef(exec, args.at(i));
+ arguments[i] = toRef(exec, exec->argument(i));
JSValueRef exception = 0;
JSValueRef result;
{
APICallbackShim callbackShim(exec);
- result = static_cast<JSCallbackFunction*>(functionObject)->m_callback(execRef, functionRef, thisObjRef, argumentCount, arguments.data(), &exception);
+ result = static_cast<JSCallbackFunction*>(toJS(functionRef))->m_callback(execRef, functionRef, thisObjRef, argumentCount, arguments.data(), &exception);
}
if (exception)
- exec->setException(toJS(exec, exception));
+ throwError(exec, toJS(exec, exception));
- return toJS(exec, result);
+ return JSValue::encode(toJS(exec, result));
}
CallType JSCallbackFunction::getCallData(CallData& callData)
class JSCallbackFunction : public InternalFunction {
public:
- JSCallbackFunction(ExecState*, JSObjectCallAsFunctionCallback, const Identifier& name);
+ JSCallbackFunction(ExecState*, JSGlobalObject*, JSObjectCallAsFunctionCallback, const Identifier& name);
- static const ClassInfo info;
+ static const ClassInfo s_info;
// InternalFunction mish-mashes constructor and function behavior -- we should
// refactor the code so this override isn't necessary
- static PassRefPtr<Structure> createStructure(JSValue proto)
+ static Structure* createStructure(JSGlobalData& globalData, JSValue proto)
{
- return Structure::create(proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
+ return Structure::create(globalData, proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
}
private:
virtual CallType getCallData(CallData&);
- virtual const ClassInfo* classInfo() const { return &info; }
- static JSValue JSC_HOST_CALL call(ExecState*, JSObject*, JSValue, const ArgList&);
+ static EncodedJSValue JSC_HOST_CALL call(ExecState*);
JSObjectCallAsFunctionCallback m_callback;
};
#include "config.h"
#include "JSCallbackObject.h"
-#include "Collector.h"
+#include "Heap.h"
#include <wtf/text/StringHash.h>
namespace JSC {
-ASSERT_CLASS_FITS_IN_CELL(JSCallbackObject<JSObject>);
+ASSERT_CLASS_FITS_IN_CELL(JSCallbackObject<JSObjectWithGlobalObject>);
ASSERT_CLASS_FITS_IN_CELL(JSCallbackObject<JSGlobalObject>);
// Define the two types of JSCallbackObjects we support.
-template <> const ClassInfo JSCallbackObject<JSObject>::info = { "CallbackObject", 0, 0, 0 };
-template <> const ClassInfo JSCallbackObject<JSGlobalObject>::info = { "CallbackGlobalObject", 0, 0, 0 };
+template <> const ClassInfo JSCallbackObject<JSObjectWithGlobalObject>::s_info = { "CallbackObject", &JSObjectWithGlobalObject::s_info, 0, 0 };
+template <> const ClassInfo JSCallbackObject<JSGlobalObject>::s_info = { "CallbackGlobalObject", &JSGlobalObject::s_info, 0, 0 };
+void JSCallbackObjectData::finalize(Handle<Unknown> handle, void* context)
+{
+ JSClassRef jsClass = static_cast<JSClassRef>(context);
+ JSObjectRef thisRef = toRef(asObject(handle.get()));
+
+ for (; jsClass; jsClass = jsClass->parentClass)
+ if (JSObjectFinalizeCallback finalize = jsClass->finalize)
+ finalize(thisRef);
+ HandleSlot slot = handle.slot();
+ HandleHeap::heapFor(slot)->deallocate(slot);
+}
+
} // namespace JSC
/*
- * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2007, 2008, 2010 Apple Inc. All rights reserved.
* Copyright (C) 2007 Eric Seidel <eric@webkit.org>
*
* Redistribution and use in source and binary forms, with or without
#include "JSObjectRef.h"
#include "JSValueRef.h"
#include "JSObject.h"
+#include <wtf/PassOwnPtr.h>
namespace JSC {
-struct JSCallbackObjectData {
+struct JSCallbackObjectData : WeakHandleOwner {
JSCallbackObjectData(void* privateData, JSClassRef jsClass)
: privateData(privateData)
, jsClass(jsClass)
return m_privateProperties->getPrivateProperty(propertyName);
}
- void setPrivateProperty(const Identifier& propertyName, JSValue value)
+ void setPrivateProperty(JSGlobalData& globalData, JSCell* owner, const Identifier& propertyName, JSValue value)
{
if (!m_privateProperties)
- m_privateProperties.set(new JSPrivatePropertyMap);
- m_privateProperties->setPrivateProperty(propertyName, value);
+ m_privateProperties = adoptPtr(new JSPrivatePropertyMap);
+ m_privateProperties->setPrivateProperty(globalData, owner, propertyName, value);
}
void deletePrivateProperty(const Identifier& propertyName)
m_privateProperties->deletePrivateProperty(propertyName);
}
- void markChildren(MarkStack& markStack)
+ void visitChildren(SlotVisitor& visitor)
{
if (!m_privateProperties)
return;
- m_privateProperties->markChildren(markStack);
+ m_privateProperties->visitChildren(visitor);
}
void* privateData;
struct JSPrivatePropertyMap {
JSValue getPrivateProperty(const Identifier& propertyName) const
{
- PrivatePropertyMap::const_iterator location = m_propertyMap.find(propertyName.ustring().rep());
+ PrivatePropertyMap::const_iterator location = m_propertyMap.find(propertyName.impl());
if (location == m_propertyMap.end())
return JSValue();
- return location->second;
+ return location->second.get();
}
- void setPrivateProperty(const Identifier& propertyName, JSValue value)
+ void setPrivateProperty(JSGlobalData& globalData, JSCell* owner, const Identifier& propertyName, JSValue value)
{
- m_propertyMap.set(propertyName.ustring().rep(), value);
+ WriteBarrier<Unknown> empty;
+ m_propertyMap.add(propertyName.impl(), empty).first->second.set(globalData, owner, value);
}
void deletePrivateProperty(const Identifier& propertyName)
{
- m_propertyMap.remove(propertyName.ustring().rep());
+ m_propertyMap.remove(propertyName.impl());
}
- void markChildren(MarkStack& markStack)
+ void visitChildren(SlotVisitor& visitor)
{
for (PrivatePropertyMap::iterator ptr = m_propertyMap.begin(); ptr != m_propertyMap.end(); ++ptr) {
if (ptr->second)
- markStack.append(ptr->second);
+ visitor.append(&ptr->second);
}
}
private:
- typedef HashMap<RefPtr<UString::Rep>, JSValue, IdentifierRepHash> PrivatePropertyMap;
+ typedef HashMap<RefPtr<StringImpl>, WriteBarrier<Unknown>, IdentifierRepHash> PrivatePropertyMap;
PrivatePropertyMap m_propertyMap;
};
OwnPtr<JSPrivatePropertyMap> m_privateProperties;
+ virtual void finalize(Handle<Unknown>, void*);
};
template <class Base>
class JSCallbackObject : public Base {
public:
- JSCallbackObject(ExecState*, NonNullPassRefPtr<Structure>, JSClassRef, void* data);
- JSCallbackObject(JSClassRef);
- virtual ~JSCallbackObject();
+ JSCallbackObject(ExecState*, JSGlobalObject*, Structure*, JSClassRef, void* data);
+ JSCallbackObject(JSGlobalData&, JSClassRef, Structure*);
void setPrivate(void* data);
void* getPrivate();
- static const ClassInfo info;
+ static const ClassInfo s_info;
JSClassRef classRef() const { return m_callbackObjectData->jsClass; }
bool inherits(JSClassRef) const;
- static PassRefPtr<Structure> createStructure(JSValue proto)
+ static Structure* createStructure(JSGlobalData& globalData, JSValue proto)
{
- return Structure::create(proto, TypeInfo(ObjectType, StructureFlags), Base::AnonymousSlotCount);
+ return Structure::create(globalData, proto, TypeInfo(ObjectType, StructureFlags), Base::AnonymousSlotCount, &s_info);
}
JSValue getPrivateProperty(const Identifier& propertyName) const
return m_callbackObjectData->getPrivateProperty(propertyName);
}
- void setPrivateProperty(const Identifier& propertyName, JSValue value)
+ void setPrivateProperty(JSGlobalData& globalData, const Identifier& propertyName, JSValue value)
{
- m_callbackObjectData->setPrivateProperty(propertyName, value);
+ m_callbackObjectData->setPrivateProperty(globalData, this, propertyName, value);
}
void deletePrivateProperty(const Identifier& propertyName)
}
protected:
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | ImplementsHasInstance | OverridesHasInstance | OverridesMarkChildren | OverridesGetPropertyNames | Base::StructureFlags;
+ static const unsigned StructureFlags = ProhibitsPropertyCaching | OverridesGetOwnPropertySlot | ImplementsHasInstance | OverridesHasInstance | OverridesVisitChildren | OverridesGetPropertyNames | Base::StructureFlags;
private:
virtual UString className() const;
virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
- virtual bool getOwnPropertySlot(ExecState*, unsigned, PropertySlot&);
virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
virtual void put(ExecState*, const Identifier&, JSValue, PutPropertySlot&);
virtual ConstructType getConstructData(ConstructData&);
virtual CallType getCallData(CallData&);
- virtual const ClassInfo* classInfo() const { return &info; }
- virtual void markChildren(MarkStack& markStack)
+ virtual void visitChildren(SlotVisitor& visitor)
{
- Base::markChildren(markStack);
- m_callbackObjectData->markChildren(markStack);
+ Base::visitChildren(visitor);
+ m_callbackObjectData->visitChildren(visitor);
}
void init(ExecState*);
static JSCallbackObject* asCallbackObject(JSValue);
- static JSValue JSC_HOST_CALL call(ExecState*, JSObject* functionObject, JSValue thisValue, const ArgList&);
- static JSObject* construct(ExecState*, JSObject* constructor, const ArgList&);
+ static EncodedJSValue JSC_HOST_CALL call(ExecState*);
+ static EncodedJSValue JSC_HOST_CALL construct(ExecState*);
- static JSValue staticValueGetter(ExecState*, JSValue, const Identifier&);
+ JSValue getStaticValue(ExecState*, const Identifier&);
static JSValue staticFunctionGetter(ExecState*, JSValue, const Identifier&);
static JSValue callbackGetter(ExecState*, JSValue, const Identifier&);
#include "APIShims.h"
#include "APICast.h"
#include "Error.h"
+#include "ExceptionHelpers.h"
#include "JSCallbackFunction.h"
#include "JSClassRef.h"
+#include "JSFunction.h"
#include "JSGlobalObject.h"
#include "JSLock.h"
#include "JSObjectRef.h"
template <class Base>
inline JSCallbackObject<Base>* JSCallbackObject<Base>::asCallbackObject(JSValue value)
{
- ASSERT(asObject(value)->inherits(&info));
+ ASSERT(asObject(value)->inherits(&s_info));
return static_cast<JSCallbackObject*>(asObject(value));
}
template <class Base>
-JSCallbackObject<Base>::JSCallbackObject(ExecState* exec, NonNullPassRefPtr<Structure> structure, JSClassRef jsClass, void* data)
- : Base(structure)
- , m_callbackObjectData(new JSCallbackObjectData(data, jsClass))
+JSCallbackObject<Base>::JSCallbackObject(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, JSClassRef jsClass, void* data)
+ : Base(globalObject, structure)
+ , m_callbackObjectData(adoptPtr(new JSCallbackObjectData(data, jsClass)))
{
+ ASSERT(Base::inherits(&s_info));
init(exec);
}
// Global object constructor.
// FIXME: Move this into a separate JSGlobalCallbackObject class derived from this one.
template <class Base>
-JSCallbackObject<Base>::JSCallbackObject(JSClassRef jsClass)
- : Base()
- , m_callbackObjectData(new JSCallbackObjectData(0, jsClass))
+JSCallbackObject<Base>::JSCallbackObject(JSGlobalData& globalData, JSClassRef jsClass, Structure* structure)
+ : Base(globalData, structure)
+ , m_callbackObjectData(adoptPtr(new JSCallbackObjectData(0, jsClass)))
{
+ ASSERT(Base::inherits(&s_info));
ASSERT(Base::isGlobalObject());
init(static_cast<JSGlobalObject*>(this)->globalExec());
}
JSObjectInitializeCallback initialize = initRoutines[i];
initialize(toRef(exec), toRef(this));
}
-}
-template <class Base>
-JSCallbackObject<Base>::~JSCallbackObject()
-{
- JSObjectRef thisRef = toRef(this);
-
- for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass)
- if (JSObjectFinalizeCallback finalize = jsClass->finalize)
- finalize(thisRef);
+ bool needsFinalizer = false;
+ for (JSClassRef jsClassPtr = classRef(); jsClassPtr && !needsFinalizer; jsClassPtr = jsClassPtr->parentClass)
+ needsFinalizer = jsClassPtr->finalize;
+ if (needsFinalizer) {
+ HandleSlot slot = exec->globalData().allocateGlobalHandle();
+ HandleHeap::heapFor(slot)->makeWeak(slot, m_callbackObjectData.get(), classRef());
+ HandleHeap::heapFor(slot)->writeBarrier(slot, this);
+ *slot = this;
+ }
}
template <class Base>
value = getProperty(ctx, thisRef, propertyNameRef.get(), &exception);
}
if (exception) {
- exec->setException(toJS(exec, exception));
+ throwError(exec, toJS(exec, exception));
slot.setValue(jsUndefined());
return true;
}
}
if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) {
- if (staticValues->contains(propertyName.ustring().rep())) {
- slot.setCustom(this, staticValueGetter);
- return true;
+ if (staticValues->contains(propertyName.impl())) {
+ JSValue value = getStaticValue(exec, propertyName);
+ if (value) {
+ slot.setValue(value);
+ return true;
+ }
}
}
if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) {
- if (staticFunctions->contains(propertyName.ustring().rep())) {
+ if (staticFunctions->contains(propertyName.impl())) {
slot.setCustom(this, staticFunctionGetter);
return true;
}
return Base::getOwnPropertySlot(exec, propertyName, slot);
}
-template <class Base>
-bool JSCallbackObject<Base>::getOwnPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
-{
- return getOwnPropertySlot(exec, Identifier::from(exec, propertyName), slot);
-}
-
template <class Base>
bool JSCallbackObject<Base>::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
{
result = setProperty(ctx, thisRef, propertyNameRef.get(), valueRef, &exception);
}
if (exception)
- exec->setException(toJS(exec, exception));
+ throwError(exec, toJS(exec, exception));
if (result || exception)
return;
}
if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) {
- if (StaticValueEntry* entry = staticValues->get(propertyName.ustring().rep())) {
+ if (StaticValueEntry* entry = staticValues->get(propertyName.impl())) {
if (entry->attributes & kJSPropertyAttributeReadOnly)
return;
if (JSObjectSetPropertyCallback setProperty = entry->setProperty) {
result = setProperty(ctx, thisRef, propertyNameRef.get(), valueRef, &exception);
}
if (exception)
- exec->setException(toJS(exec, exception));
+ throwError(exec, toJS(exec, exception));
if (result || exception)
return;
- } else
- throwError(exec, ReferenceError, "Attempt to set a property that is not settable.");
+ }
}
}
if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) {
- if (StaticFunctionEntry* entry = staticFunctions->get(propertyName.ustring().rep())) {
+ if (StaticFunctionEntry* entry = staticFunctions->get(propertyName.impl())) {
if (entry->attributes & kJSPropertyAttributeReadOnly)
return;
- JSCallbackObject<Base>::putDirect(propertyName, value); // put as override property
+ JSCallbackObject<Base>::putDirect(exec->globalData(), propertyName, value); // put as override property
return;
}
}
result = deleteProperty(ctx, thisRef, propertyNameRef.get(), &exception);
}
if (exception)
- exec->setException(toJS(exec, exception));
+ throwError(exec, toJS(exec, exception));
if (result || exception)
return true;
}
if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) {
- if (StaticValueEntry* entry = staticValues->get(propertyName.ustring().rep())) {
+ if (StaticValueEntry* entry = staticValues->get(propertyName.impl())) {
if (entry->attributes & kJSPropertyAttributeDontDelete)
return false;
return true;
}
if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) {
- if (StaticFunctionEntry* entry = staticFunctions->get(propertyName.ustring().rep())) {
+ if (StaticFunctionEntry* entry = staticFunctions->get(propertyName.impl())) {
if (entry->attributes & kJSPropertyAttributeDontDelete)
return false;
return true;
}
template <class Base>
-JSObject* JSCallbackObject<Base>::construct(ExecState* exec, JSObject* constructor, const ArgList& args)
+EncodedJSValue JSCallbackObject<Base>::construct(ExecState* exec)
{
+ JSObject* constructor = exec->callee();
JSContextRef execRef = toRef(exec);
JSObjectRef constructorRef = toRef(constructor);
for (JSClassRef jsClass = static_cast<JSCallbackObject<Base>*>(constructor)->classRef(); jsClass; jsClass = jsClass->parentClass) {
if (JSObjectCallAsConstructorCallback callAsConstructor = jsClass->callAsConstructor) {
- int argumentCount = static_cast<int>(args.size());
+ int argumentCount = static_cast<int>(exec->argumentCount());
Vector<JSValueRef, 16> arguments(argumentCount);
for (int i = 0; i < argumentCount; i++)
- arguments[i] = toRef(exec, args.at(i));
+ arguments[i] = toRef(exec, exec->argument(i));
JSValueRef exception = 0;
JSObject* result;
{
result = toJS(callAsConstructor(execRef, constructorRef, argumentCount, arguments.data(), &exception));
}
if (exception)
- exec->setException(toJS(exec, exception));
- return result;
+ throwError(exec, toJS(exec, exception));
+ return JSValue::encode(result);
}
}
ASSERT_NOT_REACHED(); // getConstructData should prevent us from reaching here
- return 0;
+ return JSValue::encode(JSValue());
}
template <class Base>
result = hasInstance(execRef, thisRef, valueRef, &exception);
}
if (exception)
- exec->setException(toJS(exec, exception));
+ throwError(exec, toJS(exec, exception));
return result;
}
}
}
template <class Base>
-JSValue JSCallbackObject<Base>::call(ExecState* exec, JSObject* functionObject, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSCallbackObject<Base>::call(ExecState* exec)
{
JSContextRef execRef = toRef(exec);
- JSObjectRef functionRef = toRef(functionObject);
- JSObjectRef thisObjRef = toRef(thisValue.toThisObject(exec));
+ JSObjectRef functionRef = toRef(exec->callee());
+ JSObjectRef thisObjRef = toRef(exec->hostThisValue().toThisObject(exec));
- for (JSClassRef jsClass = static_cast<JSCallbackObject<Base>*>(functionObject)->classRef(); jsClass; jsClass = jsClass->parentClass) {
+ for (JSClassRef jsClass = static_cast<JSCallbackObject<Base>*>(toJS(functionRef))->classRef(); jsClass; jsClass = jsClass->parentClass) {
if (JSObjectCallAsFunctionCallback callAsFunction = jsClass->callAsFunction) {
- int argumentCount = static_cast<int>(args.size());
+ int argumentCount = static_cast<int>(exec->argumentCount());
Vector<JSValueRef, 16> arguments(argumentCount);
for (int i = 0; i < argumentCount; i++)
- arguments[i] = toRef(exec, args.at(i));
+ arguments[i] = toRef(exec, exec->argument(i));
JSValueRef exception = 0;
JSValue result;
{
result = toJS(exec, callAsFunction(execRef, functionRef, thisObjRef, argumentCount, arguments.data(), &exception));
}
if (exception)
- exec->setException(toJS(exec, exception));
- return result;
+ throwError(exec, toJS(exec, exception));
+ return JSValue::encode(result);
}
}
ASSERT_NOT_REACHED(); // getCallData should prevent us from reaching here
- return JSValue();
+ return JSValue::encode(JSValue());
}
template <class Base>
typedef OpaqueJSClassStaticValuesTable::const_iterator iterator;
iterator end = staticValues->end();
for (iterator it = staticValues->begin(); it != end; ++it) {
- UString::Rep* name = it->first.get();
+ StringImpl* name = it->first.get();
StaticValueEntry* entry = it->second;
if (entry->getProperty && (!(entry->attributes & kJSPropertyAttributeDontEnum) || (mode == IncludeDontEnumProperties)))
propertyNames.add(Identifier(exec, name));
typedef OpaqueJSClassStaticFunctionsTable::const_iterator iterator;
iterator end = staticFunctions->end();
for (iterator it = staticFunctions->begin(); it != end; ++it) {
- UString::Rep* name = it->first.get();
+ StringImpl* name = it->first.get();
StaticFunctionEntry* entry = it->second;
if (!(entry->attributes & kJSPropertyAttributeDontEnum) || (mode == IncludeDontEnumProperties))
propertyNames.add(Identifier(exec, name));
value = convertToType(ctx, thisRef, kJSTypeNumber, &exception);
}
if (exception) {
- exec->setException(toJS(exec, exception));
+ throwError(exec, toJS(exec, exception));
return 0;
}
value = convertToType(ctx, thisRef, kJSTypeString, &exception);
}
if (exception) {
- exec->setException(toJS(exec, exception));
+ throwError(exec, toJS(exec, exception));
return "";
}
if (value)
}
template <class Base>
-JSValue JSCallbackObject<Base>::staticValueGetter(ExecState* exec, JSValue slotBase, const Identifier& propertyName)
+JSValue JSCallbackObject<Base>::getStaticValue(ExecState* exec, const Identifier& propertyName)
{
- JSCallbackObject* thisObj = asCallbackObject(slotBase);
-
- JSObjectRef thisRef = toRef(thisObj);
+ JSObjectRef thisRef = toRef(this);
RefPtr<OpaqueJSString> propertyNameRef;
- for (JSClassRef jsClass = thisObj->classRef(); jsClass; jsClass = jsClass->parentClass)
+ for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass)
if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec))
- if (StaticValueEntry* entry = staticValues->get(propertyName.ustring().rep()))
+ if (StaticValueEntry* entry = staticValues->get(propertyName.impl()))
if (JSObjectGetPropertyCallback getProperty = entry->getProperty) {
if (!propertyNameRef)
propertyNameRef = OpaqueJSString::create(propertyName.ustring());
value = getProperty(toRef(exec), thisRef, propertyNameRef.get(), &exception);
}
if (exception) {
- exec->setException(toJS(exec, exception));
+ throwError(exec, toJS(exec, exception));
return jsUndefined();
}
if (value)
return toJS(exec, value);
}
- return throwError(exec, ReferenceError, "Static value property defined with NULL getProperty callback.");
+ return JSValue();
}
template <class Base>
for (JSClassRef jsClass = thisObj->classRef(); jsClass; jsClass = jsClass->parentClass) {
if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) {
- if (StaticFunctionEntry* entry = staticFunctions->get(propertyName.ustring().rep())) {
+ if (StaticFunctionEntry* entry = staticFunctions->get(propertyName.impl())) {
if (JSObjectCallAsFunctionCallback callAsFunction = entry->callAsFunction) {
- JSObject* o = new (exec) JSCallbackFunction(exec, callAsFunction, propertyName);
- thisObj->putDirect(propertyName, o, entry->attributes);
+
+ JSObject* o = new (exec) JSCallbackFunction(exec, asGlobalObject(thisObj->getAnonymousValue(0)), callAsFunction, propertyName);
+ thisObj->putDirect(exec->globalData(), propertyName, o, entry->attributes);
return o;
}
}
}
}
- return throwError(exec, ReferenceError, "Static function property defined with NULL callAsFunction callback.");
+ return throwError(exec, createReferenceError(exec, "Static function property defined with NULL callAsFunction callback."));
}
template <class Base>
value = getProperty(toRef(exec), thisRef, propertyNameRef.get(), &exception);
}
if (exception) {
- exec->setException(toJS(exec, exception));
+ throwError(exec, toJS(exec, exception));
return jsUndefined();
}
if (value)
return toJS(exec, value);
}
- return throwError(exec, ReferenceError, "hasProperty callback returned true for a property that doesn't exist.");
+ return throwError(exec, createReferenceError(exec, "hasProperty callback returned true for a property that doesn't exist."));
}
} // namespace JSC
static inline UString tryCreateStringFromUTF8(const char* string)
{
if (!string)
- return UString::null();
+ return UString();
size_t length = strlen(string);
Vector<UChar, 1024> buffer(length);
UChar* p = buffer.data();
if (conversionOK != convertUTF8ToUTF16(&string, string + length, &p, p + length))
- return UString::null();
+ return UString();
return UString(buffer.data(), p - buffer.data());
}
if (!valueName.isNull()) {
// Use a local variable here to sidestep an RVCT compiler bug.
StaticValueEntry* entry = new StaticValueEntry(staticValue->getProperty, staticValue->setProperty, staticValue->attributes);
- UStringImpl* impl = valueName.rep();
- impl->ref();
- m_staticValues->add(impl, entry);
+ StringImpl* impl = valueName.impl();
+ StaticValueEntry* existingEntry = m_staticValues->get(impl);
+ m_staticValues->set(impl, entry);
+ delete existingEntry;
}
++staticValue;
}
if (!functionName.isNull()) {
// Use a local variable here to sidestep an RVCT compiler bug.
StaticFunctionEntry* entry = new StaticFunctionEntry(staticFunction->callAsFunction, staticFunction->attributes);
- UStringImpl* impl = functionName.rep();
- impl->ref();
- m_staticFunctions->add(impl, entry);
+ StringImpl* impl = functionName.impl();
+ StaticFunctionEntry* existingEntry = m_staticFunctions->get(impl);
+ m_staticFunctions->set(impl, entry);
+ delete existingEntry;
}
++staticFunction;
}
OpaqueJSClass::~OpaqueJSClass()
{
// The empty string is shared across threads & is an identifier, in all other cases we should have done a deep copy in className(), below.
- ASSERT(!m_className.size() || !m_className.rep()->isIdentifier());
+ ASSERT(!m_className.length() || !m_className.impl()->isIdentifier());
if (m_staticValues) {
OpaqueJSClassStaticValuesTable::const_iterator end = m_staticValues->end();
return adoptRef(new OpaqueJSClass(definition, 0));
}
-static void clearReferenceToPrototype(JSObjectRef prototype)
-{
- OpaqueJSClassContextData* jsClassData = static_cast<OpaqueJSClassContextData*>(JSObjectGetPrivate(prototype));
- ASSERT(jsClassData);
- jsClassData->cachedPrototype.clear(toJS(prototype));
-}
-
PassRefPtr<OpaqueJSClass> OpaqueJSClass::create(const JSClassDefinition* clientDefinition)
{
JSClassDefinition definition = *clientDefinition; // Avoid modifying client copy.
JSClassDefinition protoDefinition = kJSClassDefinitionEmpty;
- protoDefinition.finalize = clearReferenceToPrototype;
+ protoDefinition.finalize = 0;
swap(definition.staticFunctions, protoDefinition.staticFunctions); // Move static functions to the prototype.
// We are supposed to use JSClassRetain/Release but since we know that we currently have
return adoptRef(new OpaqueJSClass(&definition, protoClass.get()));
}
-OpaqueJSClassContextData::OpaqueJSClassContextData(OpaqueJSClass* jsClass)
+OpaqueJSClassContextData::OpaqueJSClassContextData(JSC::JSGlobalData&, OpaqueJSClass* jsClass)
: m_class(jsClass)
{
if (jsClass->m_staticValues) {
ASSERT(!it->first->isIdentifier());
// Use a local variable here to sidestep an RVCT compiler bug.
StaticValueEntry* entry = new StaticValueEntry(it->second->getProperty, it->second->setProperty, it->second->attributes);
- staticValues->add(UString::Rep::create(it->first->characters(), it->first->length()), entry);
+ staticValues->add(StringImpl::create(it->first->characters(), it->first->length()), entry);
}
} else
staticValues = 0;
ASSERT(!it->first->isIdentifier());
// Use a local variable here to sidestep an RVCT compiler bug.
StaticFunctionEntry* entry = new StaticFunctionEntry(it->second->callAsFunction, it->second->attributes);
- staticFunctions->add(UString::Rep::create(it->first->characters(), it->first->length()), entry);
+ staticFunctions->add(StringImpl::create(it->first->characters(), it->first->length()), entry);
}
} else
{
OpaqueJSClassContextData*& contextData = exec->globalData().opaqueJSClassData.add(this, 0).first->second;
if (!contextData)
- contextData = new OpaqueJSClassContextData(this);
+ contextData = new OpaqueJSClassContextData(exec->globalData(), this);
return *contextData;
}
UString OpaqueJSClass::className()
{
// Make a deep copy, so that the caller has no chance to put the original into IdentifierTable.
- return UString(m_className.data(), m_className.size());
+ return UString(m_className.characters(), m_className.length());
}
OpaqueJSClassStaticValuesTable* OpaqueJSClass::staticValues(JSC::ExecState* exec)
if (!jsClassData.cachedPrototype) {
// Recursive, but should be good enough for our purposes
- jsClassData.cachedPrototype = new (exec) JSCallbackObject<JSObject>(exec, exec->lexicalGlobalObject()->callbackObjectStructure(), prototypeClass, &jsClassData); // set jsClassData as the object's private data, so it can clear our reference on destruction
+ jsClassData.cachedPrototype.set(exec->globalData(), new (exec) JSCallbackObject<JSObjectWithGlobalObject>(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->callbackObjectStructure(), prototypeClass, &jsClassData), 0); // set jsClassData as the object's private data, so it can clear our reference on destruction
if (parentClass) {
if (JSObject* prototype = parentClass->prototype(exec))
- jsClassData.cachedPrototype->setPrototype(prototype);
+ jsClassData.cachedPrototype->setPrototype(exec->globalData(), prototype);
}
}
return jsClassData.cachedPrototype.get();
#include "JSObjectRef.h"
-#include <runtime/JSObject.h>
-#include <runtime/Protect.h>
-#include <runtime/UString.h>
-#include <runtime/WeakGCPtr.h>
+#include "Weak.h"
+#include "JSObject.h"
+#include "Protect.h"
+#include "UString.h"
#include <wtf/HashMap.h>
-#include <wtf/RefCounted.h>
-struct StaticValueEntry : FastAllocBase {
+struct StaticValueEntry {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
StaticValueEntry(JSObjectGetPropertyCallback _getProperty, JSObjectSetPropertyCallback _setProperty, JSPropertyAttributes _attributes)
: getProperty(_getProperty), setProperty(_setProperty), attributes(_attributes)
{
JSPropertyAttributes attributes;
};
-struct StaticFunctionEntry : FastAllocBase {
+struct StaticFunctionEntry {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
StaticFunctionEntry(JSObjectCallAsFunctionCallback _callAsFunction, JSPropertyAttributes _attributes)
: callAsFunction(_callAsFunction), attributes(_attributes)
{
JSPropertyAttributes attributes;
};
-typedef HashMap<RefPtr<JSC::UString::Rep>, StaticValueEntry*> OpaqueJSClassStaticValuesTable;
-typedef HashMap<RefPtr<JSC::UString::Rep>, StaticFunctionEntry*> OpaqueJSClassStaticFunctionsTable;
+typedef HashMap<RefPtr<StringImpl>, StaticValueEntry*> OpaqueJSClassStaticValuesTable;
+typedef HashMap<RefPtr<StringImpl>, StaticFunctionEntry*> OpaqueJSClassStaticFunctionsTable;
struct OpaqueJSClass;
// An OpaqueJSClass (JSClass) is created without a context, so it can be used with any context, even across context groups.
// This structure holds data members that vary across context groups.
-struct OpaqueJSClassContextData : Noncopyable {
- OpaqueJSClassContextData(OpaqueJSClass*);
+struct OpaqueJSClassContextData {
+ WTF_MAKE_NONCOPYABLE(OpaqueJSClassContextData); WTF_MAKE_FAST_ALLOCATED;
+public:
+ OpaqueJSClassContextData(JSC::JSGlobalData&, OpaqueJSClass*);
~OpaqueJSClassContextData();
// It is necessary to keep OpaqueJSClass alive because of the following rare scenario:
OpaqueJSClassStaticValuesTable* staticValues;
OpaqueJSClassStaticFunctionsTable* staticFunctions;
- JSC::WeakGCPtr<JSC::JSObject> cachedPrototype;
+ JSC::Weak<JSC::JSObject> cachedPrototype;
};
-struct OpaqueJSClass : public ThreadSafeShared<OpaqueJSClass> {
+struct OpaqueJSClass : public ThreadSafeRefCounted<OpaqueJSClass> {
static PassRefPtr<OpaqueJSClass> create(const JSClassDefinition*);
static PassRefPtr<OpaqueJSClass> createNoAutomaticPrototype(const JSClassDefinition*);
~OpaqueJSClass();
#include "APICast.h"
#include "InitializeThreading.h"
+#include <interpreter/CallFrame.h>
+#include <interpreter/Interpreter.h>
#include "JSCallbackObject.h"
#include "JSClassRef.h"
#include "JSGlobalObject.h"
#include "JSObject.h"
+#include "UStringBuilder.h"
#include <wtf/text/StringHash.h>
+
#if OS(DARWIN)
#include <mach-o/dyld.h>
JSContextGroupRef JSContextGroupCreate()
{
initializeThreading();
- return toRef(JSGlobalData::createContextGroup(ThreadStackTypeSmall).releaseRef());
+ return toRef(JSGlobalData::createContextGroup(ThreadStackTypeSmall).leakRef());
}
JSContextGroupRef JSContextGroupRetain(JSContextGroupRef group)
#if OS(DARWIN)
// When running on Tiger or Leopard, or if the application was linked before JSGlobalContextCreate was changed
// to use a unique JSGlobalData, we use a shared one for compatibility.
-#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+#ifndef BUILDING_ON_LEOPARD
if (NSVersionOfLinkTimeLibrary("JavaScriptCore") <= webkitFirstVersionWithConcurrentGlobalContexts) {
#else
{
#endif
if (!globalObjectClass) {
- JSGlobalObject* globalObject = new (globalData.get()) JSGlobalObject;
+ JSGlobalObject* globalObject = new (globalData.get()) JSGlobalObject(*globalData, JSGlobalObject::createStructure(*globalData, jsNull()));
return JSGlobalContextRetain(toGlobalRef(globalObject->globalExec()));
}
- JSGlobalObject* globalObject = new (globalData.get()) JSCallbackObject<JSGlobalObject>(globalObjectClass);
+ JSGlobalObject* globalObject = new (globalData.get()) JSCallbackObject<JSGlobalObject>(*globalData, globalObjectClass, JSCallbackObject<JSGlobalObject>::createStructure(*globalData, jsNull()));
ExecState* exec = globalObject->globalExec();
JSValue prototype = globalObjectClass->prototype(exec);
if (!prototype)
prototype = jsNull();
- globalObject->resetPrototype(prototype);
+ globalObject->resetPrototype(*globalData, prototype);
return JSGlobalContextRetain(toGlobalRef(exec));
}
// * If this is the last reference to any contexts in the given context group,
// call destroy on the heap (the global data is being freed).
// * If this was the last reference to the global object, then unprotecting
- // it may release a lot of GC memory - run the garbage collector now.
+ // it may release a lot of GC memory - tickle the activity callback to
+ // garbage collect soon.
// * If there are more references remaining the the global object, then do nothing
// (specifically that is more protects, which we assume come from other JSGlobalContextRefs).
- if (releasingContextGroup)
+ if (releasingContextGroup) {
+ globalData.clearBuiltinStructures();
globalData.heap.destroy();
- else if (releasingGlobalObject)
- globalData.heap.collectAllGarbage();
+ } else if (releasingGlobalObject) {
+ globalData.heap.activityCallback()->synchronize();
+ (*globalData.heap.activityCallback())();
+ }
globalData.deref();
return toGlobalRef(exec->lexicalGlobalObject()->globalExec());
}
+
+JSStringRef JSContextCreateBacktrace(JSContextRef ctx, unsigned maxStackSize)
+{
+ ExecState* exec = toJS(ctx);
+ JSLock lock(exec);
+
+ unsigned count = 0;
+ UStringBuilder builder;
+ CallFrame* callFrame = exec;
+ UString functionName;
+ if (exec->callee()) {
+ if (asObject(exec->callee())->inherits(&InternalFunction::s_info)) {
+ functionName = asInternalFunction(exec->callee())->name(exec);
+ builder.append("#0 ");
+ builder.append(functionName);
+ builder.append("() ");
+ count++;
+ }
+ }
+ while (true) {
+ ASSERT(callFrame);
+ int signedLineNumber;
+ intptr_t sourceID;
+ UString urlString;
+ JSValue function;
+
+ UString levelStr = UString::number(count);
+
+ exec->interpreter()->retrieveLastCaller(callFrame, signedLineNumber, sourceID, urlString, function);
+
+ if (function)
+ functionName = asFunction(function)->name(exec);
+ else {
+ // Caller is unknown, but if frame is empty we should still add the frame, because
+ // something called us, and gave us arguments.
+ if (count)
+ break;
+ }
+ unsigned lineNumber = signedLineNumber >= 0 ? signedLineNumber : 0;
+ if (!builder.isEmpty())
+ builder.append("\n");
+ builder.append("#");
+ builder.append(levelStr);
+ builder.append(" ");
+ builder.append(functionName);
+ builder.append("() at ");
+ builder.append(urlString);
+ builder.append(":");
+ builder.append(UString::number(lineNumber));
+ if (!function || ++count == maxStackSize)
+ break;
+ callFrame = callFrame->callerFrame();
+ }
+ return OpaqueJSString::create(builder.toUString()).leakRef();
+}
+
+
*/
JS_EXPORT JSGlobalContextRef JSContextGetGlobalContext(JSContextRef ctx);
+
+/*!
+@function
+@abstract Gets a Backtrace for the existing context
+@param ctx The JSContext whose backtrace you want to get
+@result A string containing the backtrace
+*/
+JS_EXPORT JSStringRef JSContextCreateBacktrace(JSContextRef ctx, unsigned maxStackSize) AVAILABLE_IN_WEBKIT_VERSION_4_0;
+
#ifdef __cplusplus
}
#endif
? OpaqueJSClass::createNoAutomaticPrototype(definition)
: OpaqueJSClass::create(definition);
- return jsClass.release().releaseRef();
+ return jsClass.release().leakRef();
}
JSClassRef JSClassRetain(JSClassRef jsClass)
APIEntryShim entryShim(exec);
if (!jsClass)
- return toRef(new (exec) JSObject(exec->lexicalGlobalObject()->emptyObjectStructure())); // slightly more efficient
+ return toRef(constructEmptyObject(exec));
- JSCallbackObject<JSObject>* object = new (exec) JSCallbackObject<JSObject>(exec, exec->lexicalGlobalObject()->callbackObjectStructure(), jsClass, data);
+ JSCallbackObject<JSObjectWithGlobalObject>* object = new (exec) JSCallbackObject<JSObjectWithGlobalObject>(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->callbackObjectStructure(), jsClass, data);
if (JSObject* prototype = jsClass->prototype(exec))
- object->setPrototype(prototype);
+ object->setPrototype(exec->globalData(), prototype);
return toRef(object);
}
Identifier nameID = name ? name->identifier(&exec->globalData()) : Identifier(exec, "anonymous");
- return toRef(new (exec) JSCallbackFunction(exec, callAsFunction, nameID));
+ return toRef(new (exec) JSCallbackFunction(exec, exec->lexicalGlobalObject(), callAsFunction, nameID));
}
JSObjectRef JSObjectMakeConstructor(JSContextRef ctx, JSClassRef jsClass, JSObjectCallAsConstructorCallback callAsConstructor)
if (!jsPrototype)
jsPrototype = exec->lexicalGlobalObject()->objectPrototype();
- JSCallbackConstructor* constructor = new (exec) JSCallbackConstructor(exec->lexicalGlobalObject()->callbackConstructorStructure(), jsClass, callAsConstructor);
- constructor->putDirect(exec->propertyNames().prototype, jsPrototype, DontEnum | DontDelete | ReadOnly);
+ JSCallbackConstructor* constructor = new (exec) JSCallbackConstructor(exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->callbackConstructorStructure(), jsClass, callAsConstructor);
+ constructor->putDirect(exec->globalData(), exec->propertyNames().prototype, jsPrototype, DontEnum | DontDelete | ReadOnly);
return toRef(constructor);
}
args.append(jsString(exec, parameterNames[i]->ustring()));
args.append(jsString(exec, body->ustring()));
- JSObject* result = constructFunction(exec, args, nameID, sourceURL->ustring(), startingLineNumber);
+ JSObject* result = constructFunction(exec, exec->lexicalGlobalObject(), args, nameID, sourceURL->ustring(), startingLineNumber);
if (exec->hadException()) {
if (exception)
*exception = toRef(exec, exec->exception());
for (size_t i = 0; i < argumentCount; ++i)
argList.append(toJS(exec, arguments[i]));
- JSObject* result = constructDate(exec, argList);
+ JSObject* result = constructDate(exec, exec->lexicalGlobalObject(), argList);
if (exec->hadException()) {
if (exception)
*exception = toRef(exec, exec->exception());
ExecState* exec = toJS(ctx);
APIEntryShim entryShim(exec);
- MarkedArgumentBuffer argList;
- for (size_t i = 0; i < argumentCount; ++i)
- argList.append(toJS(exec, arguments[i]));
+ JSValue message = argumentCount ? toJS(exec, arguments[0]) : jsUndefined();
+ Structure* errorStructure = exec->lexicalGlobalObject()->errorStructure();
+ JSObject* result = ErrorInstance::create(exec, errorStructure, message);
- JSObject* result = constructError(exec, argList);
if (exec->hadException()) {
if (exception)
*exception = toRef(exec, exec->exception());
for (size_t i = 0; i < argumentCount; ++i)
argList.append(toJS(exec, arguments[i]));
- JSObject* result = constructRegExp(exec, argList);
+ JSObject* result = constructRegExp(exec, exec->lexicalGlobalObject(), argList);
if (exec->hadException()) {
if (exception)
*exception = toRef(exec, exec->exception());
JSObject* jsObject = toJS(object);
JSValue jsValue = toJS(exec, value);
- jsObject->setPrototype(jsValue.isObject() ? jsValue : jsNull());
+ jsObject->setPrototypeWithCycleCheck(exec->globalData(), jsValue.isObject() ? jsValue : jsNull());
}
bool JSObjectHasProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName)
{
JSObject* jsObject = toJS(object);
- if (jsObject->inherits(&JSCallbackObject<JSGlobalObject>::info))
+ if (jsObject->inherits(&JSCallbackObject<JSGlobalObject>::s_info))
return static_cast<JSCallbackObject<JSGlobalObject>*>(jsObject)->getPrivate();
- else if (jsObject->inherits(&JSCallbackObject<JSObject>::info))
- return static_cast<JSCallbackObject<JSObject>*>(jsObject)->getPrivate();
+ if (jsObject->inherits(&JSCallbackObject<JSObjectWithGlobalObject>::s_info))
+ return static_cast<JSCallbackObject<JSObjectWithGlobalObject>*>(jsObject)->getPrivate();
return 0;
}
{
JSObject* jsObject = toJS(object);
- if (jsObject->inherits(&JSCallbackObject<JSGlobalObject>::info)) {
+ if (jsObject->inherits(&JSCallbackObject<JSGlobalObject>::s_info)) {
static_cast<JSCallbackObject<JSGlobalObject>*>(jsObject)->setPrivate(data);
return true;
- } else if (jsObject->inherits(&JSCallbackObject<JSObject>::info)) {
- static_cast<JSCallbackObject<JSObject>*>(jsObject)->setPrivate(data);
+ }
+ if (jsObject->inherits(&JSCallbackObject<JSObjectWithGlobalObject>::s_info)) {
+ static_cast<JSCallbackObject<JSObjectWithGlobalObject>*>(jsObject)->setPrivate(data);
return true;
}
JSObject* jsObject = toJS(object);
JSValue result;
Identifier name(propertyName->identifier(&exec->globalData()));
- if (jsObject->inherits(&JSCallbackObject<JSGlobalObject>::info))
+ if (jsObject->inherits(&JSCallbackObject<JSGlobalObject>::s_info))
result = static_cast<JSCallbackObject<JSGlobalObject>*>(jsObject)->getPrivateProperty(name);
- else if (jsObject->inherits(&JSCallbackObject<JSObject>::info))
- result = static_cast<JSCallbackObject<JSObject>*>(jsObject)->getPrivateProperty(name);
+ else if (jsObject->inherits(&JSCallbackObject<JSObjectWithGlobalObject>::s_info))
+ result = static_cast<JSCallbackObject<JSObjectWithGlobalObject>*>(jsObject)->getPrivateProperty(name);
return toRef(exec, result);
}
ExecState* exec = toJS(ctx);
APIEntryShim entryShim(exec);
JSObject* jsObject = toJS(object);
- JSValue jsValue = toJS(exec, value);
+ JSValue jsValue = value ? toJS(exec, value) : JSValue();
Identifier name(propertyName->identifier(&exec->globalData()));
- if (jsObject->inherits(&JSCallbackObject<JSGlobalObject>::info)) {
- static_cast<JSCallbackObject<JSGlobalObject>*>(jsObject)->setPrivateProperty(name, jsValue);
+ if (jsObject->inherits(&JSCallbackObject<JSGlobalObject>::s_info)) {
+ static_cast<JSCallbackObject<JSGlobalObject>*>(jsObject)->setPrivateProperty(exec->globalData(), name, jsValue);
return true;
}
- if (jsObject->inherits(&JSCallbackObject<JSObject>::info)) {
- static_cast<JSCallbackObject<JSObject>*>(jsObject)->setPrivateProperty(name, jsValue);
+ if (jsObject->inherits(&JSCallbackObject<JSObjectWithGlobalObject>::s_info)) {
+ static_cast<JSCallbackObject<JSObjectWithGlobalObject>*>(jsObject)->setPrivateProperty(exec->globalData(), name, jsValue);
return true;
}
return false;
APIEntryShim entryShim(exec);
JSObject* jsObject = toJS(object);
Identifier name(propertyName->identifier(&exec->globalData()));
- if (jsObject->inherits(&JSCallbackObject<JSGlobalObject>::info)) {
+ if (jsObject->inherits(&JSCallbackObject<JSGlobalObject>::s_info)) {
static_cast<JSCallbackObject<JSGlobalObject>*>(jsObject)->deletePrivateProperty(name);
return true;
}
- if (jsObject->inherits(&JSCallbackObject<JSObject>::info)) {
- static_cast<JSCallbackObject<JSObject>*>(jsObject)->deletePrivateProperty(name);
+ if (jsObject->inherits(&JSCallbackObject<JSObjectWithGlobalObject>::s_info)) {
+ static_cast<JSCallbackObject<JSObjectWithGlobalObject>*>(jsObject)->deletePrivateProperty(name);
return true;
}
return false;
return result;
}
-struct OpaqueJSPropertyNameArray : FastAllocBase {
+struct OpaqueJSPropertyNameArray {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
OpaqueJSPropertyNameArray(JSGlobalData* globalData)
: refCount(0)
, globalData(globalData)
size_t size = array.size();
propertyNames->array.reserveInitialCapacity(size);
for (size_t i = 0; i < size; ++i)
- propertyNames->array.append(JSRetainPtr<JSStringRef>(Adopt, OpaqueJSString::create(array[i].ustring()).releaseRef()));
+ propertyNames->array.append(JSRetainPtr<JSStringRef>(Adopt, OpaqueJSString::create(array[i].ustring()).leakRef()));
return JSPropertyNameArrayRetain(propertyNames);
}
/*
- * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2005, 2006, 2007, 2010 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
#ifndef JSRetainPtr_h
#define JSRetainPtr_h
+#include <JavaScriptCore/JSContextRef.h>
#include <JavaScriptCore/JSStringRef.h>
#include <algorithm>
inline void JSRetain(JSStringRef string) { JSStringRetain(string); }
inline void JSRelease(JSStringRef string) { JSStringRelease(string); }
+inline void JSRetain(JSGlobalContextRef context) { JSGlobalContextRetain(context); }
+inline void JSRelease(JSGlobalContextRef context) { JSGlobalContextRelease(context); }
enum AdoptTag { Adopt };
-template <typename T> class JSRetainPtr {
+template<typename T> class JSRetainPtr {
public:
- JSRetainPtr() : m_ptr(0) {}
+ JSRetainPtr() : m_ptr(0) { }
JSRetainPtr(T ptr) : m_ptr(ptr) { if (ptr) JSRetain(ptr); }
-
JSRetainPtr(AdoptTag, T ptr) : m_ptr(ptr) { }
-
- JSRetainPtr(const JSRetainPtr& o) : m_ptr(o.m_ptr) { if (T ptr = m_ptr) JSRetain(ptr); }
-
- ~JSRetainPtr() { if (T ptr = m_ptr) JSRelease(ptr); }
-
- template <typename U> JSRetainPtr(const JSRetainPtr<U>& o) : m_ptr(o.get()) { if (T ptr = m_ptr) JSRetain(ptr); }
+ JSRetainPtr(const JSRetainPtr&);
+ template<typename U> JSRetainPtr(const JSRetainPtr<U>&);
+ ~JSRetainPtr();
T get() const { return m_ptr; }
- T releaseRef() { T tmp = m_ptr; m_ptr = 0; return tmp; }
-
+ void clear();
+ T leakRef();
+
T operator->() const { return m_ptr; }
bool operator!() const { return !m_ptr; }
operator UnspecifiedBoolType() const { return m_ptr ? &JSRetainPtr::m_ptr : 0; }
JSRetainPtr& operator=(const JSRetainPtr&);
- template <typename U> JSRetainPtr& operator=(const JSRetainPtr<U>&);
+ template<typename U> JSRetainPtr& operator=(const JSRetainPtr<U>&);
JSRetainPtr& operator=(T);
- template <typename U> JSRetainPtr& operator=(U*);
+ template<typename U> JSRetainPtr& operator=(U*);
void adopt(T);
void swap(JSRetainPtr&);
+ // FIXME: Remove releaseRef once we change all callers to call leakRef instead.
+ T releaseRef() { return leakRef(); }
+
private:
T m_ptr;
};
-template <typename T> inline JSRetainPtr<T>& JSRetainPtr<T>::operator=(const JSRetainPtr<T>& o)
+template<typename T> inline JSRetainPtr<T>::JSRetainPtr(const JSRetainPtr& o)
+ : m_ptr(o.m_ptr)
+{
+ if (m_ptr)
+ JSRetain(m_ptr);
+}
+
+template<typename T> template<typename U> inline JSRetainPtr<T>::JSRetainPtr(const JSRetainPtr<U>& o)
+ : m_ptr(o.get())
+{
+ if (m_ptr)
+ JSRetain(m_ptr);
+}
+
+template<typename T> inline JSRetainPtr<T>::~JSRetainPtr()
+{
+ if (m_ptr)
+ JSRelease(m_ptr);
+}
+
+template<typename T> inline void JSRetainPtr<T>::clear()
+{
+ if (T ptr = m_ptr) {
+ m_ptr = 0;
+ JSRelease(ptr);
+ }
+}
+
+template<typename T> inline T JSRetainPtr<T>::leakRef()
+{
+ T ptr = m_ptr;
+ m_ptr = 0;
+ return ptr;
+}
+
+template<typename T> inline JSRetainPtr<T>& JSRetainPtr<T>::operator=(const JSRetainPtr<T>& o)
{
T optr = o.get();
if (optr)
return *this;
}
-template <typename T> template <typename U> inline JSRetainPtr<T>& JSRetainPtr<T>::operator=(const JSRetainPtr<U>& o)
+template<typename T> template<typename U> inline JSRetainPtr<T>& JSRetainPtr<T>::operator=(const JSRetainPtr<U>& o)
{
T optr = o.get();
if (optr)
return *this;
}
-template <typename T> inline JSRetainPtr<T>& JSRetainPtr<T>::operator=(T optr)
+template<typename T> inline JSRetainPtr<T>& JSRetainPtr<T>::operator=(T optr)
{
if (optr)
JSRetain(optr);
return *this;
}
-template <typename T> inline void JSRetainPtr<T>::adopt(T optr)
+template<typename T> inline void JSRetainPtr<T>::adopt(T optr)
{
T ptr = m_ptr;
m_ptr = optr;
JSRelease(ptr);
}
-template <typename T> template <typename U> inline JSRetainPtr<T>& JSRetainPtr<T>::operator=(U* optr)
+template<typename T> template<typename U> inline JSRetainPtr<T>& JSRetainPtr<T>::operator=(U* optr)
{
if (optr)
JSRetain(optr);
return *this;
}
-template <class T> inline void JSRetainPtr<T>::swap(JSRetainPtr<T>& o)
+template<typename T> inline void JSRetainPtr<T>::swap(JSRetainPtr<T>& o)
{
std::swap(m_ptr, o.m_ptr);
}
-template <class T> inline void swap(JSRetainPtr<T>& a, JSRetainPtr<T>& b)
+template<typename T> inline void swap(JSRetainPtr<T>& a, JSRetainPtr<T>& b)
{
a.swap(b);
}
-template <typename T, typename U> inline bool operator==(const JSRetainPtr<T>& a, const JSRetainPtr<U>& b)
+template<typename T, typename U> inline bool operator==(const JSRetainPtr<T>& a, const JSRetainPtr<U>& b)
{
return a.get() == b.get();
}
-template <typename T, typename U> inline bool operator==(const JSRetainPtr<T>& a, U* b)
+template<typename T, typename U> inline bool operator==(const JSRetainPtr<T>& a, U* b)
{
return a.get() == b;
}
-template <typename T, typename U> inline bool operator==(T* a, const JSRetainPtr<U>& b)
+template<typename T, typename U> inline bool operator==(T* a, const JSRetainPtr<U>& b)
{
return a == b.get();
}
-template <typename T, typename U> inline bool operator!=(const JSRetainPtr<T>& a, const JSRetainPtr<U>& b)
+template<typename T, typename U> inline bool operator!=(const JSRetainPtr<T>& a, const JSRetainPtr<U>& b)
{
return a.get() != b.get();
}
-template <typename T, typename U> inline bool operator!=(const JSRetainPtr<T>& a, U* b)
+template<typename T, typename U> inline bool operator!=(const JSRetainPtr<T>& a, U* b)
{
return a.get() != b;
}
-template <typename T, typename U> inline bool operator!=(T* a, const JSRetainPtr<U>& b)
+template<typename T, typename U> inline bool operator!=(T* a, const JSRetainPtr<U>& b)
{
return a != b.get();
}
JSStringRef JSStringCreateWithCharacters(const JSChar* chars, size_t numChars)
{
initializeThreading();
- return OpaqueJSString::create(chars, numChars).releaseRef();
+ return OpaqueJSString::create(chars, numChars).leakRef();
}
JSStringRef JSStringCreateWithUTF8CString(const char* string)
Vector<UChar, 1024> buffer(length);
UChar* p = buffer.data();
if (conversionOK == convertUTF8ToUTF16(&string, string + length, &p, p + length))
- return OpaqueJSString::create(buffer.data(), p - buffer.data()).releaseRef();
+ return OpaqueJSString::create(buffer.data(), p - buffer.data()).leakRef();
}
// Null string.
- return OpaqueJSString::create().releaseRef();
+ return OpaqueJSString::create().leakRef();
}
JSStringRef JSStringRetain(JSStringRef string)
#endif
#if !defined(WIN32) && !defined(_WIN32) && !defined(__WINSCW__) \
- && !((defined(__CC_ARM) || defined(__ARMCC__)) && defined(__SYMBIAN32__)) /* RVCT */
+ && !((defined(__CC_ARM) || defined(__ARMCC__)) && !defined(__linux__)) /* RVCT */
/*!
@typedef JSChar
@abstract A Unicode character.
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
+ */
#include "config.h"
#include "JSStringRefBSTR.h"
// it can hold. (<rdar://problem/6806478>)
size_t length = CFStringGetLength(string);
if (length) {
- OwnArrayPtr<UniChar> buffer(new UniChar[length]);
+ OwnArrayPtr<UniChar> buffer = adoptArrayPtr(new UniChar[length]);
CFStringGetCharacters(string, CFRangeMake(0, length), buffer.get());
COMPILE_ASSERT(sizeof(UniChar) == sizeof(UChar), unichar_and_uchar_must_be_same_size);
- return OpaqueJSString::create(reinterpret_cast<UChar*>(buffer.get()), length).releaseRef();
+ return OpaqueJSString::create(reinterpret_cast<UChar*>(buffer.get()), length).leakRef();
} else {
- return OpaqueJSString::create(0, 0).releaseRef();
+ return OpaqueJSString::create(0, 0).leakRef();
}
}
JSValue jsValue = toJS(exec, value);
if (JSObject* o = jsValue.getObject()) {
- if (o->inherits(&JSCallbackObject<JSGlobalObject>::info))
+ if (o->inherits(&JSCallbackObject<JSGlobalObject>::s_info))
return static_cast<JSCallbackObject<JSGlobalObject>*>(o)->inherits(jsClass);
- else if (o->inherits(&JSCallbackObject<JSObject>::info))
- return static_cast<JSCallbackObject<JSObject>*>(o)->inherits(jsClass);
+ if (o->inherits(&JSCallbackObject<JSObjectWithGlobalObject>::s_info))
+ return static_cast<JSCallbackObject<JSObjectWithGlobalObject>*>(o)->inherits(jsClass);
}
return false;
}
if (isnan(value))
value = NaN;
- return toRef(exec, jsNumber(exec, value));
+ return toRef(exec, jsNumber(value));
}
JSValueRef JSValueMakeString(JSContextRef ctx, JSStringRef string)
{
ExecState* exec = toJS(ctx);
APIEntryShim entryShim(exec);
- LiteralParser parser(exec, string->ustring(), LiteralParser::StrictJSON);
+ UString str = string->ustring();
+ LiteralParser parser(exec, str.characters(), str.length(), LiteralParser::StrictJSON);
return toRef(exec, parser.tryLiteralParse());
}
exec->clearException();
return 0;
}
- return OpaqueJSString::create(result).releaseRef();
+ return OpaqueJSString::create(result).leakRef();
}
bool JSValueToBoolean(JSContextRef ctx, JSValueRef value)
exec->clearException();
stringRef.clear();
}
- return stringRef.release().releaseRef();
+ return stringRef.release().leakRef();
}
JSObjectRef JSValueToObject(JSContextRef ctx, JSValueRef value, JSValueRef* exception)
typedef void (*JSWeakMapDestroyedCallback)(struct OpaqueJSWeakObjectMap*, void*);
-typedef JSC::WeakGCMap<void*, JSC::JSObject*> WeakMapType;
+typedef JSC::WeakGCMap<void*, JSC::JSObject> WeakMapType;
struct OpaqueJSWeakObjectMap : public RefCounted<OpaqueJSWeakObjectMap> {
public:
#include "JSValue.h"
#include "JSWeakObjectMapRefInternal.h"
#include <wtf/HashMap.h>
-#include <wtf/RefCounted.h>
#include <wtf/text/StringHash.h>
using namespace WTF;
JSObject* obj = toJS(object);
if (!obj)
return;
- ASSERT(obj->inherits(&JSCallbackObject<JSGlobalObject>::info) || obj->inherits(&JSCallbackObject<JSObject>::info));
- map->map().set(key, obj);
+ ASSERT(obj->inherits(&JSCallbackObject<JSGlobalObject>::s_info) || obj->inherits(&JSCallbackObject<JSObjectWithGlobalObject>::s_info));
+ map->map().set(exec->globalData(), key, obj);
}
JSObjectRef JSWeakObjectMapGet(JSContextRef ctx, JSWeakObjectMapRef map, void* key)
return toRef(static_cast<JSObject*>(map->map().get(key)));
}
-bool JSWeakObjectMapClear(JSContextRef ctx, JSWeakObjectMapRef map, void* key, JSObjectRef object)
+void JSWeakObjectMapRemove(JSContextRef ctx, JSWeakObjectMapRef map, void* key)
{
ExecState* exec = toJS(ctx);
APIEntryShim entryShim(exec);
- JSObject* obj = toJS(object);
- if (map->map().uncheckedRemove(key, obj))
- return true;
- return false;
+ map->map().take(key);
+}
+
+// We need to keep this function in the build to keep the nightlies running.
+JS_EXPORT bool JSWeakObjectMapClear(JSContextRef, JSWeakObjectMapRef, void*, JSObjectRef);
+bool JSWeakObjectMapClear(JSContextRef, JSWeakObjectMapRef, void*, JSObjectRef)
+{
+ return true;
}
#ifdef __cplusplus
@param destructor A function to call when the weak map is destroyed.
@result A JSWeakObjectMapRef bound to the given context, data and destructor.
@discussion The JSWeakObjectMapRef can be used as a storage mechanism to hold custom JS objects without forcing those objects to
- remain live as JSValueProtect would. Any objects that are intended to be stored in a weak map must be user defined objects that
- remove themselves from the map in their finalizer.
+ remain live as JSValueProtect would.
*/
JS_EXPORT JSWeakObjectMapRef JSWeakObjectMapCreate(JSContextRef ctx, void* data, JSWeakMapDestroyedCallback destructor);
/*!
@function
- @abstract Clears the association between a key and an object in a JSWeakObjectMapRef
+ @abstract Removes the entry for the given key if the key is present, otherwise it has no effect.
@param ctx The execution context to use.
- @param map The map to clear the key association from.
- @param key The key to use.
- @param object The old object value.
- @result Returns true if the key/object association was present in map, and has been removed.
+ @param map The map to use.
+ @param key The key to remove.
*/
-JS_EXPORT bool JSWeakObjectMapClear(JSContextRef ctx, JSWeakObjectMapRef map, void* key, JSObjectRef object);
+JS_EXPORT void JSWeakObjectMapRemove(JSContextRef ctx, JSWeakObjectMapRef map, void* key);
#ifdef __cplusplus
}
PassRefPtr<OpaqueJSString> OpaqueJSString::create(const UString& ustring)
{
if (!ustring.isNull())
- return adoptRef(new OpaqueJSString(ustring.data(), ustring.size()));
+ return adoptRef(new OpaqueJSString(ustring.characters(), ustring.length()));
return 0;
}
{
if (this && m_characters)
return UString(m_characters, m_length);
- return UString::null();
+ return UString();
}
Identifier OpaqueJSString::identifier(JSGlobalData* globalData) const
class JSGlobalData;
}
-struct OpaqueJSString : public ThreadSafeShared<OpaqueJSString> {
+struct OpaqueJSString : public ThreadSafeRefCounted<OpaqueJSString> {
static PassRefPtr<OpaqueJSString> create() // null
{
JSC::Identifier identifier(JSC::JSGlobalData*) const;
private:
- friend class WTF::ThreadSafeShared<OpaqueJSString>;
+ friend class WTF::ThreadSafeRefCounted<OpaqueJSString>;
OpaqueJSString()
: m_characters(0)
#include <wtf/Assertions.h>
#include <wtf/UnusedParam.h>
+#if OS(WINDOWS)
+#include <windows.h>
+#endif
+
#if COMPILER(MSVC)
#include <wtf/MathExtras.h>
return JSValueMakeNull(context);
}
+static bool MyObject_set_nullGetForwardSet(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
+{
+ UNUSED_PARAM(ctx);
+ UNUSED_PARAM(object);
+ UNUSED_PARAM(propertyName);
+ UNUSED_PARAM(value);
+ UNUSED_PARAM(exception);
+ return false; // Forward to parent class.
+}
+
static JSStaticValue evilStaticValues[] = {
{ "nullGetSet", 0, 0, kJSPropertyAttributeNone },
+ { "nullGetForwardSet", 0, MyObject_set_nullGetForwardSet, kJSPropertyAttributeNone },
{ 0, 0, 0, 0 }
};
return jsClass;
}
+static JSValueRef PropertyCatchalls_getProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
+{
+ UNUSED_PARAM(context);
+ UNUSED_PARAM(object);
+ UNUSED_PARAM(propertyName);
+ UNUSED_PARAM(exception);
+
+ if (JSStringIsEqualToUTF8CString(propertyName, "x")) {
+ static size_t count;
+ if (count++ < 5)
+ return NULL;
+
+ // Swallow all .x gets after 5, returning null.
+ return JSValueMakeNull(context);
+ }
+
+ if (JSStringIsEqualToUTF8CString(propertyName, "y")) {
+ static size_t count;
+ if (count++ < 5)
+ return NULL;
+
+ // Swallow all .y gets after 5, returning null.
+ return JSValueMakeNull(context);
+ }
+
+ if (JSStringIsEqualToUTF8CString(propertyName, "z")) {
+ static size_t count;
+ if (count++ < 5)
+ return NULL;
+
+ // Swallow all .y gets after 5, returning null.
+ return JSValueMakeNull(context);
+ }
+
+ return NULL;
+}
+
+static bool PropertyCatchalls_setProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
+{
+ UNUSED_PARAM(context);
+ UNUSED_PARAM(object);
+ UNUSED_PARAM(propertyName);
+ UNUSED_PARAM(value);
+ UNUSED_PARAM(exception);
+
+ if (JSStringIsEqualToUTF8CString(propertyName, "x")) {
+ static size_t count;
+ if (count++ < 5)
+ return false;
+
+ // Swallow all .x sets after 4.
+ return true;
+ }
+
+ return false;
+}
+
+static void PropertyCatchalls_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef propertyNames)
+{
+ UNUSED_PARAM(context);
+ UNUSED_PARAM(object);
+
+ static size_t count;
+ static const char* numbers[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
+
+ // Provide a property of a different name every time.
+ JSStringRef propertyName = JSStringCreateWithUTF8CString(numbers[count++ % 10]);
+ JSPropertyNameAccumulatorAddName(propertyNames, propertyName);
+ JSStringRelease(propertyName);
+}
+
+JSClassDefinition PropertyCatchalls_definition = {
+ 0,
+ kJSClassAttributeNone,
+
+ "PropertyCatchalls",
+ NULL,
+
+ NULL,
+ NULL,
+
+ NULL,
+ NULL,
+ NULL,
+ PropertyCatchalls_getProperty,
+ PropertyCatchalls_setProperty,
+ NULL,
+ PropertyCatchalls_getPropertyNames,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+};
+
+static JSClassRef PropertyCatchalls_class(JSContextRef context)
+{
+ UNUSED_PARAM(context);
+
+ static JSClassRef jsClass;
+ if (!jsClass)
+ jsClass = JSClassCreate(&PropertyCatchalls_definition);
+
+ return jsClass;
+}
+
static bool EvilExceptionObject_hasInstance(JSContextRef context, JSObjectRef constructor, JSValueRef possibleValue, JSValueRef* exception)
{
UNUSED_PARAM(context);
v = NULL;
}
+static bool assertTrue(bool value, const char* message)
+{
+ if (!value) {
+ if (message)
+ fprintf(stderr, "assertTrue failed: '%s'\n", message);
+ else
+ fprintf(stderr, "assertTrue failed.\n");
+ failed = 1;
+ }
+ return value;
+}
+
+static bool checkForCycleInPrototypeChain()
+{
+ bool result = true;
+ JSGlobalContextRef context = JSGlobalContextCreate(0);
+ JSObjectRef object1 = JSObjectMake(context, /* jsClass */ 0, /* data */ 0);
+ JSObjectRef object2 = JSObjectMake(context, /* jsClass */ 0, /* data */ 0);
+ JSObjectRef object3 = JSObjectMake(context, /* jsClass */ 0, /* data */ 0);
+
+ JSObjectSetPrototype(context, object1, JSValueMakeNull(context));
+ ASSERT(JSValueIsNull(context, JSObjectGetPrototype(context, object1)));
+
+ // object1 -> object1
+ JSObjectSetPrototype(context, object1, object1);
+ result &= assertTrue(JSValueIsNull(context, JSObjectGetPrototype(context, object1)), "It is possible to assign self as a prototype");
+
+ // object1 -> object2 -> object1
+ JSObjectSetPrototype(context, object2, object1);
+ ASSERT(JSValueIsStrictEqual(context, JSObjectGetPrototype(context, object2), object1));
+ JSObjectSetPrototype(context, object1, object2);
+ result &= assertTrue(JSValueIsNull(context, JSObjectGetPrototype(context, object1)), "It is possible to close a prototype chain cycle");
+
+ // object1 -> object2 -> object3 -> object1
+ JSObjectSetPrototype(context, object2, object3);
+ ASSERT(JSValueIsStrictEqual(context, JSObjectGetPrototype(context, object2), object3));
+ JSObjectSetPrototype(context, object1, object2);
+ ASSERT(JSValueIsStrictEqual(context, JSObjectGetPrototype(context, object1), object2));
+ JSObjectSetPrototype(context, object3, object1);
+ result &= assertTrue(!JSValueIsStrictEqual(context, JSObjectGetPrototype(context, object3), object1), "It is possible to close a prototype chain cycle");
+
+ JSValueRef exception;
+ JSStringRef code = JSStringCreateWithUTF8CString("o = { }; p = { }; o.__proto__ = p; p.__proto__ = o");
+ JSStringRef file = JSStringCreateWithUTF8CString("");
+ result &= assertTrue(!JSEvaluateScript(context, code, /* thisObject*/ 0, file, 1, &exception)
+ , "An exception should be thrown");
+
+ JSStringRelease(code);
+ JSStringRelease(file);
+ JSGlobalContextRelease(context);
+ return result;
+}
+
int main(int argc, char* argv[])
{
+#if OS(WINDOWS)
+ // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for
+ // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the
+ // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>.
+ ::SetErrorMode(0);
+#endif
+
const char *scriptPath = "testapi.js";
if (argc > 1) {
scriptPath = argv[1];
ASSERT(JSValueGetType(context, jsCFEmptyString) == kJSTypeString);
ASSERT(JSValueGetType(context, jsCFEmptyStringWithCharacters) == kJSTypeString);
+ JSObjectRef propertyCatchalls = JSObjectMake(context, PropertyCatchalls_class(context), NULL);
+ JSStringRef propertyCatchallsString = JSStringCreateWithUTF8CString("PropertyCatchalls");
+ JSObjectSetProperty(context, globalObject, propertyCatchallsString, propertyCatchalls, kJSPropertyAttributeNone, NULL);
+ JSStringRelease(propertyCatchallsString);
+
JSObjectRef myObject = JSObjectMake(context, MyObject_class(context), NULL);
JSStringRef myObjectIString = JSStringCreateWithUTF8CString("MyObject");
JSObjectSetProperty(context, globalObject, myObjectIString, myObject, kJSPropertyAttributeNone, NULL);
JSStringRelease(EmptyObjectIString);
JSStringRef lengthStr = JSStringCreateWithUTF8CString("length");
- aHeapRef = JSObjectMakeArray(context, 0, 0, 0);
+ JSObjectRef aStackRef = JSObjectMakeArray(context, 0, 0, 0);
+ aHeapRef = aStackRef;
JSObjectSetProperty(context, aHeapRef, lengthStr, JSValueMakeNumber(context, 10), 0, 0);
JSStringRef privatePropertyName = JSStringCreateWithUTF8CString("privateProperty");
if (!JSObjectSetPrivateProperty(context, myObject, privatePropertyName, aHeapRef)) {
printf("FAIL: Could not set private property.\n");
- failed = 1;
- } else {
+ failed = 1;
+ } else
printf("PASS: Set private property.\n");
- }
+ aStackRef = 0;
if (JSObjectSetPrivateProperty(context, aHeapRef, privatePropertyName, aHeapRef)) {
printf("FAIL: JSObjectSetPrivateProperty should fail on non-API objects.\n");
- failed = 1;
- } else {
+ failed = 1;
+ } else
printf("PASS: Did not allow JSObjectSetPrivateProperty on a non-API object.\n");
- }
if (JSObjectGetPrivateProperty(context, myObject, privatePropertyName) != aHeapRef) {
printf("FAIL: Could not retrieve private property.\n");
failed = 1;
failed = 1;
} else
printf("PASS: JSObjectGetPrivateProperty return NULL.\n");
-
+
if (JSObjectGetProperty(context, myObject, privatePropertyName, 0) == aHeapRef) {
printf("FAIL: Accessed private property through ordinary property lookup.\n");
failed = 1;
} else
printf("PASS: Cannot access private property through ordinary property lookup.\n");
-
+
JSGarbageCollect(context);
-
+
for (int i = 0; i < 10000; i++)
JSObjectMake(context, 0, 0);
+ aHeapRef = JSValueToObject(context, JSObjectGetPrivateProperty(context, myObject, privatePropertyName), 0);
if (JSValueToNumber(context, JSObjectGetProperty(context, aHeapRef, lengthStr, 0), 0) != 10) {
printf("FAIL: Private property has been collected.\n");
failed = 1;
} else
printf("PASS: Private property does not appear to have been collected.\n");
JSStringRelease(lengthStr);
-
+
+ if (!JSObjectSetPrivateProperty(context, myObject, privatePropertyName, 0)) {
+ printf("FAIL: Could not set private property to NULL.\n");
+ failed = 1;
+ } else
+ printf("PASS: Set private property to NULL.\n");
+ if (JSObjectGetPrivateProperty(context, myObject, privatePropertyName)) {
+ printf("FAIL: Could not retrieve private property.\n");
+ failed = 1;
+ } else
+ printf("PASS: Retrieved private property.\n");
+
JSStringRef validJSON = JSStringCreateWithUTF8CString("{\"aProperty\":true}");
JSValueRef jsonObject = JSValueMakeFromJSONString(context, validJSON);
JSStringRelease(validJSON);
printf("PASS: Infinite prototype chain does not occur.\n");
+ if (checkForCycleInPrototypeChain())
+ printf("PASS: A cycle in a prototype chain can't be created.\n");
+ else {
+ printf("FAIL: A cycle in a prototype chain can be created.\n");
+ failed = true;
+ }
+
if (failed) {
printf("FAIL: Some tests failed.\n");
return 1;
shouldBe("new MyObject('throwOnConstruct')", "an exception");
shouldBe("'throwOnHasInstance' instanceof MyObject", "an exception");
+MyObject.nullGetForwardSet = 1;
+shouldBe("MyObject.nullGetForwardSet", 1);
+
var foundMyPropertyName = false;
var foundRegularType = false;
for (var p in MyObject) {
shouldBe("myObject instanceof MyObject", true);
shouldBe("(new Object()) instanceof MyObject", false);
-shouldThrow("MyObject.nullGetSet = 1");
-shouldThrow("MyObject.nullGetSet");
+MyObject.nullGetSet = 1;
+shouldBe("MyObject.nullGetSet", 1);
shouldThrow("MyObject.nullCall()");
shouldThrow("MyObject.hasPropertyLie");
shouldBe("EmptyObject", "[object CallbackObject]");
+for (var i = 0; i < 6; ++i)
+ PropertyCatchalls.x = i;
+shouldBe("PropertyCatchalls.x", 4);
+
+for (var i = 0; i < 6; ++i)
+ var x = PropertyCatchalls.x;
+shouldBe("x", null);
+
+for (var i = 0; i < 10; ++i) {
+ for (var p in PropertyCatchalls) {
+ if (p == "x")
+ continue;
+ shouldBe("p", i % 10);
+ break;
+ }
+}
+
+PropertyCatchalls.__proto__ = { y: 1 };
+for (var i = 0; i < 6; ++i)
+ var y = PropertyCatchalls.y;
+shouldBe("y", null);
+
+var o = { __proto__: PropertyCatchalls };
+for (var i = 0; i < 6; ++i)
+ var z = PropertyCatchalls.z;
+shouldBe("z", null);
+
if (failed)
throw "Some tests failed";
-
+++ /dev/null
-##
-## Copyright 2009, The Android Open Source Project
-##
-## Redistribution and use in source and binary forms, with or without
-## modification, are permitted provided that the following conditions
-## are met:
-## * Redistributions of source code must retain the above copyright
-## notice, this list of conditions and the following disclaimer.
-## * Redistributions in binary form must reproduce the above copyright
-## notice, this list of conditions and the following disclaimer in the
-## documentation and/or other materials provided with the distribution.
-##
-## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
-## EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-## EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-## PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-## PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
-## OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-##
-
-LOCAL_SRC_FILES := \
- API/JSValueRef.cpp \
- API/JSCallbackObject.cpp \
- API/OpaqueJSString.cpp \
- \
- bytecode/CodeBlock.cpp \
- bytecode/JumpTable.cpp \
- bytecode/Opcode.cpp \
- bytecode/SamplingTool.cpp \
- bytecode/StructureStubInfo.cpp \
- \
- bytecompiler/BytecodeGenerator.cpp \
- bytecompiler/NodesCodegen.cpp \
- \
- debugger/Debugger.cpp \
- debugger/DebuggerActivation.cpp \
- debugger/DebuggerCallFrame.cpp \
- \
- interpreter/CallFrame.cpp \
- interpreter/Interpreter.cpp \
- interpreter/RegisterFile.cpp \
- \
- jit/ExecutableAllocator.cpp\
- jit/ExecutableAllocatorFixedVMPool.cpp \
- jit/ExecutableAllocatorPosix.cpp \
- jit/JIT.cpp \
- jit/JITArithmetic.cpp \
- jit/JITCall.cpp \
- jit/JITOpcodes.cpp \
- jit/JITPropertyAccess.cpp \
- jit/JITStubs.cpp \
- \
- parser/Lexer.cpp \
- parser/Nodes.cpp \
- parser/Parser.cpp \
- parser/ParserArena.cpp \
- \
- pcre/pcre_compile.cpp \
- pcre/pcre_exec.cpp \
- pcre/pcre_tables.cpp \
- pcre/pcre_ucp_searchfuncs.cpp \
- pcre/pcre_xclass.cpp \
- \
- profiler/Profile.cpp \
- profiler/ProfileGenerator.cpp \
- profiler/ProfileNode.cpp \
- profiler/Profiler.cpp \
- \
- runtime/ArgList.cpp \
- runtime/Arguments.cpp \
- runtime/ArrayConstructor.cpp \
- runtime/ArrayPrototype.cpp \
- runtime/BooleanConstructor.cpp \
- runtime/BooleanObject.cpp \
- runtime/BooleanPrototype.cpp \
- runtime/CallData.cpp \
- runtime/Collector.cpp \
- runtime/CommonIdentifiers.cpp \
- runtime/Completion.cpp \
- runtime/ConstructData.cpp \
- runtime/DateConstructor.cpp \
- runtime/DateConversion.cpp \
- runtime/DateInstance.cpp \
- runtime/DatePrototype.cpp \
- runtime/Error.cpp \
- runtime/ErrorConstructor.cpp \
- runtime/ErrorInstance.cpp \
- runtime/ErrorPrototype.cpp \
- runtime/ExceptionHelpers.cpp \
- runtime/Executable.cpp \
- runtime/FunctionConstructor.cpp \
- runtime/FunctionPrototype.cpp \
- runtime/GetterSetter.cpp \
- runtime/GlobalEvalFunction.cpp \
- runtime/Identifier.cpp \
- runtime/InitializeThreading.cpp \
- runtime/InternalFunction.cpp \
- runtime/JSAPIValueWrapper.cpp \
- runtime/JSActivation.cpp \
- runtime/JSArray.cpp \
- runtime/JSByteArray.cpp \
- runtime/JSCell.cpp \
- runtime/JSFunction.cpp \
- runtime/JSGlobalData.cpp \
- runtime/JSGlobalObject.cpp \
- runtime/JSGlobalObjectFunctions.cpp \
- runtime/JSImmediate.cpp \
- runtime/JSLock.cpp \
- runtime/JSNotAnObject.cpp \
- runtime/JSNumberCell.cpp \
- runtime/JSONObject.cpp \
- runtime/JSObject.cpp \
- runtime/JSPropertyNameIterator.cpp \
- runtime/JSStaticScopeObject.cpp \
- runtime/JSString.cpp \
- runtime/JSValue.cpp \
- runtime/JSVariableObject.cpp \
- runtime/JSWrapperObject.cpp \
- runtime/LiteralParser.cpp \
- runtime/Lookup.cpp \
- runtime/MarkStack.cpp \
- runtime/MarkStackPosix.cpp \
- runtime/MathObject.cpp \
- runtime/NativeErrorConstructor.cpp \
- runtime/NativeErrorPrototype.cpp \
- runtime/NumberConstructor.cpp \
- runtime/NumberObject.cpp \
- runtime/NumberPrototype.cpp \
- runtime/ObjectConstructor.cpp \
- runtime/ObjectPrototype.cpp \
- runtime/Operations.cpp \
- runtime/PropertyDescriptor.cpp \
- runtime/PropertyNameArray.cpp \
- runtime/PropertySlot.cpp \
- runtime/PrototypeFunction.cpp \
- runtime/RegExp.cpp \
- runtime/RegExpConstructor.cpp \
- runtime/RegExpObject.cpp \
- runtime/RegExpPrototype.cpp \
- runtime/ScopeChain.cpp \
- runtime/SmallStrings.cpp \
- runtime/StringConstructor.cpp \
- runtime/StringObject.cpp \
- runtime/StringPrototype.cpp \
- runtime/Structure.cpp \
- runtime/StructureChain.cpp \
- runtime/TimeoutChecker.cpp \
- runtime/UString.cpp \
- \
- wtf/Assertions.cpp \
- wtf/ByteArray.cpp \
- wtf/CurrentTime.cpp \
- wtf/DateMath.cpp \
- wtf/FastMalloc.cpp \
- wtf/HashTable.cpp \
- wtf/MainThread.cpp \
- wtf/RandomNumber.cpp \
- wtf/RefCountedLeakCounter.cpp \
- wtf/TCSystemAlloc.cpp \
- wtf/ThreadIdentifierDataPthreads.cpp \
- wtf/Threading.cpp \
- wtf/ThreadingPthreads.cpp \
- wtf/WTFThreadData.cpp \
- \
- wtf/TypeTraits.cpp \
- wtf/dtoa.cpp \
- \
- wtf/android/MainThreadAndroid.cpp \
- \
- wtf/text/AtomicString.cpp \
- wtf/text/CString.cpp \
- wtf/text/StringImpl.cpp \
- wtf/text/WTFString.cpp \
- \
- wtf/unicode/CollatorDefault.cpp \
- wtf/unicode/UTF8.cpp \
- \
- wtf/unicode/icu/CollatorICU.cpp \
- \
- yarr/RegexCompiler.cpp \
- yarr/RegexInterpreter.cpp \
- yarr/RegexJIT.cpp
-
-# Rule to build grammar.y with our custom bison.
-GEN := $(intermediates)/parser/Grammar.cpp
-$(GEN) : PRIVATE_YACCFLAGS := -p jscyy
-$(GEN) : $(LOCAL_PATH)/parser/Grammar.y
- $(call local-transform-y-to-cpp,.cpp)
-$(GEN) : $(LOCAL_BISON)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-# generated headers
-JSC_OBJECTS := $(addprefix $(intermediates)/runtime/, \
- ArrayPrototype.lut.h \
- DatePrototype.lut.h \
- JSONObject.lut.h \
- MathObject.lut.h \
- NumberConstructor.lut.h \
- RegExpConstructor.lut.h \
- RegExpObject.lut.h \
- StringPrototype.lut.h \
- )
-$(JSC_OBJECTS): PRIVATE_PATH := $(LOCAL_PATH)
-$(JSC_OBJECTS): PRIVATE_CUSTOM_TOOL = perl $(PRIVATE_PATH)/create_hash_table $< -i > $@
-$(JSC_OBJECTS): $(LOCAL_PATH)/create_hash_table
-$(JSC_OBJECTS): $(intermediates)/%.lut.h : $(LOCAL_PATH)/%.cpp
- $(transform-generated-source)
-
-
-LEXER_HEADER := $(intermediates)/Lexer.lut.h
-$(LEXER_HEADER): PRIVATE_PATH := $(LOCAL_PATH)
-$(LEXER_HEADER): PRIVATE_CUSTOM_TOOL = perl $(PRIVATE_PATH)/create_hash_table $< -i > $@
-$(LEXER_HEADER): $(LOCAL_PATH)/create_hash_table
-$(LEXER_HEADER): $(intermediates)/%.lut.h : $(LOCAL_PATH)/parser/Keywords.table
- $(transform-generated-source)
-
-CHARTABLES := $(intermediates)/chartables.c
-$(CHARTABLES): PRIVATE_PATH := $(LOCAL_PATH)
-$(CHARTABLES): PRIVATE_CUSTOM_TOOL = perl $(PRIVATE_PATH)/pcre/dftables $@
-$(CHARTABLES): $(LOCAL_PATH)/pcre/dftables
-$(CHARTABLES): $(LOCAL_PATH)/pcre/pcre_internal.h
- $(transform-generated-source)
-
-LOCAL_GENERATED_SOURCES += $(JSC_OBJECTS) $(LEXER_HEADER) $(CHARTABLES)
+++ /dev/null
-##
-## Copyright 2009, The Android Open Source Project
-##
-## Redistribution and use in source and binary forms, with or without
-## modification, are permitted provided that the following conditions
-## are met:
-## * Redistributions of source code must retain the above copyright
-## notice, this list of conditions and the following disclaimer.
-## * Redistributions in binary form must reproduce the above copyright
-## notice, this list of conditions and the following disclaimer in the
-## documentation and/or other materials provided with the distribution.
-##
-## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
-## EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-## EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-## PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-## PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
-## OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-##
-
-# wtf source files
-
-LOCAL_SRC_FILES := \
- pcre/pcre_compile.cpp \
- pcre/pcre_exec.cpp \
- pcre/pcre_tables.cpp \
- pcre/pcre_ucp_searchfuncs.cpp \
- pcre/pcre_xclass.cpp \
- \
- wtf/Assertions.cpp \
- wtf/ByteArray.cpp \
- wtf/CurrentTime.cpp \
- wtf/DateMath.cpp \
- wtf/FastMalloc.cpp \
- wtf/HashTable.cpp \
- wtf/MainThread.cpp \
- wtf/RandomNumber.cpp \
- wtf/RefCountedLeakCounter.cpp \
- wtf/TCSystemAlloc.cpp \
- wtf/ThreadIdentifierDataPthreads.cpp \
- wtf/Threading.cpp \
- wtf/ThreadingPthreads.cpp \
- wtf/WTFThreadData.cpp \
- \
- wtf/TypeTraits.cpp \
- wtf/dtoa.cpp \
- \
- wtf/android/MainThreadAndroid.cpp \
- \
- wtf/text/AtomicString.cpp \
- wtf/text/CString.cpp \
- wtf/text/StringImpl.cpp \
- wtf/text/WTFString.cpp \
- \
- wtf/unicode/CollatorDefault.cpp \
- wtf/unicode/UTF8.cpp \
- \
- wtf/unicode/icu/CollatorICU.cpp
-
-CHARTABLES := $(intermediates)/chartables.c
-$(CHARTABLES): PRIVATE_PATH := $(LOCAL_PATH)
-$(CHARTABLES): PRIVATE_CUSTOM_TOOL = perl $(PRIVATE_PATH)/pcre/dftables $@
-$(CHARTABLES): $(LOCAL_PATH)/pcre/dftables
-$(CHARTABLES): $(LOCAL_PATH)/pcre/pcre_internal.h
- $(transform-generated-source)
-
-$(intermediates)/pcre/pcre_tables.o : $(CHARTABLES)
-
-# We do not add $(CHARTABLES) to LOCAL_GENERATED_SOURCES because the chartables.c file
-# is explicitly #included in pcre_tables.cpp.
--- /dev/null
+SET(JavaScriptCore_INCLUDE_DIRECTORIES
+ "${CMAKE_BINARY_DIR}"
+ "${JAVASCRIPTCORE_DIR}"
+ "${JAVASCRIPTCORE_DIR}/API"
+ "${JAVASCRIPTCORE_DIR}/ForwardingHeaders"
+ "${JAVASCRIPTCORE_DIR}/assembler"
+ "${JAVASCRIPTCORE_DIR}/bytecode"
+ "${JAVASCRIPTCORE_DIR}/bytecompiler"
+ "${JAVASCRIPTCORE_DIR}/heap"
+ "${JAVASCRIPTCORE_DIR}/debugger"
+ "${JAVASCRIPTCORE_DIR}/interpreter"
+ "${JAVASCRIPTCORE_DIR}/jit"
+ "${JAVASCRIPTCORE_DIR}/parser"
+ "${JAVASCRIPTCORE_DIR}/profiler"
+ "${JAVASCRIPTCORE_DIR}/runtime"
+ "${JAVASCRIPTCORE_DIR}/yarr"
+ "${WTF_INCLUDE_DIRECTORIES}"
+ "${CMAKE_SOURCE_DIR}"
+)
+
+SET(JavaScriptCore_SOURCES
+ API/JSBase.cpp
+ API/JSCallbackConstructor.cpp
+ API/JSCallbackFunction.cpp
+ API/JSCallbackObject.cpp
+ API/JSClassRef.cpp
+ API/JSContextRef.cpp
+ API/JSObjectRef.cpp
+ API/JSProfilerPrivate.cpp
+ API/JSStringRef.cpp
+ API/JSValueRef.cpp
+ API/JSWeakObjectMapRefPrivate.cpp
+ API/OpaqueJSString.cpp
+
+ bytecode/CodeBlock.cpp
+ bytecode/JumpTable.cpp
+ bytecode/Opcode.cpp
+ bytecode/SamplingTool.cpp
+ bytecode/StructureStubInfo.cpp
+
+ bytecompiler/BytecodeGenerator.cpp
+ bytecompiler/NodesCodegen.cpp
+
+ heap/Heap.cpp
+ heap/HandleHeap.cpp
+ heap/HandleStack.cpp
+ heap/MachineStackMarker.cpp
+ heap/MarkedBlock.cpp
+ heap/MarkedSpace.cpp
+ heap/ConservativeRoots.cpp
+ heap/MarkStack.cpp
+
+ debugger/Debugger.cpp
+ debugger/DebuggerActivation.cpp
+ debugger/DebuggerCallFrame.cpp
+
+ interpreter/CallFrame.cpp
+ interpreter/Interpreter.cpp
+ interpreter/RegisterFile.cpp
+
+ jit/ExecutableAllocator.cpp
+ jit/JITArithmetic32_64.cpp
+ jit/JITArithmetic.cpp
+ jit/JITCall32_64.cpp
+ jit/JITCall.cpp
+ jit/JIT.cpp
+ jit/JITOpcodes32_64.cpp
+ jit/JITOpcodes.cpp
+ jit/JITPropertyAccess32_64.cpp
+ jit/JITPropertyAccess.cpp
+ jit/JITStubs.cpp
+ jit/ThunkGenerators.cpp
+
+ parser/JSParser.cpp
+ parser/Lexer.cpp
+ parser/Nodes.cpp
+ parser/Parser.cpp
+ parser/ParserArena.cpp
+ parser/SourceProviderCache.cpp
+
+ profiler/Profile.cpp
+ profiler/ProfileGenerator.cpp
+ profiler/ProfileNode.cpp
+ profiler/Profiler.cpp
+
+ runtime/ArgList.cpp
+ runtime/Arguments.cpp
+ runtime/ArrayConstructor.cpp
+ runtime/ArrayPrototype.cpp
+ runtime/BooleanConstructor.cpp
+ runtime/BooleanObject.cpp
+ runtime/BooleanPrototype.cpp
+ runtime/CallData.cpp
+ runtime/CommonIdentifiers.cpp
+ runtime/Completion.cpp
+ runtime/ConstructData.cpp
+ runtime/DateConstructor.cpp
+ runtime/DateConversion.cpp
+ runtime/DateInstance.cpp
+ runtime/DatePrototype.cpp
+ runtime/Error.cpp
+ runtime/ErrorConstructor.cpp
+ runtime/ErrorInstance.cpp
+ runtime/ErrorPrototype.cpp
+ runtime/ExceptionHelpers.cpp
+ runtime/Executable.cpp
+ runtime/FunctionConstructor.cpp
+ runtime/FunctionPrototype.cpp
+ runtime/GCActivityCallback.cpp
+ runtime/GetterSetter.cpp
+ runtime/Identifier.cpp
+ runtime/InitializeThreading.cpp
+ runtime/InternalFunction.cpp
+ runtime/JSActivation.cpp
+ runtime/JSAPIValueWrapper.cpp
+ runtime/JSArray.cpp
+ runtime/JSByteArray.cpp
+ runtime/JSCell.cpp
+ runtime/JSFunction.cpp
+ runtime/JSGlobalData.cpp
+ runtime/JSGlobalObject.cpp
+ runtime/JSGlobalObjectFunctions.cpp
+ runtime/JSLock.cpp
+ runtime/JSNotAnObject.cpp
+ runtime/JSObject.cpp
+ runtime/JSObjectWithGlobalObject.cpp
+ runtime/JSONObject.cpp
+ runtime/JSPropertyNameIterator.cpp
+ runtime/JSStaticScopeObject.cpp
+ runtime/JSString.cpp
+ runtime/JSValue.cpp
+ runtime/JSVariableObject.cpp
+ runtime/JSWrapperObject.cpp
+ runtime/JSZombie.cpp
+ runtime/LiteralParser.cpp
+ runtime/Lookup.cpp
+ runtime/MathObject.cpp
+ runtime/NativeErrorConstructor.cpp
+ runtime/NativeErrorPrototype.cpp
+ runtime/NumberConstructor.cpp
+ runtime/NumberObject.cpp
+ runtime/NumberPrototype.cpp
+ runtime/ObjectConstructor.cpp
+ runtime/ObjectPrototype.cpp
+ runtime/Operations.cpp
+ runtime/PropertyDescriptor.cpp
+ runtime/PropertyNameArray.cpp
+ runtime/PropertySlot.cpp
+ runtime/RegExp.cpp
+ runtime/RegExpCache.cpp
+ runtime/RegExpConstructor.cpp
+ runtime/RegExpObject.cpp
+ runtime/RegExpPrototype.cpp
+ runtime/RopeImpl.cpp
+ runtime/ScopeChain.cpp
+ runtime/SmallStrings.cpp
+ runtime/StrictEvalActivation.cpp
+ runtime/StringConstructor.cpp
+ runtime/StringObject.cpp
+ runtime/StringPrototype.cpp
+ runtime/StringRecursionChecker.cpp
+ runtime/Structure.cpp
+ runtime/StructureChain.cpp
+ runtime/TimeoutChecker.cpp
+ runtime/UString.cpp
+
+ yarr/YarrPattern.cpp
+ yarr/YarrInterpreter.cpp
+ yarr/YarrJIT.cpp
+ yarr/YarrSyntaxChecker.cpp
+
+ wtf/DateMath.cpp
+ wtf/PageAllocationAligned.cpp
+ wtf/PageBlock.cpp
+)
+SET(JavaScriptCore_HEADERS )
+
+SET(JavaScriptCore_LUT_FILES
+ runtime/ArrayConstructor.cpp
+ runtime/ArrayPrototype.cpp
+ runtime/BooleanPrototype.cpp
+ runtime/DateConstructor.cpp
+ runtime/DatePrototype.cpp
+ runtime/ErrorPrototype.cpp
+ runtime/JSGlobalObject.cpp
+ runtime/JSONObject.cpp
+ runtime/MathObject.cpp
+ runtime/NumberConstructor.cpp
+ runtime/NumberPrototype.cpp
+ runtime/ObjectConstructor.cpp
+ runtime/ObjectPrototype.cpp
+ runtime/RegExpConstructor.cpp
+ runtime/RegExpObject.cpp
+ runtime/RegExpPrototype.cpp
+ runtime/StringConstructor.cpp
+ runtime/StringPrototype.cpp
+)
+
+SET(JavaScriptCore_LIBRARIES
+ ${WTF_LIBRARY_NAME}
+)
+
+
+# GENERATOR 1-A: LUT creator
+FOREACH (_file ${JavaScriptCore_LUT_FILES})
+ GET_FILENAME_COMPONENT(_name ${_file} NAME_WE)
+ GENERATE_HASH_LUT(${JAVASCRIPTCORE_DIR}/${_file} ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/${_name}.lut.h)
+ LIST(APPEND JavaScriptCore_HEADERS ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/${_name}.lut.h)
+ENDFOREACH ()
+
+
+# GENERATOR 1-B: particular LUT creator (for 1 file only)
+GENERATE_HASH_LUT(${JAVASCRIPTCORE_DIR}/parser/Keywords.table ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/Lexer.lut.h MAIN_DEPENDENCY)
+LIST(APPEND JavaScriptCore_HEADERS ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/Lexer.lut.h)
+
+#GENERATOR: "RegExpJitTables.h": tables used by Yarr
+ADD_CUSTOM_COMMAND(
+ OUTPUT ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/RegExpJitTables.h
+ MAIN_DEPENDENCY ${JAVASCRIPTCORE_DIR}/create_regex_tables
+ COMMAND ${PYTHON_EXECUTABLE} ${JAVASCRIPTCORE_DIR}/create_regex_tables > ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/RegExpJitTables.h
+ VERBATIM)
+ADD_SOURCE_DEPENDENCIES(${JAVASCRIPTCORE_DIR}/yarr/YarrPattern.cpp ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/RegExpJitTables.h)
+
+
+#GENERATOR: "KeywordLookup.h": keyword decision tree used by the lexer
+ADD_CUSTOM_COMMAND(
+ OUTPUT ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/KeywordLookup.h
+ MAIN_DEPENDENCY ${JAVASCRIPTCORE_DIR}/KeywordLookupGenerator.py
+ COMMAND ${PYTHON_EXECUTABLE} ${JAVASCRIPTCORE_DIR}/KeywordLookupGenerator.py ${JAVASCRIPTCORE_DIR}/parser/Keywords.table > ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/KeywordLookup.h
+ VERBATIM)
+ADD_SOURCE_DEPENDENCIES(${JAVASCRIPTCORE_DIR}/parser/Lexer.cpp ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/KeywordLookup.h)
+
+IF (WTF_CPU_ARM)
+ LIST(APPEND JavaScriptCore_SOURCES
+ assembler/ARMAssembler.cpp
+ assembler/ARMv7Assembler.cpp
+ assembler/MacroAssemblerARM.cpp
+ )
+ELSEIF (WTF_CPU_MIPS)
+ELSEIF (WTF_CPU_X86)
+ELSEIF (WTF_CPU_X86_64)
+ELSE ()
+ MESSAGE(FATAL_ERROR "Unknown CPU")
+ENDIF ()
+
+
+INCLUDE_IF_EXISTS(${JAVASCRIPTCORE_DIR}/CMakeLists${PORT}.txt)
+
+
+ADD_SUBDIRECTORY(wtf)
+ADD_SUBDIRECTORY(shell)
+
+WEBKIT_WRAP_SOURCELIST(${JavaScriptCore_SOURCES})
+INCLUDE_DIRECTORIES(${JavaScriptCore_INCLUDE_DIRECTORIES})
+ADD_DEFINITIONS(-DBUILDING_JavaScriptCore)
+ADD_LIBRARY(${JavaScriptCore_LIBRARY_NAME} ${JavaScriptCore_LIBRARY_TYPE} ${JavaScriptCore_HEADERS} ${JavaScriptCore_SOURCES})
+TARGET_LINK_LIBRARIES(${JavaScriptCore_LIBRARY_NAME} ${JavaScriptCore_LIBRARIES})
+
+IF (JavaScriptCore_LINK_FLAGS)
+ ADD_TARGET_PROPERTIES(${JavaScriptCore_LIBRARY_NAME} LINK_FLAGS "${JavaScriptCore_LINK_FLAGS}")
+ENDIF ()
+
+IF (SHARED_CORE)
+ SET_TARGET_PROPERTIES(${JavaScriptCore_LIBRARY_NAME} PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION_MAJOR})
+ INSTALL(TARGETS ${JavaScriptCore_LIBRARY_NAME} DESTINATION lib)
+ENDIF ()
--- /dev/null
+LIST(APPEND JavaScriptCore_SOURCES
+ jit/ExecutableAllocatorFixedVMPool.cpp
+ jit/ExecutableAllocator.cpp
+ heap/MarkStackPosix.cpp
+ wtf/OSAllocatorPosix.cpp
+)
+
+LIST(APPEND JavaScriptCore_LIBRARIES
+ ${ICU_I18N_LIBRARIES}
+)
+
+IF (ENABLE_GLIB_SUPPORT)
+ LIST(APPEND JavaScriptCore_INCLUDE_DIRECTORIES
+ ${JAVASCRIPTCORE_DIR}/wtf/gobject
+ )
+ENDIF ()
+
+LIST(APPEND JavaScriptCore_LINK_FLAGS
+ ${ECORE_LDFLAGS}
+)
--- /dev/null
+LIST(APPEND JavaScriptCore_SOURCES
+ jit/ExecutableAllocator.cpp
+
+ heap/MarkStackWin.cpp
+)
+
+IF (ENABLE_JIT AND WTF_CPU_ARM)
+ ADD_CUSTOM_COMMAND(
+ OUTPUT ${DERIVED_SOURCES_DIR}/GeneratedJITStubs.asm
+ MAIN_DEPENDENCY ${JAVASCRIPTCORE_DIR}/create_jit_stubs
+ DEPENDS ${JAVASCRIPTCORE_DIR}/jit/JITStubs.cpp
+ COMMAND ${PERL_EXECUTABLE} ${JAVASCRIPTCORE_DIR}/create_jit_stubs --prefix=MSVC ${JAVASCRIPTCORE_DIR}/jit/JITStubs.cpp > ${DERIVED_SOURCES_DIR}/GeneratedJITStubs.asm
+ VERBATIM)
+
+ ADD_CUSTOM_COMMAND(
+ OUTPUT ${DERIVED_SOURCES_DIR}/GeneratedJITStubs.obj
+ MAIN_DEPENDENCY ${DERIVED_SOURCES_DIR}/GeneratedJITStubs.asm
+ COMMAND armasm -nologo ${DERIVED_SOURCES_DIR}/GeneratedJITStubs.asm ${DERIVED_SOURCES_DIR}/GeneratedJITStubs.obj
+ VERBATIM)
+
+ LIST (APPEND JavaScriptCore_SOURCES ${DERIVED_SOURCES_DIR}/GeneratedJITStubs.obj)
+ENDIF ()
-# Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+# Copyright (C) 2006, 2007, 2008, 2009, 2011 Apple Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
VPATH = \
$(JavaScriptCore) \
$(JavaScriptCore)/parser \
- $(JavaScriptCore)/pcre \
$(JavaScriptCore)/docs \
$(JavaScriptCore)/runtime \
$(JavaScriptCore)/interpreter \
.PHONY : all
all : \
+ ArrayConstructor.lut.h \
ArrayPrototype.lut.h \
- chartables.c \
+ BooleanPrototype.lut.h \
+ DateConstructor.lut.h \
DatePrototype.lut.h \
- Grammar.cpp \
+ ErrorPrototype.lut.h \
+ HeaderDetection.h \
JSONObject.lut.h \
+ JavaScriptCore.JSVALUE32_64.exp \
+ JavaScriptCore.JSVALUE64.exp \
+ JSGlobalObject.lut.h \
+ KeywordLookup.h \
Lexer.lut.h \
MathObject.lut.h \
NumberConstructor.lut.h \
+ NumberPrototype.lut.h \
+ ObjectConstructor.lut.h \
+ ObjectPrototype.lut.h \
RegExpConstructor.lut.h \
+ RegExpPrototype.lut.h \
+ RegExpJitTables.h \
RegExpObject.lut.h \
+ StringConstructor.lut.h \
StringPrototype.lut.h \
docs/bytecode.html \
- RegExpJitTables.h \
#
# lookup tables for classes
Lexer.lut.h: create_hash_table Keywords.table
$^ > $@
-# JavaScript language grammar
-
-Grammar.cpp: Grammar.y
- bison -d -p jscyy $< -o $@ > bison_out.txt 2>&1
- perl -p -e 'END { if ($$conflict) { unlink "Grammar.cpp"; die; } } $$conflict ||= /conflict/' < bison_out.txt
- touch Grammar.cpp.h
- touch Grammar.hpp
- cat Grammar.cpp.h Grammar.hpp > Grammar.h
- rm -f Grammar.cpp.h Grammar.hpp bison_out.txt
-
-# character tables for PCRE
-
-chartables.c : dftables
- $^ $@
-
docs/bytecode.html: make-bytecode-docs.pl Interpreter.cpp
perl $^ $@
-#character tables for Yarr
+# character tables for Yarr
+
RegExpJitTables.h: create_regex_tables
python $^ > $@
+
+KeywordLookup.h: KeywordLookupGenerator.py Keywords.table
+ python $^ > $@
+
+# export files
+
+JavaScriptCore.JSVALUE32_64.exp: JavaScriptCore.exp JavaScriptCore.JSVALUE32_64only.exp
+ cat $^ > $@
+
+JavaScriptCore.JSVALUE64.exp: JavaScriptCore.exp JavaScriptCore.JSVALUE64only.exp
+ cat $^ > $@
+
+
+# header detection
+
+ifeq ($(OS),MACOS)
+
+HeaderDetection.h : DerivedSources.make /System/Library/CoreServices/SystemVersion.plist
+ rm -f $@
+ echo "/* This is a generated file. Do not edit. */" > $@
+ if [ -f $(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/pthread_machdep.h ]; then echo "#define HAVE_PTHREAD_MACHDEP_H 1" >> $@; else echo >> $@; fi
+
+else
+
+HeaderDetection.h :
+ echo > $@
+
+endif
}
LUT_FILES += \
+ runtime/ArrayConstructor.cpp \
runtime/ArrayPrototype.cpp \
+ runtime/BooleanPrototype.cpp \
+ runtime/DateConstructor.cpp \
runtime/DatePrototype.cpp \
+ runtime/ErrorPrototype.cpp \
+ runtime/JSGlobalObject.cpp \
runtime/JSONObject.cpp \
runtime/MathObject.cpp \
runtime/NumberConstructor.cpp \
+ runtime/NumberPrototype.cpp \
+ runtime/ObjectConstructor.cpp \
+ runtime/ObjectPrototype.cpp \
runtime/RegExpConstructor.cpp \
runtime/RegExpObject.cpp \
- runtime/StringPrototype.cpp
+ runtime/RegExpPrototype.cpp \
+ runtime/StringConstructor.cpp \
+ runtime/StringPrototype.cpp \
KEYWORDLUT_FILES += \
parser/Keywords.table
-JSCBISON += \
- parser/Grammar.y
-
-RVCT_STUB_FILES += \
+JIT_STUB_FILES += \
jit/JITStubs.cpp
defineTest(addExtraCompiler) {
keywordlut.depends = ${QMAKE_FILE_NAME}
addExtraCompiler(keywordlut)
-# GENERATOR 2: bison grammar
-jscbison.output = $${JSC_GENERATED_SOURCES_DIR}$${QMAKE_DIR_SEP}${QMAKE_FILE_BASE}.cpp
-jscbison.input = JSCBISON
-jscbison.commands = bison -d -p jscyy ${QMAKE_FILE_NAME} -o $${JSC_GENERATED_SOURCES_DIR}$${QMAKE_DIR_SEP}${QMAKE_FILE_BASE}.tab.c && $(MOVE) $${JSC_GENERATED_SOURCES_DIR}$${QMAKE_DIR_SEP}${QMAKE_FILE_BASE}.tab.c ${QMAKE_FILE_OUT} && $(MOVE) $${JSC_GENERATED_SOURCES_DIR}$${QMAKE_DIR_SEP}${QMAKE_FILE_BASE}.tab.h $${JSC_GENERATED_SOURCES_DIR}$${QMAKE_DIR_SEP}${QMAKE_FILE_BASE}.h
-jscbison.depends = ${QMAKE_FILE_NAME}
-addExtraCompiler(jscbison)
-
-# GENERATOR 3: JIT Stub functions for RVCT
+# GENERATOR 2-A: JIT Stub functions for RVCT
rvctstubs.output = $${JSC_GENERATED_SOURCES_DIR}$${QMAKE_DIR_SEP}Generated${QMAKE_FILE_BASE}_RVCT.h
rvctstubs.wkScript = $$PWD/create_jit_stubs
rvctstubs.commands = perl -i $$rvctstubs.wkScript --prefix RVCT ${QMAKE_FILE_NAME} > ${QMAKE_FILE_OUT}
rvctstubs.depends = ${QMAKE_FILE_NAME}
-rvctstubs.input = RVCT_STUB_FILES
+rvctstubs.input = JIT_STUB_FILES
rvctstubs.CONFIG += no_link
addExtraCompiler(rvctstubs)
-# GENERATOR: "chartables.c": compile and execute the chartables generator (and add it to sources)
-win32-msvc*|wince*: PREPROCESSOR = "--preprocessor=\"$$QMAKE_CC /E\""
-ctgen.output = $$JSC_GENERATED_SOURCES_DIR/chartables.c
-ctgen.wkScript = $$PWD/pcre/dftables
-ctgen.input = ctgen.wkScript
-ctgen.commands = perl $$ctgen.wkScript ${QMAKE_FILE_OUT} $$PREPROCESSOR
-ctgen.clean = ${QMAKE_FILE_OUT} ${QMAKE_VAR_JSC_GENERATED_SOURCES_DIR}${QMAKE_FILE_BASE}
-addExtraCompiler(ctgen)
+# GENERATOR 2-B: JIT Stub functions for MSVC
+msvcstubs.output = $${JSC_GENERATED_SOURCES_DIR}$${QMAKE_DIR_SEP}Generated${QMAKE_FILE_BASE}_MSVC.asm
+msvcstubs.wkScript = $$PWD/create_jit_stubs
+msvcstubs.commands = perl -i $$msvcstubs.wkScript --prefix MSVC ${QMAKE_FILE_NAME} > ${QMAKE_FILE_OUT}
+msvcstubs.depends = ${QMAKE_FILE_NAME}
+msvcstubs.input = JIT_STUB_FILES
+msvcstubs.CONFIG += no_link
+addExtraCompiler(msvcstubs)
#GENERATOR: "RegExpJitTables.h": tables used by Yarr
retgen.output = $$JSC_GENERATED_SOURCES_DIR/RegExpJitTables.h
retgen.input = retgen.wkScript
retgen.commands = python $$retgen.wkScript > ${QMAKE_FILE_OUT}
addExtraCompiler(retgen)
+
+#GENERATOR: "KeywordLookup.h": decision tree used by the lexer
+klgen.output = $$JSC_GENERATED_SOURCES_DIR/KeywordLookup.h
+klgen.wkScript = $$PWD/KeywordLookupGenerator.py
+klgen.input = KEYWORDLUT_FILES
+klgen.commands = python $$klgen.wkScript ${QMAKE_FILE_NAME} > ${QMAKE_FILE_OUT}
+addExtraCompiler(klgen)
--- /dev/null
+#include <JavaScriptCore/API/APIShims.h>
-javascriptcore_cppflags += \
- -I$(srcdir)/JavaScriptCore \
- -I$(srcdir)/JavaScriptCore/API \
- -I$(srcdir)/JavaScriptCore/ForwardingHeaders \
- -I$(srcdir)/JavaScriptCore/interpreter \
- -I$(srcdir)/JavaScriptCore/bytecode \
- -I$(srcdir)/JavaScriptCore/bytecompiler \
- -I$(srcdir)/JavaScriptCore/debugger \
- -I$(srcdir)/JavaScriptCore/jit \
- -I$(srcdir)/JavaScriptCore/pcre \
- -I$(srcdir)/JavaScriptCore/profiler \
- -I$(srcdir)/JavaScriptCore/runtime \
- -I$(srcdir)/JavaScriptCore/jit \
- -I$(srcdir)/JavaScriptCore/assembler \
- -I$(srcdir)/JavaScriptCore/wtf \
- -I$(srcdir)/JavaScriptCore/wtf/text \
- -I$(srcdir)/JavaScriptCore/wtf/unicode \
- -I$(srcdir)/JavaScriptCore/yarr \
- -I$(top_builddir)/JavaScriptCore \
- -I$(top_builddir)/JavaScriptCore/pcre \
- -I$(top_builddir)/JavaScriptCore/parser \
- -I$(top_builddir)/JavaScriptCore/runtime
-
-javascriptcore_h_api += \
- JavaScriptCore/API/JSBase.h \
- JavaScriptCore/API/JSContextRef.h \
- JavaScriptCore/API/JSObjectRef.h \
- JavaScriptCore/API/JSStringRef.h \
- JavaScriptCore/API/JSStringRefBSTR.h \
- JavaScriptCore/API/JSStringRefCF.h \
- JavaScriptCore/API/JSValueRef.h \
- JavaScriptCore/API/JavaScript.h \
- JavaScriptCore/API/JavaScriptCore.h \
- JavaScriptCore/API/WebKitAvailability.h
-
-javascriptcore_built_nosources += \
- DerivedSources/Lexer.lut.h \
- JavaScriptCore/RegExpJitTables.h \
- JavaScriptCore/runtime/ArrayPrototype.lut.h \
- JavaScriptCore/runtime/DatePrototype.lut.h \
- JavaScriptCore/runtime/JSONObject.lut.h \
- JavaScriptCore/runtime/MathObject.lut.h \
- JavaScriptCore/runtime/NumberConstructor.lut.h \
- JavaScriptCore/runtime/RegExpConstructor.lut.h \
- JavaScriptCore/runtime/RegExpObject.lut.h \
- JavaScriptCore/runtime/StringPrototype.lut.h \
- JavaScriptCore/pcre/chartables.c
-
-javascriptcore_sources += \
- JavaScriptCore/API/APICast.h \
- JavaScriptCore/API/APIShims.h \
- JavaScriptCore/API/JSBase.cpp \
- JavaScriptCore/API/JSBasePrivate.h \
- JavaScriptCore/API/JSCallbackConstructor.cpp \
- JavaScriptCore/API/JSCallbackConstructor.h \
- JavaScriptCore/API/JSCallbackFunction.cpp \
- JavaScriptCore/API/JSCallbackFunction.h \
- JavaScriptCore/API/JSCallbackObject.cpp \
- JavaScriptCore/API/JSCallbackObject.h \
- JavaScriptCore/API/JSCallbackObjectFunctions.h \
- JavaScriptCore/API/JSClassRef.cpp \
- JavaScriptCore/API/JSClassRef.h \
- JavaScriptCore/API/JSContextRef.cpp \
- JavaScriptCore/API/JSContextRefPrivate.h \
- JavaScriptCore/API/JSObjectRef.cpp \
- JavaScriptCore/API/JSRetainPtr.h \
- JavaScriptCore/API/JSStringRef.cpp \
- JavaScriptCore/API/JSValueRef.cpp \
- JavaScriptCore/API/OpaqueJSString.cpp \
- JavaScriptCore/API/OpaqueJSString.h \
- JavaScriptCore/ForwardingHeaders/JavaScriptCore/APICast.h \
- JavaScriptCore/ForwardingHeaders/JavaScriptCore/JSBase.h \
- JavaScriptCore/ForwardingHeaders/JavaScriptCore/JSContextRef.h \
- JavaScriptCore/ForwardingHeaders/JavaScriptCore/JSObjectRef.h \
- JavaScriptCore/ForwardingHeaders/JavaScriptCore/JSRetainPtr.h \
- JavaScriptCore/ForwardingHeaders/JavaScriptCore/JSStringRef.h \
- JavaScriptCore/ForwardingHeaders/JavaScriptCore/JSStringRefCF.h \
- JavaScriptCore/ForwardingHeaders/JavaScriptCore/JSValueRef.h \
- JavaScriptCore/ForwardingHeaders/JavaScriptCore/JavaScript.h \
- JavaScriptCore/ForwardingHeaders/JavaScriptCore/JavaScriptCore.h \
- JavaScriptCore/ForwardingHeaders/JavaScriptCore/OpaqueJSString.h \
- JavaScriptCore/ForwardingHeaders/JavaScriptCore/WebKitAvailability.h \
- JavaScriptCore/JavaScriptCorePrefix.h \
- JavaScriptCore/jit/ExecutableAllocator.h \
- JavaScriptCore/jit/JIT.cpp \
- JavaScriptCore/jit/JITOpcodes.cpp \
- JavaScriptCore/jit/JITOpcodes32_64.cpp \
- JavaScriptCore/jit/JITCall.cpp \
- JavaScriptCore/jit/JITCode.h \
- JavaScriptCore/jit/JITPropertyAccess.cpp \
- JavaScriptCore/jit/JITPropertyAccess32_64.cpp \
- JavaScriptCore/jit/JITArithmetic.cpp \
- JavaScriptCore/jit/JITArithmetic32_64.cpp \
- JavaScriptCore/jit/ExecutableAllocator.cpp \
- JavaScriptCore/jit/JIT.h \
- JavaScriptCore/jit/JITInlineMethods.h \
- JavaScriptCore/jit/JITStubs.cpp \
- JavaScriptCore/jit/JITStubs.h \
- JavaScriptCore/jit/JITStubCall.h \
- JavaScriptCore/jit/JSInterfaceJIT.h \
- JavaScriptCore/jit/SpecializedThunkJIT.h \
- JavaScriptCore/jit/ThunkGenerators.cpp \
- JavaScriptCore/jit/ThunkGenerators.h \
- JavaScriptCore/bytecode/StructureStubInfo.cpp \
- JavaScriptCore/bytecode/StructureStubInfo.h \
- JavaScriptCore/bytecode/CodeBlock.cpp \
- JavaScriptCore/bytecode/CodeBlock.h \
- JavaScriptCore/bytecode/JumpTable.cpp \
- JavaScriptCore/bytecode/JumpTable.h \
- JavaScriptCore/bytecode/EvalCodeCache.h \
- JavaScriptCore/bytecode/Instruction.h \
- JavaScriptCore/bytecompiler/Label.h \
- JavaScriptCore/interpreter/Interpreter.cpp \
- JavaScriptCore/interpreter/Interpreter.h \
- JavaScriptCore/bytecode/Opcode.cpp \
- JavaScriptCore/bytecode/Opcode.h \
- JavaScriptCore/interpreter/Register.h \
- JavaScriptCore/bytecompiler/RegisterID.h \
- JavaScriptCore/bytecode/SamplingTool.cpp \
- JavaScriptCore/bytecode/SamplingTool.h \
- JavaScriptCore/config.h \
- JavaScriptCore/debugger/DebuggerActivation.cpp \
- JavaScriptCore/debugger/DebuggerActivation.h \
- JavaScriptCore/debugger/DebuggerCallFrame.cpp \
- JavaScriptCore/debugger/DebuggerCallFrame.h \
- JavaScriptCore/icu/unicode/parseerr.h \
- JavaScriptCore/icu/unicode/platform.h \
- JavaScriptCore/icu/unicode/putil.h \
- JavaScriptCore/icu/unicode/uchar.h \
- JavaScriptCore/icu/unicode/ucnv.h \
- JavaScriptCore/icu/unicode/ucnv_err.h \
- JavaScriptCore/icu/unicode/ucol.h \
- JavaScriptCore/icu/unicode/uconfig.h \
- JavaScriptCore/icu/unicode/uenum.h \
- JavaScriptCore/icu/unicode/uiter.h \
- JavaScriptCore/icu/unicode/uloc.h \
- JavaScriptCore/icu/unicode/umachine.h \
- JavaScriptCore/icu/unicode/unorm.h \
- JavaScriptCore/icu/unicode/urename.h \
- JavaScriptCore/icu/unicode/uset.h \
- JavaScriptCore/icu/unicode/ustring.h \
- JavaScriptCore/icu/unicode/utf.h \
- JavaScriptCore/icu/unicode/utf16.h \
- JavaScriptCore/icu/unicode/utf8.h \
- JavaScriptCore/icu/unicode/utf_old.h \
- JavaScriptCore/icu/unicode/utypes.h \
- JavaScriptCore/icu/unicode/uversion.h \
- JavaScriptCore/assembler/ARMAssembler.h \
- JavaScriptCore/assembler/ARMAssembler.cpp \
- JavaScriptCore/assembler/X86Assembler.h \
- JavaScriptCore/assembler/AbstractMacroAssembler.h \
- JavaScriptCore/assembler/AssemblerBuffer.h \
- JavaScriptCore/assembler/AssemblerBufferWithConstantPool.h \
- JavaScriptCore/assembler/CodeLocation.h \
- JavaScriptCore/assembler/LinkBuffer.h \
- JavaScriptCore/assembler/MacroAssembler.h \
- JavaScriptCore/assembler/MacroAssemblerARM.h \
- JavaScriptCore/assembler/MacroAssemblerARM.cpp \
- JavaScriptCore/assembler/MacroAssemblerCodeRef.h \
- JavaScriptCore/assembler/MacroAssemblerX86.h \
- JavaScriptCore/assembler/MacroAssemblerX86_64.h \
- JavaScriptCore/assembler/MacroAssemblerX86Common.h \
- JavaScriptCore/assembler/RepatchBuffer.h \
- JavaScriptCore/os-win32/stdbool.h \
- JavaScriptCore/os-win32/stdint.h \
- JavaScriptCore/pcre/pcre.h \
- JavaScriptCore/pcre/pcre_compile.cpp \
- JavaScriptCore/pcre/pcre_exec.cpp \
- JavaScriptCore/pcre/pcre_internal.h \
- JavaScriptCore/pcre/pcre_tables.cpp \
- JavaScriptCore/pcre/pcre_ucp_searchfuncs.cpp \
- JavaScriptCore/pcre/pcre_xclass.cpp \
- JavaScriptCore/pcre/ucpinternal.h \
- JavaScriptCore/profiler/CallIdentifier.h \
- JavaScriptCore/profiler/Profile.cpp \
- JavaScriptCore/profiler/Profile.h \
- JavaScriptCore/profiler/ProfileGenerator.cpp \
- JavaScriptCore/profiler/ProfileGenerator.h \
- JavaScriptCore/profiler/ProfileNode.cpp \
- JavaScriptCore/profiler/ProfileNode.h \
- JavaScriptCore/profiler/Profiler.cpp \
- JavaScriptCore/profiler/Profiler.h \
- JavaScriptCore/interpreter/CachedCall.h \
- JavaScriptCore/interpreter/CallFrame.cpp \
- JavaScriptCore/interpreter/CallFrame.h \
- JavaScriptCore/interpreter/CallFrameClosure.h \
- JavaScriptCore/runtime/ExceptionHelpers.cpp \
- JavaScriptCore/runtime/ExceptionHelpers.h \
- JavaScriptCore/runtime/Executable.cpp \
- JavaScriptCore/runtime/Executable.h \
- JavaScriptCore/runtime/InitializeThreading.cpp \
- JavaScriptCore/runtime/InitializeThreading.h \
- JavaScriptCore/runtime/JSActivation.cpp \
- JavaScriptCore/runtime/JSActivation.h \
- JavaScriptCore/runtime/JSByteArray.cpp \
- JavaScriptCore/runtime/JSByteArray.h \
- JavaScriptCore/runtime/JSGlobalData.cpp \
- JavaScriptCore/runtime/JSGlobalData.h \
- JavaScriptCore/runtime/JSNotAnObject.cpp \
- JavaScriptCore/runtime/JSNotAnObject.h \
- JavaScriptCore/runtime/JSONObject.cpp \
- JavaScriptCore/runtime/JSONObject.h \
- JavaScriptCore/runtime/JSPropertyNameIterator.cpp \
- JavaScriptCore/runtime/JSPropertyNameIterator.h \
- JavaScriptCore/runtime/JSStringBuilder.h \
- JavaScriptCore/runtime/JSZombie.h \
- JavaScriptCore/runtime/LiteralParser.cpp \
- JavaScriptCore/runtime/LiteralParser.h \
- JavaScriptCore/runtime/MarkStack.cpp \
- JavaScriptCore/runtime/MarkStack.h \
- JavaScriptCore/runtime/NumericStrings.h \
- JavaScriptCore/runtime/PropertyDescriptor.h \
- JavaScriptCore/runtime/PropertyDescriptor.cpp \
- JavaScriptCore/runtime/SmallStrings.cpp \
- JavaScriptCore/runtime/SmallStrings.h \
- JavaScriptCore/runtime/StringBuilder.h \
- JavaScriptCore/runtime/Structure.cpp \
- JavaScriptCore/runtime/Structure.h \
- JavaScriptCore/runtime/StructureChain.cpp \
- JavaScriptCore/runtime/StructureChain.h \
- JavaScriptCore/runtime/StructureTransitionTable.h \
- JavaScriptCore/runtime/Terminator.h \
- JavaScriptCore/runtime/TimeoutChecker.cpp \
- JavaScriptCore/runtime/TimeoutChecker.h \
- JavaScriptCore/runtime/JSTypeInfo.h \
- JavaScriptCore/runtime/WeakGCMap.h \
- JavaScriptCore/runtime/WeakGCPtr.h \
- JavaScriptCore/wtf/ASCIICType.h \
- JavaScriptCore/wtf/AVLTree.h \
- JavaScriptCore/wtf/AlwaysInline.h \
- JavaScriptCore/wtf/Assertions.cpp \
- JavaScriptCore/wtf/Assertions.h \
- JavaScriptCore/wtf/Atomics.h \
- JavaScriptCore/wtf/ByteArray.cpp \
- JavaScriptCore/wtf/ByteArray.h \
- JavaScriptCore/wtf/CrossThreadRefCounted.h \
- JavaScriptCore/wtf/CurrentTime.cpp \
- JavaScriptCore/wtf/CurrentTime.h \
- JavaScriptCore/wtf/DateMath.cpp \
- JavaScriptCore/wtf/DateMath.h \
- JavaScriptCore/wtf/Deque.h \
- JavaScriptCore/wtf/DisallowCType.h \
- JavaScriptCore/wtf/Forward.h \
- JavaScriptCore/wtf/GetPtr.h \
- JavaScriptCore/wtf/HashCountedSet.h \
- JavaScriptCore/wtf/HashFunctions.h \
- JavaScriptCore/wtf/HashIterators.h \
- JavaScriptCore/wtf/HashMap.h \
- JavaScriptCore/wtf/HashSet.h \
- JavaScriptCore/wtf/HashTable.cpp \
- JavaScriptCore/wtf/HashTable.h \
- JavaScriptCore/wtf/HashTraits.h \
- JavaScriptCore/wtf/ListHashSet.h \
- JavaScriptCore/wtf/ListRefPtr.h \
- JavaScriptCore/wtf/Locker.h \
- JavaScriptCore/wtf/MD5.cpp \
- JavaScriptCore/wtf/MD5.h \
- JavaScriptCore/wtf/MainThread.cpp \
- JavaScriptCore/wtf/MainThread.h \
- JavaScriptCore/wtf/MathExtras.h \
- JavaScriptCore/wtf/MessageQueue.h \
- JavaScriptCore/wtf/Noncopyable.h \
- JavaScriptCore/wtf/NotFound.h \
- JavaScriptCore/wtf/OwnArrayPtr.h \
- JavaScriptCore/wtf/OwnFastMallocPtr.h \
- JavaScriptCore/wtf/OwnPtr.h \
- JavaScriptCore/wtf/OwnPtrCommon.h \
- JavaScriptCore/wtf/PassOwnPtr.h \
- JavaScriptCore/wtf/PassRefPtr.h \
- JavaScriptCore/wtf/Platform.h \
- JavaScriptCore/wtf/PossiblyNull.h \
- JavaScriptCore/wtf/RandomNumber.cpp \
- JavaScriptCore/wtf/RandomNumber.h \
- JavaScriptCore/wtf/RandomNumberSeed.h \
- JavaScriptCore/wtf/RefCounted.h \
- JavaScriptCore/wtf/RefCountedLeakCounter.cpp \
- JavaScriptCore/wtf/RefCountedLeakCounter.h \
- JavaScriptCore/wtf/RefPtr.h \
- JavaScriptCore/wtf/RefPtrHashMap.h \
- JavaScriptCore/wtf/RetainPtr.h \
- JavaScriptCore/wtf/SegmentedVector.h \
- JavaScriptCore/wtf/StaticConstructors.h \
- JavaScriptCore/wtf/StdLibExtras.h \
- JavaScriptCore/wtf/StringExtras.h \
- JavaScriptCore/wtf/StringHashFunctions.h \
- JavaScriptCore/wtf/TCPackedCache.h \
- JavaScriptCore/wtf/TCPageMap.h \
- JavaScriptCore/wtf/TCSpinLock.h \
- JavaScriptCore/wtf/ThreadIdentifierDataPthreads.cpp \
- JavaScriptCore/wtf/ThreadIdentifierDataPthreads.h \
- JavaScriptCore/wtf/Threading.cpp \
- JavaScriptCore/wtf/Threading.h \
- JavaScriptCore/wtf/ThreadingPrimitives.h \
- JavaScriptCore/wtf/ThreadingPthreads.cpp \
- JavaScriptCore/wtf/ThreadSafeShared.h \
- JavaScriptCore/wtf/ThreadSpecific.h \
- JavaScriptCore/wtf/TypeTraits.cpp \
- JavaScriptCore/wtf/TypeTraits.h \
- JavaScriptCore/wtf/UnusedParam.h \
- JavaScriptCore/wtf/ValueCheck.h \
- JavaScriptCore/wtf/Vector.h \
- JavaScriptCore/wtf/VectorTraits.h \
- JavaScriptCore/wtf/WTFThreadData.cpp \
- JavaScriptCore/wtf/WTFThreadData.h \
- JavaScriptCore/wtf/gobject/GOwnPtr.cpp \
- JavaScriptCore/wtf/gobject/GOwnPtr.h \
- JavaScriptCore/wtf/gobject/GRefPtr.cpp \
- JavaScriptCore/wtf/gobject/GRefPtr.h \
- JavaScriptCore/wtf/gtk/MainThreadGtk.cpp \
- JavaScriptCore/wtf/gtk/ThreadingGtk.cpp \
- JavaScriptCore/wtf/text/AtomicString.cpp \
- JavaScriptCore/wtf/text/AtomicString.h \
- JavaScriptCore/wtf/text/AtomicStringImpl.h \
- JavaScriptCore/wtf/text/CString.cpp \
- JavaScriptCore/wtf/text/CString.h \
- JavaScriptCore/wtf/text/StringHash.h \
- JavaScriptCore/wtf/text/StringImpl.cpp \
- JavaScriptCore/wtf/text/StringImpl.h \
- JavaScriptCore/wtf/text/StringStatics.cpp \
- JavaScriptCore/wtf/text/WTFString.cpp \
- JavaScriptCore/wtf/text/WTFString.h \
- JavaScriptCore/wtf/unicode/Collator.h \
- JavaScriptCore/wtf/unicode/CollatorDefault.cpp \
- JavaScriptCore/wtf/unicode/UTF8.cpp \
- JavaScriptCore/wtf/unicode/UTF8.h \
- JavaScriptCore/wtf/unicode/Unicode.h
+include $(srcdir)/Source/JavaScriptCore/GNUmakefile.list.am
-if TARGET_WIN32
-javascriptcore_sources += \
- JavaScriptCore/wtf/ThreadSpecificWin.cpp \
- JavaScriptCore/jit/ExecutableAllocatorWin.cpp \
- JavaScriptCore/runtime/MarkStackWin.cpp
-else
-javascriptcore_sources += \
- JavaScriptCore/jit/ExecutableAllocatorPosix.cpp \
- JavaScriptCore/runtime/MarkStackPosix.cpp
-endif
+lib_LTLIBRARIES += \
+ libjavascriptcoregtk-@WEBKITGTK_API_MAJOR_VERSION@.@WEBKITGTK_API_MINOR_VERSION@.la
-# ----
-# icu unicode backend
-# ----
-if USE_ICU_UNICODE
-javascriptcore_sources += \
- JavaScriptCore/wtf/unicode/icu/CollatorICU.cpp \
- JavaScriptCore/wtf/unicode/icu/UnicodeIcu.h
-endif # USE_ICU_UNICODE
+# We are going to make everything public for now. When
+# https://bugs.webkit.org/show_bug.cgi?id=27551 is fixed we'll able to
+# simply rely on the usual symbol visibility flags.
+libjavascriptcoregtk_@WEBKITGTK_API_MAJOR_VERSION@_@WEBKITGTK_API_MINOR_VERSION@_la_LDFLAGS = \
+ -version-info @LIBWEBKITGTK_VERSION@ \
+ $(no_undefined)
-# ----
-# glib unicode backend
-# ----
-if USE_GLIB_UNICODE
-javascriptcore_sources += \
- JavaScriptCore/wtf/unicode/glib/UnicodeGLib.h \
- JavaScriptCore/wtf/unicode/glib/UnicodeGLib.cpp \
- JavaScriptCore/wtf/unicode/glib/UnicodeMacrosFromICU.h
-endif
+nodist_EXTRA_libjavascriptcoregtk_@WEBKITGTK_API_MAJOR_VERSION@_@WEBKITGTK_API_MINOR_VERSION@_la_SOURCES = \
+ $(javascriptcore_built_nosources)
-javascriptcore_sources += \
- JavaScriptCore/wtf/VMTags.h \
- JavaScriptCore/yarr/RegexCompiler.cpp \
- JavaScriptCore/yarr/RegexCompiler.h \
- JavaScriptCore/yarr/RegexInterpreter.cpp \
- JavaScriptCore/yarr/RegexInterpreter.h \
- JavaScriptCore/yarr/RegexJIT.cpp \
- JavaScriptCore/yarr/RegexJIT.h \
- JavaScriptCore/yarr/RegexParser.h \
- JavaScriptCore/yarr/RegexPattern.h
+nodist_libjavascriptcoregtk_@WEBKITGTK_API_MAJOR_VERSION@_@WEBKITGTK_API_MINOR_VERSION@_la_SOURCES = \
+ $(javascriptcore_built_sources)
-javascriptcore_sources += \
- JavaScriptCore/interpreter/RegisterFile.cpp \
- JavaScriptCore/interpreter/RegisterFile.h \
- JavaScriptCore/bytecompiler/BytecodeGenerator.cpp \
- JavaScriptCore/bytecompiler/BytecodeGenerator.h \
- JavaScriptCore/bytecompiler/NodesCodegen.cpp \
- JavaScriptCore/bytecompiler/LabelScope.h \
- JavaScriptCore/debugger/Debugger.cpp \
- JavaScriptCore/debugger/Debugger.h \
- JavaScriptCore/parser/Lexer.cpp \
- JavaScriptCore/parser/Lexer.h \
- JavaScriptCore/parser/NodeConstructors.h \
- JavaScriptCore/parser/NodeInfo.h \
- JavaScriptCore/parser/Nodes.cpp \
- JavaScriptCore/parser/Nodes.h \
- JavaScriptCore/parser/Parser.cpp \
- JavaScriptCore/parser/Parser.h \
- JavaScriptCore/parser/ParserArena.cpp \
- JavaScriptCore/parser/ParserArena.h \
- JavaScriptCore/parser/ResultType.h \
- JavaScriptCore/parser/SourceCode.h \
- JavaScriptCore/parser/SourceProvider.h \
- JavaScriptCore/runtime/ArgList.cpp \
- JavaScriptCore/runtime/ArgList.h \
- JavaScriptCore/runtime/Arguments.cpp \
- JavaScriptCore/runtime/Arguments.h \
- JavaScriptCore/runtime/ArrayConstructor.cpp \
- JavaScriptCore/runtime/ArrayConstructor.h \
- JavaScriptCore/runtime/ArrayPrototype.cpp \
- JavaScriptCore/runtime/ArrayPrototype.h \
- JavaScriptCore/runtime/BatchedTransitionOptimizer.h \
- JavaScriptCore/runtime/BooleanConstructor.cpp \
- JavaScriptCore/runtime/BooleanConstructor.h \
- JavaScriptCore/runtime/BooleanObject.cpp \
- JavaScriptCore/runtime/BooleanObject.h \
- JavaScriptCore/runtime/BooleanPrototype.cpp \
- JavaScriptCore/runtime/BooleanPrototype.h \
- JavaScriptCore/runtime/CallData.cpp \
- JavaScriptCore/runtime/CallData.h \
- JavaScriptCore/runtime/ClassInfo.h \
- JavaScriptCore/runtime/Collector.cpp \
- JavaScriptCore/runtime/Collector.h \
- JavaScriptCore/runtime/CollectorHeapIterator.h \
- JavaScriptCore/runtime/CommonIdentifiers.cpp \
- JavaScriptCore/runtime/CommonIdentifiers.h \
- JavaScriptCore/runtime/Completion.h \
- JavaScriptCore/runtime/ConstructData.cpp \
- JavaScriptCore/runtime/ConstructData.h \
- JavaScriptCore/runtime/DateConstructor.cpp \
- JavaScriptCore/runtime/DateConstructor.h \
- JavaScriptCore/runtime/DateConversion.cpp \
- JavaScriptCore/runtime/DateConversion.h \
- JavaScriptCore/runtime/DateInstance.cpp \
- JavaScriptCore/runtime/DateInstance.h \
- JavaScriptCore/runtime/DateInstanceCache.h \
- JavaScriptCore/runtime/DatePrototype.cpp \
- JavaScriptCore/runtime/DatePrototype.h \
- JavaScriptCore/runtime/Error.cpp \
- JavaScriptCore/runtime/Error.h \
- JavaScriptCore/runtime/ErrorConstructor.cpp \
- JavaScriptCore/runtime/ErrorConstructor.h \
- JavaScriptCore/runtime/ErrorInstance.cpp \
- JavaScriptCore/runtime/ErrorInstance.h \
- JavaScriptCore/runtime/ErrorPrototype.cpp \
- JavaScriptCore/runtime/ErrorPrototype.h \
- JavaScriptCore/runtime/FunctionConstructor.cpp \
- JavaScriptCore/runtime/FunctionConstructor.h \
- JavaScriptCore/runtime/FunctionPrototype.cpp \
- JavaScriptCore/runtime/FunctionPrototype.h \
- JavaScriptCore/runtime/GetterSetter.cpp \
- JavaScriptCore/runtime/GetterSetter.h \
- JavaScriptCore/runtime/GlobalEvalFunction.cpp \
- JavaScriptCore/runtime/GlobalEvalFunction.h \
- JavaScriptCore/runtime/Identifier.cpp \
- JavaScriptCore/runtime/Identifier.h \
- JavaScriptCore/runtime/InternalFunction.cpp \
- JavaScriptCore/runtime/InternalFunction.h \
- JavaScriptCore/runtime/Completion.cpp \
- JavaScriptCore/runtime/JSArray.cpp \
- JavaScriptCore/runtime/JSArray.h \
- JavaScriptCore/runtime/JSAPIValueWrapper.cpp \
- JavaScriptCore/runtime/JSAPIValueWrapper.h \
- JavaScriptCore/runtime/JSCell.cpp \
- JavaScriptCore/runtime/JSCell.h \
- JavaScriptCore/runtime/JSFunction.cpp \
- JavaScriptCore/runtime/JSFunction.h \
- JavaScriptCore/runtime/JSGlobalObject.cpp \
- JavaScriptCore/runtime/JSGlobalObject.h \
- JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp \
- JavaScriptCore/runtime/JSGlobalObjectFunctions.h \
- JavaScriptCore/runtime/JSImmediate.cpp \
- JavaScriptCore/runtime/JSImmediate.h \
- JavaScriptCore/runtime/JSLock.cpp \
- JavaScriptCore/runtime/JSLock.h \
- JavaScriptCore/runtime/JSNumberCell.cpp \
- JavaScriptCore/runtime/JSNumberCell.h \
- JavaScriptCore/runtime/JSObject.cpp \
- JavaScriptCore/runtime/JSObject.h \
- JavaScriptCore/runtime/JSStaticScopeObject.cpp \
- JavaScriptCore/runtime/JSStaticScopeObject.h \
- JavaScriptCore/runtime/JSString.cpp \
- JavaScriptCore/runtime/JSString.h \
- JavaScriptCore/runtime/JSType.h \
- JavaScriptCore/runtime/JSValue.cpp \
- JavaScriptCore/runtime/JSValue.h \
- JavaScriptCore/runtime/JSVariableObject.cpp \
- JavaScriptCore/runtime/JSVariableObject.h \
- JavaScriptCore/runtime/JSWrapperObject.cpp \
- JavaScriptCore/runtime/JSWrapperObject.h \
- JavaScriptCore/runtime/Lookup.cpp \
- JavaScriptCore/runtime/Lookup.h \
- JavaScriptCore/runtime/MathObject.cpp \
- JavaScriptCore/runtime/MathObject.h \
- JavaScriptCore/runtime/NativeErrorConstructor.cpp \
- JavaScriptCore/runtime/NativeErrorConstructor.h \
- JavaScriptCore/runtime/NativeErrorPrototype.cpp \
- JavaScriptCore/runtime/NativeErrorPrototype.h \
- JavaScriptCore/runtime/NativeFunctionWrapper.h \
- JavaScriptCore/runtime/NumberConstructor.cpp \
- JavaScriptCore/runtime/NumberConstructor.h \
- JavaScriptCore/runtime/NumberObject.cpp \
- JavaScriptCore/runtime/NumberObject.h \
- JavaScriptCore/runtime/NumberPrototype.cpp \
- JavaScriptCore/runtime/NumberPrototype.h \
- JavaScriptCore/runtime/ObjectConstructor.cpp \
- JavaScriptCore/runtime/ObjectConstructor.h \
- JavaScriptCore/runtime/ObjectPrototype.cpp \
- JavaScriptCore/runtime/ObjectPrototype.h \
- JavaScriptCore/runtime/Operations.cpp \
- JavaScriptCore/runtime/Operations.h \
- JavaScriptCore/runtime/PropertyMapHashTable.h \
- JavaScriptCore/runtime/PropertyNameArray.cpp \
- JavaScriptCore/runtime/PropertyNameArray.h \
- JavaScriptCore/runtime/PropertySlot.cpp \
- JavaScriptCore/runtime/PropertySlot.h \
- JavaScriptCore/runtime/Protect.h \
- JavaScriptCore/runtime/PrototypeFunction.cpp \
- JavaScriptCore/runtime/PrototypeFunction.h \
- JavaScriptCore/runtime/PutPropertySlot.h \
- JavaScriptCore/runtime/RegExp.cpp \
- JavaScriptCore/runtime/RegExp.h \
- JavaScriptCore/runtime/RegExpCache.cpp \
- JavaScriptCore/runtime/RegExpCache.h \
- JavaScriptCore/runtime/RegExpConstructor.cpp \
- JavaScriptCore/runtime/RegExpConstructor.h \
- JavaScriptCore/runtime/RegExpKey.h \
- JavaScriptCore/runtime/RegExpMatchesArray.h \
- JavaScriptCore/runtime/RegExpObject.cpp \
- JavaScriptCore/runtime/RegExpObject.h \
- JavaScriptCore/runtime/RegExpPrototype.cpp \
- JavaScriptCore/runtime/RegExpPrototype.h \
- JavaScriptCore/runtime/RopeImpl.cpp \
- JavaScriptCore/runtime/RopeImpl.h \
- JavaScriptCore/runtime/ScopeChain.cpp \
- JavaScriptCore/runtime/ScopeChain.h \
- JavaScriptCore/runtime/ScopeChainMark.h \
- JavaScriptCore/runtime/StringConstructor.cpp \
- JavaScriptCore/runtime/StringConstructor.h \
- JavaScriptCore/runtime/StringObject.cpp \
- JavaScriptCore/runtime/StringObject.h \
- JavaScriptCore/runtime/StringObjectThatMasqueradesAsUndefined.h \
- JavaScriptCore/runtime/StringPrototype.cpp \
- JavaScriptCore/runtime/StringPrototype.h \
- JavaScriptCore/runtime/SymbolTable.h \
- JavaScriptCore/runtime/Tracing.h \
- JavaScriptCore/runtime/UString.cpp \
- JavaScriptCore/runtime/UString.h \
- JavaScriptCore/runtime/UStringImpl.h \
- JavaScriptCore/runtime/WeakRandom.h \
- JavaScriptCore/wtf/FastAllocBase.h \
- JavaScriptCore/wtf/FastMalloc.cpp \
- JavaScriptCore/wtf/FastMalloc.h \
- JavaScriptCore/wtf/MallocZoneSupport.h \
- JavaScriptCore/wtf/TCSystemAlloc.cpp \
- JavaScriptCore/wtf/TCSystemAlloc.h \
- JavaScriptCore/wtf/dtoa.cpp \
- JavaScriptCore/wtf/dtoa.h
+libjavascriptcoregtk_@WEBKITGTK_API_MAJOR_VERSION@_@WEBKITGTK_API_MINOR_VERSION@_ladir = $(prefix)/include/webkit-@WEBKITGTK_API_VERSION@/JavaScriptCore
+libjavascriptcoregtk_@WEBKITGTK_API_MAJOR_VERSION@_@WEBKITGTK_API_MINOR_VERSION@_la_HEADERS = $(javascriptcore_h_api)
-javascriptcore_built_sources += \
- DerivedSources/Grammar.cpp \
- DerivedSources/Grammar.h
+libjavascriptcoregtk_@WEBKITGTK_API_MAJOR_VERSION@_@WEBKITGTK_API_MINOR_VERSION@_la_SOURCES = \
+ $(javascriptcore_sources)
-DerivedSources/Grammar.h: DerivedSources/Grammar.cpp;
+libjavascriptcoregtk_@WEBKITGTK_API_MAJOR_VERSION@_@WEBKITGTK_API_MINOR_VERSION@_la_LIBADD = \
+ $(UNICODE_LIBS) \
+ $(GLIB_LIBS) \
+ $(WINMM_LIBS) \
+ -lpthread
-DerivedSources/Grammar.cpp: $(srcdir)/JavaScriptCore/parser/Grammar.y
- $(BISON) -d -p jscyy $(srcdir)/JavaScriptCore/parser/Grammar.y -o $@ > bison_out.txt 2>&1
- $(PERL) -p -e 'END { if ($$conflict) { unlink "Grammar.cpp"; die; } } $$conflict ||= /conflict/' < bison_out.txt
- cat $(GENSOURCES)/Grammar.hpp > $(GENSOURCES)/Grammar.h
- rm -f $(GENSOURCES)/Grammar.hpp bison_out.txt
-
-DerivedSources/Lexer.lut.h: $(CREATE_HASH_TABLE) $(srcdir)/JavaScriptCore/parser/Keywords.table
- $(PERL) $^ > $@
+libjavascriptcoregtk_@WEBKITGTK_API_MAJOR_VERSION@_@WEBKITGTK_API_MINOR_VERSION@_la_CXXFLAGS = \
+ $(global_cxxflags) \
+ $(libjavascriptcoregtk_@WEBKITGTK_API_MAJOR_VERSION@_@WEBKITGTK_API_MINOR_VERSION@_la_CFLAGS)
-JavaScriptCore/%.lut.h: $(CREATE_HASH_TABLE) $(srcdir)/JavaScriptCore/%.cpp
- $(PERL) $^ -i > $@
+libjavascriptcoregtk_@WEBKITGTK_API_MAJOR_VERSION@_@WEBKITGTK_API_MINOR_VERSION@_la_CFLAGS = \
+ -fstrict-aliasing \
+ -O3 \
+ $(global_cflags) \
+ $(GLIB_CFLAGS) \
+ $(UNICODE_CFLAGS)
-JavaScriptCore/RegExpJitTables.h: $(srcdir)/JavaScriptCore/create_regex_tables
- $(PYTHON) $(srcdir)/JavaScriptCore/create_regex_tables > $@
+libjavascriptcoregtk_@WEBKITGTK_API_MAJOR_VERSION@_@WEBKITGTK_API_MINOR_VERSION@_la_CPPFLAGS = \
+ $(global_cppflags) \
+ $(javascriptcore_cppflags)
-JavaScriptCore/pcre/chartables.c: $(srcdir)/JavaScriptCore/pcre/dftables
- $(PERL) $^ $@
+javascriptcore_cppflags += \
+ -I$(srcdir)/Source \
+ -I$(srcdir)/Source/JavaScriptCore \
+ -I$(srcdir)/Source/JavaScriptCore/API \
+ -I$(srcdir)/Source/JavaScriptCore/assembler \
+ -I$(srcdir)/Source/JavaScriptCore/bytecode \
+ -I$(srcdir)/Source/JavaScriptCore/bytecompiler \
+ -I$(srcdir)/Source/JavaScriptCore/heap \
+ -I$(srcdir)/Source/JavaScriptCore/debugger \
+ -I$(srcdir)/Source/JavaScriptCore/ForwardingHeaders \
+ -I$(srcdir)/Source/JavaScriptCore/interpreter \
+ -I$(srcdir)/Source/JavaScriptCore/jit \
+ -I$(srcdir)/Source/JavaScriptCore/jit \
+ -I$(srcdir)/Source/JavaScriptCore/parser \
+ -I$(srcdir)/Source/JavaScriptCore/profiler \
+ -I$(srcdir)/Source/JavaScriptCore/runtime \
+ -I$(srcdir)/Source/JavaScriptCore/wtf \
+ -I$(srcdir)/Source/JavaScriptCore/wtf \
+ -I$(srcdir)/Source/JavaScriptCore/wtf/gobject \
+ -I$(srcdir)/Source/JavaScriptCore/wtf/gtk \
+ -I$(srcdir)/Source/JavaScriptCore/wtf/text \
+ -I$(srcdir)/Source/JavaScriptCore/wtf/unicode \
+ -I$(srcdir)/Source/JavaScriptCore/yarr \
+ -I$(top_builddir)/Source/JavaScriptCore \
+ -I$(top_builddir)/Source/JavaScriptCore/parser \
+ -I$(top_builddir)/Source/JavaScriptCore/runtime
+
+Source/JavaScriptCore/Lexer.lut.h: $(srcdir)/Source/JavaScriptCore/create_hash_table $(srcdir)/Source/JavaScriptCore/parser/Keywords.table
+ $(AM_V_GEN)$(PERL) $^ > $@
+
+Source/JavaScriptCore/%.lut.h: $(srcdir)/Source/JavaScriptCore/create_hash_table $(srcdir)/Source/JavaScriptCore/%.cpp
+ $(AM_V_GEN)$(PERL) $^ -i > $@
+
+Source/JavaScriptCore/RegExpJitTables.h: $(srcdir)/Source/JavaScriptCore/create_regex_tables
+ $(AM_V_GEN)$(PYTHON) $^ > $@
+
+Source/JavaScriptCore/KeywordLookup.h: $(srcdir)/Source/JavaScriptCore/KeywordLookupGenerator.py $(srcdir)/Source/JavaScriptCore/parser/Keywords.table
+ $(AM_V_GEN)$(PYTHON) $^ > $@
+
+jsc: $(javascriptcore_built_nosources) Programs/jsc$(EXEEXT)
bin_PROGRAMS += \
- Programs/jsc
+ Programs/jsc-@WEBKITGTK_API_MAJOR_VERSION@$(EXEEXT)
noinst_PROGRAMS += \
+ Programs/jsc \
Programs/minidom
-# minidom
-Programs_minidom_SOURCES = \
- JavaScriptCore/API/tests/JSNode.c \
- JavaScriptCore/API/tests/JSNode.h \
- JavaScriptCore/API/tests/JSNodeList.c \
- JavaScriptCore/API/tests/JSNodeList.h \
- JavaScriptCore/API/tests/Node.c \
- JavaScriptCore/API/tests/Node.h \
- JavaScriptCore/API/tests/NodeList.c \
- JavaScriptCore/API/tests/NodeList.h \
- JavaScriptCore/API/tests/minidom.c
-
Programs_minidom_CPPFLAGS = \
$(global_cppflags) \
$(javascriptcore_cppflags)
$(GLOBALDEPS_CFLAGS)
Programs_minidom_LDADD = \
- libJavaScriptCore.la \
- -lm \
- -lstdc++
+ libjavascriptcoregtk-@WEBKITGTK_API_MAJOR_VERSION@.@WEBKITGTK_API_MINOR_VERSION@.la \
+ $(WINMM_LIBS) \
+ -lm \
+ -lpthread \
+ -lstdc++
Programs_minidom_LDFLAGS = \
-no-install \
-no-fast-install
# jsc
-Programs_jsc_SOURCES = \
- JavaScriptCore/jsc.cpp
+Programs/jsc$(EXEEXT): Programs/jsc-@WEBKITGTK_API_MAJOR_VERSION@$(EXEEXT)
+ $(AM_V_GEN)cp -f Programs/jsc-@WEBKITGTK_API_MAJOR_VERSION@$(EXEEXT) Programs/jsc$(EXEEXT)
+Programs_jsc_LDADD =
+Programs_jsc_SOURCES =
-Programs_jsc_CPPFLAGS = \
+Programs_jsc_@WEBKITGTK_API_MAJOR_VERSION@_CPPFLAGS = \
$(global_cppflags) \
$(javascriptcore_cppflags)
-Programs_jsc_CXXFLAGS = \
+Programs_jsc_@WEBKITGTK_API_MAJOR_VERSION@_CXXFLAGS = \
-fno-strict-aliasing \
$(global_cxxflags) \
$(global_cflags) \
$(GLOBALDEPS_CFLAGS) \
$(UNICODE_CFLAGS)
-Programs_jsc_LDADD = \
- libJavaScriptCore.la
-
-javascriptcore_dist += \
- $(CREATE_HASH_TABLE) \
- $(CREATE_REGEXP_TABLES) \
- JavaScriptCore/AUTHORS \
- JavaScriptCore/COPYING.LIB \
- JavaScriptCore/ChangeLog \
- JavaScriptCore/THANKS \
- JavaScriptCore/icu/LICENSE \
- JavaScriptCore/icu/README \
- JavaScriptCore/pcre/COPYING \
- JavaScriptCore/pcre/AUTHORS \
- JavaScriptCore/pcre/dftables \
- JavaScriptCore/pcre/ucptable.cpp \
- JavaScriptCore/parser/Grammar.y \
- JavaScriptCore/parser/Keywords.table
+Programs_jsc_@WEBKITGTK_API_MAJOR_VERSION@_LDADD = \
+ -lpthread \
+ libjavascriptcoregtk-@WEBKITGTK_API_MAJOR_VERSION@.@WEBKITGTK_API_MINOR_VERSION@.la \
+ $(WINMM_LIBS)
+
+EXTRA_DIST += \
+ Source/JavaScriptCore/AUTHORS \
+ Source/JavaScriptCore/ChangeLog \
+ Source/JavaScriptCore/COPYING.LIB \
+ Source/JavaScriptCore/create_hash_table \
+ Source/JavaScriptCore/create_regex_tables \
+ Source/JavaScriptCore/icu/LICENSE \
+ Source/JavaScriptCore/icu/README \
+ Source/JavaScriptCore/parser/Keywords.table \
+ Source/JavaScriptCore/THANKS
# Clean rules for JavaScriptCore
+# FIXME: Should this list be generated from javascriptcore_built_nosources?
CLEANFILES += \
- JavaScriptCore/runtime/ArrayPrototype.lut.h \
- JavaScriptCore/runtime/DatePrototype.lut.h \
- JavaScriptCore/runtime/JSONObject.lut.h \
- JavaScriptCore/runtime/MathObject.lut.h \
- JavaScriptCore/runtime/NumberConstructor.lut.h \
- JavaScriptCore/runtime/RegExpConstructor.lut.h \
- JavaScriptCore/runtime/RegExpObject.lut.h \
- JavaScriptCore/runtime/StringPrototype.lut.h \
- JavaScriptCore/pcre/chartables.c \
+ Source/JavaScriptCore/Lexer.lut.h \
+ Source/JavaScriptCore/RegExpJitTables.h \
+ Source/JavaScriptCore/runtime/ArrayConstructor.lut.h \
+ Source/JavaScriptCore/runtime/ArrayPrototype.lut.h \
+ Source/JavaScriptCore/runtime/BooleanPrototype.lut.h \
+ Source/JavaScriptCore/runtime/DateConstructor.lut.h \
+ Source/JavaScriptCore/runtime/DatePrototype.lut.h \
+ Source/JavaScriptCore/runtime/ErrorPrototype.lut.h \
+ Source/JavaScriptCore/runtime/JSGlobalObject.lut.h \
+ Source/JavaScriptCore/runtime/JSONObject.lut.h \
+ Source/JavaScriptCore/runtime/MathObject.lut.h \
+ Source/JavaScriptCore/runtime/NumberConstructor.lut.h \
+ Source/JavaScriptCore/runtime/NumberPrototype.lut.h \
+ Source/JavaScriptCore/runtime/ObjectConstructor.lut.h \
+ Source/JavaScriptCore/runtime/ObjectPrototype.lut.h \
+ Source/JavaScriptCore/runtime/RegExpConstructor.lut.h \
+ Source/JavaScriptCore/runtime/RegExpObject.lut.h \
+ Source/JavaScriptCore/runtime/RegExpPrototype.lut.h \
+ Source/JavaScriptCore/runtime/StringConstructor.lut.h \
+ Source/JavaScriptCore/runtime/StringPrototype.lut.h \
Programs/jsc \
+ Programs/jsc-@WEBKITGTK_API_MAJOR_VERSION@ \
Programs/minidom
--- /dev/null
+javascriptcore_h_api += \
+ Source/JavaScriptCore/API/JSBase.h \
+ Source/JavaScriptCore/API/JSContextRef.h \
+ Source/JavaScriptCore/API/JSObjectRef.h \
+ Source/JavaScriptCore/API/JSStringRef.h \
+ Source/JavaScriptCore/API/JSStringRefBSTR.h \
+ Source/JavaScriptCore/API/JSStringRefCF.h \
+ Source/JavaScriptCore/API/JSValueRef.h \
+ Source/JavaScriptCore/API/JavaScript.h \
+ Source/JavaScriptCore/API/JavaScriptCore.h \
+ Source/JavaScriptCore/API/WebKitAvailability.h
+
+javascriptcore_built_nosources += \
+ Source/JavaScriptCore/Lexer.lut.h \
+ Source/JavaScriptCore/RegExpJitTables.h \
+ Source/JavaScriptCore/runtime/ArrayConstructor.lut.h \
+ Source/JavaScriptCore/runtime/ArrayPrototype.lut.h \
+ Source/JavaScriptCore/runtime/BooleanPrototype.lut.h \
+ Source/JavaScriptCore/runtime/DateConstructor.lut.h \
+ Source/JavaScriptCore/runtime/DatePrototype.lut.h \
+ Source/JavaScriptCore/runtime/ErrorPrototype.lut.h \
+ Source/JavaScriptCore/runtime/JSGlobalObject.lut.h \
+ Source/JavaScriptCore/runtime/JSONObject.lut.h \
+ Source/JavaScriptCore/runtime/MathObject.lut.h \
+ Source/JavaScriptCore/runtime/NumberConstructor.lut.h \
+ Source/JavaScriptCore/runtime/NumberPrototype.lut.h \
+ Source/JavaScriptCore/runtime/ObjectConstructor.lut.h \
+ Source/JavaScriptCore/runtime/ObjectPrototype.lut.h \
+ Source/JavaScriptCore/runtime/RegExpConstructor.lut.h \
+ Source/JavaScriptCore/runtime/RegExpObject.lut.h \
+ Source/JavaScriptCore/runtime/RegExpPrototype.lut.h \
+ Source/JavaScriptCore/runtime/StringConstructor.lut.h \
+ Source/JavaScriptCore/runtime/StringPrototype.lut.h
+
+javascriptcore_sources += \
+ Source/JavaScriptCore/API/APICast.h \
+ Source/JavaScriptCore/API/APIShims.h \
+ Source/JavaScriptCore/API/JSBase.cpp \
+ Source/JavaScriptCore/API/JSBasePrivate.h \
+ Source/JavaScriptCore/API/JSCallbackConstructor.cpp \
+ Source/JavaScriptCore/API/JSCallbackConstructor.h \
+ Source/JavaScriptCore/API/JSCallbackFunction.cpp \
+ Source/JavaScriptCore/API/JSCallbackFunction.h \
+ Source/JavaScriptCore/API/JSCallbackObject.cpp \
+ Source/JavaScriptCore/API/JSCallbackObjectFunctions.h \
+ Source/JavaScriptCore/API/JSCallbackObject.h \
+ Source/JavaScriptCore/API/JSClassRef.cpp \
+ Source/JavaScriptCore/API/JSClassRef.h \
+ Source/JavaScriptCore/API/JSContextRef.cpp \
+ Source/JavaScriptCore/API/JSContextRefPrivate.h \
+ Source/JavaScriptCore/API/JSObjectRef.cpp \
+ Source/JavaScriptCore/API/JSObjectRefPrivate.h \
+ Source/JavaScriptCore/API/JSRetainPtr.h \
+ Source/JavaScriptCore/API/JSStringRef.cpp \
+ Source/JavaScriptCore/API/JSValueRef.cpp \
+ Source/JavaScriptCore/API/JSWeakObjectMapRefInternal.h \
+ Source/JavaScriptCore/API/OpaqueJSString.cpp \
+ Source/JavaScriptCore/API/OpaqueJSString.h \
+ Source/JavaScriptCore/assembler/AbstractMacroAssembler.h \
+ Source/JavaScriptCore/assembler/ARMAssembler.cpp \
+ Source/JavaScriptCore/assembler/ARMAssembler.h \
+ Source/JavaScriptCore/assembler/ARMv7Assembler.cpp \
+ Source/JavaScriptCore/assembler/ARMv7Assembler.h \
+ Source/JavaScriptCore/assembler/AssemblerBuffer.h \
+ Source/JavaScriptCore/assembler/AssemblerBufferWithConstantPool.h \
+ Source/JavaScriptCore/assembler/CodeLocation.h \
+ Source/JavaScriptCore/assembler/LinkBuffer.h \
+ Source/JavaScriptCore/assembler/MacroAssemblerARM.cpp \
+ Source/JavaScriptCore/assembler/MacroAssemblerARM.h \
+ Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h \
+ Source/JavaScriptCore/assembler/MacroAssemblerCodeRef.h \
+ Source/JavaScriptCore/assembler/MacroAssembler.h \
+ Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h \
+ Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h \
+ Source/JavaScriptCore/assembler/MacroAssemblerX86.h \
+ Source/JavaScriptCore/assembler/MacroAssemblerSH4.h \
+ Source/JavaScriptCore/assembler/MacroAssemblerSH4.cpp \
+ Source/JavaScriptCore/assembler/SH4Assembler.h \
+ Source/JavaScriptCore/assembler/RepatchBuffer.h \
+ Source/JavaScriptCore/assembler/X86Assembler.h \
+ Source/JavaScriptCore/bytecode/CodeBlock.cpp \
+ Source/JavaScriptCore/bytecode/CodeBlock.h \
+ Source/JavaScriptCore/bytecode/EvalCodeCache.h \
+ Source/JavaScriptCore/bytecode/Instruction.h \
+ Source/JavaScriptCore/bytecode/JumpTable.cpp \
+ Source/JavaScriptCore/bytecode/JumpTable.h \
+ Source/JavaScriptCore/bytecode/Opcode.cpp \
+ Source/JavaScriptCore/bytecode/Opcode.h \
+ Source/JavaScriptCore/bytecode/SamplingTool.cpp \
+ Source/JavaScriptCore/bytecode/SamplingTool.h \
+ Source/JavaScriptCore/bytecode/StructureStubInfo.cpp \
+ Source/JavaScriptCore/bytecode/StructureStubInfo.h \
+ Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp \
+ Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h \
+ Source/JavaScriptCore/bytecompiler/Label.h \
+ Source/JavaScriptCore/bytecompiler/LabelScope.h \
+ Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp \
+ Source/JavaScriptCore/bytecompiler/RegisterID.h \
+ Source/JavaScriptCore/heap/ConservativeRoots.cpp \
+ Source/JavaScriptCore/heap/ConservativeRoots.h \
+ Source/JavaScriptCore/heap/Handle.h \
+ Source/JavaScriptCore/heap/HandleHeap.cpp \
+ Source/JavaScriptCore/heap/HandleHeap.h \
+ Source/JavaScriptCore/heap/HandleStack.cpp \
+ Source/JavaScriptCore/heap/HandleStack.h \
+ Source/JavaScriptCore/heap/HandleTypes.h \
+ Source/JavaScriptCore/heap/Heap.cpp \
+ Source/JavaScriptCore/heap/Heap.h \
+ Source/JavaScriptCore/heap/Local.h \
+ Source/JavaScriptCore/heap/LocalScope.h \
+ Source/JavaScriptCore/heap/MachineStackMarker.cpp \
+ Source/JavaScriptCore/heap/MachineStackMarker.h \
+ Source/JavaScriptCore/heap/MarkStack.cpp \
+ Source/JavaScriptCore/heap/MarkStack.h \
+ Source/JavaScriptCore/heap/MarkedBlock.cpp \
+ Source/JavaScriptCore/heap/MarkedBlock.h \
+ Source/JavaScriptCore/heap/MarkedSpace.cpp \
+ Source/JavaScriptCore/heap/MarkedSpace.h \
+ Source/JavaScriptCore/heap/Strong.h \
+ Source/JavaScriptCore/heap/Weak.h \
+ Source/JavaScriptCore/config.h \
+ Source/JavaScriptCore/debugger/DebuggerActivation.cpp \
+ Source/JavaScriptCore/debugger/DebuggerActivation.h \
+ Source/JavaScriptCore/debugger/DebuggerCallFrame.cpp \
+ Source/JavaScriptCore/debugger/DebuggerCallFrame.h \
+ Source/JavaScriptCore/debugger/Debugger.cpp \
+ Source/JavaScriptCore/debugger/Debugger.h \
+ Source/JavaScriptCore/ForwardingHeaders/JavaScriptCore/APICast.h \
+ Source/JavaScriptCore/ForwardingHeaders/JavaScriptCore/APIShims.h \
+ Source/JavaScriptCore/ForwardingHeaders/JavaScriptCore/JavaScriptCore.h \
+ Source/JavaScriptCore/ForwardingHeaders/JavaScriptCore/JavaScript.h \
+ Source/JavaScriptCore/ForwardingHeaders/JavaScriptCore/JSBase.h \
+ Source/JavaScriptCore/ForwardingHeaders/JavaScriptCore/JSContextRef.h \
+ Source/JavaScriptCore/ForwardingHeaders/JavaScriptCore/JSObjectRef.h \
+ Source/JavaScriptCore/ForwardingHeaders/JavaScriptCore/JSRetainPtr.h \
+ Source/JavaScriptCore/ForwardingHeaders/JavaScriptCore/JSStringRefCF.h \
+ Source/JavaScriptCore/ForwardingHeaders/JavaScriptCore/JSStringRef.h \
+ Source/JavaScriptCore/ForwardingHeaders/JavaScriptCore/JSValueRef.h \
+ Source/JavaScriptCore/ForwardingHeaders/JavaScriptCore/OpaqueJSString.h \
+ Source/JavaScriptCore/ForwardingHeaders/JavaScriptCore/WebKitAvailability.h \
+ Source/JavaScriptCore/icu/unicode/parseerr.h \
+ Source/JavaScriptCore/icu/unicode/platform.h \
+ Source/JavaScriptCore/icu/unicode/putil.h \
+ Source/JavaScriptCore/icu/unicode/uchar.h \
+ Source/JavaScriptCore/icu/unicode/ucnv_err.h \
+ Source/JavaScriptCore/icu/unicode/ucnv.h \
+ Source/JavaScriptCore/icu/unicode/ucol.h \
+ Source/JavaScriptCore/icu/unicode/uconfig.h \
+ Source/JavaScriptCore/icu/unicode/uenum.h \
+ Source/JavaScriptCore/icu/unicode/uiter.h \
+ Source/JavaScriptCore/icu/unicode/uloc.h \
+ Source/JavaScriptCore/icu/unicode/umachine.h \
+ Source/JavaScriptCore/icu/unicode/unorm.h \
+ Source/JavaScriptCore/icu/unicode/urename.h \
+ Source/JavaScriptCore/icu/unicode/uset.h \
+ Source/JavaScriptCore/icu/unicode/ustring.h \
+ Source/JavaScriptCore/icu/unicode/utf16.h \
+ Source/JavaScriptCore/icu/unicode/utf8.h \
+ Source/JavaScriptCore/icu/unicode/utf.h \
+ Source/JavaScriptCore/icu/unicode/utf_old.h \
+ Source/JavaScriptCore/icu/unicode/utypes.h \
+ Source/JavaScriptCore/icu/unicode/uversion.h \
+ Source/JavaScriptCore/interpreter/CachedCall.h \
+ Source/JavaScriptCore/interpreter/CallFrameClosure.h \
+ Source/JavaScriptCore/interpreter/CallFrame.cpp \
+ Source/JavaScriptCore/interpreter/CallFrame.h \
+ Source/JavaScriptCore/interpreter/Interpreter.cpp \
+ Source/JavaScriptCore/interpreter/Interpreter.h \
+ Source/JavaScriptCore/interpreter/RegisterFile.cpp \
+ Source/JavaScriptCore/interpreter/RegisterFile.h \
+ Source/JavaScriptCore/interpreter/Register.h \
+ Source/JavaScriptCore/JavaScriptCorePrefix.h \
+ Source/JavaScriptCore/jit/ExecutableAllocator.cpp \
+ Source/JavaScriptCore/jit/ExecutableAllocator.h \
+ Source/JavaScriptCore/jit/JITArithmetic32_64.cpp \
+ Source/JavaScriptCore/jit/JITArithmetic.cpp \
+ Source/JavaScriptCore/jit/JITCall32_64.cpp \
+ Source/JavaScriptCore/jit/JITCall.cpp \
+ Source/JavaScriptCore/jit/JITCode.h \
+ Source/JavaScriptCore/jit/JIT.cpp \
+ Source/JavaScriptCore/jit/JIT.h \
+ Source/JavaScriptCore/jit/JITInlineMethods.h \
+ Source/JavaScriptCore/jit/JITOpcodes32_64.cpp \
+ Source/JavaScriptCore/jit/JITOpcodes.cpp \
+ Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp \
+ Source/JavaScriptCore/jit/JITPropertyAccess.cpp \
+ Source/JavaScriptCore/jit/JITStubCall.h \
+ Source/JavaScriptCore/jit/JITStubs.cpp \
+ Source/JavaScriptCore/jit/JITStubs.h \
+ Source/JavaScriptCore/jit/JSInterfaceJIT.h \
+ Source/JavaScriptCore/jit/SpecializedThunkJIT.h \
+ Source/JavaScriptCore/jit/ThunkGenerators.cpp \
+ Source/JavaScriptCore/jit/ThunkGenerators.h \
+ Source/JavaScriptCore/os-win32/stdbool.h \
+ Source/JavaScriptCore/os-win32/stdint.h \
+ Source/JavaScriptCore/parser/ASTBuilder.h \
+ Source/JavaScriptCore/parser/JSParser.cpp \
+ Source/JavaScriptCore/parser/JSParser.h \
+ Source/JavaScriptCore/parser/Lexer.cpp \
+ Source/JavaScriptCore/parser/Lexer.h \
+ Source/JavaScriptCore/parser/NodeConstructors.h \
+ Source/JavaScriptCore/parser/NodeInfo.h \
+ Source/JavaScriptCore/parser/Nodes.cpp \
+ Source/JavaScriptCore/parser/Nodes.h \
+ Source/JavaScriptCore/parser/ParserArena.cpp \
+ Source/JavaScriptCore/parser/ParserArena.h \
+ Source/JavaScriptCore/parser/Parser.cpp \
+ Source/JavaScriptCore/parser/Parser.h \
+ Source/JavaScriptCore/parser/ResultType.h \
+ Source/JavaScriptCore/parser/SourceCode.h \
+ Source/JavaScriptCore/parser/SourceProvider.h \
+ Source/JavaScriptCore/parser/SourceProviderCache.cpp \
+ Source/JavaScriptCore/parser/SourceProviderCache.h \
+ Source/JavaScriptCore/parser/SourceProviderCacheItem.h \
+ Source/JavaScriptCore/parser/SyntaxChecker.h \
+ Source/JavaScriptCore/profiler/CallIdentifier.h \
+ Source/JavaScriptCore/profiler/Profile.cpp \
+ Source/JavaScriptCore/profiler/ProfileGenerator.cpp \
+ Source/JavaScriptCore/profiler/ProfileGenerator.h \
+ Source/JavaScriptCore/profiler/Profile.h \
+ Source/JavaScriptCore/profiler/ProfileNode.cpp \
+ Source/JavaScriptCore/profiler/ProfileNode.h \
+ Source/JavaScriptCore/profiler/Profiler.cpp \
+ Source/JavaScriptCore/profiler/Profiler.h \
+ Source/JavaScriptCore/runtime/ArgList.cpp \
+ Source/JavaScriptCore/runtime/ArgList.h \
+ Source/JavaScriptCore/runtime/Arguments.cpp \
+ Source/JavaScriptCore/runtime/Arguments.h \
+ Source/JavaScriptCore/runtime/ArrayConstructor.cpp \
+ Source/JavaScriptCore/runtime/ArrayConstructor.h \
+ Source/JavaScriptCore/runtime/ArrayPrototype.cpp \
+ Source/JavaScriptCore/runtime/ArrayPrototype.h \
+ Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h \
+ Source/JavaScriptCore/runtime/BooleanConstructor.cpp \
+ Source/JavaScriptCore/runtime/BooleanConstructor.h \
+ Source/JavaScriptCore/runtime/BooleanObject.cpp \
+ Source/JavaScriptCore/runtime/BooleanObject.h \
+ Source/JavaScriptCore/runtime/BooleanPrototype.cpp \
+ Source/JavaScriptCore/runtime/BooleanPrototype.h \
+ Source/JavaScriptCore/runtime/CachedTranscendentalFunction.h \
+ Source/JavaScriptCore/runtime/CallData.cpp \
+ Source/JavaScriptCore/runtime/CallData.h \
+ Source/JavaScriptCore/runtime/ClassInfo.h \
+ Source/JavaScriptCore/runtime/CommonIdentifiers.cpp \
+ Source/JavaScriptCore/runtime/CommonIdentifiers.h \
+ Source/JavaScriptCore/runtime/Completion.cpp \
+ Source/JavaScriptCore/runtime/Completion.h \
+ Source/JavaScriptCore/runtime/ConstructData.cpp \
+ Source/JavaScriptCore/runtime/ConstructData.h \
+ Source/JavaScriptCore/runtime/DateConstructor.cpp \
+ Source/JavaScriptCore/runtime/DateConstructor.h \
+ Source/JavaScriptCore/runtime/DateConversion.cpp \
+ Source/JavaScriptCore/runtime/DateConversion.h \
+ Source/JavaScriptCore/runtime/DateInstanceCache.h \
+ Source/JavaScriptCore/runtime/DateInstance.cpp \
+ Source/JavaScriptCore/runtime/DateInstance.h \
+ Source/JavaScriptCore/runtime/DatePrototype.cpp \
+ Source/JavaScriptCore/runtime/DatePrototype.h \
+ Source/JavaScriptCore/runtime/ErrorConstructor.cpp \
+ Source/JavaScriptCore/runtime/ErrorConstructor.h \
+ Source/JavaScriptCore/runtime/Error.cpp \
+ Source/JavaScriptCore/runtime/Error.h \
+ Source/JavaScriptCore/runtime/ErrorInstance.cpp \
+ Source/JavaScriptCore/runtime/ErrorInstance.h \
+ Source/JavaScriptCore/runtime/ErrorPrototype.cpp \
+ Source/JavaScriptCore/runtime/ErrorPrototype.h \
+ Source/JavaScriptCore/runtime/ExceptionHelpers.cpp \
+ Source/JavaScriptCore/runtime/ExceptionHelpers.h \
+ Source/JavaScriptCore/runtime/Executable.cpp \
+ Source/JavaScriptCore/runtime/Executable.h \
+ Source/JavaScriptCore/runtime/FunctionConstructor.cpp \
+ Source/JavaScriptCore/runtime/FunctionConstructor.h \
+ Source/JavaScriptCore/runtime/FunctionPrototype.cpp \
+ Source/JavaScriptCore/runtime/FunctionPrototype.h \
+ Source/JavaScriptCore/runtime/GCActivityCallback.cpp \
+ Source/JavaScriptCore/runtime/GCActivityCallback.h \
+ Source/JavaScriptCore/runtime/GetterSetter.cpp \
+ Source/JavaScriptCore/runtime/GetterSetter.h \
+ Source/JavaScriptCore/runtime/Identifier.cpp \
+ Source/JavaScriptCore/runtime/Identifier.h \
+ Source/JavaScriptCore/runtime/InitializeThreading.cpp \
+ Source/JavaScriptCore/runtime/InitializeThreading.h \
+ Source/JavaScriptCore/runtime/InternalFunction.cpp \
+ Source/JavaScriptCore/runtime/InternalFunction.h \
+ Source/JavaScriptCore/runtime/JSActivation.cpp \
+ Source/JavaScriptCore/runtime/JSActivation.h \
+ Source/JavaScriptCore/runtime/JSAPIValueWrapper.cpp \
+ Source/JavaScriptCore/runtime/JSAPIValueWrapper.h \
+ Source/JavaScriptCore/runtime/JSArray.cpp \
+ Source/JavaScriptCore/runtime/JSArray.h \
+ Source/JavaScriptCore/runtime/JSByteArray.cpp \
+ Source/JavaScriptCore/runtime/JSByteArray.h \
+ Source/JavaScriptCore/runtime/JSCell.cpp \
+ Source/JavaScriptCore/runtime/JSCell.h \
+ Source/JavaScriptCore/runtime/JSFunction.cpp \
+ Source/JavaScriptCore/runtime/JSFunction.h \
+ Source/JavaScriptCore/runtime/JSGlobalData.cpp \
+ Source/JavaScriptCore/runtime/JSGlobalData.h \
+ Source/JavaScriptCore/runtime/JSGlobalObject.cpp \
+ Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp \
+ Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.h \
+ Source/JavaScriptCore/runtime/JSGlobalObject.h \
+ Source/JavaScriptCore/runtime/JSLock.cpp \
+ Source/JavaScriptCore/runtime/JSLock.h \
+ Source/JavaScriptCore/runtime/JSNotAnObject.cpp \
+ Source/JavaScriptCore/runtime/JSNotAnObject.h \
+ Source/JavaScriptCore/runtime/JSObject.cpp \
+ Source/JavaScriptCore/runtime/JSObject.h \
+ Source/JavaScriptCore/runtime/JSObjectWithGlobalObject.cpp \
+ Source/JavaScriptCore/runtime/JSObjectWithGlobalObject.h \
+ Source/JavaScriptCore/runtime/JSONObject.cpp \
+ Source/JavaScriptCore/runtime/JSONObject.h \
+ Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp \
+ Source/JavaScriptCore/runtime/JSPropertyNameIterator.h \
+ Source/JavaScriptCore/runtime/JSStaticScopeObject.cpp \
+ Source/JavaScriptCore/runtime/JSStaticScopeObject.h \
+ Source/JavaScriptCore/runtime/JSStringBuilder.h \
+ Source/JavaScriptCore/runtime/JSString.cpp \
+ Source/JavaScriptCore/runtime/JSString.h \
+ Source/JavaScriptCore/runtime/JSType.h \
+ Source/JavaScriptCore/runtime/JSTypeInfo.h \
+ Source/JavaScriptCore/runtime/JSValue.cpp \
+ Source/JavaScriptCore/runtime/JSValue.h \
+ Source/JavaScriptCore/runtime/JSValueInlineMethods.h \
+ Source/JavaScriptCore/runtime/JSVariableObject.cpp \
+ Source/JavaScriptCore/runtime/JSVariableObject.h \
+ Source/JavaScriptCore/runtime/JSWrapperObject.cpp \
+ Source/JavaScriptCore/runtime/JSWrapperObject.h \
+ Source/JavaScriptCore/runtime/JSZombie.h \
+ Source/JavaScriptCore/runtime/LiteralParser.cpp \
+ Source/JavaScriptCore/runtime/LiteralParser.h \
+ Source/JavaScriptCore/runtime/Lookup.cpp \
+ Source/JavaScriptCore/runtime/Lookup.h \
+ Source/JavaScriptCore/runtime/MathObject.cpp \
+ Source/JavaScriptCore/runtime/MathObject.h \
+ Source/JavaScriptCore/runtime/NativeErrorConstructor.cpp \
+ Source/JavaScriptCore/runtime/NativeErrorConstructor.h \
+ Source/JavaScriptCore/runtime/NativeErrorPrototype.cpp \
+ Source/JavaScriptCore/runtime/NativeErrorPrototype.h \
+ Source/JavaScriptCore/runtime/NumberConstructor.cpp \
+ Source/JavaScriptCore/runtime/NumberConstructor.h \
+ Source/JavaScriptCore/runtime/NumberObject.cpp \
+ Source/JavaScriptCore/runtime/NumberObject.h \
+ Source/JavaScriptCore/runtime/NumberPrototype.cpp \
+ Source/JavaScriptCore/runtime/NumberPrototype.h \
+ Source/JavaScriptCore/runtime/NumericStrings.h \
+ Source/JavaScriptCore/runtime/ObjectConstructor.cpp \
+ Source/JavaScriptCore/runtime/ObjectConstructor.h \
+ Source/JavaScriptCore/runtime/ObjectPrototype.cpp \
+ Source/JavaScriptCore/runtime/ObjectPrototype.h \
+ Source/JavaScriptCore/runtime/Operations.cpp \
+ Source/JavaScriptCore/runtime/Operations.h \
+ Source/JavaScriptCore/runtime/PropertyDescriptor.cpp \
+ Source/JavaScriptCore/runtime/PropertyDescriptor.h \
+ Source/JavaScriptCore/runtime/PropertyMapHashTable.h \
+ Source/JavaScriptCore/runtime/PropertyNameArray.cpp \
+ Source/JavaScriptCore/runtime/PropertyNameArray.h \
+ Source/JavaScriptCore/runtime/PropertySlot.cpp \
+ Source/JavaScriptCore/runtime/PropertySlot.h \
+ Source/JavaScriptCore/runtime/Protect.h \
+ Source/JavaScriptCore/runtime/PutPropertySlot.h \
+ Source/JavaScriptCore/runtime/RegExpCache.cpp \
+ Source/JavaScriptCore/runtime/RegExpCache.h \
+ Source/JavaScriptCore/runtime/RegExpConstructor.cpp \
+ Source/JavaScriptCore/runtime/RegExpConstructor.h \
+ Source/JavaScriptCore/runtime/RegExp.cpp \
+ Source/JavaScriptCore/runtime/RegExp.h \
+ Source/JavaScriptCore/runtime/RegExpKey.h \
+ Source/JavaScriptCore/runtime/RegExpMatchesArray.h \
+ Source/JavaScriptCore/runtime/RegExpObject.cpp \
+ Source/JavaScriptCore/runtime/RegExpObject.h \
+ Source/JavaScriptCore/runtime/RegExpPrototype.cpp \
+ Source/JavaScriptCore/runtime/RegExpPrototype.h \
+ Source/JavaScriptCore/runtime/RopeImpl.cpp \
+ Source/JavaScriptCore/runtime/RopeImpl.h \
+ Source/JavaScriptCore/runtime/ScopeChain.cpp \
+ Source/JavaScriptCore/runtime/ScopeChain.h \
+ Source/JavaScriptCore/runtime/ScopeChainMark.h \
+ Source/JavaScriptCore/runtime/SmallStrings.cpp \
+ Source/JavaScriptCore/runtime/SmallStrings.h \
+ Source/JavaScriptCore/runtime/StrictEvalActivation.cpp \
+ Source/JavaScriptCore/runtime/StrictEvalActivation.h \
+ Source/JavaScriptCore/runtime/StringConstructor.cpp \
+ Source/JavaScriptCore/runtime/StringConstructor.h \
+ Source/JavaScriptCore/runtime/StringObject.cpp \
+ Source/JavaScriptCore/runtime/StringObject.h \
+ Source/JavaScriptCore/runtime/StringObjectThatMasqueradesAsUndefined.h \
+ Source/JavaScriptCore/runtime/StringPrototype.cpp \
+ Source/JavaScriptCore/runtime/StringPrototype.h \
+ Source/JavaScriptCore/runtime/StringRecursionChecker.cpp \
+ Source/JavaScriptCore/runtime/StringRecursionChecker.h \
+ Source/JavaScriptCore/runtime/StructureChain.cpp \
+ Source/JavaScriptCore/runtime/StructureChain.h \
+ Source/JavaScriptCore/runtime/Structure.cpp \
+ Source/JavaScriptCore/runtime/Structure.h \
+ Source/JavaScriptCore/runtime/StructureTransitionTable.h \
+ Source/JavaScriptCore/runtime/SymbolTable.h \
+ Source/JavaScriptCore/runtime/Terminator.h \
+ Source/JavaScriptCore/runtime/TimeoutChecker.cpp \
+ Source/JavaScriptCore/runtime/TimeoutChecker.h \
+ Source/JavaScriptCore/runtime/Tracing.h \
+ Source/JavaScriptCore/runtime/UString.cpp \
+ Source/JavaScriptCore/runtime/UString.h \
+ Source/JavaScriptCore/runtime/UStringBuilder.h \
+ Source/JavaScriptCore/runtime/UStringConcatenate.h \
+ Source/JavaScriptCore/runtime/WeakGCMap.h \
+ Source/JavaScriptCore/runtime/WeakRandom.h \
+ Source/JavaScriptCore/runtime/WriteBarrier.h \
+ Source/JavaScriptCore/wtf/AlwaysInline.h \
+ Source/JavaScriptCore/wtf/ASCIICType.h \
+ Source/JavaScriptCore/wtf/Assertions.cpp \
+ Source/JavaScriptCore/wtf/Assertions.h \
+ Source/JavaScriptCore/wtf/Atomics.h \
+ Source/JavaScriptCore/wtf/AVLTree.h \
+ Source/JavaScriptCore/wtf/Bitmap.h \
+ Source/JavaScriptCore/wtf/BlockStack.h \
+ Source/JavaScriptCore/wtf/BloomFilter.h \
+ Source/JavaScriptCore/wtf/BumpPointerAllocator.h \
+ Source/JavaScriptCore/wtf/ByteArray.cpp \
+ Source/JavaScriptCore/wtf/ByteArray.h \
+ Source/JavaScriptCore/wtf/CrossThreadRefCounted.h \
+ Source/JavaScriptCore/wtf/CryptographicallyRandomNumber.cpp \
+ Source/JavaScriptCore/wtf/CryptographicallyRandomNumber.h \
+ Source/JavaScriptCore/wtf/CurrentTime.cpp \
+ Source/JavaScriptCore/wtf/CurrentTime.h \
+ Source/JavaScriptCore/wtf/DateMath.cpp \
+ Source/JavaScriptCore/wtf/DateMath.h \
+ Source/JavaScriptCore/wtf/DecimalNumber.h \
+ Source/JavaScriptCore/wtf/DecimalNumber.cpp \
+ Source/JavaScriptCore/wtf/Decoder.h \
+ Source/JavaScriptCore/wtf/Deque.h \
+ Source/JavaScriptCore/wtf/DisallowCType.h \
+ Source/JavaScriptCore/wtf/DoublyLinkedList.h \
+ Source/JavaScriptCore/wtf/dtoa.cpp \
+ Source/JavaScriptCore/wtf/dtoa.h \
+ Source/JavaScriptCore/wtf/DynamicAnnotations.cpp \
+ Source/JavaScriptCore/wtf/DynamicAnnotations.h \
+ Source/JavaScriptCore/wtf/Encoder.h \
+ Source/JavaScriptCore/wtf/FastAllocBase.h \
+ Source/JavaScriptCore/wtf/FastMalloc.cpp \
+ Source/JavaScriptCore/wtf/FastMalloc.h \
+ Source/JavaScriptCore/wtf/FixedArray.h \
+ Source/JavaScriptCore/wtf/Forward.h \
+ Source/JavaScriptCore/wtf/GetPtr.h \
+ Source/JavaScriptCore/wtf/gobject/GOwnPtr.cpp \
+ Source/JavaScriptCore/wtf/gobject/GOwnPtr.h \
+ Source/JavaScriptCore/wtf/gobject/GRefPtr.cpp \
+ Source/JavaScriptCore/wtf/gobject/GRefPtr.h \
+ Source/JavaScriptCore/wtf/gobject/GTypedefs.h \
+ Source/JavaScriptCore/wtf/gtk/MainThreadGtk.cpp \
+ Source/JavaScriptCore/wtf/gtk/ThreadingGtk.cpp \
+ Source/JavaScriptCore/wtf/HashCountedSet.h \
+ Source/JavaScriptCore/wtf/HashFunctions.h \
+ Source/JavaScriptCore/wtf/HashIterators.h \
+ Source/JavaScriptCore/wtf/HashMap.h \
+ Source/JavaScriptCore/wtf/HashSet.h \
+ Source/JavaScriptCore/wtf/HashTable.cpp \
+ Source/JavaScriptCore/wtf/HashTable.h \
+ Source/JavaScriptCore/wtf/HashTraits.h \
+ Source/JavaScriptCore/wtf/HexNumber.h \
+ Source/JavaScriptCore/wtf/ListHashSet.h \
+ Source/JavaScriptCore/wtf/ListRefPtr.h \
+ Source/JavaScriptCore/wtf/Locker.h \
+ Source/JavaScriptCore/wtf/MainThread.cpp \
+ Source/JavaScriptCore/wtf/MainThread.h \
+ Source/JavaScriptCore/wtf/MallocZoneSupport.h \
+ Source/JavaScriptCore/wtf/MathExtras.h \
+ Source/JavaScriptCore/wtf/MD5.cpp \
+ Source/JavaScriptCore/wtf/MD5.h \
+ Source/JavaScriptCore/wtf/MessageQueue.h \
+ Source/JavaScriptCore/wtf/NonCopyingSort.h \
+ Source/JavaScriptCore/wtf/Noncopyable.h \
+ Source/JavaScriptCore/wtf/NotFound.h \
+ Source/JavaScriptCore/wtf/NullPtr.h \
+ Source/JavaScriptCore/wtf/OSAllocator.h \
+ Source/JavaScriptCore/wtf/OSRandomSource.cpp \
+ Source/JavaScriptCore/wtf/OSRandomSource.h \
+ Source/JavaScriptCore/wtf/OwnArrayPtr.h \
+ Source/JavaScriptCore/wtf/OwnFastMallocPtr.h \
+ Source/JavaScriptCore/wtf/OwnPtrCommon.h \
+ Source/JavaScriptCore/wtf/OwnPtr.h \
+ Source/JavaScriptCore/wtf/PageAllocation.h \
+ Source/JavaScriptCore/wtf/PageAllocationAligned.cpp \
+ Source/JavaScriptCore/wtf/PageAllocationAligned.h \
+ Source/JavaScriptCore/wtf/PageReservation.h \
+ Source/JavaScriptCore/wtf/PageBlock.cpp \
+ Source/JavaScriptCore/wtf/PageBlock.h \
+ Source/JavaScriptCore/wtf/PassOwnArrayPtr.h \
+ Source/JavaScriptCore/wtf/PassOwnPtr.h \
+ Source/JavaScriptCore/wtf/PassRefPtr.h \
+ Source/JavaScriptCore/wtf/PassTraits.h \
+ Source/JavaScriptCore/wtf/ParallelJobs.h \
+ Source/JavaScriptCore/wtf/ParallelJobsGeneric.cpp \
+ Source/JavaScriptCore/wtf/ParallelJobsGeneric.h \
+ Source/JavaScriptCore/wtf/ParallelJobsLibdispatch.h \
+ Source/JavaScriptCore/wtf/ParallelJobsOpenMP.h \
+ Source/JavaScriptCore/wtf/Platform.h \
+ Source/JavaScriptCore/wtf/PossiblyNull.h \
+ Source/JavaScriptCore/wtf/RandomNumber.cpp \
+ Source/JavaScriptCore/wtf/RandomNumber.h \
+ Source/JavaScriptCore/wtf/RandomNumberSeed.h \
+ Source/JavaScriptCore/wtf/RefCounted.h \
+ Source/JavaScriptCore/wtf/RefCountedLeakCounter.cpp \
+ Source/JavaScriptCore/wtf/RefCountedLeakCounter.h \
+ Source/JavaScriptCore/wtf/RefPtr.h \
+ Source/JavaScriptCore/wtf/RefPtrHashMap.h \
+ Source/JavaScriptCore/wtf/RetainPtr.h \
+ Source/JavaScriptCore/wtf/SegmentedVector.h \
+ Source/JavaScriptCore/wtf/SentinelLinkedList.h \
+ Source/JavaScriptCore/wtf/SHA1.cpp \
+ Source/JavaScriptCore/wtf/SHA1.h \
+ Source/JavaScriptCore/wtf/SinglyLinkedList.h \
+ Source/JavaScriptCore/wtf/StackBounds.cpp \
+ Source/JavaScriptCore/wtf/StackBounds.h \
+ Source/JavaScriptCore/wtf/StaticConstructors.h \
+ Source/JavaScriptCore/wtf/StdLibExtras.h \
+ Source/JavaScriptCore/wtf/StringExtras.h \
+ Source/JavaScriptCore/wtf/StringHasher.h \
+ Source/JavaScriptCore/wtf/TCPackedCache.h \
+ Source/JavaScriptCore/wtf/TCPageMap.h \
+ Source/JavaScriptCore/wtf/TCSpinLock.h \
+ Source/JavaScriptCore/wtf/TCSystemAlloc.cpp \
+ Source/JavaScriptCore/wtf/TCSystemAlloc.h \
+ Source/JavaScriptCore/wtf/text/AtomicString.cpp \
+ Source/JavaScriptCore/wtf/text/AtomicString.h \
+ Source/JavaScriptCore/wtf/text/AtomicStringHash.h \
+ Source/JavaScriptCore/wtf/text/AtomicStringImpl.h \
+ Source/JavaScriptCore/wtf/text/CString.cpp \
+ Source/JavaScriptCore/wtf/text/CString.h \
+ Source/JavaScriptCore/wtf/text/StringBuffer.h \
+ Source/JavaScriptCore/wtf/text/StringBuilder.cpp \
+ Source/JavaScriptCore/wtf/text/StringBuilder.h \
+ Source/JavaScriptCore/wtf/text/StringConcatenate.h \
+ Source/JavaScriptCore/wtf/text/StringHash.h \
+ Source/JavaScriptCore/wtf/text/StringImplBase.h \
+ Source/JavaScriptCore/wtf/text/StringImpl.cpp \
+ Source/JavaScriptCore/wtf/text/StringImpl.h \
+ Source/JavaScriptCore/wtf/text/StringOperators.h \
+ Source/JavaScriptCore/wtf/text/StringStatics.cpp \
+ Source/JavaScriptCore/wtf/text/TextPosition.h \
+ Source/JavaScriptCore/wtf/text/WTFString.cpp \
+ Source/JavaScriptCore/wtf/text/WTFString.h \
+ Source/JavaScriptCore/wtf/ThreadIdentifierDataPthreads.cpp \
+ Source/JavaScriptCore/wtf/ThreadIdentifierDataPthreads.h \
+ Source/JavaScriptCore/wtf/Threading.cpp \
+ Source/JavaScriptCore/wtf/Threading.h \
+ Source/JavaScriptCore/wtf/ThreadingPrimitives.h \
+ Source/JavaScriptCore/wtf/ThreadingPthreads.cpp \
+ Source/JavaScriptCore/wtf/ThreadSafeRefCounted.h \
+ Source/JavaScriptCore/wtf/ThreadSpecific.h \
+ Source/JavaScriptCore/wtf/TypeTraits.cpp \
+ Source/JavaScriptCore/wtf/TypeTraits.h \
+ Source/JavaScriptCore/wtf/unicode/CharacterNames.h \
+ Source/JavaScriptCore/wtf/unicode/CollatorDefault.cpp \
+ Source/JavaScriptCore/wtf/unicode/Collator.h \
+ Source/JavaScriptCore/wtf/unicode/Unicode.h \
+ Source/JavaScriptCore/wtf/unicode/UTF8.cpp \
+ Source/JavaScriptCore/wtf/unicode/UTF8.h \
+ Source/JavaScriptCore/wtf/UnusedParam.h \
+ Source/JavaScriptCore/wtf/ValueCheck.h \
+ Source/JavaScriptCore/wtf/Vector.h \
+ Source/JavaScriptCore/wtf/VectorTraits.h \
+ Source/JavaScriptCore/wtf/VMTags.h \
+ Source/JavaScriptCore/wtf/WTFThreadData.cpp \
+ Source/JavaScriptCore/wtf/WTFThreadData.h \
+ Source/JavaScriptCore/yarr/Yarr.h \
+ Source/JavaScriptCore/yarr/YarrInterpreter.cpp \
+ Source/JavaScriptCore/yarr/YarrInterpreter.h \
+ Source/JavaScriptCore/yarr/YarrJIT.cpp \
+ Source/JavaScriptCore/yarr/YarrJIT.h \
+ Source/JavaScriptCore/yarr/YarrParser.h \
+ Source/JavaScriptCore/yarr/YarrPattern.cpp \
+ Source/JavaScriptCore/yarr/YarrPattern.h \
+ Source/JavaScriptCore/yarr/YarrSyntaxChecker.cpp \
+ Source/JavaScriptCore/yarr/YarrSyntaxChecker.h
+
+if TARGET_WIN32
+javascriptcore_sources += \
+ Source/JavaScriptCore/heap/MarkStackWin.cpp \
+ Source/JavaScriptCore/wtf/OSAllocatorWin.cpp
+else
+javascriptcore_sources += \
+ Source/JavaScriptCore/jit/ExecutableAllocatorFixedVMPool.cpp \
+ Source/JavaScriptCore/heap/MarkStackPosix.cpp \
+ Source/JavaScriptCore/wtf/OSAllocatorPosix.cpp
+endif
+
+# ----
+# icu unicode backend
+# ----
+if USE_ICU_UNICODE
+javascriptcore_sources += \
+ Source/JavaScriptCore/wtf/unicode/icu/CollatorICU.cpp \
+ Source/JavaScriptCore/wtf/unicode/icu/UnicodeIcu.h
+endif # USE_ICU_UNICODE
+
+# ----
+# glib unicode backend
+# ----
+if USE_GLIB_UNICODE
+javascriptcore_sources += \
+ Source/JavaScriptCore/wtf/unicode/UnicodeMacrosFromICU.h \
+ Source/JavaScriptCore/wtf/unicode/glib/UnicodeGLib.h \
+ Source/JavaScriptCore/wtf/unicode/glib/UnicodeGLib.cpp
+endif # USE_GLIB_UNICODE
+
+# minidom
+Programs_minidom_SOURCES = \
+ Source/JavaScriptCore/API/tests/JSNode.c \
+ Source/JavaScriptCore/API/tests/JSNode.h \
+ Source/JavaScriptCore/API/tests/JSNodeList.c \
+ Source/JavaScriptCore/API/tests/JSNodeList.h \
+ Source/JavaScriptCore/API/tests/Node.c \
+ Source/JavaScriptCore/API/tests/Node.h \
+ Source/JavaScriptCore/API/tests/NodeList.c \
+ Source/JavaScriptCore/API/tests/NodeList.h \
+ Source/JavaScriptCore/API/tests/minidom.c
+
+Programs_jsc_@WEBKITGTK_API_MAJOR_VERSION@_SOURCES = \
+ Source/JavaScriptCore/jsc.cpp
<key>CFBundleExecutable</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundleGetInfoString</key>
- <string>${BUNDLE_VERSION}, Copyright 2003-2010 Apple Inc.; Copyright 1999-2001 Harri Porten <porten@kde.org>; Copyright 2001 Peter Kelly <pmk@post.com>; Copyright 1997-2005 University of Cambridge; Copyright 1991, 2000, 2001 by Lucent Technologies.</string>
+ <string>${BUNDLE_VERSION}, Copyright 2003-2011 Apple Inc.; Copyright 1999-2001 Harri Porten <porten@kde.org>; Copyright 2001 Peter Kelly <pmk@post.com>; Copyright 1997-2005 University of Cambridge; Copyright 1991, 2000, 2001 by Lucent Technologies.</string>
<key>CFBundleIdentifier</key>
<string>com.apple.${PRODUCT_NAME}</string>
<key>CFBundleInfoDictionaryVersion</key>
--- /dev/null
+__ZN3JSC10JSFunctionC1EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureEiRKNS_10IdentifierEPFxS2_E
--- /dev/null
+__ZN3JSC10JSFunctionC1EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureEiRKNS_10IdentifierEPFPvS2_E
_JSContextGroupCreate
_JSContextGroupRelease
_JSContextGroupRetain
+_JSContextCreateBacktrace
_JSEndProfiling
_JSEvaluateScript
_JSGarbageCollect
_JSWeakObjectMapClear
_JSWeakObjectMapCreate
_JSWeakObjectMapGet
+_JSWeakObjectMapRemove
_JSWeakObjectMapSet
_WTFLog
_WTFLogVerbose
_WTFReportArgumentAssertionFailure
_WTFReportAssertionFailure
_WTFReportAssertionFailureWithMessage
+_WTFReportBacktrace
_WTFReportError
_WTFReportFatalError
_WebCoreWebThreadIsLockedOrDisabled
-__Z12jsRegExpFreeP8JSRegExp
-__Z15jsRegExpCompilePKti24JSRegExpIgnoreCaseOption23JSRegExpMultilineOptionPjPPKc
-__Z15jsRegExpExecutePK8JSRegExpPKtiiPii
__ZN14OpaqueJSString6createERKN3JSC7UStringE
-__ZN3JSC10Identifier11addSlowCaseEPNS_12JSGlobalDataEPN7WebCore10StringImplE
-__ZN3JSC10Identifier11addSlowCaseEPNS_9ExecStateEPN7WebCore10StringImplE
+__ZN3JSC10HandleHeap12writeBarrierEPNS_7JSValueERKS1_
+__ZN3JSC10HandleHeap4growEv
+__ZN3JSC10Identifier11addSlowCaseEPNS_12JSGlobalDataEPN3WTF10StringImplE
+__ZN3JSC10Identifier11addSlowCaseEPNS_9ExecStateEPN3WTF10StringImplE
__ZN3JSC10Identifier27checkCurrentIdentifierTableEPNS_12JSGlobalDataE
__ZN3JSC10Identifier27checkCurrentIdentifierTableEPNS_9ExecStateE
__ZN3JSC10Identifier3addEPNS_9ExecStateEPKc
__ZN3JSC10Identifier4fromEPNS_9ExecStateEi
__ZN3JSC10Identifier4fromEPNS_9ExecStateEj
-__ZN3JSC10Identifier5equalEPKN7WebCore10StringImplEPKc
-__ZN3JSC10JSFunctionC1EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEiRKNS_10IdentifierEPFNS_7JSValueES2_PNS_8JSObjectESA_RKNS_7ArgListEE
-__ZN3JSC10throwErrorEPNS_9ExecStateENS_9ErrorTypeE
-__ZN3JSC10throwErrorEPNS_9ExecStateENS_9ErrorTypeEPKc
-__ZN3JSC10throwErrorEPNS_9ExecStateENS_9ErrorTypeERKNS_7UStringE
-__ZN3JSC11JSByteArray15createStructureENS_7JSValueE
-__ZN3JSC11JSByteArrayC1EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEPNS3_9ByteArrayEPKNS_9ClassInfoE
+__ZN3JSC10Identifier5equalEPKN3WTF10StringImplEPKc
+__ZN3JSC10Identifier8toUInt32ERKNS_7UStringERb
+__ZN3JSC10JSFunction4nameEPNS_9ExecStateE
+__ZN3JSC10JSFunction6s_infoE
+__ZN3JSC10throwErrorEPNS_9ExecStateENS_7JSValueE
+__ZN3JSC10throwErrorEPNS_9ExecStateEPNS_8JSObjectE
+__ZN3JSC11JSByteArray13s_defaultInfoE
+__ZN3JSC11JSByteArray15createStructureERNS_12JSGlobalDataENS_7JSValueEPKNS_9ClassInfoE
+__ZN3JSC11JSByteArrayC1EPNS_9ExecStateEPNS_9StructureEPN3WTF9ByteArrayE
+__ZN3JSC11MarkedSpace21allocateFromSizeClassERNS0_9SizeClassE
__ZN3JSC11ParserArena5resetEv
__ZN3JSC11checkSyntaxEPNS_9ExecStateERKNS_10SourceCodeE
-__ZN3JSC12DateInstance4infoE
-__ZN3JSC12DateInstanceC1EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEd
-__ZN3JSC12DateInstanceC1EPNS_9ExecStateEd
+__ZN3JSC11createErrorEPNS_9ExecStateERKNS_7UStringE
+__ZN3JSC11regExpFlagsERKNS_7UStringE
+__ZN3JSC12DateInstance6s_infoE
+__ZN3JSC12DateInstanceC1EPNS_9ExecStateEPNS_9StructureEd
__ZN3JSC12JSGlobalData10ClientDataD2Ev
__ZN3JSC12JSGlobalData11jsArrayVPtrE
__ZN3JSC12JSGlobalData12createLeakedENS_15ThreadStackTypeE
__ZN3JSC12JSGlobalData14dumpSampleDataEPNS_9ExecStateE
__ZN3JSC12JSGlobalData14resetDateCacheEv
__ZN3JSC12JSGlobalData14sharedInstanceEv
+__ZN3JSC12JSGlobalData15dumpRegExpTraceEv
+__ZN3JSC12JSGlobalData22clearBuiltinStructuresEv
+#ifndef NDEBUG
+__ZN3JSC12JSGlobalData23releaseExecutableMemoryEv
+#endif
__ZN3JSC12JSGlobalData6createENS_15ThreadStackTypeE
__ZN3JSC12JSGlobalDataD1Ev
+__ZN3JSC12RegExpObject6s_infoE
+__ZN3JSC12RegExpObjectC1EPNS_14JSGlobalObjectEPNS_9StructureEPNS_6RegExpE
__ZN3JSC12SamplingTool5setupEv
__ZN3JSC12SmallStrings17createEmptyStringEPNS_12JSGlobalDataE
__ZN3JSC12SmallStrings27createSingleCharacterStringEPNS_12JSGlobalDataEh
__ZN3JSC12StringObject19getOwnPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayENS_15EnumerationModeE
__ZN3JSC12StringObject24getOwnPropertyDescriptorEPNS_9ExecStateERKNS_10IdentifierERNS_18PropertyDescriptorE
__ZN3JSC12StringObject3putEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueERNS_15PutPropertySlotE
-__ZN3JSC12StringObject4infoE
-__ZN3JSC12StringObjectC2EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEERKNS_7UStringE
-__ZN3JSC12jsNumberCellEPNS_9ExecStateEd
+__ZN3JSC12StringObject6s_infoE
+__ZN3JSC12StringObjectC2EPNS_9ExecStateEPNS_9StructureERKNS_7UStringE
__ZN3JSC12nonInlineNaNEv
__ZN3JSC13SamplingFlags4stopEv
__ZN3JSC13SamplingFlags5startEv
__ZN3JSC13SamplingFlags7s_flagsE
__ZN3JSC13StatementNode6setLocEii
__ZN3JSC14JSGlobalObject10globalExecEv
+__ZN3JSC14JSGlobalObject11disableEvalEv
__ZN3JSC14JSGlobalObject12defineGetterEPNS_9ExecStateERKNS_10IdentifierEPNS_8JSObjectEj
__ZN3JSC14JSGlobalObject12defineSetterEPNS_9ExecStateERKNS_10IdentifierEPNS_8JSObjectEj
-__ZN3JSC14JSGlobalObject12markChildrenERNS_9MarkStackE
+__ZN3JSC14JSGlobalObject13visitChildrenERNS_9MarkStackE
+__ZN3JSC14JSGlobalObject16addStaticGlobalsEPNS0_18GlobalPropertyInfoEi
__ZN3JSC14JSGlobalObject17putWithAttributesEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueEj
-__ZN3JSC14JSGlobalObject25destroyJSGlobalObjectDataEPv
+__ZN3JSC14JSGlobalObject18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
+__ZN3JSC14JSGlobalObject24getOwnPropertyDescriptorEPNS_9ExecStateERKNS_10IdentifierERNS_18PropertyDescriptorE
__ZN3JSC14JSGlobalObject3putEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueERNS_15PutPropertySlotE
__ZN3JSC14JSGlobalObject4initEPNS_8JSObjectE
+__ZN3JSC14JSGlobalObject6s_infoE
__ZN3JSC14JSGlobalObjectD2Ev
__ZN3JSC14JSGlobalObjectnwEmPNS_12JSGlobalDataE
+__ZN3JSC14MachineThreads16addCurrentThreadEv
+__ZN3JSC14MachineThreads29makeUsableFromMultipleThreadsEv
__ZN3JSC14SamplingThread4stopEv
__ZN3JSC14SamplingThread5startEj
+__ZN3JSC14ScopeChainNode6s_infoE
__ZN3JSC14TimeoutChecker10didTimeOutEPNS_9ExecStateE
__ZN3JSC14TimeoutChecker5resetEv
-__ZN3JSC15JSWrapperObject12markChildrenERNS_9MarkStackE
-__ZN3JSC15createTypeErrorEPNS_9ExecStateEPKc
-__ZN3JSC15toInt32SlowCaseEdRb
-__ZN3JSC16InternalFunction4infoE
+__ZN3JSC14throwTypeErrorEPNS_9ExecStateE
+__ZN3JSC15JSWrapperObject13visitChildrenERNS_9MarkStackE
+__ZN3JSC15WeakHandleOwner26isReachableFromOpaqueRootsENS_6HandleINS_7UnknownEEEPvRNS_9MarkStackE
+__ZN3JSC15WeakHandleOwner8finalizeENS_6HandleINS_7UnknownEEEPv
+__ZN3JSC15WeakHandleOwnerD2Ev
+__ZN3JSC15createTypeErrorEPNS_9ExecStateERKNS_7UStringE
+__ZN3JSC16InternalFunction12vtableAnchorEv
__ZN3JSC16InternalFunction4nameEPNS_9ExecStateE
-__ZN3JSC16InternalFunctionC2EPNS_12JSGlobalDataEN3WTF17NonNullPassRefPtrINS_9StructureEEERKNS_10IdentifierE
+__ZN3JSC16InternalFunction6s_infoE
+__ZN3JSC16InternalFunctionC2EPNS_12JSGlobalDataEPNS_14JSGlobalObjectEPNS_9StructureERKNS_10IdentifierE
__ZN3JSC16JSVariableObject14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE
__ZN3JSC16JSVariableObject14symbolTableGetERKNS_10IdentifierERNS_18PropertyDescriptorE
__ZN3JSC16JSVariableObject19getOwnPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayENS_15EnumerationModeE
-__ZN3JSC16toUInt32SlowCaseEdRb
+__ZN3JSC16createRangeErrorEPNS_9ExecStateERKNS_7UStringE
+__ZN3JSC16slowValidateCellEPNS_14JSGlobalObjectE
+__ZN3JSC16slowValidateCellEPNS_6JSCellE
+__ZN3JSC16throwSyntaxErrorEPNS_9ExecStateE
__ZN3JSC17BytecodeGenerator21setDumpsGeneratedCodeEb
-__ZN3JSC17PropertyNameArray3addEPN7WebCore10StringImplE
-__ZN3JSC17PrototypeFunctionC1EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEiRKNS_10IdentifierEPFNS_7JSValueES2_PNS_8JSObjectESA_RKNS_7ArgListEE
-__ZN3JSC17PrototypeFunctionC1EPNS_9ExecStateEiRKNS_10IdentifierEPFNS_7JSValueES2_PNS_8JSObjectES6_RKNS_7ArgListEE
-__ZN3JSC17constructFunctionEPNS_9ExecStateERKNS_7ArgListERKNS_10IdentifierERKNS_7UStringEi
-__ZN3JSC18DebuggerActivationC1EPNS_8JSObjectE
+__ZN3JSC17PropertyNameArray3addEPN3WTF10StringImplE
+__ZN3JSC17constructFunctionEPNS_9ExecStateEPNS_14JSGlobalObjectERKNS_7ArgListERKNS_10IdentifierERKNS_7UStringEi
+__ZN3JSC17createSyntaxErrorEPNS_9ExecStateERKNS_7UStringE
+__ZN3JSC18DebuggerActivationC1ERNS_12JSGlobalDataEPNS_8JSObjectE
__ZN3JSC18PropertyDescriptor11setWritableEb
__ZN3JSC18PropertyDescriptor12setUndefinedEv
__ZN3JSC18PropertyDescriptor13setDescriptorENS_7JSValueEj
__ZN3JSC18PropertyDescriptor21setAccessorDescriptorENS_7JSValueES1_j
__ZN3JSC18PropertyDescriptor9setGetterENS_7JSValueE
__ZN3JSC18PropertyDescriptor9setSetterENS_7JSValueE
+__ZN3JSC19SourceProviderCache5clearEv
+__ZN3JSC19SourceProviderCacheD1Ev
__ZN3JSC19initializeThreadingEv
__ZN3JSC20MarkedArgumentBuffer10slowAppendENS_7JSValueE
+__ZN3JSC20createReferenceErrorEPNS_9ExecStateERKNS_7UStringE
+__ZN3JSC22globalMemoryStatisticsEv
+__ZN3JSC22objectConstructorTableE
__ZN3JSC23AbstractSamplingCounter4dumpEv
-__ZN3JSC23objectProtoFuncToStringEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
+__ZN3JSC23objectProtoFuncToStringEPNS_9ExecStateE
__ZN3JSC23setUpStaticFunctionSlotEPNS_9ExecStateEPKNS_9HashEntryEPNS_8JSObjectERKNS_10IdentifierERNS_12PropertySlotE
-__ZN3JSC24DynamicGlobalObjectScopeC1EPNS_9ExecStateEPNS_14JSGlobalObjectE
+__ZN3JSC24DynamicGlobalObjectScopeC1ERNS_12JSGlobalDataEPNS_14JSGlobalObjectE
+__ZN3JSC24JSObjectWithGlobalObjectC2EPNS_14JSGlobalObjectEPNS_9StructureE
+__ZN3JSC24JSObjectWithGlobalObjectC2ERNS_12JSGlobalDataEPNS_14JSGlobalObjectEPNS_9StructureE
__ZN3JSC24createStackOverflowErrorEPNS_9ExecStateE
__ZN3JSC25evaluateInGlobalCallFrameERKNS_7UStringERNS_7JSValueEPNS_14JSGlobalObjectE
__ZN3JSC35createInterruptedExecutionExceptionEPNS_12JSGlobalDataE
__ZN3JSC3NaNE
-__ZN3JSC4Heap14primaryHeapEndEv
-__ZN3JSC4Heap15recordExtraCostEm
+__ZN3JSC41constructFunctionSkippingEvalEnabledCheckEPNS_9ExecStateEPNS_14JSGlobalObjectERKNS_7ArgListERKNS_10IdentifierERKNS_7UStringEi
+__ZN3JSC4Heap16activityCallbackEv
+__ZN3JSC4Heap16allocateSlowCaseEm
__ZN3JSC4Heap16objectTypeCountsEv
-__ZN3JSC4Heap16primaryHeapBeginEv
__ZN3JSC4Heap17collectAllGarbageEv
__ZN3JSC4Heap17globalObjectCountEv
+__ZN3JSC4Heap19setActivityCallbackEN3WTF10PassOwnPtrINS_18GCActivityCallbackEEE
__ZN3JSC4Heap20protectedObjectCountEv
__ZN3JSC4Heap25protectedObjectTypeCountsEv
__ZN3JSC4Heap26protectedGlobalObjectCountEv
-__ZN3JSC4Heap6isBusyEv
+__ZN3JSC4Heap29reportExtraMemoryCostSlowCaseEm
__ZN3JSC4Heap7destroyEv
__ZN3JSC4Heap7protectENS_7JSValueE
-__ZN3JSC4Heap8allocateEm
__ZN3JSC4Heap9unprotectENS_7JSValueE
+__ZN3JSC4Yarr11YarrPatternC1ERKNS_7UStringEbbPPKc
+__ZN3JSC4Yarr11byteCompileERNS0_11YarrPatternEPN3WTF20BumpPointerAllocatorE
+__ZN3JSC4Yarr9interpretEPNS0_15BytecodePatternEPKtjjPi
__ZN3JSC4callEPNS_9ExecStateENS_7JSValueENS_8CallTypeERKNS_8CallDataES2_RKNS_7ArgListE
__ZN3JSC6JSCell11getCallDataERNS_8CallDataE
__ZN3JSC6JSCell11getJSNumberEv
__ZN3JSC6JSLock12DropAllLocksC1ENS_14JSLockBehaviorE
__ZN3JSC6JSLock12DropAllLocksC1EPNS_9ExecStateE
__ZN3JSC6JSLock12DropAllLocksD1Ev
+__ZN3JSC6JSLock26currentThreadIsHoldingLockEv
__ZN3JSC6JSLock4lockENS_14JSLockBehaviorE
__ZN3JSC6JSLock6unlockENS_14JSLockBehaviorE
__ZN3JSC6JSLock9lockCountEv
__ZN3JSC6JSLockC1EPNS_9ExecStateE
-__ZN3JSC6Parser5parseEPNS_12JSGlobalDataEPiPNS_7UStringE
-__ZN3JSC7JSArray12markChildrenERNS_9MarkStackE
+__ZN3JSC6RegExp6createEPNS_12JSGlobalDataERKNS_7UStringENS_11RegExpFlagsE
+__ZN3JSC6RegExpD1Ev
+__ZN3JSC7JSArray13visitChildrenERNS_9MarkStackE
__ZN3JSC7JSArray15setSubclassDataEPv
-__ZN3JSC7JSArray4infoE
+__ZN3JSC7JSArray18getOwnPropertySlotEPNS_9ExecStateEjRNS_12PropertySlotE
+__ZN3JSC7JSArray6s_infoE
__ZN3JSC7JSArray9setLengthEj
-__ZN3JSC7JSArrayC1EN3WTF17NonNullPassRefPtrINS_9StructureEEE
-__ZN3JSC7JSArrayC1EN3WTF17NonNullPassRefPtrINS_9StructureEEERKNS_7ArgListE
-__ZN3JSC7JSArrayC2EN3WTF17NonNullPassRefPtrINS_9StructureEEE
+__ZN3JSC7JSArrayC1ERNS_12JSGlobalDataEPNS_9StructureE
+__ZN3JSC7JSArrayC1ERNS_12JSGlobalDataEPNS_9StructureERKNS_7ArgListE
+__ZN3JSC7JSArrayC2ERNS_12JSGlobalDataEPNS_9StructureE
__ZN3JSC7JSArrayD2Ev
+__ZN3JSC7JSValue13isValidCalleeEv
__ZN3JSC7Profile10restoreAllEv
__ZN3JSC7Profile5focusEPKNS_11ProfileNodeE
__ZN3JSC7Profile7excludeEPKNS_11ProfileNodeE
__ZN3JSC7Profile7forEachEMNS_11ProfileNodeEFvvE
-__ZN3JSC7UString4fromEd
-__ZN3JSC7UString4fromEi
-__ZN3JSC7UString4fromEj
-__ZN3JSC7UString4fromEl
+__ZN3JSC7UString6numberEd
+__ZN3JSC7UString6numberEi
+__ZN3JSC7UString6numberEj
+__ZN3JSC7UString6numberEl
__ZN3JSC7UStringC1EPKc
+__ZN3JSC7UStringC1EPKcj
+__ZN3JSC7UStringC1EPKt
__ZN3JSC7UStringC1EPKtj
+__ZN3JSC7toInt32Ed
__ZN3JSC8Debugger23recompileAllJSFunctionsEPNS_12JSGlobalDataE
__ZN3JSC8Debugger6attachEPNS_14JSGlobalObjectE
__ZN3JSC8Debugger6detachEPNS_14JSGlobalObjectE
__ZN3JSC8JSObject12defineSetterEPNS_9ExecStateERKNS_10IdentifierEPS0_j
__ZN3JSC8JSObject12lookupGetterEPNS_9ExecStateERKNS_10IdentifierE
__ZN3JSC8JSObject12lookupSetterEPNS_9ExecStateERKNS_10IdentifierE
-__ZN3JSC8JSObject12markChildrenERNS_9MarkStackE
+__ZN3JSC8JSObject13visitChildrenERNS_9MarkStackE
__ZN3JSC8JSObject14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE
__ZN3JSC8JSObject14deletePropertyEPNS_9ExecStateEj
__ZN3JSC8JSObject15unwrappedObjectEv
__ZN3JSC8JSObject16getPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayENS_15EnumerationModeE
-__ZN3JSC8JSObject17createInheritorIDEv
__ZN3JSC8JSObject17defineOwnPropertyEPNS_9ExecStateERKNS_10IdentifierERNS_18PropertyDescriptorEb
+__ZN3JSC8JSObject17preventExtensionsERNS_12JSGlobalDataE
+__ZN3JSC8JSObject17putDirectFunctionEPNS_9ExecStateEPNS_10JSFunctionEj
__ZN3JSC8JSObject17putDirectFunctionEPNS_9ExecStateEPNS_16InternalFunctionEj
+__ZN3JSC8JSObject17putWithAttributesEPNS_12JSGlobalDataERKNS_10IdentifierENS_7JSValueEj
+__ZN3JSC8JSObject17putWithAttributesEPNS_12JSGlobalDataERKNS_10IdentifierENS_7JSValueEjbRNS_15PutPropertySlotE
+__ZN3JSC8JSObject17putWithAttributesEPNS_12JSGlobalDataEjNS_7JSValueEj
__ZN3JSC8JSObject17putWithAttributesEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueEj
__ZN3JSC8JSObject17putWithAttributesEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueEjbRNS_15PutPropertySlotE
__ZN3JSC8JSObject17putWithAttributesEPNS_9ExecStateEjNS_7JSValueEj
__ZN3JSC8JSObject18getPrimitiveNumberEPNS_9ExecStateERdRNS_7JSValueE
__ZN3JSC8JSObject19getOwnPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayENS_15EnumerationModeE
__ZN3JSC8JSObject21getPropertyDescriptorEPNS_9ExecStateERKNS_10IdentifierERNS_18PropertyDescriptorE
-__ZN3JSC8JSObject22fillGetterPropertySlotERNS_12PropertySlotEPNS_7JSValueE
+__ZN3JSC8JSObject22fillGetterPropertySlotERNS_12PropertySlotEPNS_16WriteBarrierBaseINS_7UnknownEEE
__ZN3JSC8JSObject23allocatePropertyStorageEmm
__ZN3JSC8JSObject24getOwnPropertyDescriptorEPNS_9ExecStateERKNS_10IdentifierERNS_18PropertyDescriptorE
__ZN3JSC8JSObject3putEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueERNS_15PutPropertySlotE
-__ZN3JSC8JSObject3putEPNS_9ExecStateEjNS_7JSValueE
+__ZN3JSC8JSObject3putEPNS_9ExecStateEjNS_7JSValueE
+__ZN3JSC8JSObject6s_infoE
__ZN3JSC8Profiler13stopProfilingEPNS_9ExecStateERKNS_7UStringE
__ZN3JSC8Profiler14startProfilingEPNS_9ExecStateERKNS_7UStringE
__ZN3JSC8Profiler8profilerEv
-__ZN3JSC8evaluateEPNS_9ExecStateERNS_10ScopeChainERKNS_10SourceCodeENS_7JSValueE
+__ZN3JSC8evaluateEPNS_9ExecStateEPNS_14ScopeChainNodeERKNS_10SourceCodeENS_7JSValueE
+__ZN3JSC8isZombieEPKNS_6JSCellE
__ZN3JSC9CodeBlockD1Ev
__ZN3JSC9CodeBlockD2Ev
__ZN3JSC9MarkStack10s_pageSizeE
-__ZN3JSC9MarkStack12releaseStackEPvm
-__ZN3JSC9MarkStack13allocateStackEm
__ZN3JSC9MarkStack18initializePagesizeEv
-__ZN3JSC9Structure13hasTransitionEPN7WebCore10StringImplEj
-__ZN3JSC9Structure17stopIgnoringLeaksEv
-__ZN3JSC9Structure18startIgnoringLeaksEv
-__ZN3JSC9Structure21addPropertyTransitionEPS0_RKNS_10IdentifierEjPNS_6JSCellERm
-__ZN3JSC9Structure22materializePropertyMapEv
-__ZN3JSC9Structure25changePrototypeTransitionEPS0_NS_7JSValueE
-__ZN3JSC9Structure27despecifyDictionaryFunctionERKNS_10IdentifierE
-__ZN3JSC9Structure27despecifyFunctionTransitionEPS0_RKNS_10IdentifierE
-__ZN3JSC9Structure28addPropertyWithoutTransitionERKNS_10IdentifierEjPNS_6JSCellE
-__ZN3JSC9Structure3getEPKN7WebCore10StringImplERjRPNS_6JSCellE
+__ZN3JSC9Structure21addPropertyTransitionERNS_12JSGlobalDataEPS0_RKNS_10IdentifierEjPNS_6JSCellERm
+__ZN3JSC9Structure22materializePropertyMapERNS_12JSGlobalDataE
+__ZN3JSC9Structure25changePrototypeTransitionERNS_12JSGlobalDataEPS0_NS_7JSValueE
+__ZN3JSC9Structure27despecifyDictionaryFunctionERNS_12JSGlobalDataERKNS_10IdentifierE
+__ZN3JSC9Structure27despecifyFunctionTransitionERNS_12JSGlobalDataEPS0_RKNS_10IdentifierE
+__ZN3JSC9Structure28addPropertyWithoutTransitionERNS_12JSGlobalDataERKNS_10IdentifierEjPNS_6JSCellE
+__ZN3JSC9Structure3getERNS_12JSGlobalDataEPN3WTF10StringImplERjRPNS_6JSCellE
__ZN3JSC9Structure40addPropertyTransitionToExistingStructureEPS0_RKNS_10IdentifierEjPNS_6JSCellERm
-__ZN3JSC9StructureC1ENS_7JSValueERKNS_8TypeInfoEj
+__ZN3JSC9Structure6s_infoE
+__ZN3JSC9StructureC1ERNS_12JSGlobalDataENS_7JSValueERKNS_8TypeInfoEjPKNS_9ClassInfoE
__ZN3JSC9StructureD1Ev
__ZN3JSC9constructEPNS_9ExecStateENS_7JSValueENS_13ConstructTypeERKNS_13ConstructDataERKNS_7ArgListE
__ZN3JSCeqERKNS_7UStringEPKc
__ZN3JSCgtERKNS_7UStringES2_
__ZN3JSCltERKNS_7UStringES2_
+__ZN3WTF10StringImpl11reverseFindEPS0_j
+__ZN3WTF10StringImpl11reverseFindEtj
+__ZN3WTF10StringImpl12sharedBufferEv
+__ZN3WTF10StringImpl16findIgnoringCaseEPKcj
+__ZN3WTF10StringImpl16findIgnoringCaseEPS0_j
+__ZN3WTF10StringImpl18simplifyWhiteSpaceEv
+__ZN3WTF10StringImpl19characterStartingAtEj
+__ZN3WTF10StringImpl19createUninitializedEjRPt
+__ZN3WTF10StringImpl22containsOnlyWhitespaceEv
+__ZN3WTF10StringImpl23defaultWritingDirectionEPb
+__ZN3WTF10StringImpl23reverseFindIgnoringCaseEPS0_j
+__ZN3WTF10StringImpl37createStrippingNullCharactersSlowCaseEPKtj
+__ZN3WTF10StringImpl4findEPFbtEj
+__ZN3WTF10StringImpl4findEPKcj
+__ZN3WTF10StringImpl4findEPS0_j
+__ZN3WTF10StringImpl4findEtj
+__ZN3WTF10StringImpl5adoptERNS_12StringBufferE
+__ZN3WTF10StringImpl5emptyEv
+__ZN3WTF10StringImpl5lowerEv
+__ZN3WTF10StringImpl5toIntEPb
+__ZN3WTF10StringImpl5upperEv
+__ZN3WTF10StringImpl6createEPKc
+__ZN3WTF10StringImpl6createEPKcj
+__ZN3WTF10StringImpl6createEPKtj
+__ZN3WTF10StringImpl6secureEtNS0_21LastCharacterBehaviorE
+__ZN3WTF10StringImpl7replaceEPS0_S1_
+__ZN3WTF10StringImpl7replaceEjjPS0_
+__ZN3WTF10StringImpl7replaceEtPS0_
+__ZN3WTF10StringImpl7replaceEtt
+__ZN3WTF10StringImpl8endsWithEPS0_b
+__ZN3WTF10StringImpl9substringEjj
+__ZN3WTF10StringImplD1Ev
__ZN3WTF10fastCallocEmm
__ZN3WTF10fastMallocEm
__ZN3WTF10fastStrDupEPKc
+__ZN3WTF11OSAllocator16reserveAndCommitEmNS0_5UsageEbbb
+__ZN3WTF11OSAllocator18releaseDecommittedEPvm
+__ZN3WTF11commentAtomE
__ZN3WTF11currentTimeEv
+__ZN3WTF11dtoaRoundDPEPcdiRbRiRj
+__ZN3WTF11dtoaRoundSFEPcdiRbRiRj
+__ZN3WTF11emptyStringEv
__ZN3WTF11fastReallocEPvm
+__ZN3WTF12AtomicString11addSlowCaseEPNS_10StringImplE
+__ZN3WTF12AtomicString16fromUTF8InternalEPKcS2_
+__ZN3WTF12AtomicString3addEPKc
+__ZN3WTF12AtomicString3addEPKt
+__ZN3WTF12AtomicString3addEPKtj
+__ZN3WTF12AtomicString3addEPKtjj
+__ZN3WTF12AtomicString4findEPKtjj
+__ZN3WTF12AtomicString4initEv
__ZN3WTF12createThreadEPFPvS0_ES0_
__ZN3WTF12createThreadEPFPvS0_ES0_PKc
__ZN3WTF12detachThreadEj
__ZN3WTF12isMainThreadEv
__ZN3WTF12randomNumberEv
+__ZN3WTF13StringBuilder11reifyStringEv
+__ZN3WTF13StringBuilder11shrinkToFitEv
+__ZN3WTF13StringBuilder15reserveCapacityEj
+__ZN3WTF13StringBuilder6appendEPKcj
+__ZN3WTF13StringBuilder6appendEPKtj
+__ZN3WTF13StringBuilder6resizeEj
__ZN3WTF13WTFThreadData10staticDataE
__ZN3WTF13WTFThreadDataC1Ev
__ZN3WTF13WTFThreadDataD1Ev
__ZN3WTF13tryFastCallocEmm
__ZN3WTF13tryFastMallocEm
__ZN3WTF14fastMallocSizeEPKv
+__ZN3WTF14numberToStringEdPt
+__ZN3WTF14tryFastReallocEPvm
__ZN3WTF15ThreadCondition4waitERNS_5MutexE
__ZN3WTF15ThreadCondition6signalEv
__ZN3WTF15ThreadCondition9broadcastEv
__ZN3WTF15ThreadCondition9timedWaitERNS_5MutexEd
__ZN3WTF15ThreadConditionC1Ev
__ZN3WTF15ThreadConditionD1Ev
+__ZN3WTF15charactersToIntEPKtmPb
__ZN3WTF16callOnMainThreadEPFvPvES0_
+__ZN3WTF16codePointCompareERKNS_6StringES2_
__ZN3WTF16fastZeroedMallocEm
+__ZN3WTF17charactersToFloatEPKtmPbS2_
+__ZN3WTF17equalIgnoringCaseEPKtPKcj
+__ZN3WTF17equalIgnoringCaseEPNS_10StringImplEPKc
+__ZN3WTF17equalIgnoringCaseEPNS_10StringImplES1_
+__ZN3WTF18calculateDSTOffsetEdd
+__ZN3WTF18calculateUTCOffsetEv
+__ZN3WTF18charactersToDoubleEPKtmPbS2_
__ZN3WTF18dateToDaysFrom1970Eiii
__ZN3WTF18monthFromDayInYearEib
__ZN3WTF19initializeThreadingEv
+__ZN3WTF20equalIgnoringNullityEPNS_10StringImplES1_
__ZN3WTF20fastMallocStatisticsEv
__ZN3WTF20initializeMainThreadEv
__ZN3WTF21RefCountedLeakCounter16suppressMessagesEPKc
__ZN3WTF21RefCountedLeakCounter9incrementEv
__ZN3WTF21RefCountedLeakCounterC1EPKc
__ZN3WTF21RefCountedLeakCounterD1Ev
+__ZN3WTF21charactersToIntStrictEPKtmPbi
+__ZN3WTF22cancelCallOnMainThreadEPFvPvES0_
+__ZN3WTF22charactersToUIntStrictEPKtmPbi
__ZN3WTF23callOnMainThreadAndWaitEPFvPvES0_
__ZN3WTF23dayInMonthFromDayInYearEib
__ZN3WTF23waitForThreadCompletionEjPPv
__ZN3WTF27releaseFastMallocFreeMemoryEv
__ZN3WTF28setMainThreadCallbacksPausedEb
-__ZN3WTF32doubleToStringInJavaScriptFormatEdPcPj
+__ZN3WTF29cryptographicallyRandomNumberEv
+__ZN3WTF29cryptographicallyRandomValuesEPvm
__ZN3WTF36lockAtomicallyInitializedStaticMutexEv
__ZN3WTF37parseDateFromNullTerminatedCharactersEPKc
__ZN3WTF38unlockAtomicallyInitializedStaticMutexEv
__ZN3WTF39initializeMainThreadToProcessMainThreadEv
__ZN3WTF3MD58addBytesEPKhm
-__ZN3WTF3MD58checksumEv
+__ZN3WTF3MD58checksumERNS_6VectorIhLm16EEE
__ZN3WTF3MD5C1Ev
+__ZN3WTF4SHA111computeHashERNS_6VectorIhLm20EEE
+__ZN3WTF4SHA18addBytesEPKhm
+__ZN3WTF4SHA1C1Ev
+__ZN3WTF4dtoaEPcdRbRiRj
__ZN3WTF5Mutex4lockEv
__ZN3WTF5Mutex6unlockEv
__ZN3WTF5Mutex7tryLockEv
__ZN3WTF5MutexC1Ev
__ZN3WTF5MutexD1Ev
+__ZN3WTF5equalEPKNS_10StringImplEPKc
+__ZN3WTF5equalEPKNS_10StringImplES2_
+__ZN3WTF5yieldEv
+__ZN3WTF6String26fromUTF8WithLatin1FallbackEPKcm
+__ZN3WTF6String29charactersWithNullTerminationEv
+__ZN3WTF6String6appendEPKtj
+__ZN3WTF6String6appendERKS0_
+__ZN3WTF6String6appendEc
+__ZN3WTF6String6appendEt
+__ZN3WTF6String6formatEPKcz
+__ZN3WTF6String6insertERKS0_j
+__ZN3WTF6String6numberEd
+__ZN3WTF6String6numberEi
+__ZN3WTF6String6numberEj
+__ZN3WTF6String6numberEl
+__ZN3WTF6String6numberEm
+__ZN3WTF6String6numberEt
+__ZN3WTF6String6numberEx
+__ZN3WTF6String6numberEy
+__ZN3WTF6String6removeEji
+__ZN3WTF6String8fromUTF8EPKc
+__ZN3WTF6String8fromUTF8EPKcm
+__ZN3WTF6String8truncateEj
+__ZN3WTF6StringC1EPKc
+__ZN3WTF6StringC1EPKcj
+__ZN3WTF6StringC1EPKt
+__ZN3WTF6StringC1EPKtj
__ZN3WTF6strtodEPKcPPc
__ZN3WTF7CString11mutableDataEv
__ZN3WTF7CString16newUninitializedEmRPc
__ZN3WTF7CStringC1EPKc
-__ZN3WTF7CStringC1EPKcj
+__ZN3WTF7CStringC1EPKcm
__ZN3WTF7Unicode18convertUTF16ToUTF8EPPKtS2_PPcS4_b
__ZN3WTF7Unicode18convertUTF8ToUTF16EPPKcS2_PPtS4_b
+__ZN3WTF7xmlAtomE
__ZN3WTF8Collator18setOrderLowerFirstEb
__ZN3WTF8CollatorC1EPKc
__ZN3WTF8CollatorD1Ev
+__ZN3WTF8Internal21fastMallocMatchFailedEPv
__ZN3WTF8fastFreeEPv
__ZN3WTF8msToYearEd
+__ZN3WTF8nullAtomE
+__ZN3WTF8starAtomE
+__ZN3WTF8textAtomE
__ZN3WTF9ByteArray6createEm
__ZN3WTF9dayInYearEdi
+__ZN3WTF9emptyAtomE
+__ZN3WTF9xmlnsAtomE
+__ZN3WTFeqERKNS_12AtomicStringEPKc
+__ZN3WTFeqERKNS_12AtomicStringERKNS_6VectorItLm0EEE
__ZN3WTFeqERKNS_7CStringES2_
-__ZN7WebCore10StringImpl11reverseFindEPS0_ib
-__ZN7WebCore10StringImpl11reverseFindEti
-__ZN7WebCore10StringImpl12sharedBufferEv
-__ZN7WebCore10StringImpl18simplifyWhiteSpaceEv
-__ZN7WebCore10StringImpl19characterStartingAtEj
-__ZN7WebCore10StringImpl19createUninitializedEjRPt
-__ZN7WebCore10StringImpl22containsOnlyWhitespaceEv
-__ZN7WebCore10StringImpl23defaultWritingDirectionEv
-__ZN7WebCore10StringImpl37createStrippingNullCharactersSlowCaseEPKtj
-__ZN7WebCore10StringImpl4findEPFbtEi
-__ZN7WebCore10StringImpl4findEPKcib
-__ZN7WebCore10StringImpl4findEPS0_ib
-__ZN7WebCore10StringImpl4findEti
-__ZN7WebCore10StringImpl5adoptERNS_12StringBufferE
-__ZN7WebCore10StringImpl5emptyEv
-__ZN7WebCore10StringImpl5lowerEv
-__ZN7WebCore10StringImpl5toIntEPb
-__ZN7WebCore10StringImpl5upperEv
-__ZN7WebCore10StringImpl6createEPKc
-__ZN7WebCore10StringImpl6createEPKcj
-__ZN7WebCore10StringImpl6createEPKtj
-__ZN7WebCore10StringImpl6createEPKtjN3WTF10PassRefPtrINS3_21CrossThreadRefCountedINS3_16OwnFastMallocPtrIS1_EEEEEE
-__ZN7WebCore10StringImpl6secureEtb
-__ZN7WebCore10StringImpl7replaceEPS0_S1_
-__ZN7WebCore10StringImpl7replaceEjjPS0_
-__ZN7WebCore10StringImpl7replaceEtPS0_
-__ZN7WebCore10StringImpl7replaceEtt
-__ZN7WebCore10StringImpl8endsWithEPS0_b
-__ZN7WebCore10StringImpl9substringEjj
-__ZN7WebCore10StringImplD1Ev
-__ZN7WebCore11commentAtomE
-__ZN7WebCore12AtomicString11addSlowCaseEPNS_10StringImplE
-__ZN7WebCore12AtomicString3addEPKc
-__ZN7WebCore12AtomicString3addEPKt
-__ZN7WebCore12AtomicString3addEPKtj
-__ZN7WebCore12AtomicString3addEPKtjj
-__ZN7WebCore12AtomicString4findEPKtjj
-__ZN7WebCore12AtomicString4initEv
-__ZN7WebCore15charactersToIntEPKtmPb
-__ZN7WebCore17charactersToFloatEPKtmPb
-__ZN7WebCore17equalIgnoringCaseEPKtPKcj
-__ZN7WebCore17equalIgnoringCaseEPNS_10StringImplEPKc
-__ZN7WebCore17equalIgnoringCaseEPNS_10StringImplES1_
-__ZN7WebCore18charactersToDoubleEPKtmPb
-__ZN7WebCore20equalIgnoringNullityEPNS_10StringImplES1_
-__ZN7WebCore21charactersToIntStrictEPKtmPbi
-__ZN7WebCore22charactersToUIntStrictEPKtmPbi
-__ZN7WebCore5equalEPKNS_10StringImplEPKc
-__ZN7WebCore5equalEPKNS_10StringImplES2_
-__ZN7WebCore6String26fromUTF8WithLatin1FallbackEPKcm
-__ZN7WebCore6String29charactersWithNullTerminationEv
-__ZN7WebCore6String6appendEPKtj
-__ZN7WebCore6String6appendERKS0_
-__ZN7WebCore6String6appendEc
-__ZN7WebCore6String6appendEt
-__ZN7WebCore6String6formatEPKcz
-__ZN7WebCore6String6insertERKS0_j
-__ZN7WebCore6String6numberEd
-__ZN7WebCore6String6numberEi
-__ZN7WebCore6String6numberEj
-__ZN7WebCore6String6numberEl
-__ZN7WebCore6String6numberEm
-__ZN7WebCore6String6numberEt
-__ZN7WebCore6String6numberEx
-__ZN7WebCore6String6numberEy
-__ZN7WebCore6String6removeEji
-__ZN7WebCore6String8fromUTF8EPKc
-__ZN7WebCore6String8fromUTF8EPKcm
-__ZN7WebCore6String8truncateEj
-__ZN7WebCore6StringC1EPKt
-__ZN7WebCore7xmlAtomE
-__ZN7WebCore8nullAtomE
-__ZN7WebCore8starAtomE
-__ZN7WebCore8textAtomE
-__ZN7WebCore9emptyAtomE
-__ZN7WebCore9xmlnsAtomE
-__ZN7WebCoreeqERKNS_12AtomicStringEPKc
-__ZN7WebCoreplEPKcRKNS_6StringE
-__ZN7WebCoreplERKNS_6StringEPKc
-__ZN7WebCoreplERKNS_6StringES2_
__ZNK3JSC10JSFunction23isHostFunctionNonInlineEv
-__ZNK3JSC11Interpreter14retrieveCallerEPNS_9ExecStateEPNS_16InternalFunctionE
+__ZNK3JSC11Interpreter14retrieveCallerEPNS_9ExecStateEPNS_10JSFunctionE
__ZNK3JSC11Interpreter18retrieveLastCallerEPNS_9ExecStateERiRlRNS_7UStringERNS_7JSValueE
__ZNK3JSC12PropertySlot14functionGetterEPNS_9ExecStateE
__ZNK3JSC14JSGlobalObject14isDynamicScopeERb
-__ZNK3JSC16InternalFunction9classInfoEv
__ZNK3JSC16JSVariableObject16isVariableObjectEv
__ZNK3JSC17DebuggerCallFrame10thisObjectEv
__ZNK3JSC17DebuggerCallFrame12functionNameEv
__ZNK3JSC18PropertyDescriptor6getterEv
__ZNK3JSC18PropertyDescriptor6setterEv
__ZNK3JSC18PropertyDescriptor8writableEv
-__ZNK3JSC4Heap10statisticsEv
+__ZNK3JSC19SourceProviderCache8byteSizeEv
__ZNK3JSC4Heap11objectCountEv
+__ZNK3JSC4Heap4sizeEv
+__ZNK3JSC4Heap8capacityEv
__ZNK3JSC6JSCell11toPrimitiveEPNS_9ExecStateENS_22PreferredPrimitiveTypeE
__ZNK3JSC6JSCell12toThisObjectEPNS_9ExecStateE
__ZNK3JSC6JSCell14isGetterSetterEv
__ZNK3JSC6JSCell8toNumberEPNS_9ExecStateE
-__ZNK3JSC6JSCell8toObjectEPNS_9ExecStateE
+__ZNK3JSC6JSCell8toObjectEPNS_9ExecStateEPNS_14JSGlobalObjectE
__ZNK3JSC6JSCell8toStringEPNS_9ExecStateE
-__ZNK3JSC6JSCell9classInfoEv
__ZNK3JSC6JSCell9getStringEPNS_9ExecStateE
__ZNK3JSC6JSCell9getStringEPNS_9ExecStateERNS_7UStringE
__ZNK3JSC6JSCell9getUInt32ERj
__ZNK3JSC6JSCell9toBooleanEPNS_9ExecStateE
__ZNK3JSC7ArgList8getSliceEiRS0_
__ZNK3JSC7JSArray12subclassDataEv
-__ZNK3JSC7JSValue16toObjectSlowCaseEPNS_9ExecStateE
+__ZNK3JSC7JSValue16toObjectSlowCaseEPNS_9ExecStateEPNS_14JSGlobalObjectE
__ZNK3JSC7JSValue19synthesizePrototypeEPNS_9ExecStateE
__ZNK3JSC7JSValue20toThisObjectSlowCaseEPNS_9ExecStateE
__ZNK3JSC7JSValue9toIntegerEPNS_9ExecStateE
-__ZNK3JSC7UString10UTF8StringEb
-__ZNK3JSC7UString14toStrictUInt32EPb
+__ZNK3JSC7UString20substringSharingImplEjj
+__ZNK3JSC7UString4utf8Eb
__ZNK3JSC7UString5asciiEv
-__ZNK3JSC7UString6is8BitEv
-__ZNK3JSC7UString6substrEjj
-__ZNK3JSC7UString8toUInt32EPb
-__ZNK3JSC7UString8toUInt32EPbb
__ZNK3JSC8JSObject11hasPropertyEPNS_9ExecStateERKNS_10IdentifierE
__ZNK3JSC8JSObject11hasPropertyEPNS_9ExecStateEj
__ZNK3JSC8JSObject12defaultValueEPNS_9ExecStateENS_22PreferredPrimitiveTypeE
__ZNK3JSC8JSObject12toThisObjectEPNS_9ExecStateE
+__ZNK3JSC8JSObject18toStrictThisObjectEPNS_9ExecStateE
__ZNK3JSC8JSObject8toNumberEPNS_9ExecStateE
-__ZNK3JSC8JSObject8toObjectEPNS_9ExecStateE
+__ZNK3JSC8JSObject8toObjectEPNS_9ExecStateEPNS_14JSGlobalObjectE
__ZNK3JSC8JSObject8toStringEPNS_9ExecStateE
__ZNK3JSC8JSObject9classNameEv
__ZNK3JSC8JSObject9toBooleanEPNS_9ExecStateE
__ZNK3JSC8JSString11resolveRopeEPNS_9ExecStateE
__ZNK3JSC9HashTable11createTableEPNS_12JSGlobalDataE
__ZNK3JSC9HashTable11deleteTableEv
+__ZNK3WTF12AtomicString5lowerEv
+__ZNK3WTF13DecimalNumber15toStringDecimalEPtj
+__ZNK3WTF13DecimalNumber19toStringExponentialEPtj
+__ZNK3WTF13DecimalNumber28bufferLengthForStringDecimalEv
+__ZNK3WTF13DecimalNumber32bufferLengthForStringExponentialEv
+__ZNK3WTF6String11toIntStrictEPbi
+__ZNK3WTF6String12toUIntStrictEPbi
+__ZNK3WTF6String13toInt64StrictEPbi
+__ZNK3WTF6String14threadsafeCopyEv
+__ZNK3WTF6String15stripWhiteSpaceEv
+__ZNK3WTF6String16removeCharactersEPFbtE
+__ZNK3WTF6String17crossThreadStringEv
+__ZNK3WTF6String18simplifyWhiteSpaceEv
+__ZNK3WTF6String19characterStartingAtEj
+__ZNK3WTF6String4utf8Eb
+__ZNK3WTF6String5asciiEv
+__ZNK3WTF6String5lowerEv
+__ZNK3WTF6String5splitERKS0_RNS_6VectorIS0_Lm0EEE
+__ZNK3WTF6String5splitERKS0_bRNS_6VectorIS0_Lm0EEE
+__ZNK3WTF6String5splitEtRNS_6VectorIS0_Lm0EEE
+__ZNK3WTF6String5splitEtbRNS_6VectorIS0_Lm0EEE
+__ZNK3WTF6String5toIntEPb
+__ZNK3WTF6String5upperEv
+__ZNK3WTF6String6latin1Ev
+__ZNK3WTF6String6toUIntEPb
+__ZNK3WTF6String7toFloatEPbS1_
+__ZNK3WTF6String8foldCaseEv
+__ZNK3WTF6String8toDoubleEPbS1_
+__ZNK3WTF6String8toIntPtrEPb
+__ZNK3WTF6String8toUInt64EPb
+__ZNK3WTF6String9substringEjj
__ZNK3WTF8Collator7collateEPKtmS2_m
-__ZNK7WebCore12AtomicString5lowerEv
-__ZNK7WebCore6String11toIntStrictEPbi
-__ZNK7WebCore6String12toUIntStrictEPbi
-__ZNK7WebCore6String14threadsafeCopyEv
-__ZNK7WebCore6String15stripWhiteSpaceEv
-__ZNK7WebCore6String16removeCharactersEPFbtE
-__ZNK7WebCore6String17crossThreadStringEv
-__ZNK7WebCore6String18simplifyWhiteSpaceEv
-__ZNK7WebCore6String19characterStartingAtEj
-__ZNK7WebCore6String4utf8Ev
-__ZNK7WebCore6String5asciiEv
-__ZNK7WebCore6String5lowerEv
-__ZNK7WebCore6String5splitERKS0_RN3WTF6VectorIS0_Lm0EEE
-__ZNK7WebCore6String5splitERKS0_bRN3WTF6VectorIS0_Lm0EEE
-__ZNK7WebCore6String5splitEtRN3WTF6VectorIS0_Lm0EEE
-__ZNK7WebCore6String5splitEtbRN3WTF6VectorIS0_Lm0EEE
-__ZNK7WebCore6String5toIntEPb
-__ZNK7WebCore6String5upperEv
-__ZNK7WebCore6String6latin1Ev
-__ZNK7WebCore6String6toUIntEPb
-__ZNK7WebCore6String7toFloatEPb
-__ZNK7WebCore6String8foldCaseEv
-__ZNK7WebCore6String8toDoubleEPb
-__ZNK7WebCore6String8toIntPtrEPb
-__ZNK7WebCore6String8toUInt64EPb
-__ZNK7WebCore6String9substringEjj
__ZTVN3JSC12StringObjectE
__ZTVN3JSC14JSGlobalObjectE
+__ZTVN3JSC14ScopeChainNodeE
__ZTVN3JSC15JSWrapperObjectE
+__ZTVN3JSC15WeakHandleOwnerE
__ZTVN3JSC16InternalFunctionE
__ZTVN3JSC16JSVariableObjectE
__ZTVN3JSC8DebuggerE
_jscore_fastmalloc_introspection
_kJSClassDefinitionEmpty
-# iOS Methods
+# iOS methods
+__ZN3WTF11isWebThreadEv
+__ZN3JSC12JSGlobalData23recompileAllJSFunctionsEv
__ZN3JSC12JSGlobalData20sharedInstanceExistsEv
+__ZN3JSC25DefaultGCActivityCallbackC2EPNS_4HeapEP11__CFRunLoop
+__ZN3JSC25DefaultGCActivityCallbackD2Ev
+__ZN3JSC25DefaultGCActivityCallbackclEv
+__ZN3JSC25DefaultGCActivityCallback11synchronizeEv
+__ZTVN3JSC25DefaultGCActivityCallbackE
'chromium_src_dir': '../../WebKit/chromium',
},{
# WebKit is checked out in src/chromium/third_party/WebKit
- 'chromium_src_dir': '../../../..',
+ 'chromium_src_dir': '../../../../..',
}],
],
},
'../wtf/unicode',
],
'sources': [
+ '<@(javascriptcore_publicheader_files)',
+ '<@(javascriptcore_privateheader_files)',
'<@(javascriptcore_files)',
],
'sources/': [
['exclude', '../'],
# ... Then include what we want.
['include', '../wtf/'],
+ # FIXME: This is clearly not sustainable.
+ ['exclude', '../wtf/android'],
+ ['exclude', '../wtf/brew'],
+ ['exclude', '../wtf/efl'],
+ ['exclude', '../wtf/gobject'],
+ ['exclude', '../wtf/gtk'],
+ ['exclude', '../wtf/haiku'],
+ ['exclude', '../wtf/mac'],
+ ['exclude', '../wtf/qt'],
+ ['exclude', '../wtf/url'],
+ ['exclude', '../wtf/wince'],
+ ['exclude', '../wtf/wx'],
+ ['exclude', '../wtf/unicode/brew'],
+ ['exclude', '../wtf/unicode/wince'],
+ ['exclude', '../wtf/unicode/glib'],
+ ['exclude', '../wtf/unicode/qt4'],
# GLib/GTK, even though its name doesn't really indicate.
['exclude', '/(gtk|glib|gobject)/.*\\.(cpp|h)$'],
- ['exclude', '(Default|Gtk|Mac|None|Qt|Win|Wx)\\.(cpp|mm)$'],
+ ['exclude', '(Default|Gtk|Mac|None|Qt|Win|Wx|Efl|Symbian)\\.(cpp|mm)$'],
['exclude', 'wtf/CurrentTime\\.cpp$'],
+ ['exclude', 'wtf/OSRandomSource\\.cpp$'],
['exclude', 'wtf/MainThread.cpp$'],
['exclude', 'wtf/TC.*\\.(cpp|h)$'],
],
'../',
'../wtf',
],
+ # Some warnings occur in JSC headers, so they must also be disabled
+ # in targets that use JSC.
+ 'msvs_disabled_warnings': [
+ # Don't complain about calling specific versions of templatized
+ # functions (e.g. in RefPtrHashMap.h).
+ 4344,
+ # Don't complain about using "this" in an initializer list
+ # (e.g. in StringImpl.h).
+ 4355,
+ ],
},
'export_dependent_settings': [
'wtf_config',
'sources/': [
['exclude', 'ThreadIdentifierDataPthreads\\.(h|cpp)$'],
['exclude', 'ThreadingPthreads\\.cpp$'],
- ['include', 'Thread(ing|Specific)Win\\.cpp$']
+ ['include', 'Thread(ing|Specific)Win\\.cpp$'],
+ ['exclude', 'OSAllocatorPosix\\.cpp$'],
+ ['include', 'OSAllocatorWin\\.cpp$']
],
'include_dirs!': [
'<(SHARED_INTERMEDIATE_DIR)/webkit',
],
+ 'conditions': [
+ ['inside_chromium_build==1 and component=="shared_library"', {
+ # Chromium windows multi-dll build enables c++ exception and this
+ # causes wtf generates 4291 warning due to operator new/delete
+ # implementations. Disable the warning for chromium windows
+ # multi-dll build.
+ 'msvs_disabled_warnings': [4291],
+ 'direct_dependent_settings': {
+ 'msvs_disabled_warnings': [4291],
+ },
+ }],
+ ],
}],
],
},
{
- 'target_name': 'pcre',
+ 'target_name': 'yarr',
'type': '<(library)',
'dependencies': [
'wtf',
'msvs_guid': '49909552-0B0C-4C14-8CF6-DB8A2ADE0934',
'actions': [
{
- 'action_name': 'dftables',
+ 'action_name': 'retgen',
+ 'inputs': [
+ '../create_regex_tables',
+ ],
+ 'arguments': [
+ '--no-tables',
+ ],
+ 'outputs': [
+ '<(INTERMEDIATE_DIR)/RegExpJitTables.h',
+ ],
+ 'action': ['python', '<@(_inputs)', '<@(_arguments)', '<@(_outputs)'],
+ },
+ {
+ 'action_name': 'klgen',
'inputs': [
- '../pcre/dftables',
+ '../KeywordLookupGenerator.py',
+ '../parser/Keywords.table'
+ ],
+ 'arguments': [
],
'outputs': [
- '<(INTERMEDIATE_DIR)/chartables.c',
+ '<(INTERMEDIATE_DIR)/KeywordLookup.h',
],
- 'action': ['perl', '-w', '<@(_inputs)', '<@(_outputs)'],
+ 'action': ['python', '<@(_inputs)', '<@(_arguments)', '<@(_outputs)'],
},
],
'include_dirs': [
'<(INTERMEDIATE_DIR)',
+ '../runtime',
],
'sources': [
'<@(javascriptcore_files)',
# First exclude everything ...
['exclude', '../'],
# ... Then include what we want.
- ['include', '../pcre/'],
- # ucptable.cpp is #included by pcre_ucp_searchfunchs.cpp and is not
- # intended to be compiled directly.
- ['exclude', '../pcre/ucptable.cpp$'],
+ ['include', '../yarr/'],
+ # The Yarr JIT isn't used in WebCore.
+ ['exclude', '../yarr/YarrJIT\\.(h|cpp)$'],
],
'export_dependent_settings': [
'wtf',
{
'variables': {
- 'javascriptcore_files': [
- 'API/APICast.h',
+ 'project_dir': ['.'],
+ # These headers are part of JavaScriptCore's public API in the Apple Mac build.
+ 'javascriptcore_publicheader_files': [
+ 'API/JSBase.h',
+ 'API/JSContextRef.h',
+ 'API/JSObjectRef.h',
+ 'API/JSStringRef.h',
+ 'API/JSStringRefCF.h',
+ 'API/JSValueRef.h',
'API/JavaScript.h',
'API/JavaScriptCore.h',
- 'API/JSBase.cpp',
- 'API/JSBase.h',
+ 'API/WebKitAvailability.h',
+ ],
+ # These headers are part of JavaScriptCore's private API in the Apple Mac build.
+ 'javascriptcore_privateheader_files': [
+ 'API/APICast.h',
+ 'API/APIShims.h',
'API/JSBasePrivate.h',
+ 'API/JSContextRefPrivate.h',
+ 'API/JSObjectRefPrivate.h',
+ 'API/JSProfilerPrivate.h',
+ 'API/JSRetainPtr.h',
+ 'API/JSWeakObjectMapRefInternal.h',
+ 'API/JSWeakObjectMapRefPrivate.h',
+ 'API/OpaqueJSString.h',
+ 'assembler/MacroAssemblerCodeRef.h',
+ 'bytecode/Opcode.h',
+ 'heap/ConservativeRoots.h',
+ 'heap/Handle.h',
+ 'heap/HandleHeap.h',
+ 'heap/HandleStack.h',
+ 'heap/HandleTypes.h',
+ 'heap/Heap.h',
+ 'heap/Local.h',
+ 'heap/LocalScope.h',
+ 'heap/Strong.h',
+ 'heap/Weak.h',
+ 'config.h',
+ 'debugger/Debugger.h',
+ 'debugger/DebuggerActivation.h',
+ 'debugger/DebuggerCallFrame.h',
+ 'interpreter/CallFrame.h',
+ 'interpreter/Interpreter.h',
+ 'interpreter/Register.h',
+ 'interpreter/RegisterFile.h',
+ 'jit/ExecutableAllocator.h',
+ 'jit/JITCode.h',
+ 'jit/JITStubs.h',
+ 'jit/ThunkGenerators.h',
+ 'parser/ResultType.h',
+ 'parser/SourceCode.h',
+ 'parser/SourceProvider.h',
+ 'parser/SourceProviderCache.h',
+ 'profiler/CallIdentifier.h',
+ 'profiler/Profile.h',
+ 'profiler/ProfileNode.h',
+ 'profiler/Profiler.h',
+ 'runtime/ArgList.h',
+ 'runtime/ArrayPrototype.h',
+ 'runtime/BooleanObject.h',
+ 'runtime/CachedTranscendentalFunction.h',
+ 'runtime/CallData.h',
+ 'runtime/ClassInfo.h',
+ 'runtime/CommonIdentifiers.h',
+ 'runtime/Completion.h',
+ 'runtime/ConstructData.h',
+ 'runtime/DateInstance.h',
+ 'runtime/DateInstanceCache.h',
+ 'runtime/Error.h',
+ 'runtime/ExceptionHelpers.h',
+ 'runtime/FunctionConstructor.h',
+ 'runtime/FunctionPrototype.h',
+ 'runtime/GCActivityCallback.h',
+ 'runtime/Identifier.h',
+ 'runtime/InitializeThreading.h',
+ 'runtime/InternalFunction.h',
+ 'runtime/JSAPIValueWrapper.h',
+ 'runtime/JSArray.h',
+ 'runtime/JSByteArray.h',
+ 'runtime/JSCell.h',
+ 'runtime/JSFunction.h',
+ 'runtime/JSGlobalData.h',
+ 'runtime/JSGlobalObject.h',
+ 'runtime/JSLock.h',
+ 'runtime/JSNumberCell.h',
+ 'runtime/JSObject.h',
+ 'runtime/JSObjectWithGlobalObject.h',
+ 'runtime/JSString.h',
+ 'runtime/JSType.h',
+ 'runtime/JSTypeInfo.h',
+ 'runtime/JSValue.h',
+ 'runtime/JSValueInlineMethods.h',
+ 'runtime/JSVariableObject.h',
+ 'runtime/JSWrapperObject.h',
+ 'runtime/Lookup.h',
+ 'runtime/MathObject.h',
+ 'runtime/MemoryStatistics.h',
+ 'runtime/NumberObject.h',
+ 'runtime/NumberPrototype.h',
+ 'runtime/NumericStrings.h',
+ 'runtime/ObjectPrototype.h',
+ 'runtime/Operations.h',
+ 'runtime/PropertyDescriptor.h',
+ 'runtime/PropertyMapHashTable.h',
+ 'runtime/PropertyNameArray.h',
+ 'runtime/PropertySlot.h',
+ 'runtime/Protect.h',
+ 'runtime/PutPropertySlot.h',
+ 'runtime/RegExp.h',
+ 'runtime/RegExpKey.h',
+ 'runtime/RegExpCache.h',
+ 'runtime/RegExpObject.h',
+ 'runtime/RopeImpl.h',
+ 'runtime/ScopeChain.h',
+ 'runtime/SmallStrings.h',
+ 'runtime/StringObject.h',
+ 'runtime/StringObjectThatMasqueradesAsUndefined.h',
+ 'runtime/StringPrototype.h',
+ 'runtime/Structure.h',
+ 'runtime/StructureChain.h',
+ 'runtime/StructureTransitionTable.h',
+ 'runtime/SymbolTable.h',
+ 'runtime/Terminator.h',
+ 'runtime/TimeoutChecker.h',
+ 'runtime/UString.h',
+ 'runtime/UStringBuilder.h',
+ 'runtime/WeakGCMap.h',
+ 'runtime/WeakRandom.h',
+ 'runtime/WriteBarrier.h',
+ 'wtf/ASCIICType.h',
+ 'wtf/AVLTree.h',
+ 'wtf/Alignment.h',
+ 'wtf/AlwaysInline.h',
+ 'wtf/Assertions.h',
+ 'wtf/Atomics.h',
+ 'wtf/Bitmap.h',
+ 'wtf/BlockStack.h',
+ 'wtf/BloomFilter.h',
+ 'wtf/BumpPointerAllocator.h',
+ 'wtf/ByteArray.h',
+ 'wtf/Complex.h',
+ 'wtf/CrossThreadRefCounted.h',
+ 'wtf/CryptographicallyRandomNumber.h',
+ 'wtf/CurrentTime.h',
+ 'wtf/DateMath.h',
+ 'wtf/DecimalNumber.h',
+ 'wtf/Decoder.h',
+ 'wtf/Deque.h',
+ 'wtf/DisallowCType.h',
+ 'wtf/DoublyLinkedList.h',
+ 'wtf/Encoder.h',
+ 'wtf/FastAllocBase.h',
+ 'wtf/FastMalloc.h',
+ 'wtf/FixedArray.h',
+ 'wtf/Forward.h',
+ 'wtf/GetPtr.h',
+ 'wtf/HashCountedSet.h',
+ 'wtf/HashFunctions.h',
+ 'wtf/HashIterators.h',
+ 'wtf/HashMap.h',
+ 'wtf/HashSet.h',
+ 'wtf/HashTable.h',
+ 'wtf/HashTraits.h',
+ 'wtf/HexNumber.h',
+ 'wtf/ListHashSet.h',
+ 'wtf/ListRefPtr.h',
+ 'wtf/Locker.h',
+ 'wtf/MD5.h',
+ 'wtf/MainThread.h',
+ 'wtf/MathExtras.h',
+ 'wtf/MessageQueue.h',
+ 'wtf/NonCopyingSort.h',
+ 'wtf/Noncopyable.h',
+ 'wtf/NotFound.h',
+ 'wtf/NullPtr.h',
+ 'wtf/OSAllocator.h',
+ 'wtf/OwnArrayPtr.h',
+ 'wtf/OwnFastMallocPtr.h',
+ 'wtf/OwnPtr.h',
+ 'wtf/OwnPtrCommon.h',
+ 'wtf/PageAllocation.h',
+ 'wtf/PageAllocationAligned.h',
+ 'wtf/PageBlock.h',
+ 'wtf/PageReservation.h',
+ 'wtf/PassOwnArrayPtr.h',
+ 'wtf/PassOwnPtr.h',
+ 'wtf/PassRefPtr.h',
+ 'wtf/PassTraits.h',
+ 'wtf/Platform.h',
+ 'wtf/PossiblyNull.h',
+ 'wtf/RandomNumber.h',
+ 'wtf/RefCounted.h',
+ 'wtf/RefCountedLeakCounter.h',
+ 'wtf/RefPtr.h',
+ 'wtf/RefPtrHashMap.h',
+ 'wtf/RetainPtr.h',
+ 'wtf/SentinelLinkedList.h',
+ 'wtf/SinglyLinkedList.h',
+ 'wtf/StackBounds.h',
+ 'wtf/StaticConstructors.h',
+ 'wtf/StdLibExtras.h',
+ 'wtf/StringExtras.h',
+ 'wtf/StringHasher.h',
+ 'wtf/ThreadSafeRefCounted.h',
+ 'wtf/ThreadSpecific.h',
+ 'wtf/Threading.h',
+ 'wtf/ThreadingPrimitives.h',
+ 'wtf/TypeTraits.h',
+ 'wtf/UnusedParam.h',
+ 'wtf/VMTags.h',
+ 'wtf/ValueCheck.h',
+ 'wtf/Vector.h',
+ 'wtf/VectorTraits.h',
+ 'wtf/WTFThreadData.h',
+ 'wtf/dtoa.h',
+ 'wtf/text/AtomicString.h',
+ 'wtf/text/AtomicStringHash.h',
+ 'wtf/text/AtomicStringImpl.h',
+ 'wtf/text/CString.h',
+ 'wtf/text/StringBuffer.h',
+ 'wtf/text/StringBuilder.h',
+ 'wtf/text/StringConcatenate.h',
+ 'wtf/text/StringHash.h',
+ 'wtf/text/StringImpl.h',
+ 'wtf/text/StringImplBase.h',
+ 'wtf/text/StringOperators.h',
+ 'wtf/text/TextPosition.h',
+ 'wtf/text/WTFString.h',
+ 'wtf/unicode/CharacterNames.h',
+ 'wtf/unicode/Collator.h',
+ 'wtf/unicode/UTF8.h',
+ 'wtf/unicode/Unicode.h',
+ 'wtf/unicode/icu/UnicodeIcu.h',
+ 'yarr/Yarr.h',
+ 'yarr/YarrInterpreter.h',
+ 'yarr/YarrPattern.h',
+ ],
+ 'javascriptcore_files': [
+ 'API/APIShims.h',
+ 'API/JSBase.cpp',
'API/JSCallbackConstructor.cpp',
'API/JSCallbackConstructor.h',
'API/JSCallbackFunction.cpp',
'API/JSClassRef.cpp',
'API/JSClassRef.h',
'API/JSContextRef.cpp',
- 'API/JSContextRef.h',
- 'API/JSContextRefPrivate.h',
'API/JSObjectRef.cpp',
- 'API/JSObjectRef.h',
'API/JSProfilerPrivate.cpp',
- 'API/JSProfilerPrivate.h',
- 'API/JSRetainPtr.h',
'API/JSStringRef.cpp',
- 'API/JSStringRef.h',
'API/JSStringRefBSTR.cpp',
'API/JSStringRefBSTR.h',
'API/JSStringRefCF.cpp',
- 'API/JSStringRefCF.h',
'API/JSValueRef.cpp',
- 'API/JSValueRef.h',
+ 'API/JSWeakObjectMapRefPrivate.cpp',
'API/OpaqueJSString.cpp',
- 'API/OpaqueJSString.h',
- 'API/tests/JSNode.h',
- 'API/tests/JSNodeList.h',
- 'API/tests/Node.h',
- 'API/tests/NodeList.h',
- 'API/WebKitAvailability.h',
- 'assembler/AbstractMacroAssembler.h',
+ 'AllInOneFile.cpp',
+ 'ForwardingHeaders/JavaScriptCore/APICast.h',
+ 'ForwardingHeaders/JavaScriptCore/APIShims.h',
+ 'ForwardingHeaders/JavaScriptCore/JSBase.h',
+ 'ForwardingHeaders/JavaScriptCore/JSContextRef.h',
+ 'ForwardingHeaders/JavaScriptCore/JSObjectRef.h',
+ 'ForwardingHeaders/JavaScriptCore/JSRetainPtr.h',
+ 'ForwardingHeaders/JavaScriptCore/JSStringRef.h',
+ 'ForwardingHeaders/JavaScriptCore/JSStringRefCF.h',
+ 'ForwardingHeaders/JavaScriptCore/JSValueRef.h',
+ 'ForwardingHeaders/JavaScriptCore/JavaScript.h',
+ 'ForwardingHeaders/JavaScriptCore/JavaScriptCore.h',
+ 'ForwardingHeaders/JavaScriptCore/OpaqueJSString.h',
+ 'ForwardingHeaders/JavaScriptCore/WebKitAvailability.h',
+ 'JavaScriptCorePrefix.h',
+ 'assembler/ARMAssembler.cpp',
+ 'assembler/ARMAssembler.h',
+ 'assembler/ARMv7Assembler.cpp',
'assembler/ARMv7Assembler.h',
+ 'assembler/AbstractMacroAssembler.h',
'assembler/AssemblerBuffer.h',
+ 'assembler/AssemblerBufferWithConstantPool.h',
'assembler/CodeLocation.h',
+ 'assembler/LinkBuffer.h',
+ 'assembler/MIPSAssembler.h',
'assembler/MacroAssembler.h',
+ 'assembler/MacroAssemblerARM.cpp',
+ 'assembler/MacroAssemblerARM.h',
'assembler/MacroAssemblerARMv7.h',
- 'assembler/MacroAssemblerCodeRef.h',
+ 'assembler/MacroAssemblerMIPS.h',
'assembler/MacroAssemblerX86.h',
- 'assembler/MacroAssemblerX86_64.h',
'assembler/MacroAssemblerX86Common.h',
+ 'assembler/MacroAssemblerX86_64.h',
+ 'assembler/RepatchBuffer.h',
'assembler/X86Assembler.h',
'bytecode/CodeBlock.cpp',
'bytecode/CodeBlock.h',
'bytecode/JumpTable.cpp',
'bytecode/JumpTable.h',
'bytecode/Opcode.cpp',
- 'bytecode/Opcode.h',
'bytecode/SamplingTool.cpp',
'bytecode/SamplingTool.h',
'bytecode/StructureStubInfo.cpp',
'bytecode/StructureStubInfo.h',
'bytecompiler/BytecodeGenerator.cpp',
'bytecompiler/BytecodeGenerator.h',
- 'bytecompiler/NodesCodegen.cpp',
'bytecompiler/Label.h',
'bytecompiler/LabelScope.h',
+ 'bytecompiler/NodesCodegen.cpp',
'bytecompiler/RegisterID.h',
- 'config.h',
+ 'heap/ConservativeRoots.cpp',
+ 'heap/HandleHeap.cpp',
+ 'heap/HandleStack.cpp',
+ 'heap/Heap.cpp',
+ 'heap/MachineStackMarker.cpp',
+ 'heap/MachineStackMarker.h',
+ 'heap/MarkStack.cpp',
+ 'heap/MarkStack.h',
+ 'heap/MarkStackPosix.cpp',
+ 'heap/MarkStackSymbian.cpp',
+ 'heap/MarkStackWin.cpp',
+ 'heap/MarkedBlock.cpp',
+ 'heap/MarkedBlock.h',
+ 'heap/MarkedSpace.cpp',
+ 'heap/MarkedSpace.h',
'debugger/Debugger.cpp',
- 'debugger/Debugger.h',
'debugger/DebuggerActivation.cpp',
- 'debugger/DebuggerActivation.h',
'debugger/DebuggerCallFrame.cpp',
- 'debugger/DebuggerCallFrame.h',
+ 'dfg/DFGAliasTracker.h',
+ 'dfg/DFGByteCodeParser.cpp',
+ 'dfg/DFGByteCodeParser.h',
+ 'dfg/DFGGenerationInfo.h',
+ 'dfg/DFGGraph.cpp',
+ 'dfg/DFGGraph.h',
+ 'dfg/DFGJITCodeGenerator.cpp',
+ 'dfg/DFGJITCodeGenerator.h',
+ 'dfg/DFGJITCompiler.cpp',
+ 'dfg/DFGJITCompiler.h',
+ 'dfg/DFGNode.h',
+ 'dfg/DFGNonSpeculativeJIT.cpp',
+ 'dfg/DFGNonSpeculativeJIT.h',
+ 'dfg/DFGOperations.cpp',
+ 'dfg/DFGOperations.h',
+ 'dfg/DFGRegisterBank.h',
+ 'dfg/DFGScoreBoard.h',
+ 'dfg/DFGSpeculativeJIT.cpp',
+ 'dfg/DFGSpeculativeJIT.h',
'icu/unicode/parseerr.h',
'icu/unicode/platform.h',
'icu/unicode/putil.h',
'icu/unicode/uversion.h',
'interpreter/CachedCall.h',
'interpreter/CallFrame.cpp',
- 'interpreter/CallFrame.h',
'interpreter/CallFrameClosure.h',
'interpreter/Interpreter.cpp',
- 'interpreter/Interpreter.h',
- 'interpreter/Register.h',
'interpreter/RegisterFile.cpp',
- 'interpreter/RegisterFile.h',
- 'JavaScriptCorePrefix.h',
'jit/ExecutableAllocator.cpp',
- 'jit/ExecutableAllocator.h',
'jit/ExecutableAllocatorFixedVMPool.cpp',
- 'jit/ExecutableAllocatorPosix.cpp',
- 'jit/ExecutableAllocatorWin.cpp',
'jit/JIT.cpp',
'jit/JIT.h',
'jit/JITArithmetic.cpp',
'jit/JITArithmetic32_64.cpp',
'jit/JITCall.cpp',
- 'jit/JITCode.h',
+ 'jit/JITCall32_64.cpp',
'jit/JITInlineMethods.h',
'jit/JITOpcodes.cpp',
'jit/JITOpcodes32_64.cpp',
'jit/JITPropertyAccess32_64.cpp',
'jit/JITStubCall.h',
'jit/JITStubs.cpp',
- 'jit/JITStubs.h',
- 'jsc.cpp',
+ 'jit/JSInterfaceJIT.h',
+ 'jit/SpecializedThunkJIT.h',
+ 'jit/ThunkGenerators.cpp',
+ 'os-win32/WinMain.cpp',
+ 'os-win32/inttypes.h',
'os-win32/stdbool.h',
'os-win32/stdint.h',
+ 'parser/ASTBuilder.h',
+ 'parser/JSParser.cpp',
+ 'parser/JSParser.h',
'parser/Lexer.cpp',
'parser/Lexer.h',
'parser/NodeConstructors.h',
'parser/Parser.h',
'parser/ParserArena.cpp',
'parser/ParserArena.h',
- 'parser/ResultType.h',
- 'parser/SourceCode.h',
- 'parser/SourceProvider.h',
- 'pcre/pcre.h',
- 'pcre/pcre_compile.cpp',
- 'pcre/pcre_exec.cpp',
- 'pcre/pcre_internal.h',
- 'pcre/pcre_tables.cpp',
- 'pcre/pcre_ucp_searchfuncs.cpp',
- 'pcre/pcre_xclass.cpp',
- 'pcre/ucpinternal.h',
- 'pcre/ucptable.cpp',
- 'profiler/CallIdentifier.h',
+ 'parser/SourceProviderCache.cpp',
+ 'parser/SourceProviderCacheItem.h',
+ 'parser/SyntaxChecker.h',
'profiler/Profile.cpp',
- 'profiler/Profile.h',
'profiler/ProfileGenerator.cpp',
'profiler/ProfileGenerator.h',
'profiler/ProfileNode.cpp',
- 'profiler/ProfileNode.h',
'profiler/Profiler.cpp',
- 'profiler/Profiler.h',
'profiler/ProfilerServer.h',
+ 'profiler/ProfilerServer.mm',
+ 'qt/api/qscriptconverter_p.h',
+ 'qt/api/qscriptengine.cpp',
+ 'qt/api/qscriptengine.h',
+ 'qt/api/qscriptengine_p.cpp',
+ 'qt/api/qscriptengine_p.h',
+ 'qt/api/qscriptfunction.cpp',
+ 'qt/api/qscriptfunction_p.h',
+ 'qt/api/qscriptoriginalglobalobject_p.h',
+ 'qt/api/qscriptprogram.cpp',
+ 'qt/api/qscriptprogram.h',
+ 'qt/api/qscriptprogram_p.h',
+ 'qt/api/qscriptstring.cpp',
+ 'qt/api/qscriptstring.h',
+ 'qt/api/qscriptstring_p.h',
+ 'qt/api/qscriptsyntaxcheckresult.cpp',
+ 'qt/api/qscriptsyntaxcheckresult.h',
+ 'qt/api/qscriptsyntaxcheckresult_p.h',
+ 'qt/api/qscriptvalue.cpp',
+ 'qt/api/qscriptvalue.h',
+ 'qt/api/qscriptvalue_p.h',
+ 'qt/api/qscriptvalueiterator.cpp',
+ 'qt/api/qscriptvalueiterator.h',
+ 'qt/api/qscriptvalueiterator_p.h',
+ 'qt/api/qtscriptglobal.h',
+ 'qt/benchmarks/qscriptengine/tst_qscriptengine.cpp',
+ 'qt/benchmarks/qscriptvalue/tst_qscriptvalue.cpp',
+ 'qt/tests/qscriptengine/tst_qscriptengine.cpp',
+ 'qt/tests/qscriptstring/tst_qscriptstring.cpp',
+ 'qt/tests/qscriptvalue/tst_qscriptvalue.cpp',
+ 'qt/tests/qscriptvalue/tst_qscriptvalue.h',
+ 'qt/tests/qscriptvalue/tst_qscriptvalue_generated_comparison.cpp',
+ 'qt/tests/qscriptvalue/tst_qscriptvalue_generated_init.cpp',
+ 'qt/tests/qscriptvalue/tst_qscriptvalue_generated_istype.cpp',
+ 'qt/tests/qscriptvalue/tst_qscriptvalue_generated_totype.cpp',
+ 'qt/tests/qscriptvalueiterator/tst_qscriptvalueiterator.cpp',
'runtime/ArgList.cpp',
- 'runtime/ArgList.h',
'runtime/Arguments.cpp',
'runtime/Arguments.h',
'runtime/ArrayConstructor.cpp',
'runtime/ArrayConstructor.h',
'runtime/ArrayPrototype.cpp',
- 'runtime/ArrayPrototype.h',
'runtime/BatchedTransitionOptimizer.h',
'runtime/BooleanConstructor.cpp',
'runtime/BooleanConstructor.h',
'runtime/BooleanObject.cpp',
- 'runtime/BooleanObject.h',
'runtime/BooleanPrototype.cpp',
'runtime/BooleanPrototype.h',
'runtime/CallData.cpp',
- 'runtime/CallData.h',
- 'runtime/ClassInfo.h',
- 'runtime/Collector.cpp',
- 'runtime/Collector.h',
- 'runtime/CollectorHeapIterator.h',
'runtime/CommonIdentifiers.cpp',
- 'runtime/CommonIdentifiers.h',
'runtime/Completion.cpp',
- 'runtime/Completion.h',
'runtime/ConstructData.cpp',
- 'runtime/ConstructData.h',
'runtime/DateConstructor.cpp',
'runtime/DateConstructor.h',
'runtime/DateConversion.cpp',
'runtime/DateConversion.h',
'runtime/DateInstance.cpp',
- 'runtime/DateInstance.h',
- 'runtime/DateInstanceCache.h',
'runtime/DatePrototype.cpp',
'runtime/DatePrototype.h',
'runtime/Error.cpp',
- 'runtime/Error.h',
'runtime/ErrorConstructor.cpp',
'runtime/ErrorConstructor.h',
'runtime/ErrorInstance.cpp',
'runtime/ErrorPrototype.cpp',
'runtime/ErrorPrototype.h',
'runtime/ExceptionHelpers.cpp',
- 'runtime/ExceptionHelpers.h',
+ 'runtime/Executable.cpp',
+ 'runtime/Executable.h',
'runtime/FunctionConstructor.cpp',
- 'runtime/FunctionConstructor.h',
'runtime/FunctionPrototype.cpp',
- 'runtime/FunctionPrototype.h',
+ 'runtime/GCActivityCallback.cpp',
+ 'runtime/GCActivityCallbackCF.cpp',
'runtime/GetterSetter.cpp',
'runtime/GetterSetter.h',
- 'runtime/GlobalEvalFunction.cpp',
- 'runtime/GlobalEvalFunction.h',
'runtime/Identifier.cpp',
- 'runtime/Identifier.h',
'runtime/InitializeThreading.cpp',
- 'runtime/InitializeThreading.h',
'runtime/InternalFunction.cpp',
- 'runtime/InternalFunction.h',
+ 'runtime/JSAPIValueWrapper.cpp',
'runtime/JSActivation.cpp',
'runtime/JSActivation.h',
'runtime/JSArray.cpp',
- 'runtime/JSArray.h',
'runtime/JSByteArray.cpp',
- 'runtime/JSByteArray.h',
'runtime/JSCell.cpp',
- 'runtime/JSCell.h',
'runtime/JSFunction.cpp',
- 'runtime/JSFunction.h',
'runtime/JSGlobalData.cpp',
- 'runtime/JSGlobalData.h',
'runtime/JSGlobalObject.cpp',
- 'runtime/JSGlobalObject.h',
'runtime/JSGlobalObjectFunctions.cpp',
'runtime/JSGlobalObjectFunctions.h',
- 'runtime/JSImmediate.cpp',
- 'runtime/JSImmediate.h',
'runtime/JSLock.cpp',
- 'runtime/JSLock.h',
'runtime/JSNotAnObject.cpp',
'runtime/JSNotAnObject.h',
'runtime/JSNumberCell.cpp',
- 'runtime/JSNumberCell.h',
- 'runtime/JSObject.cpp',
- 'runtime/JSObject.h',
'runtime/JSONObject.cpp',
'runtime/JSONObject.h',
+ 'runtime/JSObject.cpp',
+ 'runtime/JSObjectWithGlobalObject.cpp',
'runtime/JSPropertyNameIterator.cpp',
'runtime/JSPropertyNameIterator.h',
'runtime/JSStaticScopeObject.cpp',
'runtime/JSStaticScopeObject.h',
'runtime/JSString.cpp',
- 'runtime/JSString.h',
- 'runtime/JSType.h',
- 'runtime/JSTypeInfo.h',
+ 'runtime/JSStringBuilder.h',
'runtime/JSValue.cpp',
- 'runtime/JSValue.h',
'runtime/JSVariableObject.cpp',
- 'runtime/JSVariableObject.h',
'runtime/JSWrapperObject.cpp',
- 'runtime/JSWrapperObject.h',
+ 'runtime/JSZombie.cpp',
+ 'runtime/JSZombie.h',
'runtime/LiteralParser.cpp',
'runtime/LiteralParser.h',
'runtime/Lookup.cpp',
- 'runtime/Lookup.h',
- 'runtime/MarkStack.cpp',
- 'runtime/MarkStack.h',
- 'runtime/MarkStackWin.cpp',
'runtime/MathObject.cpp',
- 'runtime/MathObject.h',
+ 'runtime/MemoryStatistics.cpp',
'runtime/NativeErrorConstructor.cpp',
'runtime/NativeErrorConstructor.h',
'runtime/NativeErrorPrototype.cpp',
'runtime/NativeErrorPrototype.h',
- 'runtime/NativeFunctionWrapper.h',
'runtime/NumberConstructor.cpp',
'runtime/NumberConstructor.h',
'runtime/NumberObject.cpp',
- 'runtime/NumberObject.h',
'runtime/NumberPrototype.cpp',
- 'runtime/NumberPrototype.h',
'runtime/ObjectConstructor.cpp',
'runtime/ObjectConstructor.h',
'runtime/ObjectPrototype.cpp',
- 'runtime/ObjectPrototype.h',
'runtime/Operations.cpp',
- 'runtime/Operations.h',
'runtime/PropertyDescriptor.cpp',
- 'runtime/PropertyDescriptor.h',
- 'runtime/PropertyMapHashTable.h',
'runtime/PropertyNameArray.cpp',
- 'runtime/PropertyNameArray.h',
'runtime/PropertySlot.cpp',
- 'runtime/PropertySlot.h',
- 'runtime/Protect.h',
- 'runtime/PrototypeFunction.cpp',
- 'runtime/PrototypeFunction.h',
- 'runtime/PutPropertySlot.h',
'runtime/RegExp.cpp',
- 'runtime/RegExp.h',
'runtime/RegExpCache.cpp',
- 'runtime/RegExpCache.h',
'runtime/RegExpConstructor.cpp',
'runtime/RegExpConstructor.h',
- 'runtime/RegExpKey.h',
'runtime/RegExpMatchesArray.h',
'runtime/RegExpObject.cpp',
- 'runtime/RegExpObject.h',
'runtime/RegExpPrototype.cpp',
'runtime/RegExpPrototype.h',
+ 'runtime/RopeImpl.cpp',
'runtime/ScopeChain.cpp',
- 'runtime/ScopeChain.h',
'runtime/ScopeChainMark.h',
'runtime/SmallStrings.cpp',
- 'runtime/SmallStrings.h',
+ 'runtime/StrictEvalActivation.cpp',
+ 'runtime/StrictEvalActivation.h',
'runtime/StringConstructor.cpp',
'runtime/StringConstructor.h',
'runtime/StringObject.cpp',
- 'runtime/StringObject.h',
- 'runtime/StringObjectThatMasqueradesAsUndefined.h',
'runtime/StringPrototype.cpp',
- 'runtime/StringPrototype.h',
+ 'runtime/StringRecursionChecker.cpp',
+ 'runtime/StringRecursionChecker.h',
'runtime/Structure.cpp',
- 'runtime/Structure.h',
'runtime/StructureChain.cpp',
- 'runtime/StructureChain.h',
- 'runtime/StructureTransitionTable.h',
- 'runtime/SymbolTable.h',
- 'runtime/Terminator.h',
'runtime/TimeoutChecker.cpp',
- 'runtime/TimeoutChecker.h',
+ 'runtime/Tracing.d',
'runtime/Tracing.h',
'runtime/UString.cpp',
- 'runtime/UString.h',
- 'runtime/WeakRandom.h',
- 'wtf/AlwaysInline.h',
- 'wtf/ASCIICType.h',
+ 'runtime/UStringConcatenate.h',
'wtf/Assertions.cpp',
- 'wtf/Assertions.h',
- 'wtf/Atomics.h',
- 'wtf/AVLTree.h',
'wtf/ByteArray.cpp',
- 'wtf/ByteArray.h',
- 'wtf/chromium/ChromiumThreading.h',
- 'wtf/chromium/MainThreadChromium.cpp',
- 'wtf/CrossThreadRefCounted.h',
+ 'wtf/CryptographicallyRandomNumber.cpp',
'wtf/CurrentTime.cpp',
- 'wtf/CurrentTime.h',
'wtf/DateMath.cpp',
- 'wtf/DateMath.h',
- 'wtf/Deque.h',
- 'wtf/DisallowCType.h',
- 'wtf/dtoa.cpp',
- 'wtf/dtoa.h',
- 'wtf/FastAllocBase.h',
+ 'wtf/DecimalNumber.cpp',
+ 'wtf/DynamicAnnotations.cpp',
+ 'wtf/DynamicAnnotations.h',
'wtf/FastMalloc.cpp',
- 'wtf/FastMalloc.h',
- 'wtf/Forward.h',
- 'wtf/GetPtr.h',
- 'wtf/gobject/GOwnPtr.cpp',
- 'wtf/gobject/GOwnPtr.h',
- 'wtf/gtk/MainThreadGtk.cpp',
- 'wtf/gtk/ThreadingGtk.cpp',
- 'wtf/HashCountedSet.h',
- 'wtf/HashFunctions.h',
- 'wtf/HashIterators.h',
- 'wtf/HashMap.h',
- 'wtf/HashSet.h',
'wtf/HashTable.cpp',
- 'wtf/HashTable.h',
- 'wtf/HashTraits.h',
- 'wtf/ListHashSet.h',
- 'wtf/ListRefPtr.h',
- 'wtf/Locker.h',
'wtf/MD5.cpp',
- 'wtf/MD5.h',
'wtf/MainThread.cpp',
- 'wtf/MainThread.h',
'wtf/MallocZoneSupport.h',
- 'wtf/MathExtras.h',
- 'wtf/MessageQueue.h',
- 'wtf/Noncopyable.h',
- 'wtf/NotFound.h',
- 'wtf/OwnArrayPtr.h',
- 'wtf/OwnFastMallocPtr.h',
- 'wtf/OwnPtr.h',
- 'wtf/OwnPtrCommon.h',
- 'wtf/PassOwnPtr.h',
- 'wtf/PassRefPtr.h',
- 'wtf/Platform.h',
- 'wtf/PtrAndFlags.h',
+ 'wtf/NullPtr.cpp',
+ 'wtf/OSAllocatorPosix.cpp',
+ 'wtf/OSAllocatorSymbian.cpp',
+ 'wtf/OSAllocatorWin.cpp',
+ 'wtf/OSRandomSource.cpp',
+ 'wtf/OSRandomSource.h',
+ 'wtf/PageAllocationAligned.cpp',
+ 'wtf/PageAllocatorSymbian.h',
+ 'wtf/PageBlock.cpp',
'wtf/RandomNumber.cpp',
- 'wtf/RandomNumber.h',
'wtf/RandomNumberSeed.h',
- 'wtf/RefCounted.h',
'wtf/RefCountedLeakCounter.cpp',
- 'wtf/RefCountedLeakCounter.h',
- 'wtf/RefPtr.h',
- 'wtf/RefPtrHashMap.h',
- 'wtf/RetainPtr.h',
+ 'wtf/SHA1.cpp',
+ 'wtf/SHA1.h',
'wtf/SegmentedVector.h',
- 'wtf/StaticConstructors.h',
- 'wtf/StdLibExtras.h',
- 'wtf/StringExtras.h',
- 'wtf/StringHashFunctions.h',
+ 'wtf/SizeLimits.cpp',
+ 'wtf/StackBounds.cpp',
+ 'wtf/StringExtras.cpp',
'wtf/TCPackedCache.h',
- 'wtf/qt/MainThreadQt.cpp',
- 'wtf/qt/StringQt.cpp',
- 'wtf/qt/ThreadingQt.cpp',
'wtf/TCPageMap.h',
'wtf/TCSpinLock.h',
'wtf/TCSystemAlloc.cpp',
'wtf/TCSystemAlloc.h',
+ 'wtf/ThreadFunctionInvocation.h',
'wtf/ThreadIdentifierDataPthreads.cpp',
'wtf/ThreadIdentifierDataPthreads.h',
+ 'wtf/ThreadSpecificWin.cpp',
'wtf/Threading.cpp',
- 'wtf/Threading.h',
'wtf/ThreadingNone.cpp',
- 'wtf/ThreadingPrimitives.h',
'wtf/ThreadingPthreads.cpp',
'wtf/ThreadingWin.cpp',
- 'wtf/ThreadSafeShared.h',
- 'wtf/ThreadSpecific.h',
- 'wtf/ThreadSpecificWin.cpp',
'wtf/TypeTraits.cpp',
- 'wtf/TypeTraits.h',
+ 'wtf/WTFThreadData.cpp',
+ 'wtf/android/AndroidThreading.h',
+ 'wtf/android/MainThreadAndroid.cpp',
+ 'wtf/brew/MainThreadBrew.cpp',
+ 'wtf/brew/OwnPtrBrew.cpp',
+ 'wtf/brew/RefPtrBrew.h',
+ 'wtf/brew/ShellBrew.h',
+ 'wtf/brew/StringBrew.cpp',
+ 'wtf/brew/SystemMallocBrew.h',
+ 'wtf/chromium/ChromiumThreading.h',
+ 'wtf/chromium/MainThreadChromium.cpp',
+ 'wtf/dtoa.cpp',
+ 'wtf/efl/MainThreadEfl.cpp',
+ 'wtf/gobject/GOwnPtr.cpp',
+ 'wtf/gobject/GOwnPtr.h',
+ 'wtf/gobject/GRefPtr.cpp',
+ 'wtf/gobject/GRefPtr.h',
+ 'wtf/gobject/GTypedefs.h',
+ 'wtf/gtk/MainThreadGtk.cpp',
+ 'wtf/gtk/ThreadingGtk.cpp',
+ 'wtf/haiku/MainThreadHaiku.cpp',
+ 'wtf/haiku/StringHaiku.cpp',
+ 'wtf/mac/MainThreadMac.mm',
+ 'wtf/qt/MainThreadQt.cpp',
+ 'wtf/qt/StringQt.cpp',
+ 'wtf/qt/ThreadingQt.cpp',
'wtf/text/AtomicString.cpp',
- 'wtf/text/AtomicString.h',
- 'wtf/text/AtomicStringImpl.h',
'wtf/text/CString.cpp',
- 'wtf/text/CString.h',
- 'wtf/text/StringHash.h',
+ 'wtf/text/StringBuilder.cpp',
'wtf/text/StringImpl.cpp',
- 'wtf/text/StringImpl.h',
'wtf/text/StringStatics.cpp',
'wtf/text/WTFString.cpp',
- 'wtf/text/WTFString.h',
- 'wtf/unicode/Collator.h',
'wtf/unicode/CollatorDefault.cpp',
+ 'wtf/unicode/UTF8.cpp',
+ 'wtf/unicode/UnicodeMacrosFromICU.h',
+ 'wtf/unicode/brew/UnicodeBrew.cpp',
+ 'wtf/unicode/brew/UnicodeBrew.h',
'wtf/unicode/glib/UnicodeGLib.cpp',
'wtf/unicode/glib/UnicodeGLib.h',
- 'wtf/unicode/glib/UnicodeMacrosFromICU.h',
'wtf/unicode/icu/CollatorICU.cpp',
- 'wtf/unicode/icu/UnicodeIcu.h',
'wtf/unicode/qt4/UnicodeQt4.h',
- 'wtf/unicode/Unicode.h',
- 'wtf/unicode/UTF8.cpp',
- 'wtf/unicode/UTF8.h',
- 'wtf/UnusedParam.h',
- 'wtf/ValueCheck.h',
- 'wtf/Vector.h',
- 'wtf/VectorTraits.h',
- 'wtf/VMTags.h',
- 'wtf/WTFThreadData.cpp',
- 'wtf/WTFThreadData.h',
+ 'wtf/unicode/wince/UnicodeWinCE.cpp',
+ 'wtf/unicode/wince/UnicodeWinCE.h',
+ 'wtf/url/api/ParsedURL.cpp',
+ 'wtf/url/api/ParsedURL.h',
+ 'wtf/url/api/URLString.h',
+ 'wtf/url/src/RawURLBuffer.h',
+ 'wtf/url/src/URLBuffer.h',
+ 'wtf/url/src/URLCharacterTypes.cpp',
+ 'wtf/url/src/URLCharacterTypes.h',
+ 'wtf/url/src/URLComponent.h',
+ 'wtf/url/src/URLEscape.cpp',
+ 'wtf/url/src/URLEscape.h',
+ 'wtf/url/src/URLParser.h',
+ 'wtf/url/src/URLQueryCanonicalizer.h',
+ 'wtf/url/src/URLSegments.cpp',
+ 'wtf/url/src/URLSegments.h',
'wtf/win/MainThreadWin.cpp',
'wtf/win/OwnPtrWin.cpp',
+ 'wtf/wince/FastMallocWinCE.h',
+ 'wtf/wince/MemoryManager.cpp',
+ 'wtf/wince/MemoryManager.h',
'wtf/wx/MainThreadWx.cpp',
- 'yarr/RegexCompiler.cpp',
- 'yarr/RegexCompiler.h',
- 'yarr/RegexInterpreter.cpp',
- 'yarr/RegexInterpreter.h',
- 'yarr/RegexJIT.cpp',
- 'yarr/RegexJIT.h',
- 'yarr/RegexParser.h',
- 'yarr/RegexPattern.h',
- ]
+ 'wtf/wx/StringWx.cpp',
+ 'yarr/YarrInterpreter.cpp',
+ 'yarr/YarrJIT.cpp',
+ 'yarr/YarrJIT.h',
+ 'yarr/YarrParser.h',
+ 'yarr/YarrPattern.cpp',
+ 'yarr/YarrSyntaxChecker.cpp',
+ 'yarr/YarrSyntaxChecker.h',
+ ],
+ 'javascriptcore_derived_source_files': [
+ '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/Lexer.lut.h',
+ '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/RegExpJitTables.h',
+ '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/TracingDtrace.h',
+ '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/ArrayConstructor.lut.h',
+ '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/ArrayPrototype.lut.h',
+ '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/BooleanPrototype.lut.h',
+ '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/DateConstructor.lut.h',
+ '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/DatePrototype.lut.h',
+ '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/ErrorPrototype.lut.h',
+ '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/JSGlobalObject.lut.h',
+ '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/JSONObject.lut.h',
+ '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/MathObject.lut.h',
+ '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/NumberConstructor.lut.h',
+ '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/NumberPrototype.lut.h',
+ '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/ObjectConstructor.lut.h',
+ '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/ObjectPrototype.lut.h',
+ '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/RegExpConstructor.lut.h',
+ '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/RegExpObject.lut.h',
+ '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/RegExpPrototype.lut.h',
+ '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/StringConstructor.lut.h',
+ '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/StringPrototype.lut.h',
+ ],
+ 'minidom_files': [
+ 'API/tests/JSNode.c',
+ 'API/tests/JSNode.h',
+ 'API/tests/JSNodeList.c',
+ 'API/tests/JSNodeList.h',
+ 'API/tests/Node.c',
+ 'API/tests/Node.h',
+ 'API/tests/NodeList.c',
+ 'API/tests/NodeList.h',
+ 'API/tests/minidom.c',
+ ],
+ 'minidom_support_files': [
+ 'API/tests/minidom.js',
+ ],
+ 'testapi_files': [
+ 'API/tests/testapi.c',
+ ],
+ 'testapi_support_files': [
+ 'API/tests/testapi.js',
+ ],
+ 'jsc_files': [
+ 'jsc.cpp',
+ ],
}
}
__ZN3WTF17TCMalloc_PageHeap10AllocLargeEm
__ZN3WTF17TCMalloc_PageHeap8GrowHeapEm
__ZN3WTF17TCMalloc_PageHeap6DeleteEPNS_4SpanE
+__ZN3WTF16fastZeroedMallocEm
__ZN3WTF8fastFreeEPv
__ZN3WTF19initializeThreadingEv
-__ZN3WTF36lockAtomicallyInitializedStaticMutexEv
-__ZN3WTF38unlockAtomicallyInitializedStaticMutexEv
+__ZN3WTFL14threadMapMutexEv
+__ZN3WTF20initializeMainThreadEv
+__ZN3WTFL24initializeMainThreadOnceEv
+__ZN3WTF5MutexC1Ev
+__ZN3WTF28initializeMainThreadPlatformEv
__ZN3JSC19initializeThreadingEv
__ZN3JSCL23initializeThreadingOnceEv
+__ZN3WTF10StringImpl5emptyEv
__ZN3WTF13WTFThreadDataC1Ev
-__ZN3JSC17initializeUStringEv
-__ZN7WebCore10StringImpl5emptyEv
+__ZN3WTF11StackBounds10initializeEv
__ZN3JSC12JSGlobalData10storeVPtrsEv
-__ZN3JSC9StructureC1ENS_7JSValueERKNS_8TypeInfoEj
-__ZN3JSC7JSArrayC1EN3WTF17NonNullPassRefPtrINS_9StructureEEE
-__ZN3WTF16fastZeroedMallocEm
-__ZN3JSC7JSArrayD1Ev
-__ZN3JSC7JSArrayD2Ev
-__ZN3JSC9StructureD1Ev
-__ZN3JSC9StructureD2Ev
-__ZN3JSC11JSByteArray15createStructureENS_7JSValueE
-__ZN3JSC11JSByteArrayD1Ev
-__ZN3JSC8JSStringD1Ev
-__ZN3JSC10JSFunctionC1EN3WTF17NonNullPassRefPtrINS_9StructureEEE
-__ZN3JSC10JSFunctionC2EN3WTF17NonNullPassRefPtrINS_9StructureEEE
-__ZN3JSC10JSFunctionD1Ev
-__ZN3JSC10JSFunctionD2Ev
-__ZN3JSC18VPtrHackExecutableD0Ev
-__ZN3WTF5MutexC1Ev
+__ZN3JSC7JSArrayC1ENS_6JSCell20VPtrStealingHackTypeE
+__ZN3JSC10JSFunctionC1ENS_6JSCell20VPtrStealingHackTypeE
__ZN3WTF15initializeDatesEv
__ZN3WTF11currentTimeEv
__ZN3WTF8msToYearEd
+__ZN3JSC12RegisterFile19initializeThreadingEv
__ZN3WTF39initializeMainThreadToProcessMainThreadEv
-__ZN3WTFL43initializeMainThreadToProcessMainThreadOnceEv
-__ZN3WTF47initializeMainThreadToProcessMainThreadPlatformEv
-__ZN3WTF20initializeMainThreadEv
-__ZN3WTF15ThreadConditionC1Ev
-__ZN7WebCore10StringImpl6createEPKtj
-__ZN7WebCore10StringImpl19createUninitializedEjRPt
+__ZN3WTF36lockAtomicallyInitializedStaticMutexEv
+__ZN3WTF38unlockAtomicallyInitializedStaticMutexEv
+__ZN3WTF6StringC1EPKc
+__ZN3WTF10StringImpl6createEPKc
+__ZN3WTF10StringImpl6createEPKcj
+__ZN3WTF10StringImpl19createUninitializedEjRPt
+__ZN3WTF5equalEPKNS_10StringImplES2_
+__ZN3WTF10StringImpl6createEPKtj
+__ZN3WTF12isMainThreadEv
+__ZN3WTF10StringImplD1Ev
+__ZN3WTF10StringImplD2Ev
__ZN3WTF5Mutex4lockEv
+__ZNK3WTF6String14threadsafeCopyEv
+__ZNK3WTF10StringImpl14threadsafeCopyEv
__ZN3WTF5Mutex6unlockEv
-__ZNK7WebCore6String17crossThreadStringEv
-__ZN7WebCore10StringImpl17crossThreadStringEv
-__ZN7WebCore10StringImpl12sharedBufferEv
-__ZN7WebCore6StringC1EPKc
-__ZN7WebCore10StringImpl6createEPKc
-__ZN7WebCore10StringImpl6createEPKcj
-__ZNK7WebCore6String14threadsafeCopyEv
-__ZNK7WebCore10StringImpl14threadsafeCopyEv
-__ZN7WebCore10StringImpl8endsWithEPS0_b
-__ZN7WebCore10StringImpl4findEPS0_ib
-__ZN7WebCore10StringImplD1Ev
-__ZN7WebCore10StringImplD2Ev
-__ZN7WebCoreplERKNS_6StringEPKc
-__ZN7WebCore6String6appendERKS0_
-__ZN7WebCoreplERKNS_6StringES2_
+__ZN3WTF10StringImpl8endsWithEPS0_b
+__ZN3WTF13tryFastMallocEm
+__ZN3WTF7CString16newUninitializedEmRPc
+__ZN3WTF15ThreadConditionC1Ev
__ZN3WTF12createThreadEPFPvS0_ES0_PKc
__ZN3WTF20createThreadInternalEPFPvS0_ES0_PKc
__ZN3WTFL35establishIdentifierForPthreadHandleERKP17_opaque_pthread_t
-__ZN3WTF9HashTableIjSt4pairIjP17_opaque_pthread_tENS_18PairFirstExtractorIS4_EENS_7IntHashIjEENS_14PairHashTraitsINS_10HashTrai
+__ZN3WTF9HashTableIjSt4pairIjP17_opaque_pthread_tENS_18PairFirstExtractorIS4_EENS_7IntHashIjEENS_14PairHashTraitsINS_10HashTraitsIjEENSA_IS3_EEEESB_E6rehashEi
+__ZN3WTF15ThreadCondition6signalEv
__ZN3WTFL16threadEntryPointEPv
__ZN3WTF31initializeCurrentThreadInternalEPKc
__ZN3WTF20ThreadIdentifierData10initializeEj
__ZN3WTF20ThreadIdentifierData23initializeKeyOnceHelperEv
__ZN3WTF5MutexD1Ev
-__ZN3WTF12isMainThreadEv
-__ZN3WTF7CString16newUninitializedEmRPc
-__ZNK3WTF7CString4dataEv
-__ZN3WTF14FastMallocZone4sizeEP14_malloc_zone_tPKv
-__ZN7WebCore6String29charactersWithNullTerminationEv
-__ZN7WebCore10StringImpl34createWithTerminatingNullCharacterERKS0_
+__ZNK3WTF6String4utf8Eb
+__ZN3WTF7Unicode18convertUTF16ToUTF8EPPKtS2_PPcS4_b
+__ZN3WTF7CStringC1EPKcm
+__ZN3WTF7CString4initEPKcm
+__ZN3WTF15ThreadCondition9timedWaitERNS_5MutexEd
+__ZN3WTF12AtomicString4initEv
+__ZN3WTF12AtomicString3addEPKc
+__ZN3WTF9HashTableIPNS_10StringImplES2_NS_17IdentityExtractorIS2_EENS_10StringHashENS_10HashTraitsIS2_EES7_E6rehashEi
+__ZNK3WTF6String9substringEjj
+__ZNK3WTF6String5lowerEv
+__ZN3WTF10StringImpl5lowerEv
+__ZN3WTF5equalEPKNS_10StringImplEPKc
+__ZN3WTF6StringC1EPKcj
+__ZN3WTF12AtomicString3addEPKtj
+__ZN3WTF17equalIgnoringCaseEPNS_10StringImplEPKc
+__ZN3WTF6String6appendERKS0_
+__ZN3WTF6StringC1EPKtj
+__ZN3WTF18charactersToDoubleEPKtmPbS2_
+__ZN3WTF6strtodEPKcPPc
+__ZN3WTF10StringImpl22containsOnlyWhitespaceEv
+__ZN3WTF12AtomicString11addSlowCaseEPNS_10StringImplE
+__ZN3WTF12AtomicString6removeEPNS_10StringImplE
+__ZN3WTF6String6numberEy
+__ZN3WTF6String6formatEPKcz
+__ZN3WTF6VectorIcLm256EE4growEm
+__ZN3WTF10StringImpl11reverseFindEtj
+__ZN3WTF10StringImpl9substringEjj
+__ZN3WTF7CString11mutableDataEv
+__ZN3WTF7CString18copyBufferIfNeededEv
+__ZNK3WTF6String17crossThreadStringEv
+__ZN3WTF10StringImpl17crossThreadStringEv
+__ZN3WTF10StringImpl12sharedBufferEv
+__ZN3WTF6String29charactersWithNullTerminationEv
+__ZN3WTF10StringImpl34createWithTerminatingNullCharacterERKS0_
__ZN3WTF13currentThreadEv
__ZN3WTF20ThreadIdentifierData10identifierEv
-__ZNK7WebCore6String15stripWhiteSpaceEv
-__ZN7WebCore10StringImpl15stripWhiteSpaceEv
-__ZN7WebCore5equalEPKNS_10StringImplES2_
-__ZN7WebCoreplEPKcRKNS_6StringE
-__ZN7WebCore6StringC1EPKt
-__ZN7WebCore6StringC2EPKt
-__ZNK7WebCore6String7isEmptyEv
+__ZNK3WTF6String15stripWhiteSpaceEv
+__ZN3WTF10StringImpl15stripWhiteSpaceEv
+_JSStringCreateWithCFString
+_JSStringRetain
+_JSStringRelease
+__ZN3WTF6String6numberEi
__ZN3WTF16callOnMainThreadEPFvPvES0_
-__ZN3WTF5DequeINS_19FunctionWithContextEE14expandCapacityEv
+__ZN3WTF5DequeINS_19FunctionWithContextELm0EE14expandCapacityEv
__ZN3WTF37scheduleDispatchFunctionsOnMainThreadEv
__ZN3WTF15ThreadCondition4waitERNS_5MutexE
-__ZN3WTF17TCMalloc_PageHeap3NewEm
-__ZN7WebCore12AtomicString4initEv
-__ZN3WTF7HashSetIPN7WebCore10StringImplENS1_10StringHashENS_10HashTraitsIS3_EEE3addIPKcNS1_17CStringTranslatorEEESt4pairINS_24H
-__ZN3WTF9HashTableIPN7WebCore10StringImplES3_NS_17IdentityExtractorIS3_EENS1_10StringHashENS_10HashTraitsIS3_EES8_E6rehashEi
-__ZN7WebCore12AtomicString3addEPKc
-__ZN7WebCore12AtomicString3addEPNS_10StringImplE
-__ZN7WebCore6StringC1EPKcj
-__ZN7WebCore5equalEPKNS_10StringImplEPKc
-__ZNK7WebCore6String6lengthEv
-__ZNK7WebCore6StringixEj
-__ZNK7WebCore6String9substringEjj
-__ZN7WebCore10StringImpl9substringEjj
-__ZNK7WebCore6String5lowerEv
-__ZN7WebCore10StringImpl5lowerEv
-__ZN7WebCore10StringImpl4findEti
-__ZNK7WebCore6String10charactersEv
-__ZN7WebCore17equalIgnoringCaseEPNS_10StringImplES1_
-__ZN7WebCore17equalIgnoringCaseEPNS_10StringImplEPKc
-__ZN7WebCore12AtomicString3addEPKtj
-__ZN3WTF7HashSetIPN7WebCore10StringImplENS1_10StringHashENS_10HashTraitsIS3_EEE3addINS1_11UCharBufferENS1_21UCharBufferTranslat
-__ZN7WebCore18charactersToDoubleEPKtmPb
-__ZN3WTF6strtodEPKcPPc
+__ZN3WTF6String8fromUTF8EPKc
+__ZN3WTF6String8fromUTF8EPKcm
+__ZN3WTF7Unicode18convertUTF8ToUTF16EPPKcS2_PPtS4_b
+__ZN3WTF7CStringC1EPKc
+__ZN3WTF11fastReallocEPvm
+-[WTFMainThreadCaller call]
+__ZN3WTF31dispatchFunctionsFromMainThreadEv
+__ZN3WTF25TCMalloc_Central_FreeList11InsertRangeEPvS1_i
+__ZN3WTF25TCMalloc_Central_FreeList11ShrinkCacheEib
__ZN3WTF15ThreadCondition9broadcastEv
-__ZN3WTF15ThreadCondition6signalEv
-__ZN7WebCore12AtomicString6removeEPNS_10StringImplE
-__ZN3JSC12JSGlobalData12createLeakedENS_15ThreadStackTypeE
-__ZN3JSC9Structure18startIgnoringLeaksEv
+__ZN3WTF20TCMalloc_ThreadCache18DestroyThreadCacheEPv
+__ZN3WTF20TCMalloc_ThreadCache11DeleteCacheEPS0_
+__ZN3WTF25TCMalloc_Central_FreeList18ReleaseListToSpansEPv
+__ZN3WTF20ThreadIdentifierData8destructEPv
+__ZN3WTF31clearPthreadHandleForIdentifierEj
+__ZN3WTF12detachThreadEj
+__ZN3WTFL26pthreadHandleForIdentifierEj
+__ZN3WTF14FastMallocZone4sizeEP14_malloc_zone_tPKv
+__ZN3WTF10StringImpl4findEtj
+___initializeScavenger_block_invoke_1
+__ZN3WTF23waitForThreadCompletionEjPPv
+__ZN3WTF22cancelCallOnMainThreadEPFvPvES0_
+__ZN3WTF6StringC1EPKt
+__ZN3WTF6StringC2EPKt
+__ZNK3WTF6String5splitEtRNS_6VectorIS0_Lm0EEE
+__ZNK3WTF6String5splitERKS0_bRNS_6VectorIS0_Lm0EEE
+__ZN3WTF10StringImpl4findEPS0_j
+__ZN3WTF6VectorINS_6StringELm0EE14expandCapacityEm
+_JSGlobalContextCreate
+__ZN3JSC6JSLock4lockENS_14JSLockBehaviorE
+__ZN3JSCL17createJSLockCountEv
+__ZN3JSC12JSGlobalData14sharedInstanceEv
__ZN3JSC12JSGlobalDataC2ENS0_14GlobalDataTypeENS_15ThreadStackTypeE
+__ZN3JSC21createIdentifierTableEv
__ZN3JSC17CommonIdentifiersC1EPNS_12JSGlobalDataE
__ZN3JSC17CommonIdentifiersC2EPNS_12JSGlobalDataE
__ZN3JSC10Identifier3addEPNS_12JSGlobalDataEPKc
-__ZN3WTF7HashSetIPN7WebCore10StringImplENS1_10StringHashENS_10HashTraitsIS3_EEE3addIPKcN3JSC27IdentifierCStringTranslatorEEESt4
-__ZN3WTF9HashTableIPN7WebCore10StringImplES3_NS_17IdentityExtractorIS3_EENS1_10StringHashENS_10HashTraitsIS3_EES8_E6expandEv
-__ZN3WTF9HashTableIPKcSt4pairIS2_NS_6RefPtrIN7WebCore10StringImplEEEENS_18PairFirstExtractorIS8_EENS_7PtrHashIS2_EENS_14PairHas
+__ZN3JSC15IdentifierTable3addIPKcNS_27IdentifierCStringTranslatorEEESt4pairIN3WTF29HashTableConstIteratorAdapterINS6_9HashTableIPNS6_10StringImplESA_NS6_17IdentityExtractorISA_EENS6_10StringHashENS6_10HashTraitsISA_EESF_EESA_EEbET_
+__ZN3WTF9HashTableIPNS_10StringImplES2_NS_17IdentityExtractorIS2_EENS_10StringHashENS_10HashTraitsIS2_EES7_E6expandEv
+__ZN3WTF9HashTableIPKcSt4pairIS2_NS_6RefPtrINS_10StringImplEEEENS_18PairFirstExtractorIS7_EENS_7PtrHashIS2_EENS_14PairHashTraitsINS_10HashTraitsIS2_EENSD_IS6_EEEESE_E6expandEv
+__ZN3WTF9HashTableIPNS_10StringImplES2_NS_17IdentityExtractorIS2_EENS_10StringHashENS_10HashTraitsIS2_EES7_E4findIS2_NS_22IdentityHashTranslatorIS2_S2_S5_EEEENS_17HashTableIteratorIS2_S2_S4_S5_S7_S7_EERKT_
__ZN3JSC10IdentifierC1EPNS_12JSGlobalDataEPKc
__ZN3JSC12SmallStringsC1Ev
__ZN3JSC19ExecutableAllocator17intializePageSizeEv
+__ZNK3JSC19ExecutableAllocator7isValidEv
+__ZN3WTF11OSAllocator18reserveUncommittedEmNS0_5UsageEbb
__ZN3JSC14ExecutablePool11systemAllocEm
+__ZN3WTF11OSAllocator6commitEPvmbb
__ZN3JSC5LexerC1EPNS_12JSGlobalDataE
__ZN3JSC11ParserArenaC1Ev
__ZN3JSC11ParserArenaC2Ev
-__ZN3JSC11InterpreterC1Ev
-__ZN3JSC11InterpreterC2Ev
+__ZN3JSC14TimeoutCheckerC1Ev
+__ZN3JSC4HeapC1EPNS_12JSGlobalDataE
+__ZN3JSC4HeapC2EPNS_12JSGlobalDataE
+__ZN3JSC11MarkedSpaceC1EPNS_12JSGlobalDataE
+__ZN3JSC25DefaultGCActivityCallbackC1EPNS_4HeapE
+__ZN3JSC25DefaultGCActivityCallback17commonConstructorEPNS_4HeapEP11__CFRunLoop
+__ZN3JSC14MachineThreadsC1EPNS_4HeapE
+__ZN3JSC9MarkStack18initializePagesizeEv
+__ZN3WTF11OSAllocator16reserveAndCommitEmNS0_5UsageEbb
+__ZN3JSC10HandleHeapC1EPNS_12JSGlobalDataE
+__ZN3WTF10BlockStackIN3JSC10HandleHeap4NodeEE4growEv
+__ZN3WTF6VectorIPN3JSC10HandleHeap4NodeELm0EE15reserveCapacityEm
+__ZN3JSC11HandleStackC1Ev
+__ZN3WTF10BlockStackIN3JSC7JSValueEE4growEv
+__ZN3WTF6VectorIPN3JSC7JSValueELm0EE15reserveCapacityEm
+__ZN3JSC25DefaultGCActivityCallbackclEv
+__ZN3JSC11RegExpCacheC1EPNS_12JSGlobalDataE
+__ZN3JSC11InterpreterC1ERNS_12JSGlobalDataE
+__ZN3JSC10HandleHeap12writeBarrierEPNS_7JSValueERKS1_
+__ZN3JSC12RegisterFile23addToCommittedByteCountEl
+__ZN3JSC11MarkedSpace21allocateFromSizeClassERNS0_9SizeClassE
+__ZN3JSC11MarkedSpace13allocateBlockERNS0_9SizeClassE
+__ZN3JSC11MarkedBlock6createEPNS_12JSGlobalDataEm
+__ZN3WTF21PageAllocationAligned8allocateEmmNS_11OSAllocator5UsageEbb
+__ZN3WTF9HashTableIPN3JSC11MarkedBlockES3_NS_17IdentityExtractorIS3_EENS_7PtrHashIS3_EENS_10HashTraitsIS3_EES9_E6rehashEi
+__ZN3JSC6JSCellD1Ev
+__ZN3JSC9StructureC1ERNS_12JSGlobalDataE
+__ZN3JSC6StrongINS_9StructureEE3setERNS_12JSGlobalDataEPS1_
+__ZN3JSC9Structure6createERNS_12JSGlobalDataENS_7JSValueERKNS_8TypeInfoEjPKNS_9ClassInfoE
+__ZN3JSC9StructureC1ERNS_12JSGlobalDataENS_7JSValueERKNS_8TypeInfoEjPKNS_9ClassInfoE
+__ZN3WTF13wtfThreadDataEv
+__ZN3JSC27startProfilerServerIfNeededEv
++[ProfilerServer sharedProfileServer]
+-[ProfilerServer init]
__ZN3JSC9JITThunksC1EPNS_12JSGlobalDataE
+__ZN3JSC9JITThunksC2EPNS_12JSGlobalDataE
__ZN3JSC3JITC1EPNS_12JSGlobalDataEPNS_9CodeBlockE
__ZN3JSC3JITC2EPNS_12JSGlobalDataEPNS_9CodeBlockE
-__ZN3JSC3JIT35privateCompileCTIMachineTrampolinesEPN3WTF6RefPtrINS_14ExecutablePoolEEEPNS_12JSGlobalDataEPNS_19TrampolineStruct
-__ZN3JSC20MacroAssemblerX86_6413branchTestPtrENS_23MacroAssemblerX86Common9ConditionENS_12X86Registers10RegisterIDES4_
+__ZN3JSC3JIT35privateCompileCTIMachineTrampolinesEPN3WTF6RefPtrINS_14ExecutablePoolEEEPNS_12JSGlobalDataEPNS_19TrampolineStructureE
+__ZN3JSC20MacroAssemblerX86_6413branchTestPtrENS_23MacroAssemblerX86Common15ResultConditionENS_12X86Registers10RegisterIDES4_
__ZN3JSC12X86Assembler23X86InstructionFormatter11oneByteOp64ENS0_15OneByteOpcodeIDEiNS_12X86Registers10RegisterIDE
__ZN3JSC12X86Assembler3jCCENS0_9ConditionE
+__ZN3JSC15AssemblerBuffer11ensureSpaceEi
__ZN3JSC12X86Assembler23X86InstructionFormatter11oneByteOp64ENS0_15OneByteOpcodeIDEiNS_12X86Registers10RegisterIDEi
__ZN3JSC12X86Assembler23X86InstructionFormatter9oneByteOpENS0_15OneByteOpcodeIDEiNS_12X86Registers10RegisterIDEi
__ZN3JSC12X86Assembler23X86InstructionFormatter11memoryModRMEiNS_12X86Registers10RegisterIDEi
+__ZN3JSC23MacroAssemblerX86Common8branch32ENS0_19RelationalConditionENS_12X86Registers10RegisterIDENS_22AbstractMacroAssemblerINS_12X86AssemblerEE12TrustedImm32E
__ZN3JSC12X86Assembler23X86InstructionFormatter9oneByteOpENS0_15OneByteOpcodeIDEiNS_12X86Registers10RegisterIDE
-__ZN3JSC15AssemblerBuffer11ensureSpaceEi
-__ZN3JSC20MacroAssemblerX86_644callEv
-__ZN3JSC20MacroAssemblerX86_647loadPtrENS_22AbstractMacroAssemblerINS_12X86AssemblerEE15ImplicitAddressENS_12X86Registers10Regi
-__ZN3JSC12X86Assembler23X86InstructionFormatter9oneByteOpENS0_15OneByteOpcodeIDENS_12X86Registers10RegisterIDE
__ZN3JSC3JIT32compileOpCallInitializeCallFrameEv
-__ZN3JSC15AssemblerBuffer4growEi
-__ZN3WTF11fastReallocEPvm
-__ZN3WTF11fastReallocILb1EEEPvS1_m
+__ZN3JSC20MacroAssemblerX86_6413branchTestPtrENS_23MacroAssemblerX86Common15ResultConditionENS_12X86Registers10RegisterIDENS_22AbstractMacroAssemblerINS_12X86AssemblerEE12TrustedImm32E
+__ZN3JSC12X86Assembler23X86InstructionFormatter9oneByteOpENS0_15OneByteOpcodeIDENS_12X86Registers10RegisterIDE
+__ZN3WTF6VectorIcLm128EE14expandCapacityEm
+__ZN3WTF6VectorIcLm128EE4growEm
+__ZN3JSC3JIT27privateCompileCTINativeCallEPNS_12JSGlobalDataEb
+__ZNK3JSC22AbstractMacroAssemblerINS_12X86AssemblerEE4Jump4linkEPS2_
__ZN3WTF10RefCountedIN3JSC14ExecutablePoolEE5derefEv
-__ZN3JSC14TimeoutCheckerC1Ev
-__ZN3JSC4HeapC1EPNS_12JSGlobalDataE
-__ZN3JSC4Heap13allocateBlockEv
-__ZN3JSC9MarkStack18initializePagesizeEv
-__ZN3JSC9MarkStack13allocateStackEm
-__ZN3JSC27startProfilerServerIfNeededEv
-+[ProfilerServer sharedProfileServer]
--[ProfilerServer init]
-__ZN3JSC9Structure17stopIgnoringLeaksEv
-__ZNK7WebCore6String6latin1Ev
-__ZNK3WTF7CString6lengthEv
-__ZN7WebCore10StringImpl22containsOnlyWhitespaceEv
-__ZN7WebCore12AtomicString3addEPKt
-__ZN7WebCore10StringImpl11reverseFindEPS0_ib
-__ZN7WebCore10StringImpl5adoptERNS_12StringBufferE
-__ZNK7WebCore6String5splitEtRN3WTF6VectorIS0_Lm0EEE
-__ZNK7WebCore6String5splitERKS0_bRN3WTF6VectorIS0_Lm0EEE
--[WTFMainThreadCaller call]
-__ZN3WTF31dispatchFunctionsFromMainThreadEv
-__ZN3WTF15ThreadCondition9timedWaitERNS_5MutexEd
-__ZN3WTF14FastMallocZone9forceLockEP14_malloc_zone_t
-__ZN3WTF14FastMallocZone11forceUnlockEP14_malloc_zone_t
-__ZN3WTF20TCMalloc_ThreadCache18DestroyThreadCacheEPv
-__ZN3WTF20TCMalloc_ThreadCache11DeleteCacheEPS0_
-__ZN3WTF25TCMalloc_Central_FreeList11InsertRangeEPvS1_i
-__ZN3WTF25TCMalloc_Central_FreeList18ReleaseListToSpansEPv
-__ZN3WTF20ThreadIdentifierData8destructEPv
-__ZN3WTF31clearPthreadHandleForIdentifierEj
-__ZN3WTF12detachThreadEj
-__ZN3WTFL26pthreadHandleForIdentifierEj
-__ZN7WebCore6StringC1EPKtj
-__Z15jsRegExpCompilePKti24JSRegExpIgnoreCaseOption23JSRegExpMultilineOptionPjPPKc
-__ZL30calculateCompiledPatternLengthPKti24JSRegExpIgnoreCaseOptionR11CompileDataR9ErrorCode
-__ZL11checkEscapePPKtS0_P9ErrorCodeib
-__ZL13compileBranchiPiPPhPPKtS3_P9ErrorCodeS_S_R11CompileData
-__Z15jsRegExpExecutePK8JSRegExpPKtiiPii
-__ZL5matchPKtPKhiR9MatchData
-__ZN7WebCore6String6formatEPKcz
-__ZNK7WebCore6String19characterStartingAtEj
-__ZN7WebCore10StringImpl19characterStartingAtEj
-__ZN3WTF25TCMalloc_Central_FreeList11ShrinkCacheEib
-__ZNK7WebCore6String16removeCharactersEPFbtE
-__ZN7WebCore10StringImpl16removeCharactersEPFbtE
-__ZN7WebCore10StringImpl7replaceEtt
-__ZNK7WebCore6String4utf8Ev
-__ZN3WTF7Unicode18convertUTF16ToUTF8EPPKtS2_PPcS4_b
-__ZN3WTF7CStringC1EPKcj
-__ZN3WTF7CString4initEPKcj
-__ZN7WebCore10StringImpl4findEPFbtEi
-__ZN3JSC4Heap8allocateEm
-__ZN3JSC6JSCellD1Ev
-__ZN3JSC4Heap7protectENS_7JSValueE
-__ZN3WTF9HashTableIPN3JSC6JSCellESt4pairIS3_jENS_18PairFirstExtractorIS5_EENS_7PtrHashIS3_EENS_14PairHashTraitsINS_10HashTraits
+__ZN3JSC14MachineThreads29makeUsableFromMultipleThreadsEv
+_JSGlobalContextCreateInGroup
+__ZN3JSC4Heap16activityCallbackEv
+__ZN3JSC25DefaultGCActivityCallback11synchronizeEv
+__ZN3JSC14TimeoutChecker5resetEv
__ZN3JSC14JSGlobalObjectnwEmPNS_12JSGlobalDataE
+__ZN3WTF12randomNumberEv
+__ZN3WTF29cryptographicallyRandomNumberEv
+__ZN3WTF35cryptographicallyRandomValuesFromOSEPhm
__ZN3JSC14JSGlobalObject4initEPNS_8JSObjectE
__ZN3JSC14JSGlobalObject5resetENS_7JSValueE
-__ZN3JSC17FunctionPrototypeC1EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEE
-__ZN3JSC17FunctionPrototypeC2EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEE
-__ZN3JSC16InternalFunctionC2EPNS_12JSGlobalDataEN3WTF17NonNullPassRefPtrINS_9StructureEEERKNS_10IdentifierE
+__ZN3JSC17FunctionPrototypeC1EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureE
+__ZN3JSC17FunctionPrototypeC2EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureE
+__ZN3JSC16InternalFunctionC2EPNS_12JSGlobalDataEPNS_14JSGlobalObjectEPNS_9StructureERKNS_10IdentifierE
+__ZN3JSC24JSObjectWithGlobalObjectC2EPNS_14JSGlobalObjectEPNS_9StructureE
__ZN3JSC7UStringC1EPKc
__ZN3JSC12SmallStrings17createEmptyStringEPNS_12JSGlobalDataE
-__ZN3JSC8JSObject17putDirectInternalERKNS_10IdentifierENS_7JSValueEjbRNS_15PutPropertySlotEPNS_6JSCellE
__ZN3JSC9Structure40addPropertyTransitionToExistingStructureEPS0_RKNS_10IdentifierEjPNS_6JSCellERm
-__ZN3JSC9Structure3getEPKN7WebCore10StringImplERjRPNS_6JSCellE
-__ZN3JSC9Structure21addPropertyTransitionEPS0_RKNS_10IdentifierEjPNS_6JSCellERm
-__ZN3JSC9Structure3putERKNS_10IdentifierEjPNS_6JSCellE
-__ZN3JSC9Structure28addPropertyWithoutTransitionERKNS_10IdentifierEjPNS_6JSCellE
-__ZN3JSC17FunctionPrototype21addFunctionPropertiesEPNS_9ExecStateEPNS_9StructureEPPNS_10JSFunctionES7_
-__ZN3JSC10JSFunctionC1EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEiRKNS_10IdentifierEPFNS_7JSValueES2_PNS_8JSObjec
-__ZN3JSC10JSFunctionC2EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEiRKNS_10IdentifierEPFNS_7JSValueES2_PNS_8JSObjec
-__ZN3JSC8JSObject34putDirectFunctionWithoutTransitionEPNS_9ExecStateEPNS_16InternalFunctionEj
-__ZN3JSC16InternalFunction4nameEPNS_9ExecStateE
-__ZN3JSC15ObjectPrototypeC1EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEPS5_
-__ZN3JSC15ObjectPrototypeC2EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEPS5_
-__ZN3JSC9Structure26rehashPropertyMapHashTableEj
-__ZN3JSC8JSObject17createInheritorIDEv
-__ZN3JSC14ArrayPrototypeC1EN3WTF17NonNullPassRefPtrINS_9StructureEEE
-__ZN3JSC7JSArrayC2EN3WTF17NonNullPassRefPtrINS_9StructureEEE
-__ZN3JSC15StringPrototypeC1EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEE
-__ZN3JSC15StringPrototypeC2EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEE
-__ZN3JSC12StringObjectC2EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEE
-__ZN3JSC16BooleanPrototypeC1EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEPS5_
-__ZN3JSC16BooleanPrototypeC2EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEPS5_
-__ZN3JSC13BooleanObjectC2EN3WTF17NonNullPassRefPtrINS_9StructureEEE
-__ZN3JSC15NumberPrototypeC1EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEPS5_
-__ZN3JSC15NumberPrototypeC2EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEPS5_
-__ZN3JSC12NumberObjectC2EN3WTF17NonNullPassRefPtrINS_9StructureEEE
-__ZN3JSC13DatePrototypeC1EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEE
-__ZN3JSC12DateInstanceC2EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEE
-__ZN3JSC15RegExpPrototypeC1EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEPS5_
-__ZN3JSC15RegExpPrototypeC2EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEPS5_
-__ZN3JSC14ErrorPrototypeC1EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEPS5_
-__ZN3JSC14ErrorPrototypeC2EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEPS5_
-__ZN3JSC13ErrorInstanceC2EN3WTF17NonNullPassRefPtrINS_9StructureEEE
-__ZN3JSC20NativeErrorPrototypeC1EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEERKNS_7UStringES9_
-__ZN3JSC20NativeErrorPrototypeC2EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEERKNS_7UStringES9_
-__ZN3JSC17ObjectConstructorC1EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEPNS_15ObjectPrototypeEPS5_
-__ZN3JSC17ObjectConstructorC2EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEPNS_15ObjectPrototypeEPS5_
-__ZN3JSC10Identifier3addEPNS_9ExecStateEPKc
-__ZN3JSC19FunctionConstructorC1EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEPNS_17FunctionPrototypeE
-__ZN3JSC19FunctionConstructorC2EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEPNS_17FunctionPrototypeE
-__ZNK3JSC16InternalFunction9classInfoEv
-__ZN3JSC16ArrayConstructorC1EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEPNS_14ArrayPrototypeEPS5_
-__ZN3JSC16ArrayConstructorC2EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEPNS_14ArrayPrototypeEPS5_
-__ZNK3JSC14ArrayPrototype9classInfoEv
-__ZN3JSC17StringConstructorC1EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEPS5_PNS_15StringPrototypeE
-__ZN3JSC17StringConstructorC2EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEPS5_PNS_15StringPrototypeE
-__ZNK3JSC15StringPrototype9classInfoEv
-__ZN3JSC9JITThunks16specializedThunkEPNS_12JSGlobalDataEPFN3WTF10PassRefPtrINS_16NativeExecutableEEES2_PNS_14ExecutablePoolEE
-__ZN3JSC26fromCharCodeThunkGeneratorEPNS_12JSGlobalDataEPNS_14ExecutablePoolE
-__ZN3JSC22AbstractMacroAssemblerINS_12X86AssemblerEE8JumpList6appendENS2_4JumpE
-__ZN3JSCL12charToStringERNS_19SpecializedThunkJITEPNS_12JSGlobalDataENS_12X86Registers10RegisterIDES5_S5_
-__ZN3JSC19SpecializedThunkJIT8finalizeEv
-__ZN3JSC10JSFunctionC1EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEiRKNS_10IdentifierEPNS_16NativeExecutableEPFNS_7
-__ZN3JSC10JSFunctionC2EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEiRKNS_10IdentifierEPNS_16NativeExecutableEPFNS_7
+__ZN3JSC9Structure3getERNS_12JSGlobalDataEPN3WTF10StringImplERjRPNS_6JSCellE
+__ZN3JSC9Structure21addPropertyTransitionERNS_12JSGlobalDataEPS0_RKNS_10IdentifierEjPNS_6JSCellERm
+__ZN3JSC9Structure17createPropertyMapEj
+__ZN3WTF14deleteOwnedPtrIN3JSC13PropertyTableEEEvPT_
+__ZN3JSC9Structure16putSpecificValueERNS_12JSGlobalDataERKNS_10IdentifierEjPNS_6JSCellE
+__ZN3JSC24StructureTransitionTable3addERNS_12JSGlobalDataEPNS_9StructureE
+__ZN3JSC9Structure28addPropertyWithoutTransitionERNS_12JSGlobalDataERKNS_10IdentifierEjPNS_6JSCellE
__ZN3JSC8JSObject23allocatePropertyStorageEmm
-__ZN3JSC18BooleanConstructorC1EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEPNS_16BooleanPrototypeE
-__ZN3JSC18BooleanConstructorC2EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEPNS_16BooleanPrototypeE
-__ZNK3JSC13BooleanObject9classInfoEv
-__ZN3JSC17NumberConstructorC1EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEPNS_15NumberPrototypeE
-__ZN3JSC17NumberConstructorC2EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEPNS_15NumberPrototypeE
-__ZN3JSC15DateConstructorC1EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEPS5_PNS_13DatePrototypeE
-__ZN3JSC15DateConstructorC2EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEPS5_PNS_13DatePrototypeE
-__ZNK3JSC13DatePrototype9classInfoEv
-__ZN3JSC17RegExpConstructorC1EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEPNS_15RegExpPrototypeE
-__ZN3JSC17RegExpConstructorC2EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEPNS_15RegExpPrototypeE
-__ZN3JSC16ErrorConstructorC1EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEPNS_14ErrorPrototypeE
-__ZN3JSC16ErrorConstructorC2EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEPNS_14ErrorPrototypeE
-__ZNK3JSC13ErrorInstance9classInfoEv
-__ZN3JSC22NativeErrorConstructorC1EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEPNS_20NativeErrorPrototypeE
-__ZN3JSC22NativeErrorConstructorC2EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEPNS_20NativeErrorPrototypeE
-__ZNK3JSC6JSCell9getStringEPNS_9ExecStateE
-__ZN3JSC10Identifier11addSlowCaseEPNS_9ExecStateEPN7WebCore10StringImplE
-__ZN3WTF7HashSetIPN7WebCore10StringImplENS1_10StringHashENS_10HashTraitsIS3_EEE3addERKS3_
-__ZN3JSC10MathObjectC1EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEE
-__ZN3JSC10MathObjectC2EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEE
+__ZN3JSC17FunctionPrototype21addFunctionPropertiesEPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureEPPNS_10JSFunctionES9_
+__ZN3JSC10JSFunctionC1EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureEiRKNS_10IdentifierEPFPvS2_E
+__ZN3JSC10JSFunctionC2EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureEiRKNS_10IdentifierEPFPvS2_E
+__ZN3JSC12JSGlobalData15getHostFunctionEPFPvPNS_9ExecStateEE
+__ZN3JSC9JITThunks16hostFunctionStubEPNS_12JSGlobalDataEPFPvPNS_9ExecStateEE
+__ZN3WTF7HashMapIPFPvPN3JSC9ExecStateEENS2_4WeakINS2_16NativeExecutableEEENS_7PtrHashIS6_EENS_10HashTraitsIS6_EENSC_IS9_EEE3addERKS6_RKS9_
+__ZN3WTF9HashTableIPFPvPN3JSC9ExecStateEESt4pairIS6_NS2_4WeakINS2_16NativeExecutableEEEENS_18PairFirstExtractorISB_EENS_7PtrHashIS6_EENS_14PairHashTraitsINS_10HashTraitsIS6_EENSH_ISA_EEEESI_E6expandEv
+__ZN3JSC3JIT27privateCompileCTINativeCallEN3WTF10PassRefPtrINS_14ExecutablePoolEEEPNS_12JSGlobalDataEPFPvPNS_9ExecStateEE
+__ZN3JSC16NativeExecutable6createERNS_12JSGlobalDataENS_21MacroAssemblerCodePtrEPFPvPNS_9ExecStateEES3_S8_
+__ZN3JSC8JSObject34putDirectFunctionWithoutTransitionEPNS_9ExecStateEPNS_10JSFunctionEj
+__ZN3JSC10JSFunction4nameEPNS_9ExecStateE
+__ZN3JSC15ObjectPrototypeC1EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureE
+__ZN3JSC8JSObject17createInheritorIDERNS_12JSGlobalDataE
+__ZN3JSC14ArrayPrototypeC1EPNS_14JSGlobalObjectEPNS_9StructureE
+__ZN3JSC7JSArrayC2ERNS_12JSGlobalDataEPNS_9StructureE
+__ZN3JSC15StringPrototypeC1EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureE
+__ZN3JSC15StringPrototypeC2EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureE
+__ZN3JSC12StringObjectC2EPNS_9ExecStateEPNS_9StructureE
+__ZN3JSC16BooleanPrototypeC1EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureE
+__ZN3JSC13BooleanObjectC2ERNS_12JSGlobalDataEPNS_9StructureE
+__ZN3JSC15NumberPrototypeC1EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureE
+__ZN3JSC12NumberObjectC2ERNS_12JSGlobalDataEPNS_9StructureE
+__ZN3JSC13DatePrototypeC1EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureE
+__ZN3JSC12DateInstanceC2EPNS_9ExecStateEPNS_9StructureE
+__ZN3JSC12nonInlineNaNEv
+__ZN3JSC15RegExpPrototypeC1EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureE
+__ZN3JSC15RegExpPrototypeC2EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureE
+__ZN3JSC6RegExp6createEPNS_12JSGlobalDataERKNS_7UStringENS_11RegExpFlagsE
+__ZN3JSC6RegExp7compileEPNS_12JSGlobalDataE
+__ZN3JSC4Yarr11YarrPatternC1ERKNS_7UStringEbbPPKc
+__ZN3JSC4Yarr11YarrPattern7compileERKNS_7UStringE
+__ZN3WTF6VectorIPN3JSC4Yarr18PatternAlternativeELm0EE14expandCapacityEm
+__ZN3JSC4Yarr6ParserINS0_22YarrPatternConstructorEE5parseEv
+__ZN3JSC4Yarr10jitCompileERNS0_11YarrPatternEPNS_12JSGlobalDataERNS0_13YarrCodeBlockE
+__ZN3JSC4Yarr13YarrGenerator13opCompileBodyEPNS0_18PatternDisjunctionE
+__ZN3WTF6VectorIN3JSC22AbstractMacroAssemblerINS1_12X86AssemblerEE4JumpELm16EED1Ev
+__ZN3JSC4Yarr13YarrGenerator20opCompileAlternativeEPNS0_18PatternAlternativeE
+__ZN3JSC4Yarr13YarrGenerator8generateEv
+__ZN3JSC4Yarr13YarrGenerator22jumpIfNoAvailableInputEj
+__ZN3JSC22AbstractMacroAssemblerINS_12X86AssemblerEE8JumpList6appendENS2_4JumpE
+__ZN3JSC4Yarr13YarrGenerator9backtrackEv
+__ZN3JSC4Yarr13YarrGenerator17BacktrackingState4linkEPNS_14MacroAssemblerE
+__ZN3JSC22AbstractMacroAssemblerINS_12X86AssemblerEE8JumpList4linkEPS2_
+__ZN3JSC12X86Assembler7addl_irEiNS_12X86Registers10RegisterIDE
+__ZN3JSC14MacroAssembler4jumpENS_22AbstractMacroAssemblerINS_12X86AssemblerEE5LabelE
+__ZN3WTF15deleteAllValuesIPN3JSC4Yarr18PatternDisjunctionELm4EEEvRKNS_6VectorIT_XT0_EEE
+__ZN3WTF15deleteAllValuesIPN3JSC4Yarr14CharacterClassELm0EEEvRKNS_6VectorIT_XT0_EEE
+__ZN3JSC12RegExpObjectC2EPNS_14JSGlobalObjectEPNS_9StructureEN3WTF17NonNullPassRefPtrINS_6RegExpEEE
+__ZN3JSC14ErrorPrototypeC1EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureE
+__ZN3JSC14ErrorPrototypeC2EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureE
+__ZN3JSC13ErrorInstanceC2EPNS_12JSGlobalDataEPNS_9StructureE
+__ZN3JSC17ObjectConstructorC1EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureEPNS_15ObjectPrototypeE
+__ZN3JSC17ObjectConstructorC2EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureEPNS_15ObjectPrototypeE
+__ZN3JSC10Identifier3addEPNS_9ExecStateEPKc
+__ZN3JSC19FunctionConstructorC1EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureEPNS_17FunctionPrototypeE
+__ZN3JSC19FunctionConstructorC2EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureEPNS_17FunctionPrototypeE
+__ZN3JSC16ArrayConstructorC1EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureEPNS_14ArrayPrototypeE
+__ZN3JSC16ArrayConstructorC2EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureEPNS_14ArrayPrototypeE
+__ZN3JSC17StringConstructorC1EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureEPNS_15StringPrototypeE
+__ZN3JSC17StringConstructorC2EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureEPNS_15StringPrototypeE
+__ZN3JSC18BooleanConstructorC1EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureEPNS_16BooleanPrototypeE
+__ZN3JSC18BooleanConstructorC2EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureEPNS_16BooleanPrototypeE
+__ZN3JSC17NumberConstructorC1EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureEPNS_15NumberPrototypeE
+__ZN3JSC17NumberConstructorC2EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureEPNS_15NumberPrototypeE
+__ZN3JSC15DateConstructorC1EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureEPNS_13DatePrototypeE
+__ZN3JSC15DateConstructorC2EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureEPNS_13DatePrototypeE
+__ZN3JSC17RegExpConstructorC1EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureEPNS_15RegExpPrototypeE
+__ZN3JSC17RegExpConstructorC2EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureEPNS_15RegExpPrototypeE
+__ZN3JSC16ErrorConstructorC1EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureEPNS_14ErrorPrototypeE
+__ZN3JSC16ErrorConstructorC2EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureEPNS_14ErrorPrototypeE
+__ZN3JSC22NativeErrorConstructorC1EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureES6_RKNS_7UStringE
+__ZN3JSC22NativeErrorConstructorC2EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureES6_RKNS_7UStringE
+__ZN3JSC10Identifier11addSlowCaseEPNS_9ExecStateEPN3WTF10StringImplE
+__ZN3JSC15IdentifierTable3addEPN3WTF10StringImplE
+__ZN3JSC20NativeErrorPrototypeC1EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureERKNS_7UStringEPNS_22NativeErrorConstructorE
+__ZN3JSC20NativeErrorPrototypeC2EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureERKNS_7UStringEPNS_22NativeErrorConstructorE
+__ZN3JSC10IdentifierC1EPNS_9ExecStateEPKc
+__ZN3JSC10MathObjectC1EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureE
+__ZN3JSC10MathObjectC2EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureE
__ZN3JSC12SmallStrings24singleCharacterStringRepEh
__ZN3JSC19SmallStringsStorageC2Ev
-__ZN3JSC18GlobalEvalFunctionC1EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEiRKNS_10IdentifierEPFNS_7JSValueES2_PNS_
-__ZN3JSC17PrototypeFunctionC2EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEiRKNS_10IdentifierEPFNS_7JSValueES2_PNS_8
-__ZN3JSC9Structure25changePrototypeTransitionEPS0_NS_7JSValueE
-__ZN3JSC9Structure17copyPropertyTableEv
-__ZN3WTF10RefCountedIN3JSC9StructureEE5derefEv
+__ZN3JSC10JSONObjectC1EPNS_14JSGlobalObjectEPNS_9StructureE
+__ZN3JSC14JSGlobalObject16addStaticGlobalsEPNS0_18GlobalPropertyInfoEi
+__ZN3WTF7HashMapINS_6RefPtrINS_10StringImplEEEN3JSC16SymbolTableEntryENS4_17IdentifierRepHashENS_10HashTraitsIS3_EENS4_26SymbolTableIndexHashTraitsEE3addEPS2_RKS5_
+__ZN3JSC9Structure25changePrototypeTransitionERNS_12JSGlobalDataEPS0_NS_7JSValueE
+__ZN3JSC9Structure17copyPropertyTableERNS_12JSGlobalDataEPS0_
__ZN3JSC14JSGlobalObject10globalExecEv
-__ZN3JSC4Heap9unprotectENS_7JSValueE
-__ZN3JSC14TimeoutChecker5resetEv
-__ZN3JSC8evaluateEPNS_9ExecStateERNS_10ScopeChainERKNS_10SourceCodeENS_7JSValueE
+_JSGlobalContextRetain
+__ZN3JSC14MachineThreads16addCurrentThreadEv
__ZN3JSC6JSLockC1EPNS_9ExecStateE
-__ZN3JSC6JSLock4lockENS_14JSLockBehaviorE
-__ZN3JSC17ProgramExecutable7compileEPNS_9ExecStateEPNS_14ScopeChainNodeE
-__ZN3JSC6Parser5parseINS_11ProgramNodeEEEN3WTF10PassRefPtrIT_EEPNS_12JSGlobalDataEPNS_8DebuggerEPNS_9ExecStateERKNS_10SourceCod
-__ZN3JSC6Parser5parseEPNS_12JSGlobalDataEPiPNS_7UStringE
-__ZN3JSC5Lexer7setCodeERKNS_10SourceCodeERNS_11ParserArenaE
-__Z10jscyyparsePv
-__ZN3JSC5Lexer3lexEPvS1_
+__ZN3JSC4Heap7protectENS_7JSValueE
+__ZN3WTF9HashTableIPN3JSC6JSCellESt4pairIS3_jENS_18PairFirstExtractorIS5_EENS_7PtrHashIS3_EENS_14PairHashTraitsINS_10HashTraitsIS3_EENSB_IjEEEESC_E4findIS3_NS_22IdentityHashTranslatorIS3_S5_S9_EEEENS_17HashTableIteratorIS3_S5_S7_S9_SE_SC_EERKT_
+__ZN3WTF9HashTableIPN3JSC6JSCellESt4pairIS3_jENS_18PairFirstExtractorIS5_EENS_7PtrHashIS3_EENS_14PairHashTraitsINS_10HashTraitsIS3_EENSB_IjEEEESC_E6rehashEi
+__ZN3JSC6JSLock6unlockENS_14JSLockBehaviorE
+_JSValueMakeFromJSONString
+__ZNK14OpaqueJSString7ustringEv
+__ZN3JSC7UStringC1EPKtj
+__ZN3JSC13LiteralParser5Lexer3lexERNS1_18LiteralParserTokenE
+__ZN3JSC13LiteralParser5parseENS0_11ParserStateE
+__ZN3JSC7JSArrayC1ERNS_12JSGlobalDataEPNS_9StructureE
+__ZN3WTF13StringBuilder6appendEPKtj
+__ZN3WTF13StringBuilder19appendUninitializedEj
+__ZN3WTF13StringBuilder14allocateBufferEPKtj
+__ZN3WTF13StringBuilder11shrinkToFitEv
+__ZN3WTF13StringBuilder11reifyStringEv
+__ZN3JSC12SmallStrings27createSingleCharacterStringEPNS_12JSGlobalDataEh
+__ZN3JSC7JSArray4pushEPNS_9ExecStateENS_7JSValueE
+__ZN3JSC7JSArray20increaseVectorLengthEj
+__ZN3WTF14tryFastReallocEPvm
+_JSValueIsNull
+_JSValueIsUndefined
+_JSValueIsBoolean
+_JSValueIsNumber
+_JSValueIsString
+_JSValueToObject
+__ZN3JSC12APIEntryShimC1EPNS_9ExecStateEb
+__ZNK3JSC8JSObject8toObjectEPNS_9ExecStateEPNS_14JSGlobalObjectE
+_JSContextGetGlobalObject
+__ZNK3JSC8JSObject12toThisObjectEPNS_9ExecStateE
+_JSStringCreateWithUTF8CString
+_JSObjectGetProperty
+__ZNK14OpaqueJSString10identifierEPN3JSC12JSGlobalDataE
__ZN3JSC10Identifier3addEPNS_12JSGlobalDataEPKti
-__ZN3WTF7HashSetIPN7WebCore10StringImplENS1_10StringHashENS_10HashTraitsIS3_EEE3addIN3JSC11UCharBufferENS9_31IdentifierUCharBuf
+__ZN3JSC14JSGlobalObject18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
+_JSValueIsInstanceOfConstructor
+__ZN3JSC16ArrayConstructor18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
+__ZN3JSC8JSObject11hasInstanceEPNS_9ExecStateENS_7JSValueES3_
+__ZN3JSC6JSCell9getObjectEv
+__ZN3JSC7JSArray18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
+_JSValueToNumber
+_JSObjectGetPropertyAtIndex
+__ZN3JSC7JSArray18getOwnPropertySlotEPNS_9ExecStateEjRNS_12PropertySlotE
+_JSValueToStringCopy
+__ZNK3JSC7JSValue8toStringEPNS_9ExecStateE
+__ZN14OpaqueJSString6createERKN3JSC7UStringE
+_JSStringCopyCFString
+_JSObjectCopyPropertyNames
+__ZN3JSC8JSObject16getPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayENS_15EnumerationModeE
+__ZN3JSC8JSObject19getOwnPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayENS_15EnumerationModeE
+__ZN3JSC9Structure16getPropertyNamesERNS_12JSGlobalDataERNS_17PropertyNameArrayENS_15EnumerationModeE
+__ZN3JSC9ExecState20objectPrototypeTableEPS0_
__ZNK3JSC9HashTable11createTableEPNS_12JSGlobalDataE
+_JSPropertyNameArrayGetCount
+_JSPropertyNameArrayRelease
+_JSGlobalContextRelease
+__ZN3JSC4Heap9unprotectENS_7JSValueE
+__ZN3JSC10HandleHeap4growEv
+__ZN3JSC37DefaultGCActivityCallbackPlatformData7triggerEP16__CFRunLoopTimerPv
+__ZN3JSC4Heap17collectAllGarbageEv
+__ZN3JSC12JSGlobalData23recompileAllJSFunctionsEv
+__ZN3JSC4Heap5resetENS0_11SweepToggleE
+__ZN3JSC4Heap9markRootsEv
+__ZN3JSC14MachineThreads23gatherConservativeRootsERNS_17ConservativeRootsEPv
+__ZN3JSC14MachineThreads23gatherFromCurrentThreadERNS_17ConservativeRootsEPv
+__ZN3JSC17ConservativeRoots3addEPvS1_
+__ZN3JSC12RegisterFile23gatherConservativeRootsERNS_17ConservativeRootsE
+__ZN3JSC11MarkedSpace10clearMarksEv
+__ZN3JSC9MarkStack6appendERNS_17ConservativeRootsE
+__ZN3JSC9MarkStack5drainEv
+__ZN3JSC4Heap20markProtectedObjectsERNS_15HeapRootVisitorE
+__ZN3JSC4Heap19markTempSortVectorsERNS_15HeapRootVisitorE
+__ZN3JSC10HandleHeap17markStrongHandlesERNS_15HeapRootVisitorE
+__ZN3JSC9MarkStack13visitChildrenEPNS_6JSCellE
+__ZN3JSC9Structure13visitChildrenERNS_9MarkStackE
+__ZN3JSC11HandleStack4markERNS_15HeapRootVisitorE
+__ZN3JSC12SmallStrings13visitChildrenERNS_15HeapRootVisitorE
+__ZN3JSC10HandleHeap15markWeakHandlesERNS_15HeapRootVisitorE
+__ZN3JSC9MarkStack5resetEv
+__ZN3JSC10HandleHeap19finalizeWeakHandlesEv
+__ZN3JSC11MarkedSpace5resetEv
+__ZN3JSC11MarkedSpace5sweepEv
+__ZN3JSC11MarkedBlock5sweepEv
+__ZN3JSC9StructureD1Ev
+__ZN3JSC8JSStringD1Ev
+__ZN3JSC10JSFunctionD1Ev
+__ZN3JSC14ArrayPrototypeD1Ev
+__ZN3JSC7JSArrayD2Ev
+__ZN3JSC13DatePrototypeD1Ev
+__ZN3JSC13JSFinalObjectD1Ev
+__ZN3JSC7JSArrayD1Ev
+__ZN3JSC14ScopeChainNodeD1Ev
+__ZN3JSC15ObjectPrototypeD1Ev
+__ZN3JSC15StringPrototypeD1Ev
+__ZN3JSC16BooleanPrototypeD1Ev
+__ZN3JSC15NumberPrototypeD1Ev
+__ZN3JSC15RegExpPrototypeD1Ev
+__ZN3JSC12RegExpObjectD2Ev
+__ZN3JSC6RegExpD1Ev
+__ZN3JSC14ErrorPrototypeD1Ev
+__ZN3JSC17RegExpConstructorD1Ev
+__ZN3JSC22NativeErrorConstructorD1Ev
+__ZN3JSC17FunctionPrototypeD1Ev
+__ZN3JSC17ObjectConstructorD1Ev
+__ZN3JSC19FunctionConstructorD1Ev
+__ZN3JSC16ArrayConstructorD1Ev
+__ZN3JSC17StringConstructorD1Ev
+__ZN3JSC18BooleanConstructorD1Ev
+__ZN3JSC17NumberConstructorD1Ev
+__ZN3JSC15DateConstructorD1Ev
+__ZN3JSC16ErrorConstructorD1Ev
+__ZN3JSC20NativeErrorPrototypeD1Ev
+__ZN3JSC10MathObjectD1Ev
+__ZN3JSC10JSONObjectD1Ev
+__ZN3JSC16NativeExecutableD1Ev
+__ZN3JSC14JSGlobalObjectD1Ev
+__ZN3JSC14JSGlobalObjectD2Ev
+__ZN3WTF9HashTableINS_6RefPtrI21OpaqueJSWeakObjectMapEES3_NS_17IdentityExtractorIS3_EENS_7PtrHashIS3_EENS_10HashTraitsIS3_EES9_E15deallocateTableEPS3_i
+__ZN3WTF9HashTableINS_6RefPtrI21OpaqueJSWeakObjectMapEES3_NS_17IdentityExtractorIS3_EENS_7PtrHashIS3_EENS_10HashTraitsIS3_EES9_E6rehashEi
+__ZN3JSC11MarkedSpace6shrinkEv
+__ZN3JSC11MarkedSpace10freeBlocksERN3WTF16DoublyLinkedListINS_11MarkedBlockEEE
+__ZN3JSC11MarkedBlock7destroyEPS0_
+__ZN3WTF21PageAllocationAligned10deallocateEv
+__ZNK3JSC11MarkedSpace4sizeEv
+__Z22TCMalloc_SystemReleasePvm
+__Z21TCMalloc_SystemCommitPvm
+__ZN3WTFL10timerFiredEP16__CFRunLoopTimerPv
+__ZN3WTF15ThreadConditionD1Ev
+__ZNK3WTF6String5toIntEPb
+__ZN3WTF10StringImpl5toIntEPb
+__ZN3WTF15charactersToIntEPKtmPb
+__ZN3WTF22charactersToUIntStrictEPKtmPbi
+__ZN3WTF6VectorIN3JSC4Yarr11PatternTermELm0EE14expandCapacityEm
+__ZN3JSC4Yarr6ParserINS0_22YarrPatternConstructorEE28CharacterClassParserDelegate20atomPatternCharacterEtb
+__ZN3JSC4Yarr25CharacterClassConstructor14addSortedRangeERN3WTF6VectorINS0_14CharacterRangeELm0EEEtt
+__ZN3WTF6VectorIN3JSC4Yarr14CharacterRangeELm0EE14expandCapacityEmPKS3_
+__ZN3WTF6VectorIN3JSC4Yarr14CharacterRangeELm0EE14expandCapacityEm
+__ZN3JSC4Yarr6ParserINS0_22YarrPatternConstructorEE11parseEscapeILb1ENS3_28CharacterClassParserDelegateEEEbRT0_
+__ZN3JSC4Yarr25CharacterClassConstructor7putCharEt
+__ZN3WTF6VectorItLm0EE14expandCapacityEm
+__ZN3JSC4Yarr22YarrPatternConstructor21atomCharacterClassEndEv
+__ZN3WTF6VectorIPN3JSC4Yarr14CharacterClassELm0EE14expandCapacityEm
+__ZN3JSC4Yarr22YarrPatternConstructor20atomPatternCharacterEt
+__ZN3JSC4Yarr6ParserINS0_22YarrPatternConstructorEE11parseEscapeILb0ES2_EEbRT0_
+__ZN3JSC4Yarr11byteCompileERNS0_11YarrPatternEPN3WTF20BumpPointerAllocatorE
+__ZN3WTF6VectorIN3JSC4Yarr8ByteTermELm0EE14expandCapacityEm
+__ZN3JSC4Yarr12ByteCompiler15emitDisjunctionEPNS0_18PatternDisjunctionEjj
+__ZN3JSC4Yarr13newlineCreateEv
+__ZN3JSC4Yarr14wordcharCreateEv
+__ZN3JSC4Yarr9interpretEPNS0_15BytecodePatternEPKtjjPi
+__ZN3JSC4Yarr11Interpreter16matchDisjunctionEPNS0_15ByteDisjunctionEPNS1_18DisjunctionContextEb
+__ZN3WTF10StringImpl23reverseFindIgnoringCaseEPS0_j
+__ZN3JSC12JSGlobalData12createLeakedENS_15ThreadStackTypeE
+__ZN3WTF10StringImpl5adoptERNS_12StringBufferE
+__ZN3WTF10StringImpl7replaceEtt
+__ZNK3WTF6String16removeCharactersEPFbtE
+__ZN3WTF10StringImpl16removeCharactersEPFbtE
+__ZN3WTF10StringImpl4findEPFbtEj
+__ZN3JSC24JSObjectWithGlobalObjectC2ERNS_12JSGlobalDataEPNS_14JSGlobalObjectEPNS_9StructureE
+_JSContextGetGlobalContext
+_JSWeakObjectMapCreate
+__ZN3JSC14JSGlobalObject17weakMapsFinalizerEv
+_JSWeakObjectMapGet
+_JSClassCreate
+__ZN13OpaqueJSClass6createEPK17JSClassDefinition
+__ZN13OpaqueJSClassC2EPK17JSClassDefinitionPS_
+__ZN3WTF9HashTableINS_6RefPtrINS_10StringImplEEESt4pairIS3_P16StaticValueEntryENS_18PairFirstExtractorIS7_EENS_10StringHashENS_14PairHashTraitsINS_10HashTraitsIS3_EENSC_IS6_EEEESD_E6expandEv
+_JSClassRetain
+_JSObjectMake
+__ZN3JSC16JSCallbackObjectINS_24JSObjectWithGlobalObjectEEC2EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureEP13OpaqueJSClassPv
+__ZN3JSC16JSCallbackObjectINS_24JSObjectWithGlobalObjectEE4initEPNS_9ExecStateE
+__ZN3JSC6JSLock12DropAllLocksC1EPNS_9ExecStateE
+_JSObjectGetPrivate
+__ZN3JSC6JSLock12DropAllLocksD1Ev
+__ZN13OpaqueJSClass9prototypeEPN3JSC9ExecStateE
+__ZN13OpaqueJSClass11contextDataEPN3JSC9ExecStateE
+__ZN3WTF9HashTableIP13OpaqueJSClassSt4pairIS2_P24OpaqueJSClassContextDataENS_18PairFirstExtractorIS6_EENS_7PtrHashIS2_EENS_14PairHashTraitsINS_10HashTraitsIS2_EENSC_IS5_EEEESD_E6expandEv
+__ZN24OpaqueJSClassContextDataC2ERN3JSC12JSGlobalDataEP13OpaqueJSClass
+_JSWeakObjectMapSet
+__ZN3WTF9HashTableIPvSt4pairIS1_PN3JSC7JSValueEENS_18PairFirstExtractorIS6_EENS_7PtrHashIS1_EENS_14PairHashTraitsINS_10HashTraitsIS1_EENSC_IS5_EEEESD_E6rehashEi
+_JSObjectSetProperty
+__ZNK3JSC8JSObject11hasPropertyEPNS_9ExecStateERKNS_10IdentifierE
+__ZN3JSC16JSCallbackObjectINS_24JSObjectWithGlobalObjectEE18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
+__ZN3JSC15ObjectPrototype18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
+__ZN3JSC8JSObject17putWithAttributesEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueEj
+__ZN3JSC10Identifier8toUInt32ERKNS_7UStringERb
+__ZN3WTF12AtomicString4findEPKtjj
+__ZNK3WTF9HashTableIPNS_10StringImplES2_NS_17IdentityExtractorIS2_EENS_10StringHashENS_10HashTraitsIS2_EES7_E4findINS_17HashAndCharactersENS_24HashSetTranslatorAdapterIS2_S7_SA_NS_27HashAndCharactersTranslatorEEEEENS_22HashTableConstIteratorIS2_S2_S4_S5_S7_S7_EERKT_
+__ZN3JSC14JSGlobalObject17putWithAttributesEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueEj
+__ZN3JSC8JSObject3putEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueERNS_15PutPropertySlotE
+__ZN3JSC8evaluateEPNS_9ExecStateEPNS_14ScopeChainNodeERKNS_10SourceCodeENS_7JSValueE
+__ZN3JSC17ProgramExecutableC1EPNS_9ExecStateERKNS_10SourceCodeE
+__ZN3JSC11Interpreter7executeEPNS_17ProgramExecutableEPNS_9ExecStateEPNS_14ScopeChainNodeEPNS_8JSObjectE
+__ZN3JSC24DynamicGlobalObjectScopeC1ERNS_12JSGlobalDataEPNS_14JSGlobalObjectE
+__ZN3JSC19ExecutableAllocator19underMemoryPressureEv
+__ZN3JSC12JSGlobalData14resetDateCacheEv
+__ZN3JSC17ProgramExecutable15compileInternalEPNS_9ExecStateEPNS_14ScopeChainNodeE
+__ZN3JSC6Parser5parseINS_11ProgramNodeEEEN3WTF10PassRefPtrIT_EEPNS_14JSGlobalObjectEPNS_8DebuggerEPNS_9ExecStateERKNS_10SourceCodeEPNS_18FunctionParametersENS_18JSParserStrictnessEPPNS_8JSObjectE
+__ZN3JSC6Parser5parseEPNS_12JSGlobalDataEPNS_18FunctionParametersENS_18JSParserStrictnessENS_12JSParserModeEPiPNS_7UStringE
+__ZN3JSC5Lexer7setCodeERKNS_10SourceCodeERNS_11ParserArenaE
+__ZN3JSC7jsParseEPNS_12JSGlobalDataEPNS_18FunctionParametersENS_18JSParserStrictnessENS_12JSParserModeEPKNS_10SourceCodeE
+__ZN3JSC8JSParserC2EPNS_5LexerEPNS_12JSGlobalDataEPNS_18FunctionParametersEbbPNS_14SourceProviderE
+__ZN3JSC8JSParser9pushScopeEv
+__ZN3JSC8JSParser4nextENS_5Lexer7LexTypeE
+__ZN3JSC5Lexer3lexEPNS_11JSTokenDataEPNS_11JSTokenInfoENS0_7LexTypeEb
+__ZN3WTF15SegmentedVectorIN3JSC10IdentifierELm64EE6appendIS2_EEvRKT_
+__ZN3JSC8JSParser12parseProgramEv
+__ZNK3JSC19SourceProviderCache8byteSizeEv
+__ZN3WTF6VectorIPN3JSC20ParserArenaDeletableELm0EE15reserveCapacityEm
+__ZN3JSC8JSParser19parseSourceElementsILNS0_18SourceElementsModeE0ENS_10ASTBuilderEEENT0_14SourceElementsERS4_
+__ZN3JSC8JSParser14parseStatementINS_10ASTBuilderEEENT_9StatementERS3_RPKNS_10IdentifierE
+__ZN3JSC8JSParser24parseFunctionDeclarationINS_10ASTBuilderEEENT_9StatementERS3_
+__ZN3JSC8JSParser17parseFunctionInfoILNS0_20FunctionRequirementsE1ELb1ENS_10ASTBuilderEEEbRT1_RPKNS_10IdentifierERNS4_19FormalParameterListERNS4_12FunctionBodyERiSE_SE_
+__ZN3JSC8JSParser16declareParameterEPKNS_10IdentifierE
+__ZN3JSC11ParserArena16allocateFreeableEm
__ZN3JSC11ParserArena20allocateFreeablePoolEv
-__ZL20makeFunctionCallNodePN3JSC12JSGlobalDataENS_8NodeInfoIPNS_14ExpressionNodeEEENS2_IPNS_13ArgumentsNodeEEEiii
-__ZNK3JSC15DotAccessorNode10isLocationEv
-__ZNK3JSC14ExpressionNode13isResolveNodeEv
-__ZNK3JSC14ExpressionNode21isBracketAccessorNodeEv
-__ZL14makeAssignNodePN3JSC12JSGlobalDataEPNS_14ExpressionNodeENS_8OperatorES3_bbiii
-__ZNK3JSC11ResolveNode10isLocationEv
-__ZNK3JSC11ResolveNode13isResolveNodeEv
+__ZN3JSC8JSParser19parseSourceElementsILNS0_18SourceElementsModeE0ENS_13SyntaxCheckerEEENT0_14SourceElementsERS4_
+__ZN3JSC8JSParser14parseStatementINS_13SyntaxCheckerEEENT_9StatementERS3_RPKNS_10IdentifierE
+__ZN3JSC8JSParser17parseForStatementINS_13SyntaxCheckerEEENT_9StatementERS3_
+__ZN3JSC8JSParser5Scope15declareVariableEPKNS_10IdentifierE
+__ZN3JSC5Lexer7record8Ei
+__ZN3JSC8JSParser25parseAssignmentExpressionINS_13SyntaxCheckerEEENT_10ExpressionERS3_
+__ZN3JSC8JSParser21parseMemberExpressionINS_13SyntaxCheckerEEENT_10ExpressionERS3_
+__ZN3JSC8JSParser15parseExpressionINS_13SyntaxCheckerEEENT_10ExpressionERS3_
+__ZN3WTF7HashSetINS_6RefPtrINS_10StringImplEEEN3JSC17IdentifierRepHashENS_10HashTraitsIS3_EEE3addERKS3_
+__ZN3JSC8JSParser16parseIfStatementINS_13SyntaxCheckerEEENT_9StatementERS3_
+__ZN3JSC8JSParser31parseExpressionOrLabelStatementINS_13SyntaxCheckerEEENT_9StatementERS3_
+__ZN3JSC5Lexer16nextTokenIsColonEv
+__ZN3JSC16FunctionBodyNode6createEPNS_12JSGlobalDataEb
+__ZN3JSC11ParserArena14derefWithArenaEN3WTF10PassRefPtrINS_21ParserArenaRefCountedEEE
+__ZN3WTF14deleteOwnedPtrIN3JSC23SourceProviderCacheItemEEEvPT_
+__ZN3JSC8JSParser5Scope29copyCapturedVariablesToVectorERKN3WTF7HashSetINS2_6RefPtrINS2_10StringImplEEENS_17IdentifierRepHashENS2_10HashTraitsIS6_EEEERNS2_6VectorIS6_Lm0EEE
+__ZN3WTF9HashTableINS_6RefPtrINS_10StringImplEEES3_NS_17IdentityExtractorIS3_EEN3JSC17IdentifierRepHashENS_10HashTraitsIS3_EES9_E13isEmptyBucketERKS3_
+__ZN3WTF9HashTableINS_6RefPtrINS_10StringImplEEES3_NS_17IdentityExtractorIS3_EEN3JSC17IdentifierRepHashENS_10HashTraitsIS3_EES9_E15deallocateTableEPS3_i
+__ZN3WTF9HashTableINS_6RefPtrINS_10StringImplEEES3_NS_17IdentityExtractorIS3_EEN3JSC17IdentifierRepHashENS_10HashTraitsIS3_EES9_E6expandEv
+__ZN3WTF9HashTableINS_6RefPtrINS_10StringImplEEES3_NS_17IdentityExtractorIS3_EEN3JSC17IdentifierRepHashENS_10HashTraitsIS3_EES9_E6rehashEi
+__ZN3WTF6VectorINS_6RefPtrINS_10StringImplEEELm0EE14expandCapacityEm
+__ZN3JSC8JSParser5ScopeD1Ev
+__ZN3JSC19SourceProviderCache3addEiN3WTF10PassOwnPtrINS_23SourceProviderCacheItemEEEj
+__ZN3WTF9HashTableIiSt4pairIiPN3JSC23SourceProviderCacheItemEENS_18PairFirstExtractorIS5_EENS_7IntHashIjEENS_14PairHashTraitsINS_10HashTraitsIiEENSB_IS4_EEEESC_E6expandEv
+__ZN3JSC5Lexer10sourceCodeEiii
+__ZN3JSC16FunctionBodyNode13finishParsingERKNS_10SourceCodeEPNS_13ParameterNodeERKNS_10IdentifierE
+__ZN3WTF6VectorIN3JSC10IdentifierELm0EE14expandCapacityEm
+__ZN3JSC16FunctionBodyNode13finishParsingEN3WTF10PassRefPtrINS_18FunctionParametersEEERKNS_10IdentifierE
+__ZN3WTF6VectorIPN3JSC16FunctionBodyNodeELm0EE15reserveCapacityEm
__ZN3JSC13StatementNode6setLocEii
-__ZN3WTF6VectorIPN3JSC20ParserArenaDeletableELm0EE14expandCapacityEm
__ZN3JSC14SourceElements6appendEPNS_13StatementNodeE
__ZNK3JSC13StatementNode16isEmptyStatementEv
__ZN3WTF6VectorIPN3JSC13StatementNodeELm0EE14expandCapacityEm
-__ZN3JSC6Parser16didFinishParsingEPNS_14SourceElementsEPNS_15ParserArenaDataIN3WTF6VectorISt4pairIPKNS_10IdentifierEjELm0EEEEEP
+__ZN3JSC8JSParser21parseConstDeclarationINS_10ASTBuilderEEENT_9StatementERS3_
+__ZN3WTF6VectorISt4pairIPKN3JSC10IdentifierEjELm0EE15reserveCapacityEm
+__ZN3JSC8JSParser25parseAssignmentExpressionINS_10ASTBuilderEEENT_10ExpressionERS3_
+__ZN3JSC8JSParser21parseMemberExpressionINS_10ASTBuilderEEENT_10ExpressionERS3_
+__ZN3JSC5Lexer10scanRegExpERPKNS_10IdentifierES4_t
+__ZN3JSC4Yarr11checkSyntaxERKNS_7UStringE
+__ZN3JSC4Yarr6ParserINS0_13SyntaxCheckerEE5parseEv
+__ZN3JSC4Yarr6ParserINS0_13SyntaxCheckerEE11parseEscapeILb1ENS3_28CharacterClassParserDelegateEEEbRT0_
+__ZN3JSC8JSParser20parseReturnStatementINS_13SyntaxCheckerEEENT_9StatementERS3_
+__ZN3WTF6VectorIiLm0EE14expandCapacityEm
+__ZN3JSC8JSParser19parseVarDeclarationINS_13SyntaxCheckerEEENT_9StatementERS3_
+__ZN3JSC8JSParser17parseFunctionInfoILNS0_20FunctionRequirementsE0ELb0ENS_13SyntaxCheckerEEEbRT1_RPKNS_10IdentifierERNS4_19FormalParameterListERNS4_12FunctionBodyERiSE_SE_
+__ZN3JSC8JSParser19parseWhileStatementINS_13SyntaxCheckerEEENT_9StatementERS3_
+__ZN3JSC10ASTBuilder20makeFunctionCallNodeEPNS_14ExpressionNodeEPNS_13ArgumentsNodeEiii
+__ZNK3JSC11ResolveNode10isLocationEv
+__ZNK3JSC11ResolveNode13isResolveNodeEv
+__ZN3WTF6VectorISt4pairIiiELm0EE14expandCapacityEm
+__ZN3JSC8JSParser22parseContinueStatementINS_13SyntaxCheckerEEENT_9StatementERS3_
+__ZN3JSC8JSParser17parseTryStatementINS_13SyntaxCheckerEEENT_9StatementERS3_
+__ZN3JSC6Parser16didFinishParsingEPNS_14SourceElementsEPNS_15ParserArenaDataIN3WTF6VectorISt4pairIPKNS_10IdentifierEjELm0EEEEEPNS3_INS5_IPNS_16FunctionBodyNodeELm0EEEEEjiiRNS4_7HashSetINS4_6RefPtrINS4_10StringImplEEENS_17IdentifierRepHashENS4_10HashTraitsISM_EEEE
+__ZN3JSC11ParserArenaD1Ev
__ZN3JSC5Lexer5clearEv
-__ZN3JSC11ProgramNode6createEPNS_12JSGlobalDataEPNS_14SourceElementsEPN3WTF6VectorISt4pairIPKNS_10IdentifierEjELm0EEEPNS6_IPNS_
-__ZN3JSC9ScopeNodeC2EPNS_12JSGlobalDataERKNS_10SourceCodeEPNS_14SourceElementsEPN3WTF6VectorISt4pairIPKNS_10IdentifierEjELm0EEE
-__ZN3JSC11ParserArena14derefWithArenaEN3WTF10PassRefPtrINS_21ParserArenaRefCountedEEE
+__ZN3JSC11ProgramNode6createEPNS_12JSGlobalDataEPNS_14SourceElementsEPN3WTF6VectorISt4pairIPKNS_10IdentifierEjELm0EEEPNS6_IPNS_16FunctionBodyNodeELm0EEERNS5_7HashSetINS5_6RefPtrINS5_10StringImplEEENS_17IdentifierRepHashENS5_10HashTraitsISL_EEEERKNS_10SourceCodeEji
+__ZN3JSC9ScopeNodeC2EPNS_12JSGlobalDataERKNS_10SourceCodeEPNS_14SourceElementsEPN3WTF6VectorISt4pairIPKNS_10IdentifierEjELm0EEEPNS9_IPNS_16FunctionBodyNodeELm0EEERNS8_7HashSetINS8_6RefPtrINS8_10StringImplEEENS_17IdentifierRepHashENS8_10HashTraitsISO_EEEEji
__ZN3JSC11ParserArena10removeLastEv
__ZN3JSC11ParserArena5resetEv
__ZN3WTF6VectorIN3JSC10IdentifierELm64EE14shrinkCapacityEm
-__ZN3JSC9CodeBlockC2EPNS_16ScriptExecutableENS_8CodeTypeEN3WTF10PassRefPtrINS_14SourceProviderEEEjPNS4_7HashMapINS4_6RefPtrIN7W
-__ZN3WTF7HashSetIPN3JSC15GlobalCodeBlockENS_7PtrHashIS3_EENS_10HashTraitsIS3_EEE3addERKS3_
-__ZN3WTF9HashTableIPN3JSC15GlobalCodeBlockES3_NS_17IdentityExtractorIS3_EENS_7PtrHashIS3_EENS_10HashTraitsIS3_EES9_E6rehashEi
-__ZN3JSC17BytecodeGeneratorC1EPNS_11ProgramNodeEPKNS_8DebuggerERKNS_10ScopeChainEPN3WTF7HashMapINS9_6RefPtrIN7WebCore10StringIm
-__ZN3JSC17BytecodeGeneratorC2EPNS_11ProgramNodeEPKNS_8DebuggerERKNS_10ScopeChainEPN3WTF7HashMapINS9_6RefPtrIN7WebCore10StringIm
+__ZN3JSC9CodeBlockC2EPNS_16ScriptExecutableENS_8CodeTypeEPNS_14JSGlobalObjectEN3WTF10PassRefPtrINS_14SourceProviderEEEjPNS6_7HashMapINS6_6RefPtrINS6_10StringImplEEENS_16SymbolTableEntryENS_17IdentifierRepHashENS6_10HashTraitsISD_EENS_26SymbolTableIndexHashTraitsEEEb
+__ZN3JSC17BytecodeGeneratorC1EPNS_11ProgramNodeEPNS_14ScopeChainNodeEPN3WTF7HashMapINS5_6RefPtrINS5_10StringImplEEENS_16SymbolTableEntryENS_17IdentifierRepHashENS5_10HashTraitsIS9_EENS_26SymbolTableIndexHashTraitsEEEPNS_16ProgramCodeBlockE
+__ZN3JSC17BytecodeGeneratorC2EPNS_11ProgramNodeEPNS_14ScopeChainNodeEPN3WTF7HashMapINS5_6RefPtrINS5_10StringImplEEENS_16SymbolTableEntryENS_17IdentifierRepHashENS5_10HashTraitsIS9_EENS_26SymbolTableIndexHashTraitsEEEPNS_16ProgramCodeBlockE
+__ZN3JSC17BytecodeGenerator10emitOpcodeENS_8OpcodeIDE
__ZN3WTF6VectorIN3JSC11InstructionELm0EE15reserveCapacityEm
-__ZN3JSC9Structure31toCacheableDictionaryTransitionEPS0_
-__ZN3JSC9Structure22toDictionaryTransitionEPS0_NS0_14DictionaryKindE
-__ZN3JSC9Structure26flattenDictionaryStructureEPNS_8JSObjectE
+__ZN3WTF15SegmentedVectorIN3JSC10RegisterIDELm32EE13ensureSegmentEmm
+__ZN3JSC8JSObject12removeDirectERNS_12JSGlobalDataERKNS_10IdentifierE
+__ZN3WTF9HashTableINS_6RefPtrINS_10StringImplEEESt4pairIS3_N3JSC16SymbolTableEntryEENS_18PairFirstExtractorIS7_EENS5_17IdentifierRepHashENS_14PairHashTraitsINS_10HashTraitsIS3_EENS5_26SymbolTableIndexHashTraitsEEESD_E13isEmptyBucketERKS7_
+__ZN3WTF9HashTableINS_6RefPtrINS_10StringImplEEESt4pairIS3_N3JSC16SymbolTableEntryEENS_18PairFirstExtractorIS7_EENS5_17IdentifierRepHashENS_14PairHashTraitsINS_10HashTraitsIS3_EENS5_26SymbolTableIndexHashTraitsEEESD_E6expandEv
+__ZN3WTF9HashTableINS_6RefPtrINS_10StringImplEEESt4pairIS3_N3JSC16SymbolTableEntryEENS_18PairFirstExtractorIS7_EENS5_17IdentifierRepHashENS_14PairHashTraitsINS_10HashTraitsIS3_EENS5_26SymbolTableIndexHashTraitsEEESD_E6rehashEi
+__ZN3WTF9HashTableIPNS_10StringImplES2_NS_17IdentityExtractorIS2_EEN3JSC17IdentifierRepHashENS_10HashTraitsIS2_EES8_E6rehashEi
+__ZN3JSC14JSGlobalObject15resizeRegistersEii
+__ZN3JSC17BytecodeGenerator12addGlobalVarERKNS_10IdentifierEbRPNS_10RegisterIDE
+__ZN3JSC18FunctionExecutableC1EPNS_9ExecStateERKNS_10IdentifierERKNS_10SourceCodeEbPNS_18FunctionParametersEbii
+__ZN3JSC10JSFunctionC1EPNS_9ExecStateEPNS_18FunctionExecutableEPNS_14ScopeChainNodeE
+__ZN3JSC10JSFunctionC2EPNS_9ExecStateEPNS_18FunctionExecutableEPNS_14ScopeChainNodeE
__ZN3JSC17BytecodeGenerator8generateEv
__ZN3JSC11ProgramNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
__ZN3JSC17BytecodeGenerator13emitDebugHookENS_11DebugHookIDEii
__ZN3JSC17BytecodeGenerator11newRegisterEv
__ZN3JSC17BytecodeGenerator8emitLoadEPNS_10RegisterIDENS_7JSValueE
__ZN3JSC17BytecodeGenerator16addConstantValueENS_7JSValueE
-__ZN3WTF9HashTableIPvSt4pairIS1_jENS_18PairFirstExtractorIS3_EENS_7PtrHashIS1_EENS_14PairHashTraitsIN3JSC24EncodedJSValueHashTr
-__ZN3WTF6VectorIN3JSC8RegisterELm0EE15reserveCapacityEm
-__ZN3WTF6VectorIN3JSC8LineInfoELm0EE14expandCapacityEm
-__ZN3JSC17ExprStatementNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC17AssignResolveNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3WTF9HashTableIPvSt4pairIS1_jENS_18PairFirstExtractorIS3_EENS_7PtrHashIS1_EENS_14PairHashTraitsIN3JSC24EncodedJSValueHashTraitsENS_10HashTraitsIjEEEESA_E6expandEv
+__ZN3WTF6VectorIN3JSC12WriteBarrierINS1_7UnknownEEELm0EE14expandCapacityEm
+__ZN3JSC12FuncDeclNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC18ConstStatementNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC17BytecodeGenerator8emitNodeEPNS_10RegisterIDEPNS_4NodeE
+__ZN3JSC13ConstDeclNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC13ConstDeclNode14emitCodeSingleERNS_17BytecodeGeneratorE
+__ZN3JSC17BytecodeGenerator16constRegisterForERKNS_10IdentifierE
+__ZN3JSC10RegExpNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC11regExpFlagsERKNS_7UStringE
+__ZN3JSC11RegExpCache14lookupOrCreateERKNS_7UStringENS_11RegExpFlagsE
+__ZN3WTF9HashTableIN3JSC9RegExpKeyESt4pairIS2_NS_6RefPtrINS1_6RegExpEEEENS_18PairFirstExtractorIS7_EENS_10RegExpHashIS2_EENS_14PairHashTraitsINS_10HashTraitsIS2_EENSD_IS6_EEEESE_E6rehashEi
+__ZN3JSC11RegExpCache6createERKNS_7UStringENS_11RegExpFlagsEN3WTF24HashTableIteratorAdapterINS5_9HashTableINS_9RegExpKeyESt4pairIS8_NS5_6RefPtrINS_6RegExpEEEENS5_18PairFirstExtractorISD_EENS5_10RegExpHashIS8_EENS5_14PairHashTraitsINS5_10HashTraitsIS8_EENSJ_ISC_EEEESK_EESD_EE
+__ZN3JSC4Yarr13YarrGenerator12generateTermEm
+__ZN3JSC4Yarr13YarrGenerator13readCharacterEiNS_12X86Registers10RegisterIDE
+__ZN3JSC4Yarr13YarrGenerator19matchCharacterClassENS_12X86Registers10RegisterIDERNS_22AbstractMacroAssemblerINS_12X86AssemblerEE8JumpListEPKNS0_14CharacterClassE
+__ZN3JSC23MacroAssemblerX86Common4moveENS_22AbstractMacroAssemblerINS_12X86AssemblerEE12TrustedImm32ENS_12X86Registers10RegisterIDE
+__ZN3JSC4Yarr13YarrGenerator12atEndOfInputEv
+__ZN3JSC14MacroAssembler4pokeENS_12X86Registers10RegisterIDEi
+__ZN3JSC4Yarr13YarrGenerator19jumpIfCharNotEqualsEti
+__ZN3JSC12X86Assembler23X86InstructionFormatter9oneByteOpENS0_15OneByteOpcodeIDEiNS_12X86Registers10RegisterIDES4_ii
+__ZN3JSC12X86Assembler7subl_irEiNS_12X86Registers10RegisterIDE
+__ZN3JSC4Yarr13YarrGenerator13backtrackTermEm
+__ZN3JSC4Yarr13YarrGenerator20backtrackTermDefaultEm
+__ZN3JSC4Yarr13YarrGenerator17BacktrackingState6linkToENS_22AbstractMacroAssemblerINS_12X86AssemblerEE5LabelEPNS_14MacroAssemblerE
+__ZN3JSC17BytecodeGenerator13emitNewRegExpEPNS_10RegisterIDEN3WTF10PassRefPtrINS_6RegExpEEE
+__ZN3JSC17BytecodeGenerator9addRegExpEN3WTF10PassRefPtrINS_6RegExpEEE
+__ZN3JSC9CodeBlock25createRareDataIfNecessaryEv
+__ZN3WTF16VectorBufferBaseIcE14allocateBufferEm
+__ZN3WTF6VectorIcLm128EE15reserveCapacityEm
+__ZN3JSC23FunctionCallResolveNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
__ZN3JSC17BytecodeGenerator11registerForERKNS_10IdentifierE
-__ZN3JSC17BytecodeGenerator18findScopedPropertyERKNS_10IdentifierERiRmbRbRPNS_8JSObjectE
-__ZN3JSC17BytecodeGenerator15emitResolveBaseEPNS_10RegisterIDERKNS_10IdentifierE
-__ZN3JSC19FunctionCallDotNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC11NewExprNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC11ResolveNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3WTF6VectorIN3JSC19ExpressionRangeInfoELm0EE14expandCapacityEm
-__ZN3JSC17BytecodeGenerator11emitResolveEPNS_10RegisterIDERKNS_10IdentifierE
-__ZN3WTF6VectorIN3JSC17GlobalResolveInfoELm0EE14expandCapacityEm
-__ZN3JSC17BytecodeGenerator11addConstantERKNS_10IdentifierE
-__ZN3WTF9HashTableINS_6RefPtrIN7WebCore10StringImplEEESt4pairIS4_iENS_18PairFirstExtractorIS6_EEN3JSC17IdentifierRepHashENS_14P
-__ZN3WTF6VectorIN3JSC10IdentifierELm0EE14expandCapacityEmPKS2_
-__ZN3WTF6VectorIN3JSC10IdentifierELm0EE15reserveCapacityEm
-__ZN3JSC17BytecodeGenerator13emitConstructEPNS_10RegisterIDES2_PNS_13ArgumentsNodeEjjj
-__ZN3WTF6VectorIN3JSC20GetByIdExceptionInfoELm0EE14expandCapacityEm
-__ZN3JSC17BytecodeGenerator11emitGetByIdEPNS_10RegisterIDES2_RKNS_10IdentifierE
-__ZN3WTF6VectorIN3JSC17StructureStubInfoELm0EE14expandCapacityEm
-__ZN3WTF6VectorIN3JSC12CallLinkInfoELm0EE15reserveCapacityEm
-__ZN3JSC17BytecodeGenerator15emitMethodCheckEv
-__ZN3JSC17BytecodeGenerator8emitCallEPNS_10RegisterIDES2_S2_PNS_13ArgumentsNodeEjjj
-__ZN3JSC17BytecodeGenerator8emitCallENS_8OpcodeIDEPNS_10RegisterIDES3_S3_PNS_13ArgumentsNodeEjjj
-__ZN3JSC17BytecodeGenerator11emitPutByIdEPNS_10RegisterIDERKNS_10IdentifierES2_
+__ZN3JSC13CallArgumentsC2ERNS_17BytecodeGeneratorEPNS_13ArgumentsNodeE
+__ZN3JSC17BytecodeGenerator8emitCallEPNS_10RegisterIDES2_RNS_13CallArgumentsEjjj
+__ZN3JSC17BytecodeGenerator8emitCallENS_8OpcodeIDEPNS_10RegisterIDES3_RNS_13CallArgumentsEjjj
+__ZN3JSC16ArgumentListNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC10StringNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC17BytecodeGenerator8emitLoadEPNS_10RegisterIDERKNS_10IdentifierE
+__ZN3WTF9HashTableIPNS_10StringImplESt4pairIS2_PN3JSC8JSStringEENS_18PairFirstExtractorIS7_EENS4_17IdentifierRepHashENS_14PairHashTraitsINS_10HashTraitsIS2_EENSC_IS6_EEEESD_E6rehashEi
+__ZN3WTF6VectorIN3JSC12CallLinkInfoELm0EE14expandCapacityEm
+__ZN3JSC11ResolveNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC17BytecodeGenerator8emitMoveEPNS_10RegisterIDES2_
+__ZN3JSC9ArrayNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC17BytecodeGenerator12emitNewArrayEPNS_10RegisterIDEPNS_11ElementNodeE
__ZN3JSC17BytecodeGenerator16emitUnaryNoDstOpENS_8OpcodeIDEPNS_10RegisterIDE
-__ZN3JSC12JSGlobalData22numericCompareFunctionEPNS_9ExecStateE
-__ZNK3JSC21UStringSourceProvider6lengthEv
-__ZN3JSC18FunctionExecutable14fromGlobalCodeERKNS_10IdentifierEPNS_9ExecStateEPNS_8DebuggerERKNS_10SourceCodeEPiPNS_7UStringE
-__ZNK3JSC21UStringSourceProvider4dataEv
-__ZN3JSC16FunctionBodyNode6createEPNS_12JSGlobalDataE
-__ZN3JSC5Lexer10sourceCodeEiii
-__ZN3JSC16FunctionBodyNode13finishParsingERKNS_10SourceCodeEPNS_13ParameterNodeERKNS_10IdentifierE
-__ZN3WTF6VectorIN3JSC10IdentifierELm0EE14expandCapacityEm
-__ZN3JSC16FunctionBodyNode13finishParsingEN3WTF10PassRefPtrINS_18FunctionParametersEEERKNS_10IdentifierE
-__ZNK3JSC9ScopeNode15singleStatementEv
-__ZNK3JSC17ExprStatementNode15isExprStatementEv
-__ZNK3JSC12FuncExprNode14isFuncExprNodeEv
-__ZThn16_N3JSC11ProgramNodeD0Ev
-__ZN3JSC11ProgramNodeD0Ev
-__ZN3JSC11ParserArenaD1Ev
-__ZN3JSC14SourceElementsD1Ev
-__ZThn16_N3JSC16FunctionBodyNodeD0Ev
-__ZN3JSC16FunctionBodyNodeD0Ev
-__ZN3JSC18FunctionExecutable7compileEPNS_9ExecStateEPNS_14ScopeChainNodeE
-__ZN3JSC6Parser5parseINS_16FunctionBodyNodeEEEN3WTF10PassRefPtrIT_EEPNS_12JSGlobalDataEPNS_8DebuggerEPNS_9ExecStateERKNS_10Sour
-__ZL11makeSubNodePN3JSC12JSGlobalDataEPNS_14ExpressionNodeES3_b
-__ZN3JSC14ExpressionNode14stripUnaryPlusEv
-__ZNK3JSC14ExpressionNode8isNumberEv
-__ZN3JSC16FunctionBodyNode6createEPNS_12JSGlobalDataEPNS_14SourceElementsEPN3WTF6VectorISt4pairIPKNS_10IdentifierEjELm0EEEPNS6_
-__ZN3JSC17BytecodeGeneratorC1EPNS_16FunctionBodyNodeEPKNS_8DebuggerERKNS_10ScopeChainEPN3WTF7HashMapINS9_6RefPtrIN7WebCore10Str
-__ZN3JSC17BytecodeGeneratorC2EPNS_16FunctionBodyNodeEPKNS_8DebuggerERKNS_10ScopeChainEPN3WTF7HashMapINS9_6RefPtrIN7WebCore10Str
-__ZN3JSC17BytecodeGenerator12addParameterERKNS_10IdentifierE
-__ZN3JSC16FunctionBodyNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC9BlockNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC10ReturnNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC12BinaryOpNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZNK3JSC11ResolveNode6isPureERNS_17BytecodeGeneratorE
-__ZN3JSC17BytecodeGenerator7isLocalERKNS_10IdentifierE
-__ZN3JSC17BytecodeGenerator12emitBinaryOpENS_8OpcodeIDEPNS_10RegisterIDES3_S3_NS_12OperandTypesE
-__ZN3JSC17BytecodeGenerator10emitReturnEPNS_10RegisterIDE
-__ZNK3JSC9BlockNode7isBlockEv
-__ZNK3JSC10ReturnNode12isReturnNodeEv
__ZN3JSC9CodeBlock11shrinkToFitEv
__ZN3WTF6VectorIN3JSC11InstructionELm0EE14shrinkCapacityEm
-__ZN3WTF6VectorIPN3JSC12CallLinkInfoELm0EE14shrinkCapacityEm
+__ZN3WTF6VectorIN3JSC17StructureStubInfoELm0EE14shrinkCapacityEm
__ZN3WTF6VectorIN3JSC10IdentifierELm0EE14shrinkCapacityEm
-__ZN3JSC17BytecodeGeneratorD2Ev
-__ZN3WTF6VectorIN3JSC11InstructionELm0EEaSERKS3_
-__ZN3JSC18FunctionExecutableD0Ev
-__ZN3JSC17FunctionCodeBlockD0Ev
-__ZN3JSC9CodeBlockD2Ev
-__ZN3JSC21UStringSourceProviderD0Ev
-__ZNK3JSC8JSObject8toObjectEPNS_9ExecStateE
-__ZN3JSC11Interpreter7executeEPNS_17ProgramExecutableEPNS_9ExecStateEPNS_14ScopeChainNodeEPNS_8JSObjectEPNS_7JSValueE
-__ZN3JSC12JSGlobalData14resetDateCacheEv
-__ZN3JSC12RegisterFile12globalObjectEv
-__ZN3JSC14JSGlobalObject13copyGlobalsToERNS_12RegisterFileE
-__ZN3JSC12RegisterFile15setGlobalObjectEPNS_14JSGlobalObjectE
-__ZN3JSC17ProgramExecutable15generateJITCodeEPNS_9ExecStateEPNS_14ScopeChainNodeE
-__ZN3JSC3JIT14privateCompileEv
+__ZN3WTF6VectorIN3JSC12WriteBarrierINS1_18FunctionExecutableEEELm0EE14shrinkCapacityEm
+__ZN3WTF6VectorIN3JSC12WriteBarrierINS1_7UnknownEEELm0EE14shrinkCapacityEm
+__ZN3WTF6VectorIN3JSC11HandlerInfoELm0EE14shrinkCapacityEm
+__ZN3WTF6VectorIN3JSC15SimpleJumpTableELm0EE14shrinkCapacityEm
+__ZN3WTF6VectorIN3JSC15StringJumpTableELm0EE14shrinkCapacityEm
+__ZN3WTF6VectorIN3JSC8LineInfoELm0EE14shrinkCapacityEm
+__ZN3JSC15ParserArenaDataIN3WTF6VectorISt4pairIPKNS_10IdentifierEjELm0EEEED1Ev
+__ZN3JSC15ParserArenaDataIN3WTF6VectorIPNS_16FunctionBodyNodeELm0EEEED1Ev
+__ZN3JSC14SourceElementsD1Ev
+__ZThn16_N3JSC16FunctionBodyNodeD0Ev
+__ZN3JSC16FunctionBodyNodeD0Ev
+__ZN3JSC3JIT14privateCompileEPNS_21MacroAssemblerCodePtrE
__ZN3JSC3JIT22privateCompileMainPassEv
__ZN3JSC3JIT13emit_op_enterEPNS_11InstructionE
__ZN3JSC3JIT11emit_op_movEPNS_11InstructionE
-__ZN3JSC3JIT22emit_op_resolve_globalEPNS_11InstructionEb
-__ZN3JSC23MacroAssemblerX86Common4moveENS_12X86Registers10RegisterIDES2_
-__ZN3WTF6VectorIN3JSC13SlowCaseEntryELm0EE14expandCapacityEmPKS2_
-__ZN3WTF6VectorIN3JSC13SlowCaseEntryELm0EE14expandCapacityEm
-__ZN3JSC3JIT17emit_op_get_by_idEPNS_11InstructionE
-__ZN3JSC3JIT21compileGetByIdHotPathEiiPNS_10IdentifierEj
-__ZN3JSC3JIT17emit_op_constructEPNS_11InstructionE
-__ZN3JSC3JIT13compileOpCallENS_8OpcodeIDEPNS_11InstructionEj
-__ZN3JSC11JITStubCall4callEv
-__ZN3WTF6VectorIN3JSC10CallRecordELm0EE14expandCapacityEm
-__ZN3JSC3JIT24emit_op_construct_verifyEPNS_11InstructionE
-__ZN3JSC3JIT20emit_op_method_checkEPNS_11InstructionE
-__ZN3WTF6VectorIN3JSC25MethodCallCompilationInfoELm0EE14expandCapacityEm
+__ZN3JSC3JIT18emit_op_new_regexpEPNS_11InstructionE
+__ZN3JSC11JITStubCall4callEj
+__ZN3WTF6VectorIN3JSC10CallRecordELm0EE15reserveCapacityEm
__ZN3JSC3JIT12emit_op_callEPNS_11InstructionE
-__ZN3JSC3JIT17emit_op_put_by_idEPNS_11InstructionE
+__ZN3JSC3JIT13compileOpCallENS_8OpcodeIDEPNS_11InstructionEj
+__ZN3WTF6VectorIN3JSC13SlowCaseEntryELm0EE14expandCapacityEm
+__ZN3JSC3JIT23emit_op_call_put_resultEPNS_11InstructionE
+__ZN3JSC3JIT17emit_op_new_arrayEPNS_11InstructionE
__ZN3JSC3JIT11emit_op_endEPNS_11InstructionE
-__ZN3WTF6VectorIN3JSC9JumpTableELm0EE14shrinkCapacityEm
+__ZN3JSC3JIT22privateCompileLinkPassEv
__ZN3JSC3JIT23privateCompileSlowCasesEv
-__ZN3JSC3JIT26emitSlow_op_resolve_globalEPNS_11InstructionERPNS_13SlowCaseEntryE
-__ZN3JSC20MacroAssemblerX86_648storePtrENS_22AbstractMacroAssemblerINS_12X86AssemblerEE6ImmPtrENS3_15ImplicitAddressE
-__ZN3JSC11JITStubCall4callEj
-__ZN3JSC3JIT21emitSlow_op_get_by_idEPNS_11InstructionERPNS_13SlowCaseEntryE
-__ZN3JSC3JIT22compileGetByIdSlowCaseEiiPNS_10IdentifierERPNS_13SlowCaseEntryEb
-__ZN3JSC3JIT21emitSlow_op_constructEPNS_11InstructionERPNS_13SlowCaseEntryE
-__ZN3JSC3JIT21compileOpCallSlowCaseEPNS_11InstructionERPNS_13SlowCaseEntryEjNS_8OpcodeIDE
-__ZN3JSC3JIT27compileOpConstructSetupArgsEPNS_11InstructionE
-__ZN3JSC3JIT28emitSlow_op_construct_verifyEPNS_11InstructionERPNS_13SlowCaseEntryE
-__ZN3JSC3JIT24emitSlow_op_method_checkEPNS_11InstructionERPNS_13SlowCaseEntryE
__ZN3JSC3JIT16emitSlow_op_callEPNS_11InstructionERPNS_13SlowCaseEntryE
-__ZN3JSC3JIT22compileOpCallSetupArgsEPNS_11InstructionE
-__ZN3JSC3JIT21emitSlow_op_put_by_idEPNS_11InstructionERPNS_13SlowCaseEntryE
-__ZN3WTF6VectorIN3JSC18MethodCallLinkInfoELm0EE14expandCapacityEm
+__ZN3JSC3JIT21compileOpCallSlowCaseEPNS_11InstructionERPNS_13SlowCaseEntryEjNS_8OpcodeIDE
+__ZN3WTF6VectorIN3JSC18MethodCallLinkInfoELm0EE4growEm
__ZN3JSC17BytecodeGenerator18dumpsGeneratedCodeEv
+__ZN3JSC4Heap29reportExtraMemoryCostSlowCaseEm
+__ZN3JSC17BytecodeGeneratorD2Ev
+__ZThn16_N3JSC11ProgramNodeD0Ev
+__ZN3JSC11ProgramNodeD0Ev
+__ZN3JSC12RegisterFile12globalObjectEv
+__ZN3JSC14JSGlobalObject13copyGlobalsToERNS_12RegisterFileE
+__ZN3JSC12RegisterFile15setGlobalObjectEPNS_14JSGlobalObjectE
_ctiTrampoline
-_cti_op_resolve_global
-_cti_op_get_by_id
-__ZNK3JSC7JSValue3getEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
-_cti_op_construct_NotJSConstruct
-__ZN3JSC15DateConstructor16getConstructDataERNS_13ConstructDataE
-__ZN3JSCL28constructWithDateConstructorEPNS_9ExecStateEPNS_8JSObjectERKNS_7ArgListE
-__ZN3JSC13constructDateEPNS_9ExecStateERKNS_7ArgListE
-__ZN3JSC12DateInstanceC1EPNS_9ExecStateEd
-__ZN3JSC12DateInstanceC2EPNS_9ExecStateEd
-__ZN3WTF8timeClipEd
+_cti_op_new_regexp
+__ZN3JSC12RegExpObjectC1EPNS_14JSGlobalObjectEPNS_9StructureEN3WTF17NonNullPassRefPtrINS_6RegExpEEE
+_cti_vm_lazyLinkCall
+__ZN3JSC18FunctionExecutable22compileForCallInternalEPNS_9ExecStateEPNS_14ScopeChainNodeE
+__ZN3JSC6Parser5parseINS_16FunctionBodyNodeEEEN3WTF10PassRefPtrIT_EEPNS_14JSGlobalObjectEPNS_8DebuggerEPNS_9ExecStateERKNS_10SourceCodeEPNS_18FunctionParametersENS_18JSParserStrictnessEPPNS_8JSObjectE
+__ZN3JSC8JSParser19parseSourceElementsILNS0_18SourceElementsModeE1ENS_10ASTBuilderEEENT0_14SourceElementsERS4_
+__ZN3JSC8JSParser20parseReturnStatementINS_10ASTBuilderEEENT_9StatementERS3_
+__ZN3JSC8JSParser15parseExpressionINS_10ASTBuilderEEENT_10ExpressionERS3_
+__ZNK3JSC15DotAccessorNode10isLocationEv
+__ZNK3JSC14ExpressionNode13isResolveNodeEv
+__ZNK3JSC14ExpressionNode21isBracketAccessorNodeEv
+__ZN3JSC16FunctionBodyNode6createEPNS_12JSGlobalDataEPNS_14SourceElementsEPN3WTF6VectorISt4pairIPKNS_10IdentifierEjELm0EEEPNS6_IPS0_Lm0EEERNS5_7HashSetINS5_6RefPtrINS5_10StringImplEEENS_17IdentifierRepHashENS5_10HashTraitsISK_EEEERKNS_10SourceCodeEji
+__ZN3JSC17BytecodeGeneratorC1EPNS_16FunctionBodyNodeEPNS_14ScopeChainNodeEPN3WTF7HashMapINS5_6RefPtrINS5_10StringImplEEENS_16SymbolTableEntryENS_17IdentifierRepHashENS5_10HashTraitsIS9_EENS_26SymbolTableIndexHashTraitsEEEPNS_9CodeBlockE
+__ZN3JSC17BytecodeGeneratorC2EPNS_16FunctionBodyNodeEPNS_14ScopeChainNodeEPN3WTF7HashMapINS5_6RefPtrINS5_10StringImplEEENS_16SymbolTableEntryENS_17IdentifierRepHashENS5_10HashTraitsIS9_EENS_26SymbolTableIndexHashTraitsEEEPNS_9CodeBlockE
+__ZN3WTF15SegmentedVectorIN3JSC10RegisterIDELm32EEC1Ev
+__ZN3WTF6VectorIN3JSC11InstructionELm0EE14expandCapacityEm
+__ZN3JSC17BytecodeGenerator12addParameterERKNS_10IdentifierEi
+__ZN3JSC16FunctionBodyNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC9BlockNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC10ReturnNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC19FunctionCallDotNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC17BytecodeGenerator11emitResolveEPNS_10RegisterIDERKNS_10IdentifierE
+__ZN3JSC17BytecodeGenerator18findScopedPropertyERKNS_10IdentifierERiRmbRbRPNS_8JSObjectE
+__ZNK3JSC16JSVariableObject16isVariableObjectEv
+__ZN3JSC17BytecodeGenerator16emitGetScopedVarEPNS_10RegisterIDEmiNS_7JSValueE
+__ZN3JSC17BytecodeGenerator15emitMethodCheckEv
+__ZN3JSC17BytecodeGenerator11emitGetByIdEPNS_10RegisterIDES2_RKNS_10IdentifierE
+__ZN3WTF6VectorIN3JSC17StructureStubInfoELm0EE14expandCapacityEm
+__ZN3JSC17BytecodeGenerator11addConstantERKNS_10IdentifierE
+__ZN3WTF6VectorIN3JSC10IdentifierELm0EE14expandCapacityEmPKS2_
+__ZN3WTF6VectorIN3JSC10IdentifierELm0EE15reserveCapacityEm
+__ZN3JSC17BytecodeGenerator10emitReturnEPNS_10RegisterIDE
+__ZNK3JSC9ScopeNode15singleStatementEv
+__ZNK3JSC9BlockNode7isBlockEv
+__ZNK3JSC10ReturnNode12isReturnNodeEv
+__ZNK3JSC14SourceElements15singleStatementEv
+__ZNK3JSC14ExpressionNode10isSubtractEv
+__ZN3JSC3JIT22emit_op_get_global_varEPNS_11InstructionE
+__ZN3JSC3JIT20emit_op_method_checkEPNS_11InstructionE
+__ZN3WTF6VectorIN3JSC25MethodCallCompilationInfoELm0EE14expandCapacityEm
+__ZN3JSC3JIT21compileGetByIdHotPathEiiPNS_10IdentifierEj
+__ZN3WTF6VectorIN3JSC13SlowCaseEntryELm0EE14expandCapacityEmPKS2_
+__ZN3WTF6VectorIN3JSC10CallRecordELm0EE14expandCapacityEmPKS2_
+__ZN3JSC3JIT11emit_op_retEPNS_11InstructionE
+__ZN3JSC3JIT24emitSlow_op_method_checkEPNS_11InstructionERPNS_13SlowCaseEntryE
+__ZN3JSC3JIT22compileGetByIdSlowCaseEiiPNS_10IdentifierERPNS_13SlowCaseEntryEb
+__ZN3JSC11JITStubCall4callEv
+_cti_register_file_check
_cti_op_get_by_id_method_check
-__ZN3JSC13DatePrototype18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
+__ZNK3JSC7JSValue3getEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
__ZN3JSC23setUpStaticFunctionSlotEPNS_9ExecStateEPKNS_9HashEntryEPNS_8JSObjectERKNS_10IdentifierERNS_12PropertySlotE
-__ZN3JSC9Structure13hasTransitionEPN7WebCore10StringImplEj
-_cti_vm_lazyLinkCall
-__ZN3JSCL20dateProtoFuncGetTimeEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZNK3JSC12DateInstance9classInfoEv
-_cti_op_put_by_id
-__ZN3JSC14JSGlobalObject3putEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueERNS_15PutPropertySlotE
-__ZN3JSC8JSObject3putEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueERNS_15PutPropertySlotE
-__ZN3JSC17ProgramExecutableD0Ev
-__ZN3JSC16ProgramCodeBlockD0Ev
-__ZN3WTF9HashTableIPN3JSC15GlobalCodeBlockES3_NS_17IdentityExtractorIS3_EENS_7PtrHashIS3_EENS_10HashTraitsIS3_EES9_E4findIS3_NS
+__ZNK3WTF12AtomicString5lowerEv
+__ZNK3JSC8JSObject24getPropertySpecificValueEPNS_9ExecStateERKNS_10IdentifierERPNS_6JSCellE
+__ZN3JSC27ctiPatchCallByReturnAddressEPNS_9CodeBlockENS_16ReturnAddressPtrENS_11FunctionPtrE
+__ZN3JSC3JIT8linkCallEPNS_10JSFunctionEPNS_9CodeBlockES4_NS_21MacroAssemblerCodePtrEPNS_12CallLinkInfoEiPNS_12JSGlobalDataE
+_cti_op_get_by_id
+_cti_op_new_array
+__ZN3JSC7JSArrayC1ERNS_12JSGlobalDataEPNS_9StructureERKNS_7ArgListE
+__ZN3JSC18FunctionExecutable11discardCodeEv
+__ZN3JSC17FunctionCodeBlockD0Ev
+__ZN3JSC9CodeBlockD2Ev
__ZN3JSC17StructureStubInfo5derefEv
-__ZN7WebCore6String8truncateEj
-__ZN3JSC5Lexer10skipRegExpEv
-__ZNK3JSC14ExpressionNode10isLocationEv
-__ZN3WTF6VectorIPN3JSC16FunctionBodyNodeELm0EE14expandCapacityEm
-__ZNK3JSC18EmptyStatementNode16isEmptyStatementEv
-__ZN3WTF6VectorISt4pairIPKN3JSC10IdentifierEjELm0EE14expandCapacityEm
-__ZN3JSC8JSObject12removeDirectERKNS_10IdentifierE
-__ZN3JSC9Structure24removePropertyTransitionEPS0_RKNS_10IdentifierERm
-__ZN3JSC9Structure6removeERKNS_10IdentifierE
-__ZN3JSC17BytecodeGenerator12addGlobalVarERKNS_10IdentifierEbRPNS_10RegisterIDE
-__ZN3JSC17BytecodeGenerator15emitNewFunctionEPNS_10RegisterIDEPNS_16FunctionBodyNodeE
-__ZN3WTF6VectorINS_6RefPtrIN3JSC18FunctionExecutableEEELm0EE14expandCapacityEm
-__ZN3JSC9Structure31removePropertyWithoutTransitionERKNS_10IdentifierE
-__ZNK3JSC8JSObject11hasPropertyEPNS_9ExecStateERKNS_10IdentifierE
-__ZNK3JSC7UString14toStrictUInt32EPb
-__ZN7WebCore12AtomicString4findEPKtjj
-__ZN3WTF9HashTableINS_6RefPtrIN7WebCore10StringImplEEESt4pairIS4_N3JSC16SymbolTableEntryEENS_18PairFirstExtractorIS8_EENS6_17Id
-__ZN3JSCL30comparePropertyMapEntryIndicesEPKvS1_
+__ZN3JSC8JSObject13visitChildrenERNS_9MarkStackE
+__ZN3JSC14JSGlobalObject13visitChildrenERNS_9MarkStackE
+__ZN3JSC9MarkStack14MarkStackArrayIPNS_6JSCellEE6appendERKS3_
+__ZN3JSC10JSFunction13visitChildrenERNS_9MarkStackE
+__ZN3JSC12RegExpObject13visitChildrenERNS_9MarkStackE
+__ZN3JSC15JSWrapperObject13visitChildrenERNS_9MarkStackE
+__ZN3JSC7JSArray13visitChildrenERNS_9MarkStackE
+__ZN3JSC22NativeErrorConstructor13visitChildrenERNS_9MarkStackE
+__ZN3JSC14ScopeChainNode13visitChildrenERNS_9MarkStackE
+__ZN3JSC16JSCallbackObjectINS_24JSObjectWithGlobalObjectEE13visitChildrenERNS_9MarkStackE
+__ZN3JSC18FunctionExecutable13visitChildrenERNS_9MarkStackE
+__ZN3JSC17ProgramExecutableD1Ev
+__ZN3JSC16ProgramCodeBlockD0Ev
+__ZN3JSC8JSParser31parseExpressionOrLabelStatementINS_10ASTBuilderEEENT_9StatementERS3_
+__ZN3JSC8JSParser17parseFunctionInfoILNS0_20FunctionRequirementsE0ELb0ENS_10ASTBuilderEEEbRT1_RPKNS_10IdentifierERNS4_19FormalParameterListERNS4_12FunctionBodyERiSE_SE_
+__ZN3JSC10ASTBuilder14makeAssignNodeEPNS_14ExpressionNodeENS_8OperatorES2_bbiii
+__ZN3JSC8JSParser19parseBreakStatementINS_13SyntaxCheckerEEENT_9StatementERS3_
+__ZN3JSC17ExprStatementNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
__ZN3JSC13AssignDotNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
__ZNK3JSC14ExpressionNode6isPureERNS_17BytecodeGeneratorE
-__ZN3JSC17BytecodeGenerator8emitMoveEPNS_10RegisterIDES2_
-__ZN3JSC17ObjectLiteralNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC17BytecodeGenerator13emitNewObjectEPNS_10RegisterIDE
-__ZN3JSC21FunctionCallValueNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC15DotAccessorNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
__ZN3JSC12FuncExprNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
__ZN3JSC17BytecodeGenerator25emitNewFunctionExpressionEPNS_10RegisterIDEPNS_12FuncExprNodeE
-__ZN3JSC12FuncDeclNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC15DotAccessorNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC16VarStatementNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC17BytecodeGenerator15isLocalConstantERKNS_10IdentifierE
-__ZN3JSC16ArgumentListNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC11BooleanNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC17BytecodeGenerator8emitLoadEPNS_10RegisterIDEb
-__ZN3JSC9ArrayNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC17BytecodeGenerator12emitNewArrayEPNS_10RegisterIDEPNS_11ElementNodeE
-__ZN3JSC23FunctionCallResolveNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC17BytecodeGenerator19emitResolveWithBaseEPNS_10RegisterIDES2_RKNS_10IdentifierE
-__ZN3JSC10NumberNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC17BytecodeGenerator8emitLoadEPNS_10RegisterIDEd
-__ZN3WTF9HashTableIdSt4pairIdN3JSC7JSValueEENS_18PairFirstExtractorIS4_EENS_9FloatHashIdEENS_14PairHashTraitsINS_10HashTraitsId
-__ZN3JSC10StringNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC17BytecodeGenerator8emitLoadEPNS_10RegisterIDERKNS_10IdentifierE
-__ZN3WTF9HashTableIPN7WebCore10StringImplESt4pairIS3_PN3JSC8JSStringEENS_18PairFirstExtractorIS8_EENS5_17IdentifierRepHashENS_1
-__ZN3JSC12SmallStrings27createSingleCharacterStringEPNS_12JSGlobalDataEh
-__ZN3JSC8NullNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC15ParserArenaDataIN3WTF6VectorIPNS_16FunctionBodyNodeELm0EEEED1Ev
-__ZN3JSC15ParserArenaDataIN3WTF6VectorISt4pairIPKNS_10IdentifierEjELm0EEEED1Ev
-__ZN3JSC3JIT16emit_op_new_funcEPNS_11InstructionE
-__ZN3JSC3JIT18emit_op_new_objectEPNS_11InstructionE
+__ZN3JSC18FunctionExecutableC1EPNS_12JSGlobalDataERKNS_10IdentifierERKNS_10SourceCodeEbPNS_18FunctionParametersEbii
+__ZN3WTF6VectorIN3JSC12WriteBarrierINS1_18FunctionExecutableEEELm0EE14expandCapacityEm
+__ZN3JSC17BytecodeGenerator11emitPutByIdEPNS_10RegisterIDERKNS_10IdentifierES2_
+__ZN3JSC3JIT17emit_op_get_by_idEPNS_11InstructionE
__ZN3JSC3JIT20emit_op_new_func_expEPNS_11InstructionE
-__ZN3JSC3JIT17emit_op_new_arrayEPNS_11InstructionE
-__ZN3JSC3JIT25emit_op_resolve_with_baseEPNS_11InstructionE
-_cti_op_new_func
-__ZN3JSC10JSFunctionC1EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_18FunctionExecutableEEEPNS_14ScopeChainNodeE
-_cti_op_new_object
-_cti_op_new_func_exp
-_cti_op_call_JSFunction
-__ZN3JSC18FunctionExecutable15generateJITCodeEPNS_9ExecStateEPNS_14ScopeChainNodeE
-__ZN3WTF7HashSetINS_6RefPtrIN7WebCore10StringImplEEEN3JSC17IdentifierRepHashENS_10HashTraitsIS4_EEE3addERKS4_
-__ZN3WTF9HashTableINS_6RefPtrIN7WebCore10StringImplEEES4_NS_17IdentityExtractorIS4_EEN3JSC17IdentifierRepHashENS_10HashTraitsIS
-__ZN3JSC17BytecodeGenerator6addVarERKNS_10IdentifierEbRPNS_10RegisterIDE
-__ZNK3JSC16JSVariableObject16isVariableObjectEv
-__ZN3JSC17BytecodeGenerator16emitGetScopedVarEPNS_10RegisterIDEmiNS_7JSValueE
-__ZNK3JSC13StatementNode12isReturnNodeEv
-__ZN3JSC3JIT29emit_op_enter_with_activationEPNS_11InstructionE
-__ZN3JSC3JIT22emit_op_get_global_varEPNS_11InstructionE
-__ZN3JSC3JIT29emitGetVariableObjectRegisterENS_12X86Registers10RegisterIDEiS2_
-__ZN3JSC3JIT27emit_op_tear_off_activationEPNS_11InstructionE
-__ZN3JSC11JITStubCall11addArgumentEjNS_12X86Registers10RegisterIDE
-__ZN3JSC3JIT11emit_op_retEPNS_11InstructionE
-_cti_register_file_check
-_cti_op_push_activation
-__ZN3JSC12JSActivationC1EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_18FunctionExecutableEEE
-__ZN3JSC12JSActivationC2EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_18FunctionExecutableEEE
-_cti_op_tear_off_activation
-_cti_op_ret_scopeChain
+__ZN3JSC20MacroAssemblerX86_648storePtrENS_22AbstractMacroAssemblerINS_12X86AssemblerEE13TrustedImmPtrENS3_15ImplicitAddressE
+__ZN3JSC3JIT17emit_op_put_by_idEPNS_11InstructionE
+__ZN3JSC3JIT21emitSlow_op_get_by_idEPNS_11InstructionERPNS_13SlowCaseEntryE
+__ZN3JSC3JIT21emitSlow_op_put_by_idEPNS_11InstructionERPNS_13SlowCaseEntryE
__ZN3JSC10JSFunction18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
-__ZN3JSC9Structure18transitionTableAddERKSt4pairIN3WTF6RefPtrIN7WebCore10StringImplEEEjEPS0_PNS_6JSCellE
-__ZN3WTF7HashMapISt4pairINS_6RefPtrIN7WebCore10StringImplEEEjES1_IPN3JSC9StructureES9_ENS7_28StructureTransitionTableHashENS7_3
-__ZN3WTF9HashTableISt4pairINS_6RefPtrIN7WebCore10StringImplEEEjES1_IS6_S1_IPN3JSC9StructureES9_EENS_18PairFirstExtractorISB_EEN
-_cti_op_new_array
-__ZN3JSC7JSArrayC1EN3WTF17NonNullPassRefPtrINS_9StructureEEERKNS_7ArgListE
-_cti_op_construct_JSConstruct
-__ZNK3JSC10NumberNode6isPureERNS_17BytecodeGeneratorE
-__ZN3JSC8ThisNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC3JIT20emit_op_convert_thisEPNS_11InstructionE
-__ZN3JSC3JIT24emitSlow_op_convert_thisEPNS_11InstructionERPNS_13SlowCaseEntryE
-_cti_op_resolve_with_base
-__ZN3JSC10JSFunction11getCallDataERNS_8CallDataE
-__ZNK3JSC7ArgList8getSliceEiRS0_
-__ZN3JSC9Structure22materializePropertyMapEv
-_cti_op_end
-__ZNK7WebCore6String7toFloatEPb
-__ZN7WebCore10StringImpl7toFloatEPb
-__ZN7WebCore17charactersToFloatEPKtmPb
-__ZN7WebCoreeqERKNS_12AtomicStringEPKc
-__ZNK7WebCore6String5toIntEPb
-__ZN7WebCore10StringImpl5toIntEPb
-__ZN7WebCore15charactersToIntEPKtmPb
-__ZN7WebCore6String6numberEi
-__ZNK7WebCore6String11toIntStrictEPbi
-__ZN7WebCore10StringImpl11toIntStrictEPbi
-__ZN7WebCore21charactersToIntStrictEPKtmPbi
-__ZN7WebCore10StringImpl7replaceEPS0_S1_
-__ZN7WebCore6String6numberEt
-__ZL11makeDivNodePN3JSC12JSGlobalDataEPNS_14ExpressionNodeES3_b
-__ZNK3JSC10NumberNode8isNumberEv
+__ZN3JSC9Structure22materializePropertyMapERNS_12JSGlobalDataE
+__ZN3WTF9HashTableISt4pairINS_6RefPtrINS_10StringImplEEEjES1_IS5_PN3JSC7JSValueEENS_18PairFirstExtractorIS9_EENS6_24StructureTransitionTable4HashENS_14PairHashTraitsINSC_10HashTraitsENS_10HashTraitsIS8_EEEESF_E6rehashEi
+_cti_op_new_func_exp
+_cti_op_put_by_id
+__ZN3JSC8JSParser20parseSwitchStatementINS_13SyntaxCheckerEEENT_9StatementERS3_
+__ZN3JSC8JSParser18parseSwitchClausesINS_13SyntaxCheckerEEENT_10ClauseListERS3_
__ZN3WTF6VectorIPvLm0EE14expandCapacityEm
-__ZN3WTF6VectorIjLm16EE6resizeEm
-__ZN3WTFL7multaddERNS_6BigIntEii
-__ZN3WTF6VectorIjLm16EEaSERKS1_
-__ZN3WTFL4multERNS_6BigIntERKS0_
-__ZL11makeAddNodePN3JSC12JSGlobalDataEPNS_14ExpressionNodeES3_b
-__ZN3WTF6VectorIPNS0_IN3JSC10IdentifierELm64EEELm32EE15reserveCapacityEm
-__ZL14makePrefixNodePN3JSC12JSGlobalDataEPNS_14ExpressionNodeENS_8OperatorEiii
-__ZN3WTF6VectorIPN3JSC10RegisterIDELm32EE15reserveCapacityEm
+__ZN3JSC8JSParser17parseForStatementINS_10ASTBuilderEEENT_9StatementERS3_
+__ZN3JSC8JSParser19parseVarDeclarationINS_10ASTBuilderEEENT_9StatementERS3_
+__ZN3JSC8JSParser21parseDoWhileStatementINS_10ASTBuilderEEENT_9StatementERS3_
+__ZNK3JSC19BracketAccessorNode10isLocationEv
+__ZNK3JSC19BracketAccessorNode21isBracketAccessorNodeEv
+__ZN3JSC10ASTBuilder14makeBinaryNodeEiSt4pairIPNS_14ExpressionNodeENS0_12BinaryOpInfoEES5_
+__ZN3JSC17ObjectLiteralNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
__ZN3JSC16PropertyListNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC15ConditionalNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC17BytecodeGenerator13emitNewObjectEPNS_10RegisterIDE
+__ZN3JSC17BytecodeGenerator17emitDirectPutByIdEPNS_10RegisterIDERKNS_10IdentifierES2_
+__ZN3WTF9HashTableINS_6RefPtrINS_10StringImplEEESt4pairIS3_iENS_18PairFirstExtractorIS5_EEN3JSC17IdentifierRepHashENS_14PairHashTraitsINS_10HashTraitsIS3_EENS8_17BytecodeGenerator28IdentifierMapIndexHashTraitsEEESC_E4findIS3_NS_22IdentityHashTranslatorIS3_S5_S9_EEEENS_17HashTableIteratorIS3_S5_S7_S9_SF_SC_EERKT_
+__ZN3WTF9HashTableINS_6RefPtrINS_10StringImplEEESt4pairIS3_iENS_18PairFirstExtractorIS5_EEN3JSC17IdentifierRepHashENS_14PairHashTraitsINS_10HashTraitsIS3_EENS8_17BytecodeGenerator28IdentifierMapIndexHashTraitsEEESC_E6rehashEi
+__ZN3JSC9ForInNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC17BytecodeGenerator13newLabelScopeENS_10LabelScope4TypeEPKNS_10IdentifierE
__ZN3JSC17BytecodeGenerator8newLabelEv
-__ZNK3JSC14ExpressionNode26hasConditionContextCodegenEv
-__ZN3JSC17BytecodeGenerator15emitJumpIfFalseEPNS_10RegisterIDEPNS_5LabelE
+__ZN3JSC17BytecodeGenerator20emitGetPropertyNamesEPNS_10RegisterIDES2_S2_S2_PNS_5LabelE
__ZN3JSC17BytecodeGenerator8emitJumpEPNS_5LabelE
__ZN3JSC17BytecodeGenerator9emitLabelEPNS_5LabelE
-__ZN3WTF6VectorIjLm0EE14expandCapacityEm
-__ZN3JSC17BytecodeGenerator14emitPutByIndexEPNS_10RegisterIDEjS2_
-__ZN3JSC6IfNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZNK3JSC14LogicalNotNode26hasConditionContextCodegenEv
-__ZN3JSC11UnaryOpNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC17BytecodeGenerator11emitUnaryOpENS_8OpcodeIDEPNS_10RegisterIDES3_
-__ZNK3JSC10StringNode6isPureERNS_17BytecodeGeneratorE
-__ZNK3JSC14ExpressionNode5isAddEv
-__ZN3JSC7ForNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC17BytecodeGenerator13newLabelScopeENS_10LabelScope4TypeEPKNS_10IdentifierE
+__ZN3WTF6VectorIjLm0EE15reserveCapacityEm
+__ZN3WTF6VectorIN3JSC12ForInContextELm0EE14expandCapacityEm
+__ZN3JSC16VarStatementNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC17AssignResolveNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC17BytecodeGenerator15isLocalConstantERKNS_10IdentifierE
+__ZN3WTF6VectorIN3JSC17GlobalResolveInfoELm0EE14expandCapacityEm
+__ZN3JSC11DoWhileNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC17AssignBracketNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZNK3JSC11ResolveNode6isPureERNS_17BytecodeGeneratorE
+__ZN3JSC17BytecodeGenerator7isLocalERKNS_10IdentifierE
+__ZN3JSC8ThisNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
__ZN3JSC19BracketAccessorNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC17BytecodeGenerator22willResolveToArgumentsERKNS_10IdentifierE
__ZN3JSC17BytecodeGenerator12emitGetByValEPNS_10RegisterIDES2_S2_
-__ZN3JSC17PrefixResolveNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC17BytecodeGenerator10emitPreIncEPNS_10RegisterIDE
+__ZN3JSC17BytecodeGenerator12emitPutByValEPNS_10RegisterIDES2_S2_
+__ZNK3JSC14ExpressionNode26hasConditionContextCodegenEv
+__ZN3JSC15StrictEqualNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC17BytecodeGenerator14emitEqualityOpENS_8OpcodeIDEPNS_10RegisterIDES3_S3_
__ZN3JSC17BytecodeGenerator14emitJumpIfTrueEPNS_10RegisterIDEPNS_5LabelE
-__ZN3JSC3JIT11emit_op_divEPNS_11InstructionE
-__ZN3JSC20MacroAssemblerX86_649branchPtrENS_23MacroAssemblerX86Common9ConditionENS_12X86Registers10RegisterIDES4_
-__ZN3JSC12X86Assembler11cvtsi2sd_rrENS_12X86Registers10RegisterIDENS1_13XMMRegisterIDE
-__ZN3JSC12X86Assembler23X86InstructionFormatter9twoByteOpENS0_15TwoByteOpcodeIDEiNS_12X86Registers10RegisterIDE
-__ZN3JSC12X86Assembler7movq_rrENS_12X86Registers10RegisterIDENS1_13XMMRegisterIDE
-__ZN3JSC23MacroAssemblerX86Common4moveENS_22AbstractMacroAssemblerINS_12X86AssemblerEE5Imm32ENS_12X86Registers10RegisterIDE
-__ZN3JSC15AssemblerBuffer7putByteEi
-__ZN3JSC3JIT14emit_op_jfalseEPNS_11InstructionE
-__ZN3JSC20MacroAssemblerX86_649branchPtrENS_23MacroAssemblerX86Common9ConditionENS_12X86Registers10RegisterIDENS_22AbstractMacr
+__ZN3JSC17BytecodeGenerator20emitNextPropertyNameEPNS_10RegisterIDES2_S2_S2_S2_PNS_5LabelE
+__ZN3JSC3JIT18emit_op_new_objectEPNS_11InstructionE
+__ZN3JSC3JIT18emit_op_get_pnamesEPNS_11InstructionE
__ZN3WTF6VectorIN3JSC9JumpTableELm0EE14expandCapacityEmPKS2_
__ZN3WTF6VectorIN3JSC9JumpTableELm0EE14expandCapacityEm
__ZN3JSC3JIT11emit_op_jmpEPNS_11InstructionE
-__ZN3JSC3JIT20emit_op_put_by_indexEPNS_11InstructionE
-__ZN3JSC3JIT13emit_op_jtrueEPNS_11InstructionE
-__ZN3JSC3JIT11emit_op_addEPNS_11InstructionE
-__ZN3JSC3JIT18emit_op_get_by_valEPNS_11InstructionE
-__ZN3JSC20MacroAssemblerX86_649branchPtrENS_23MacroAssemblerX86Common9ConditionENS_22AbstractMacroAssemblerINS_12X86AssemblerEE
-__ZN3JSC12X86Assembler23X86InstructionFormatter11oneByteOp64ENS0_15OneByteOpcodeIDEiNS_12X86Registers10RegisterIDES4_ii
-__ZN3JSC3JIT15emit_op_pre_incEPNS_11InstructionE
+__ZN3JSC3JIT22emit_op_resolve_globalEPNS_11InstructionEb
+__ZN3JSC3JIT20emit_op_get_by_pnameEPNS_11InstructionE
+__ZN3JSC12X86Assembler23X86InstructionFormatter11oneByteOp64ENS0_15OneByteOpcodeIDEiNS_12X86Registers10RegisterIDES4_ii
+__ZN3JSC3JIT18emit_op_get_by_valEPNS_11InstructionE
+__ZN3JSC20MacroAssemblerX86_649branchPtrENS_23MacroAssemblerX86Common19RelationalConditionENS_22AbstractMacroAssemblerINS_12X86AssemblerEE7AddressENS5_13TrustedImmPtrE
+__ZN3JSC3JIT18emit_op_put_by_valEPNS_11InstructionE
+__ZN3JSC3JIT16emit_op_stricteqEPNS_11InstructionE
+__ZN3JSC3JIT17compileOpStrictEqEPNS_11InstructionENS0_21CompileOpStrictEqTypeE
+__ZN3JSC12X86Assembler6orl_irEiNS_12X86Registers10RegisterIDE
__ZN3JSC3JIT16emitTimeoutCheckEv
-__ZN3JSC3JIT13emit_op_jlessEPNS_11InstructionE
-__ZN3JSC3JIT15emitSlow_op_divEPNS_11InstructionERPNS_13SlowCaseEntryE
-__ZN3JSC3JIT18emitSlow_op_jfalseEPNS_11InstructionERPNS_13SlowCaseEntryE
-__ZN3JSC23MacroAssemblerX86Common12branchTest32ENS0_9ConditionENS_12X86Registers10RegisterIDENS_22AbstractMacroAssemblerINS_12X
-__ZN3JSC3JIT17emitSlow_op_jtrueEPNS_11InstructionERPNS_13SlowCaseEntryE
+__ZN3JSC3JIT13emit_op_jtrueEPNS_11InstructionE
+__ZN3JSC20MacroAssemblerX86_649branchPtrENS_23MacroAssemblerX86Common19RelationalConditionENS_12X86Registers10RegisterIDES4_
+__ZN3JSC3JIT18emit_op_next_pnameEPNS_11InstructionE
+__ZN3JSC20MacroAssemblerX86_6413branchTestPtrENS_23MacroAssemblerX86Common15ResultConditionENS_22AbstractMacroAssemblerINS_12X86AssemblerEE7AddressENS5_12TrustedImm32E
+__ZN3JSC23MacroAssemblerX86Common12branchTest32ENS0_15ResultConditionENS_12X86Registers10RegisterIDENS_22AbstractMacroAssemblerINS_12X86AssemblerEE12TrustedImm32E
+__ZN3JSC3JIT26emitSlow_op_resolve_globalEPNS_11InstructionERPNS_13SlowCaseEntryE
+__ZN3JSC3JIT24emitSlow_op_get_by_pnameEPNS_11InstructionERPNS_13SlowCaseEntryE
+__ZN3JSC11JITStubCall11addArgumentEjNS_12X86Registers10RegisterIDE
__ZN3JSC3JIT22emitSlow_op_get_by_valEPNS_11InstructionERPNS_13SlowCaseEntryE
+__ZN3JSC9JITThunks7ctiStubEPNS_12JSGlobalDataEPFNS_21MacroAssemblerCodePtrES2_PNS_14ExecutablePoolEE
+__ZN3WTF9HashTableIPFN3JSC21MacroAssemblerCodePtrEPNS1_12JSGlobalDataEPNS1_14ExecutablePoolEESt4pairIS8_S2_ENS_18PairFirstExtractorISA_EENS_7PtrHashIS8_EENS_14PairHashTraitsINS_10HashTraitsIS8_EENSG_IS2_EEEESH_E6expandEv
__ZN3JSC3JIT27stringGetByValStubGeneratorEPNS_12JSGlobalDataEPNS_14ExecutablePoolE
-__ZN3JSC15AssemblerBuffer14executableCopyEPNS_14ExecutablePoolE
-__ZN3JSC3JIT19emitSlow_op_pre_incEPNS_11InstructionERPNS_13SlowCaseEntryE
-__ZN3JSC11JITStubCall11addArgumentENS_12X86Registers10RegisterIDE
-__ZN3JSC3JIT17emitSlow_op_jlessEPNS_11InstructionERPNS_13SlowCaseEntryE
-__ZN3JSC23MacroAssemblerX86Common12branchDoubleENS0_15DoubleConditionENS_12X86Registers13XMMRegisterIDES3_
-__ZNK3JSC13LogicalOpNode26hasConditionContextCodegenEv
-__ZN3JSC13LogicalOpNode30emitBytecodeInConditionContextERNS_17BytecodeGeneratorEPNS_5LabelES4_b
-__ZN3JSC21ReadModifyResolveNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC3JIT11emit_op_subEPNS_11InstructionE
-__ZN3JSC3JIT20compileBinaryArithOpENS_8OpcodeIDEjjjNS_12OperandTypesE
-__ZN3JSC3JIT15emitSlow_op_subEPNS_11InstructionERPNS_13SlowCaseEntryE
-__ZN3JSC3JIT28compileBinaryArithOpSlowCaseENS_8OpcodeIDERPNS_13SlowCaseEntryEjjjNS_12OperandTypesEbb
-__ZN3JSC3JIT15emitSlow_op_addEPNS_11InstructionERPNS_13SlowCaseEntryE
-__ZNK3JSC14JSGlobalObject14isDynamicScopeERb
-_cti_op_jtrue
-__ZNK3JSC8JSObject9toBooleanEPNS_9ExecStateE
-__ZNK3JSC8JSObject24getPropertySpecificValueEPNS_9ExecStateERKNS_10IdentifierERPNS_6JSCellE
-__ZN3JSC27ctiPatchCallByReturnAddressEPNS_9CodeBlockENS_16ReturnAddressPtrENS_11FunctionPtrE
-__ZN3JSC3JIT8linkCallEPNS_10JSFunctionEPNS_9CodeBlockES4_RNS_7JITCodeEPNS_12CallLinkInfoEiPNS_12JSGlobalDataE
-_cti_op_add
-__ZN3JSC13jsAddSlowCaseEPNS_9ExecStateENS_7JSValueES2_
-__ZNK3JSC8JSString11toPrimitiveEPNS_9ExecStateENS_22PreferredPrimitiveTypeE
-__ZNK3JSC7JSValue8toStringEPNS_9ExecStateE
-__ZN3JSC7UString4fromEi
-__ZNK3JSC8JSString11resolveRopeEPNS_9ExecStateE
-__ZN3WTF13tryFastMallocEm
-__ZN7WebCore10StringImpl4findEPKcib
-__ZN3JSC13LogicalOpNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZNK3JSC14ExpressionNode6isNullEv
-__ZN3JSC3JIT11emit_op_neqEPNS_11InstructionE
-__ZN3JSC12X86Assembler8shll_i8rEiNS_12X86Registers10RegisterIDE
-__ZN3JSC12X86Assembler6orl_irEiNS_12X86Registers10RegisterIDE
-__ZN3JSC3JIT15emitSlow_op_neqEPNS_11InstructionERPNS_13SlowCaseEntryE
-_cti_op_call_arityCheck
-_cti_op_eq
-__ZN3JSC9JITThunks15tryCacheGetByIDEPNS_9ExecStateEPNS_9CodeBlockENS_16ReturnAddressPtrENS_7JSValueERKNS_10IdentifierERKNS_12Pr
-__ZN3JSC14StructureChainC1EPNS_9StructureE
-__ZN3JSC14StructureChainC2EPNS_9StructureE
-__ZN3JSC3JIT26privateCompileGetByIdChainEPNS_17StructureStubInfoEPNS_9StructureEPNS_14StructureChainEmRKNS_10IdentifierERKNS_12
-__ZN3JSC3JIT22compileGetDirectOffsetEPNS_8JSObjectENS_12X86Registers10RegisterIDES4_m
+__ZN3JSC21roundUpAllocationSizeEmm
+__ZN3JSC3JIT22emitSlow_op_put_by_valEPNS_11InstructionERPNS_13SlowCaseEntryE
+__ZN3JSC3JIT20emitSlow_op_stricteqEPNS_11InstructionERPNS_13SlowCaseEntryE
+__ZN3JSC3JIT17emitSlow_op_jtrueEPNS_11InstructionERPNS_13SlowCaseEntryE
+_cti_op_new_object
+_cti_op_put_by_id_direct
+__ZN3JSC9Structure22toDictionaryTransitionERNS_12JSGlobalDataEPS0_NS0_14DictionaryKindE
+_cti_op_get_pnames
+__ZN3JSC22JSPropertyNameIterator6createEPNS_9ExecStateEPNS_8JSObjectE
+__ZN3WTF6VectorIN3JSC10IdentifierELm20EE14expandCapacityEm
+_cti_has_property
+_cti_op_resolve_global
+_cti_op_get_by_val
+_cti_op_put_by_val
+__ZN3JSC14JSGlobalObject3putEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueERNS_15PutPropertySlotE
+__ZN3JSC8JSParser20parseSwitchStatementINS_10ASTBuilderEEENT_9StatementERS3_
+__ZN3JSC8JSParser18parseSwitchClausesINS_10ASTBuilderEEENT_10ClauseListERS3_
+__ZN3JSC10SwitchNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC13CaseBlockNode20emitBytecodeForBlockERNS_17BytecodeGeneratorEPNS_10RegisterIDES4_
+__ZN3JSC13CaseBlockNode18tryOptimizedSwitchERN3WTF6VectorIPNS_14ExpressionNodeELm8EEERiS7_
+__ZN3JSCL17processClauseListEPNS_14ClauseListNodeERN3WTF6VectorIPNS_14ExpressionNodeELm8EEERNS_10SwitchKindERbRiSB_
+__ZNK3JSC14ExpressionNode8isNumberEv
+__ZNK3JSC10StringNode8isStringEv
+__ZN3JSC17BytecodeGenerator11beginSwitchEPNS_10RegisterIDENS_10SwitchInfo10SwitchTypeE
+__ZN3WTF6VectorIN3JSC10SwitchInfoELm0EE14expandCapacityEm
+__ZN3JSC17BytecodeGenerator9endSwitchEjPN3WTF6RefPtrINS_5LabelEEEPPNS_14ExpressionNodeEPS3_ii
+__ZN3WTF6VectorIN3JSC15StringJumpTableELm0EE14expandCapacityEm
+__ZNK3JSC13StatementNode12isReturnNodeEv
+__ZN3JSC15StringJumpTableC1ERKS0_
+__ZN3JSC3JIT21emit_op_switch_stringEPNS_11InstructionE
+__ZN3WTF6VectorIN3JSC12SwitchRecordELm0EE14expandCapacityEm
+_cti_op_switch_string
+__ZN3JSC9JITThunks15tryCacheGetByIDEPNS_9ExecStateEPNS_9CodeBlockENS_16ReturnAddressPtrENS_7JSValueERKNS_10IdentifierERKNS_12PropertySlotEPNS_17StructureStubInfoE
_cti_op_get_by_id_self_fail
-__ZN3JSC3JIT29privateCompileGetByIdSelfListEPNS_17StructureStubInfoEPNS_30PolymorphicAccessStructureListEiPNS_9StructureERKNS_1
+__ZN3JSC3JIT29privateCompileGetByIdSelfListEPNS_17StructureStubInfoEPNS_30PolymorphicAccessStructureListEiPNS_9StructureERKNS_10IdentifierERKNS_12PropertySlotEm
_cti_op_get_by_id_custom_stub
-__ZN3JSC10MathObject18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
-__ZN3JSCL16mathProtoFuncMaxEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZL17combineCommaNodesPN3JSC12JSGlobalDataEPNS_14ExpressionNodeES3_
-__ZNK3JSC14ExpressionNode11isCommaNodeEv
-__ZNK3JSC9CommaNode11isCommaNodeEv
-__ZN3JSC9CommaNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC19ReverseBinaryOpNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC9BreakNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC17BytecodeGenerator11breakTargetERKNS_10IdentifierE
-__ZN3JSC17BytecodeGenerator14emitJumpScopesEPNS_5LabelEi
-__ZN3JSC9CommaNodeD1Ev
+__ZN3JSC8JSParser16parseIfStatementINS_10ASTBuilderEEENT_9StatementERS3_
+__ZN3JSC5Lexer19getUnicodeCharacterEv
+__ZN3WTF6VectorIPN3JSC14ExpressionNodeELm0EE14expandCapacityEm
+__ZN3WTF6VectorIPN3JSC13StatementNodeELm0EE14expandCapacityEmPKS3_
+__ZN3WTF6VectorIPN3JSC13StatementNodeELm0EE15reserveCapacityEm
+__ZN3JSC9Structure26flattenDictionaryStructureERNS_12JSGlobalDataEPNS_8JSObjectE
+__ZN3JSC6IfNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC17BytecodeGenerator15emitJumpIfFalseEPNS_10RegisterIDEPNS_5LabelE
+__ZNK3JSC11BooleanNode6isPureERNS_17BytecodeGeneratorE
+__ZN3JSC11BooleanNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC17BytecodeGenerator8emitLoadEPNS_10RegisterIDEb
+__ZN3JSC10NumberNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC17BytecodeGenerator8emitLoadEPNS_10RegisterIDEd
+__ZN3WTF9HashTableIdSt4pairIdN3JSC7JSValueEENS_18PairFirstExtractorIS4_EENS_9FloatHashIdEENS_14PairHashTraitsINS_10HashTraitsIdEENSA_IS3_EEEESB_E6expandEv
+__ZN3JSC11NewExprNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC17BytecodeGenerator13emitConstructEPNS_10RegisterIDES2_RNS_13CallArgumentsEjjj
+__ZN3JSC10IfElseNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC12BinaryOpNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZNK3JSC10NumberNode6isPureERNS_17BytecodeGeneratorE
+__ZN3JSC17BytecodeGenerator12emitBinaryOpENS_8OpcodeIDEPNS_10RegisterIDES3_S3_NS_12OperandTypesE
+__ZN3JSC3JIT14emit_op_jfalseEPNS_11InstructionE
+__ZN3JSC3JIT17emit_op_constructEPNS_11InstructionE
__ZN3JSC3JIT14emit_op_jnlessEPNS_11InstructionE
+__ZN3JSC3JIT18emitSlow_op_jfalseEPNS_11InstructionERPNS_13SlowCaseEntryE
+__ZN3JSC3JIT21emitSlow_op_constructEPNS_11InstructionERPNS_13SlowCaseEntryE
__ZN3JSC3JIT18emitSlow_op_jnlessEPNS_11InstructionERPNS_13SlowCaseEntryE
-__ZN3JSC7JSArray18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
+__ZN3JSC12X86Assembler7movq_rrENS_12X86Registers10RegisterIDENS1_13XMMRegisterIDE
+__ZN3JSC12X86Assembler11cvtsi2sd_rrENS_12X86Registers10RegisterIDENS1_13XMMRegisterIDE
+__ZN3JSC12X86Assembler23X86InstructionFormatter9twoByteOpENS0_15TwoByteOpcodeIDEiNS_12X86Registers10RegisterIDE
+__ZN3JSC23MacroAssemblerX86Common12branchDoubleENS0_15DoubleConditionENS_12X86Registers13XMMRegisterIDES3_
+__ZN3JSC12RegExpObject18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
+__ZN3JSC15RegExpPrototype18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
+__ZN3JSCL19regExpProtoFuncTestEPNS_9ExecStateE
+__ZN3JSC12RegExpObject4testEPNS_9ExecStateE
+__ZN3JSC12RegExpObject5matchEPNS_9ExecStateE
+__ZN3JSC6RegExp5matchERKNS_7UStringEiPN3WTF6VectorIiLm32EEE
+__ZN3JSC4Yarr7executeERNS0_13YarrCodeBlockEPKtjjPi
+__ZN3JSC16JSCallbackObjectINS_24JSObjectWithGlobalObjectEE17staticValueGetterEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
+_JSValueIsObjectOfClass
+__ZN3WTF9HashTableINS_6RefPtrINS_10StringImplEEESt4pairIS3_P19StaticFunctionEntryENS_18PairFirstExtractorIS7_EENS_10StringHashENS_14PairHashTraitsINS_10HashTraitsIS3_EENSC_IS6_EEEESD_E6expandEv
+__ZN3JSC16JSCallbackObjectINS_24JSObjectWithGlobalObjectEE3putEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueERNS_15PutPropertySlotE
+_JSValueCreateJSONString
+__ZN3JSC13JSONStringifyEPNS_9ExecStateENS_7JSValueEj
+__ZN3JSC11StringifierC2EPNS_9ExecStateERKNS_5LocalINS_7UnknownEEES7_
+__ZN3JSC11Stringifier9stringifyENS_6HandleINS_7UnknownEEE
+__ZN3JSC11Stringifier22appendStringifiedValueERNS_14UStringBuilderENS_7JSValueEPNS_8JSObjectERKNS_27PropertyNameForFunctionCallE
+__ZN3WTF13StringBuilder6appendEPKcj
+__ZNK3JSC6JSCell9getStringEPNS_9ExecStateE
+_cti_vm_lazyLinkConstruct
+__ZN3JSC18FunctionExecutable27compileForConstructInternalEPNS_9ExecStateEPNS_14ScopeChainNodeE
+__ZN3JSC3JIT18emit_op_get_calleeEPNS_11InstructionE
+__ZN3JSC3JIT19emit_op_create_thisEPNS_11InstructionE
+_cti_op_create_this
+__ZN3JSC16JSCallbackObjectINS_24JSObjectWithGlobalObjectEE20staticFunctionGetterEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
+__ZN3JSC18JSCallbackFunctionC1EPNS_9ExecStateEPNS_14JSGlobalObjectEPFPK13OpaqueJSValuePK15OpaqueJSContextPS5_SB_mPKS7_PS7_ERKNS_10IdentifierE
+_cti_op_call_NotJSFunction
+__ZN3JSC18JSCallbackFunction11getCallDataERNS_8CallDataE
+__ZN3JSC18JSCallbackFunction4callEPNS_9ExecStateE
+_JSValueToBoolean
+_JSValueProtect
+_JSValueMakeUndefined
_cti_op_jless
-__ZN3JSC3JIT33privateCompilePatchGetArrayLengthENS_16ReturnAddressPtrE
-__ZN3JSC3JIT16patchGetByIdSelfEPNS_9CodeBlockEPNS_17StructureStubInfoEPNS_9StructureEmNS_16ReturnAddressPtrE
+__ZN3JSC7UString6numberEd
+__ZN3WTF14numberToStringEdPt
+__ZN3WTF4dtoaILb1ELb0ELb0ELb1EEEvPcdiRbRiRj
+__ZNK3WTF13DecimalNumber15toStringDecimalEPtj
+__ZN3WTF6String6appendEPKtj
+__ZN3WTF10StringImpl11reverseFindEPS0_j
+__ZN3WTF17equalIgnoringCaseEPNS_10StringImplES1_
+__ZN3WTF6String8truncateEj
+__ZN3JSC14JSGlobalObject15copyGlobalsFromERNS_12RegisterFileE
+__ZN3JSC8JSParser24parseFunctionDeclarationINS_13SyntaxCheckerEEENT_9StatementERS3_
+__ZN3JSC8JSParser17parseFunctionInfoILNS0_20FunctionRequirementsE1ELb1ENS_13SyntaxCheckerEEEbRT1_RPKNS_10IdentifierERNS4_19FormalParameterListERNS4_12FunctionBodyERiSE_SE_
+__ZN3JSC17BytecodeGenerator21emitResolveBaseForPutEPNS_10RegisterIDERKNS_10IdentifierE
+__ZN3JSC17BytecodeGenerator15emitResolveBaseEPNS_10RegisterIDERKNS_10IdentifierE
+__ZN3JSC17StringConstructor18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
+__ZN3JSC12StringObject3putEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueERNS_15PutPropertySlotE
+__ZN3JSCL27objectProtoFuncDefineGetterEPNS_9ExecStateE
+__ZN3JSC10JSFunction11getCallDataERNS_8CallDataE
+__ZN3JSC8JSObject12defineGetterEPNS_9ExecStateERKNS_10IdentifierEPS0_j
+__ZN3JSC7JSArray3putEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueERNS_15PutPropertySlotE
+__ZN3JSC10JSFunction3putEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueERNS_15PutPropertySlotE
+__ZN3JSC8JSParser21parseConstDeclarationINS_13SyntaxCheckerEEENT_9StatementERS3_
+__ZN3JSC8JSParser17parseFunctionInfoILNS0_20FunctionRequirementsE1ELb0ENS_10ASTBuilderEEEbRT1_RPKNS_10IdentifierERNS4_19FormalParameterListERNS4_12FunctionBodyERiSE_SE_
+__ZN3JSC8JSParser5Scope19restoreFunctionInfoEPKNS_23SourceProviderCacheItemE
+__ZN3WTF7HashMapINS_6RefPtrINS_10StringImplEEEjN3JSC17IdentifierRepHashENS_10HashTraitsIS3_EENS6_IjEEE3addEPS2_RKj
+__ZN3WTF9HashTableINS_6RefPtrINS_10StringImplEEESt4pairIS3_jENS_18PairFirstExtractorIS5_EEN3JSC17IdentifierRepHashENS_14PairHashTraitsINS_10HashTraitsIS3_EENSB_IjEEEESC_E6rehashEi
+__ZN3JSC17BytecodeGenerator13emitPutGetterEPNS_10RegisterIDERKNS_10IdentifierES2_
+__ZN3JSC17BytecodeGenerator13emitPutSetterEPNS_10RegisterIDERKNS_10IdentifierES2_
+__ZN3JSC8NullNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC3JIT18emit_op_put_getterEPNS_11InstructionE
+__ZN3JSC3JIT18emit_op_put_setterEPNS_11InstructionE
+_cti_op_put_getter
+_cti_op_put_setter
+__ZN3JSC8JSObject12defineSetterEPNS_9ExecStateERKNS_10IdentifierEPS0_j
+__ZNK3JSC12GetterSetter14isGetterSetterEv
+__ZNK3JSC18EmptyStatementNode16isEmptyStatementEv
+__ZN3JSC10ASTBuilder11makeAddNodeEPNS_14ExpressionNodeES2_b
+__ZN3JSC9ScopeNode8capturesERKNS_10IdentifierE
+__ZN3JSC17BytecodeGenerator6addVarERKNS_10IdentifierEbRPNS_10RegisterIDE
+__ZNK3JSC13LogicalOpNode26hasConditionContextCodegenEv
+__ZN3JSC13LogicalOpNode30emitBytecodeInConditionContextERNS_17BytecodeGeneratorEPNS_5LabelES4_b
+__ZNK3JSC14LogicalNotNode26hasConditionContextCodegenEv
+__ZN3JSC11UnaryOpNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC17BytecodeGenerator11emitUnaryOpENS_8OpcodeIDEPNS_10RegisterIDES3_
+__ZNK3JSC10StringNode6isPureERNS_17BytecodeGeneratorE
+__ZNK3JSC14ExpressionNode5isAddEv
+__ZNK3JSC14JSGlobalObject14isDynamicScopeERb
__ZNK3JSC7AddNode5isAddEv
-__ZN3JSC9JITThunks15tryCachePutByIDEPNS_9ExecStateEPNS_9CodeBlockENS_16ReturnAddressPtrENS_7JSValueERKNS_15PutPropertySlotEPNS_
-_cti_op_negate
-__ZN3JSC7UString4fromEj
-__ZL12makeMultNodePN3JSC12JSGlobalDataEPNS_14ExpressionNodeES3_b
-__ZN3JSC9EqualNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC17BytecodeGenerator14emitEqualityOpENS_8OpcodeIDEPNS_10RegisterIDES3_S3_
-__ZN3JSC3JIT11emit_op_notEPNS_11InstructionE
-__ZN3JSC3JIT11emit_op_mulEPNS_11InstructionE
-__ZN3JSC3JIT10emit_op_eqEPNS_11InstructionE
-__ZN3JSC3JIT15emitSlow_op_notEPNS_11InstructionERPNS_13SlowCaseEntryE
-__ZN3JSC3JIT15emitSlow_op_mulEPNS_11InstructionERPNS_13SlowCaseEntryE
-__ZN3JSC3JIT14emitSlow_op_eqEPNS_11InstructionERPNS_13SlowCaseEntryE
-_cti_op_not
-__ZN3JSC17ReadModifyDotNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC17BytecodeGenerator10emitPreDecEPNS_10RegisterIDE
-__ZN3JSC3JIT16emit_op_jnlesseqEPNS_11InstructionE
-__ZN3JSC3JIT15emit_op_jlesseqEPNS_11InstructionEb
-__ZN3JSC3JIT15emit_op_pre_decEPNS_11InstructionE
-__ZN3JSC3JIT22emit_op_loop_if_lesseqEPNS_11InstructionE
-__ZN3JSC3JIT20emitSlow_op_jnlesseqEPNS_11InstructionERPNS_13SlowCaseEntryE
-__ZN3JSC3JIT19emitSlow_op_jlesseqEPNS_11InstructionERPNS_13SlowCaseEntryEb
-__ZN3JSC3JIT19emitSlow_op_pre_decEPNS_11InstructionERPNS_13SlowCaseEntryE
-__ZN3JSC3JIT26emitSlow_op_loop_if_lesseqEPNS_11InstructionERPNS_13SlowCaseEntryE
-__ZN3JSC17powThunkGeneratorEPNS_12JSGlobalDataEPNS_14ExecutablePoolE
-__ZN3JSC19SpecializedThunkJIT12returnDoubleENS_12X86Registers13XMMRegisterIDE
-__ZN3JSC19SpecializedThunkJITD1Ev
-__ZN3JSCL16mathProtoFuncSinEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL16mathProtoFuncMinEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL18mathProtoFuncRoundEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL16mathProtoFuncLogEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC3JIT20patchMethodCallProtoEPNS_9CodeBlockERNS_18MethodCallLinkInfoEPNS_10JSFunctionEPNS_9StructureEPNS_8JSObjectENS_16R
-__ZN3JSC3JIT31privateCompilePutByIdTransitionEPNS_17StructureStubInfoEPNS_9StructureES4_mPNS_14StructureChainENS_16ReturnAddres
-__ZN3JSC3JIT13testPrototypeEPNS_9StructureERNS_22AbstractMacroAssemblerINS_12X86AssemblerEE8JumpListE
-__ZN3JSCL16mathProtoFuncAbsEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-_cti_op_jlesseq
-__ZN3WTF6VectorIPN3JSC12CallLinkInfoELm0EE15reserveCapacityEm
-__ZN3JSC10IfElseNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC17TypeOfResolveNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC7TryNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC17BytecodeGenerator9emitCatchEPNS_10RegisterIDEPNS_5LabelES4_
-__ZN3JSC9CodeBlock25createRareDataIfNecessaryEv
-__ZN3WTF6VectorIN3JSC11HandlerInfoELm0EE14expandCapacityEm
-__ZN3JSC17BytecodeGenerator16emitPushNewScopeEPNS_10RegisterIDERKNS_10IdentifierES2_
-__ZN3WTF6VectorIN3JSC18ControlFlowContextELm0EE14expandCapacityEm
-__ZN3JSC15TypeOfValueNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSCeqERKNS_7UStringEPKc
-__ZN3JSC17BytecodeGenerator12emitPopScopeEv
-__ZN3WTF6VectorIN3JSC15SimpleJumpTableELm0EE14shrinkCapacityEm
-__ZN3WTF6VectorIN3JSC15StringJumpTableELm0EE14shrinkCapacityEm
-__ZN3JSC3JIT13emit_op_catchEPNS_11InstructionE
-__ZN3JSC3JIT22emit_op_push_new_scopeEPNS_11InstructionE
-__ZN3JSC3JIT15emit_op_resolveEPNS_11InstructionE
-__ZN3JSC3JIT20emit_op_resolve_baseEPNS_11InstructionE
-__ZN3JSC3JIT17emit_op_pop_scopeEPNS_11InstructionE
-__ZL15makePostfixNodePN3JSC12JSGlobalDataEPNS_14ExpressionNodeENS_8OperatorEiii
__ZN3JSC12BinaryOpNode10emitStrcatERNS_17BytecodeGeneratorEPNS_10RegisterIDES4_PNS_21ReadModifyResolveNodeE
-__ZNK3JSC10StringNode8isStringEv
__ZNK3JSC14ExpressionNode8isStringEv
__ZN3JSC17BytecodeGenerator15emitToPrimitiveEPNS_10RegisterIDES2_
__ZN3JSC17BytecodeGenerator10emitStrcatEPNS_10RegisterIDES2_i
-__ZN3JSC18PostfixResolveNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC3JIT11emit_op_modEPNS_11InstructionE
-__ZN3JSC23MacroAssemblerX86Common8branch32ENS0_9ConditionENS_12X86Registers10RegisterIDENS_22AbstractMacroAssemblerINS_12X86Ass
+__ZN3JSC3JIT11emit_op_addEPNS_11InstructionE
__ZN3JSC3JIT20emit_op_to_primitiveEPNS_11InstructionE
-__ZN3JSC23MacroAssemblerX86Common4moveENS_22AbstractMacroAssemblerINS_12X86AssemblerEE6ImmPtrENS_12X86Registers10RegisterIDE
__ZN3JSC3JIT14emit_op_strcatEPNS_11InstructionE
-__ZN3JSC3JIT15emitSlow_op_modEPNS_11InstructionERPNS_13SlowCaseEntryE
__ZN3JSC3JIT24emitSlow_op_to_primitiveEPNS_11InstructionERPNS_13SlowCaseEntryE
-__ZN3JSCL18mathProtoFuncFloorEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL17mathProtoFuncCeilEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
+_JSValueMakeString
+_cti_op_jtrue
+__ZNK3JSC8JSString9toBooleanEPNS_9ExecStateE
_cti_op_strcat
-__ZNK3JSC19BracketAccessorNode10isLocationEv
-__ZNK3JSC19BracketAccessorNode21isBracketAccessorNodeEv
-__ZN3JSC17AssignBracketNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC17BytecodeGenerator12emitPutByValEPNS_10RegisterIDES2_S2_
-__ZN3JSC3JIT18emit_op_put_by_valEPNS_11InstructionE
-__ZN3JSC3JIT22emitSlow_op_put_by_valEPNS_11InstructionERPNS_13SlowCaseEntryE
-__ZN3JSC14ArrayPrototype18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
-__ZN3JSC14LogicalNotNode30emitBytecodeInConditionContextERNS_17BytecodeGeneratorEPNS_5LabelES4_b
+__ZNK3JSC8JSString11resolveRopeEPNS_9ExecStateE
+__ZNK3JSC8JSString19resolveRopeSlowCaseEPNS_9ExecStateEPt
+__ZN3JSC8RopeImpl20destructNonRecursiveEv
+__ZN3JSC8RopeImpl23derefFibersNonRecursiveERN3WTF6VectorIPS0_Lm32EEE
+_cti_op_construct_NotJSConstruct
+__ZN3JSC17ObjectConstructor16getConstructDataERNS_13ConstructDataE
+__ZN3JSCL30constructWithObjectConstructorEPNS_9ExecStateE
+__ZN3WTF21charactersToIntStrictEPKtmPbi
+__ZN3JSC41constructFunctionSkippingEvalEnabledCheckEPNS_9ExecStateEPNS_14JSGlobalObjectERKNS_7ArgListERKNS_10IdentifierERKNS_7UStringEi
+__ZNK3JSC21UStringSourceProvider6lengthEv
+__ZN3JSC18FunctionExecutable14fromGlobalCodeERKNS_10IdentifierEPNS_9ExecStateEPNS_8DebuggerERKNS_10SourceCodeEPPNS_8JSObjectE
+__ZNK3JSC21UStringSourceProvider4dataEv
+__ZN3JSC4callEPNS_9ExecStateENS_7JSValueENS_8CallTypeERKNS_8CallDataES2_RKNS_7ArgListE
+__ZN3JSC11Interpreter11executeCallEPNS_9ExecStateEPNS_8JSObjectENS_8CallTypeERKNS_8CallDataENS_7JSValueERKNS_7ArgListE
+__ZN3JSC10ASTBuilder15makePostfixNodeEPNS_14ExpressionNodeENS_8OperatorEiii
+__ZN3JSC7ForNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC18PostfixResolveNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC17BytecodeGenerator10emitPreIncEPNS_10RegisterIDE
+__ZN3JSC9EqualNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZNK3JSC14ExpressionNode6isNullEv
+__ZN3JSC3JIT15emit_op_pre_incEPNS_11InstructionE
+__ZN3JSC3JIT13emit_op_jlessEPNS_11InstructionE
+__ZN3JSC3JIT10emit_op_eqEPNS_11InstructionE
+__ZN3JSC3JIT19emitSlow_op_pre_incEPNS_11InstructionERPNS_13SlowCaseEntryE
+__ZN3JSC3JIT17emitSlow_op_jlessEPNS_11InstructionERPNS_13SlowCaseEntryE
+__ZN3JSC3JIT14emitSlow_op_eqEPNS_11InstructionERPNS_13SlowCaseEntryE
+__ZN3WTF11emptyStringEv
+__ZN3JSC13LogicalOpNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+_cti_op_stricteq
+_cti_op_eq
+__ZN3JSC10ASTBuilder14makePrefixNodeEPNS_14ExpressionNodeENS_8OperatorEiii
+__ZN3JSC17PrefixResolveNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC21ThrowableBinaryOpNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZNK3JSC8JSObject9toBooleanEPNS_9ExecStateE
+_cti_op_in
+__ZN3JSC9JITThunks15tryCachePutByIDEPNS_9ExecStateEPNS_9CodeBlockENS_16ReturnAddressPtrENS_7JSValueERKNS_15PutPropertySlotEPNS_17StructureStubInfoEb
+_cti_op_get_by_id_generic
+_cti_op_put_by_id_generic
+__ZN3JSC3JIT16patchGetByIdSelfEPNS_9CodeBlockEPNS_17StructureStubInfoEPNS_9StructureEmNS_16ReturnAddressPtrE
+__ZNK3JSC6JSCell14isGetterSetterEv
+_JSObjectIsFunction
+_JSObjectCallAsFunction
+__ZN3JSC3JIT20emit_op_convert_thisEPNS_11InstructionE
+__ZN3JSC23MacroAssemblerX86Common11branchTest8ENS0_15ResultConditionENS_22AbstractMacroAssemblerINS_12X86AssemblerEE7AddressENS4_12TrustedImm32E
+__ZN3JSC3JIT24emitSlow_op_convert_thisEPNS_11InstructionERPNS_13SlowCaseEntryE
+__ZN3JSC8JSObject22fillGetterPropertySlotERNS_12PropertySlotEPNS_16WriteBarrierBaseINS_7UnknownEEE
+__ZNK3JSC12PropertySlot14functionGetterEPNS_9ExecStateE
+__ZN3JSC17ReadModifyDotNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC15ConditionalNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC3JIT20compileBinaryArithOpENS_8OpcodeIDEjjjNS_12OperandTypesE
+__ZN3JSC3JIT15emitSlow_op_addEPNS_11InstructionERPNS_13SlowCaseEntryE
+__ZN3JSC3JIT28compileBinaryArithOpSlowCaseENS_8OpcodeIDERPNS_13SlowCaseEntryEjjjNS_12OperandTypesEbb
+__ZNK3JSC10NumberNode8isNumberEv
+__ZN3JSC3JIT17emit_op_nstricteqEPNS_11InstructionE
+__ZN3JSC3JIT21emitSlow_op_nstricteqEPNS_11InstructionERPNS_13SlowCaseEntryE
__ZN3JSC8JSString18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
__ZN3JSC15StringPrototype18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
__ZN3JSC12StringObject18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
-__ZN3JSCL21stringProtoFuncSubstrEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
+__ZN3JSCL22stringProtoFuncIndexOfEPNS_9ExecStateE
+_cti_op_add
+__ZN3JSC10ASTBuilder12makeMultNodeEPNS_14ExpressionNodeES2_b
+__ZN3JSC14ExpressionNode14stripUnaryPlusEv
+__ZN3JSC17BytecodeGenerator20emitInitLazyRegisterEPNS_10RegisterIDE
+__ZN3JSC17BytecodeGenerator29uncheckedRegisterForArgumentsEv
+__ZN3JSC17BytecodeGenerator20emitGetArgumentByValEPNS_10RegisterIDES2_S2_
+__ZN3JSC17BytecodeGenerator22emitGetArgumentsLengthEPNS_10RegisterIDES2_
+__ZN3JSC3JIT21emit_op_init_lazy_regEPNS_11InstructionE
+__ZN3JSC3JIT11emit_op_mulEPNS_11InstructionE
+__ZN3JSC3JIT27emit_op_get_argument_by_valEPNS_11InstructionE
+__ZN3JSC3JIT28emit_op_get_arguments_lengthEPNS_11InstructionE
+__ZN3JSC3JIT15emitSlow_op_mulEPNS_11InstructionERPNS_13SlowCaseEntryE
+__ZN3JSC3JIT31emitSlow_op_get_argument_by_valEPNS_11InstructionERPNS_13SlowCaseEntryE
+__ZN3JSC3JIT32emitSlow_op_get_arguments_lengthEPNS_11InstructionERPNS_13SlowCaseEntryE
+_cti_op_call_arityCheck
+_cti_op_convert_this
+__ZNK3JSC8JSString12toThisObjectEPNS_9ExecStateE
+__ZN3JSC12StringObjectC1ERNS_12JSGlobalDataEPNS_9StructureEPNS_8JSStringE
+__ZN3JSCL20stringProtoFuncSplitEPNS_9ExecStateE
+__ZNK3JSC8JSObject8toStringEPNS_9ExecStateE
+__ZNK3JSC8JSObject11toPrimitiveEPNS_9ExecStateENS_22PreferredPrimitiveTypeE
+__ZNK3JSC8JSObject12defaultValueEPNS_9ExecStateENS_22PreferredPrimitiveTypeE
+__ZN3JSCL23stringProtoFuncToStringEPNS_9ExecStateE
+__ZN3JSC11jsSubstringEPNS_12JSGlobalDataERKNS_7UStringEjj
+__ZN3JSC7JSArray3putEPNS_9ExecStateEjNS_7JSValueE
+__ZN3JSC7JSArray11putSlowCaseEPNS_9ExecStateEjNS_7JSValueE
+__ZN3JSC14ArrayPrototype18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
+__ZN3JSCL20arrayProtoFuncSpliceEPNS_9ExecStateE
+__ZNK3JSC8JSObject3getEPNS_9ExecStateERKNS_10IdentifierE
__ZNK3JSC7JSValue9toIntegerEPNS_9ExecStateE
-__ZN7WebCore10StringImpl6createEN3WTF10PassRefPtrIS0_EEjj
-__ZN3WTF6RefPtrIN7WebCore10StringImplEED1Ev
-__ZN3JSCL18arrayProtoFuncJoinEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZNK3JSC8JSObject12toThisObjectEPNS_9ExecStateE
-__ZN3WTF7HashSetIPN3JSC8JSObjectENS_7PtrHashIS3_EENS_10HashTraitsIS3_EEE3addERKS3_
+__ZN3JSC7JSArrayC1ERNS_12JSGlobalDataEPNS_9StructureEjNS_17ArrayCreationModeE
+__ZN3JSC7JSArray9setLengthEj
+__ZN3JSCL11getPropertyEPNS_9ExecStateEPNS_8JSObjectEj
+__ZN3JSCL18arrayProtoFuncJoinEPNS_9ExecStateE
__ZN3WTF9HashTableIPN3JSC8JSObjectES3_NS_17IdentityExtractorIS3_EENS_7PtrHashIS3_EENS_10HashTraitsIS3_EES9_E6rehashEi
-__ZNK3JSC8JSObject3getEPNS_9ExecStateERKNS_10IdentifierE
__ZN3JSC15JSStringBuilder5buildEPNS_9ExecStateE
-__ZN3WTF6VectorItLm64EE17tryExpandCapacityEm
-__ZN3JSCL18arrayProtoFuncPushEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC7JSArray4pushEPNS_9ExecStateENS_7JSValueE
-__ZN3WTF14tryFastReallocEPvm
-__ZN3JSC4Heap15recordExtraCostEm
-__ZN3JSC17BytecodeGenerator16emitPutScopedVarEmiPNS_10RegisterIDENS_7JSValueE
-__ZN3JSC3JIT22emit_op_put_scoped_varEPNS_11InstructionE
-__ZN3JSC3JIT29emitPutVariableObjectRegisterENS_12X86Registers10RegisterIDES2_i
-__ZN3JSC3JIT22emit_op_put_global_varEPNS_11InstructionE
-_cti_op_put_by_index
-__ZN3JSC7JSArray3putEPNS_9ExecStateEjNS_7JSValueE
-__ZN3JSC7JSArray11putSlowCaseEPNS_9ExecStateEjNS_7JSValueE
-__ZNK3JSC11BooleanNode6isPureERNS_17BytecodeGeneratorE
-__ZN3JSC10JSFunction3putEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueERNS_15PutPropertySlotE
-__ZNK7WebCore12AtomicString5lowerEv
+__ZN3JSC3JIT20patchMethodCallProtoERNS_12JSGlobalDataEPNS_9CodeBlockERNS_18MethodCallLinkInfoEPNS_10JSFunctionEPNS_9StructureEPNS_8JSObjectENS_16ReturnAddressPtrE
+__ZN3JSC27ctiPatchCallByReturnAddressEPNS_9CodeBlockENS_16ReturnAddressPtrENS_21MacroAssemblerCodePtrE
+__ZN3JSC23CallFunctionCallDotNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC17BytecodeGenerator25emitJumpIfNotFunctionCallEPNS_10RegisterIDEPNS_5LabelE
+__ZN3JSC3JIT16emit_op_jneq_ptrEPNS_11InstructionE
+__ZN3JSC3JIT24emit_op_create_argumentsEPNS_11InstructionE
+__ZN3JSC3JIT25emit_op_create_activationEPNS_11InstructionE
+__ZN3JSC3JIT27emit_op_tear_off_activationEPNS_11InstructionE
+_cti_op_create_arguments
+__ZN3JSCL19arrayProtoFuncSliceEPNS_9ExecStateE
+__ZN3JSC9Arguments18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
+_cti_op_push_activation
+__ZN3JSC12JSActivationC1EPNS_9ExecStateEPNS_18FunctionExecutableE
+_cti_op_tear_off_activation
+__ZN3JSCL18arrayProtoFuncPushEPNS_9ExecStateE
+__ZN3JSC5Lexer9setOffsetEi
+__ZN3WTF7HashMapIjPN3JSC16FunctionBodyNodeENS_7IntHashIjEENS_29UnsignedWithZeroKeyHashTraitsIjEENS_10HashTraitsIS3_EEE3setERKjRKS3_
+__ZN3WTF9HashTableIjSt4pairIjPN3JSC16FunctionBodyNodeEENS_18PairFirstExtractorIS5_EENS_7IntHashIjEENS_14PairHashTraitsINS_29UnsignedWithZeroKeyHashTraitsIjEENS_10HashTraitsIS4_EEEESC_E6rehashEi
+__ZN3JSC17BytecodeGenerator19emitLazyNewFunctionEPNS_10RegisterIDEPNS_16FunctionBodyNodeE
+__ZN3JSC17BytecodeGenerator23emitNewFunctionInternalEPNS_10RegisterIDEjb
+__ZN3JSC3JIT16emit_op_new_funcEPNS_11InstructionE
+__ZN3JSC8JSParser19parseWhileStatementINS_10ASTBuilderEEENT_9StatementERS3_
+__ZN3JSC9WhileNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+_JSValueMakeNumber
+_JSObjectMakeArray
+_JSValueMakeBoolean
+__ZN3JSC20MarkedArgumentBuffer10slowAppendENS_7JSValueE
+_JSValueUnprotect
+__ZN3WTF9HashTableIPN3JSC20MarkedArgumentBufferES3_NS_17IdentityExtractorIS3_EENS_7PtrHashIS3_EENS_10HashTraitsIS3_EES9_E6expandEv
+_cti_op_new_func
+__ZN3JSC3JIT26privateCompileGetByIdProtoEPNS_17StructureStubInfoEPNS_9StructureES4_RKNS_10IdentifierERKNS_12PropertySlotEmNS_16ReturnAddressPtrEPNS_9ExecStateE
+__ZN3JSC3JIT22compileGetDirectOffsetEPNS_8JSObjectENS_12X86Registers10RegisterIDEm
+__ZN3JSC10ASTBuilder11makeSubNodeEPNS_14ExpressionNodeES2_b
+__ZN3JSC8JSParser22parseContinueStatementINS_10ASTBuilderEEENT_9StatementERS3_
+__ZN3JSC8JSParser19parseBreakStatementINS_10ASTBuilderEEENT_9StatementERS3_
+__ZN3JSC17BytecodeGenerator15emitNewFunctionEPNS_10RegisterIDEPNS_16FunctionBodyNodeE
+__ZN3JSC15TypeOfValueNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSCeqERKNS_7UStringEPKc
+__ZN3WTF6VectorIPN3JSC14ExpressionNodeELm8EE14expandCapacityEm
+__ZN3WTF6VectorINS_6RefPtrIN3JSC5LabelEEELm8EE14expandCapacityEm
+__ZN3JSC19ReverseBinaryOpNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC12ContinueNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC17BytecodeGenerator14continueTargetERKNS_10IdentifierE
+__ZN3JSC17BytecodeGenerator14emitJumpScopesEPNS_5LabelEi
+__ZN3JSC9BreakNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC17BytecodeGenerator11breakTargetERKNS_10IdentifierE
+__ZN3WTF6VectorISt4pairIiiELm8EE14expandCapacityEm
+__ZN3JSC14InstanceOfNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC17BytecodeGenerator20emitCheckHasInstanceEPNS_10RegisterIDE
+__ZN3JSC17BytecodeGenerator14emitInstanceOfEPNS_10RegisterIDES2_S2_S2_
+__ZN3JSC17BytecodeGenerator19emitResolveWithBaseEPNS_10RegisterIDES2_RKNS_10IdentifierE
+__ZN3JSC23FunctionCallBracketNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC3JIT11emit_op_subEPNS_11InstructionE
+__ZN3JSC3JIT16emit_op_jnlesseqEPNS_11InstructionE
+__ZN3JSC3JIT15emit_op_jlesseqEPNS_11InstructionEb
+__ZN3JSC3JIT11emit_op_notEPNS_11InstructionE
+__ZN3JSC3JIT26emit_op_check_has_instanceEPNS_11InstructionE
+__ZN3JSC3JIT18emit_op_instanceofEPNS_11InstructionE
+__ZN3JSC3JIT15emitSlow_op_subEPNS_11InstructionERPNS_13SlowCaseEntryE
+__ZN3JSC3JIT20emitSlow_op_jnlesseqEPNS_11InstructionERPNS_13SlowCaseEntryE
+__ZN3JSC3JIT19emitSlow_op_jlesseqEPNS_11InstructionERPNS_13SlowCaseEntryEb
+__ZN3JSC3JIT15emitSlow_op_notEPNS_11InstructionERPNS_13SlowCaseEntryE
+__ZN3JSC3JIT30emitSlow_op_check_has_instanceEPNS_11InstructionERPNS_13SlowCaseEntryE
+__ZN3JSC3JIT22emitSlow_op_instanceofEPNS_11InstructionERPNS_13SlowCaseEntryE
+__ZN3JSC7UString6numberEi
+_cti_op_is_function
+__ZN3JSC16jsIsFunctionTypeENS_7JSValueE
+__ZN3JSC3JIT33privateCompilePatchGetArrayLengthENS_16ReturnAddressPtrE
+__ZN3JSC14StructureChainC1ERNS_12JSGlobalDataEPNS_9StructureES4_
+__ZN3JSC14StructureChainC2ERNS_12JSGlobalDataEPNS_9StructureES4_
+__ZN3JSC3JIT31privateCompilePutByIdTransitionEPNS_17StructureStubInfoEPNS_9StructureES4_mPNS_14StructureChainENS_16ReturnAddressPtrEb
+__ZN3JSC3JIT13testPrototypeENS_7JSValueERNS_22AbstractMacroAssemblerINS_12X86AssemblerEE8JumpListE
+__ZN3JSC3JIT26privateCompileGetByIdChainEPNS_17StructureStubInfoEPNS_9StructureEPNS_14StructureChainEmRKNS_10IdentifierERKNS_12PropertySlotEmNS_16ReturnAddressPtrEPNS_9ExecStateE
+__ZN3JSC17BytecodeGenerator10emitPreDecEPNS_10RegisterIDE
+__ZN3JSC3JIT15emit_op_pre_decEPNS_11InstructionE
+__ZN3JSC23MacroAssemblerX86Common4moveENS_12X86Registers10RegisterIDES2_
+__ZN3JSC3JIT19emitSlow_op_pre_decEPNS_11InstructionERPNS_13SlowCaseEntryE
_cti_op_get_by_id_proto_list
-__ZN3JSC3JIT30privateCompileGetByIdChainListEPNS_17StructureStubInfoEPNS_30PolymorphicAccessStructureListEiPNS_9StructureEPNS_1
+__ZN3JSC3JIT30privateCompileGetByIdChainListEPNS_17StructureStubInfoEPNS_30PolymorphicAccessStructureListEiPNS_9StructureEPNS_14StructureChainEmRKNS_10IdentifierERKNS_12PropertySlotEmPNS_9ExecStateE
+__ZN3WTF13StringBuilder15reserveCapacityEj
+__ZN3WTF4dtoaEPcdRbRiRj
+__ZNK3WTF13DecimalNumber28bufferLengthForStringDecimalEv
+__ZN3JSC18globalFuncParseIntEPNS_9ExecStateE
+__ZN3JSC7toInt32Ed
+__ZN3JSCL8parseIntERKNS_7UStringEi
+_cti_op_nstricteq
+__ZN3JSC9Arguments18getOwnPropertySlotEPNS_9ExecStateEjRNS_12PropertySlotE
+__ZN3JSC10ASTBuilder14makeDeleteNodeEPNS_14ExpressionNodeEiii
+__ZN3JSC13DeleteDotNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC17BytecodeGenerator14emitDeleteByIdEPNS_10RegisterIDES2_RKNS_10IdentifierE
+__ZN3JSC3JIT17emit_op_del_by_idEPNS_11InstructionE
+_cti_op_del_by_id
+__ZN3JSC8JSObject14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE
+_cti_op_not
+__ZN3WTF13tryFastCallocEmm
+__ZN3WTF9ByteArray6createEm
__ZN3JSC3JIT22emit_op_get_scoped_varEPNS_11InstructionE
-_cti_op_put_by_val
-__ZNK3JSC12JSActivation14isDynamicScopeERb
+__ZN3JSCL22stringProtoFuncReplaceEPNS_9ExecStateE
+__ZNK3JSC7JSValue14toThisJSStringEPNS_9ExecStateE
+__ZN3JSC9ExecState8argumentEi
+__ZN3JSC6JSCell11getCallDataERNS_8CallDataE
+__ZN3WTF6RefPtrINS_10StringImplEEaSERKS2_
+__ZNK3JSC7UString20substringSharingImplEjj
+__ZN3JSC4Heap8allocateEm
__ZN3JSC24ApplyFunctionCallDotNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
__ZNK3JSC14ExpressionNode13isSimpleArrayEv
__ZN3JSC17BytecodeGenerator26emitJumpIfNotFunctionApplyEPNS_10RegisterIDEPNS_5LabelE
-__ZN3JSC17BytecodeGenerator22willResolveToArgumentsERKNS_10IdentifierE
-__ZN3JSC17BytecodeGenerator15emitLoadVarargsEPNS_10RegisterIDES2_
+__ZNK3JSC12JSActivation14isDynamicScopeERb
+__ZN3JSC17BytecodeGenerator15emitLoadVarargsEPNS_10RegisterIDES2_S2_
__ZN3JSC17BytecodeGenerator15emitCallVarargsEPNS_10RegisterIDES2_S2_S2_jjj
-__ZN3JSC3JIT16emit_op_jneq_ptrEPNS_11InstructionE
__ZN3JSC3JIT20emit_op_load_varargsEPNS_11InstructionE
__ZN3JSC3JIT20emit_op_call_varargsEPNS_11InstructionE
__ZN3JSC3JIT20compileOpCallVarargsEPNS_11InstructionE
-__ZN3JSC3JIT29compileOpCallVarargsSetupArgsEPNS_11InstructionE
+__ZN3JSC3JIT24emitSlow_op_load_varargsEPNS_11InstructionERPNS_13SlowCaseEntryE
__ZN3JSC3JIT24emitSlow_op_call_varargsEPNS_11InstructionERPNS_13SlowCaseEntryE
__ZN3JSC3JIT28compileOpCallVarargsSlowCaseEPNS_11InstructionERPNS_13SlowCaseEntryE
-__ZN3JSC14ExecutablePool13systemReleaseERKNS0_10AllocationE
-_JSStringCreateWithCFString
-_JSStringRetain
-_JSStringRelease
-_JSEvaluateScript
-__ZN3JSC4Heap14registerThreadEv
-__ZNK14OpaqueJSString7ustringEv
-__ZN3JSC7UStringC1EPKtj
-__ZN3JSC5Lexer10scanRegExpERPKNS_10IdentifierES4_t
-__ZN3JSC18ConstStatementNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC13ConstDeclNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC13ConstDeclNode14emitCodeSingleERNS_17BytecodeGeneratorE
-__ZN3JSC17BytecodeGenerator16constRegisterForERKNS_10IdentifierE
-__ZN3JSC10RegExpNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC6RegExp6createEPNS_12JSGlobalDataERKNS_7UStringES5_
-__ZNK3JSC7UString4findEtj
-__ZN3JSC4Yarr15jitCompileRegexEPNS_12JSGlobalDataERNS0_14RegexCodeBlockERKNS_7UStringERjRPKcbb
-__ZN3JSC4Yarr12compileRegexERKNS_7UStringERNS0_12RegexPatternE
-__ZN3JSC4Yarr6ParserINS0_23RegexPatternConstructorEE5parseEv
-__ZN3JSC4Yarr18PatternDisjunction17addNewAlternativeEv
-__ZN3WTF6VectorIPN3JSC4Yarr18PatternAlternativeELm0EE15reserveCapacityEm
-__ZN3JSC4Yarr23RegexPatternConstructor20atomPatternCharacterEt
+_cti_op_create_arguments_no_params
+__ZN3JSCL20arrayProtoFuncConcatEPNS_9ExecStateE
+_cti_op_load_varargs
+__ZN3JSC7JSArray15copyToRegistersEPNS_9ExecStateEPNS_8RegisterEj
+_cti_op_call_jitCompile
+__ZN3JSC16JSCallbackObjectINS_24JSObjectWithGlobalObjectEE14callbackGetterEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
+__ZNK3JSC6JSCell9getStringEPNS_9ExecStateERNS_7UStringE
+__ZN3JSC11Stringifier6Holder18appendNextPropertyERS0_RNS_14UStringBuilderE
+__ZN3JSC8JSObject18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
+__ZN3JSC11Stringifier18appendQuotedStringERNS_14UStringBuilderERKNS_7UStringE
+__ZN3WTF10StringImpl4costEv
+__ZN3JSC7UStringC1EPKcj
+_JSObjectGetPrivateProperty
+_JSObjectSetPrivateProperty
+__ZN3JSC20JSCallbackObjectData18setPrivatePropertyERNS_12JSGlobalDataEPNS_6JSCellERKNS_10IdentifierENS_7JSValueE
+__ZN3WTF9HashTableINS_6RefPtrINS_10StringImplEEESt4pairIS3_N3JSC12WriteBarrierINS5_7UnknownEEEENS_18PairFirstExtractorIS9_EENS5_17IdentifierRepHashENS_14PairHashTraitsINS_10HashTraitsIS3_EENSE_IS8_EEEESF_E6rehashEi
+__ZN3JSC17BytecodeGenerator16emitPutScopedVarEmiPNS_10RegisterIDENS_7JSValueE
+__ZN3JSC3JIT22emit_op_put_global_varEPNS_11InstructionE
+__ZN3JSC13LiteralParser5Lexer9lexNumberERNS1_18LiteralParserTokenE
+__ZN3JSC8JSParser17parseTryStatementINS_10ASTBuilderEEENT_9StatementERS3_
+__ZN3JSC7TryNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC17BytecodeGenerator9emitCatchEPNS_10RegisterIDEPNS_5LabelES4_
+__ZN3WTF6VectorIN3JSC11HandlerInfoELm0EE14expandCapacityEm
+__ZN3JSC17BytecodeGenerator16emitPushNewScopeEPNS_10RegisterIDERKNS_10IdentifierES2_
+__ZN3WTF6VectorIN3JSC18ControlFlowContextELm0EE14expandCapacityEm
+__ZN3JSC17BytecodeGenerator12emitPopScopeEv
+__ZN3JSC3JIT13emit_op_catchEPNS_11InstructionE
+__ZN3JSC20MacroAssemblerX86_647loadPtrENS_22AbstractMacroAssemblerINS_12X86AssemblerEE15ImplicitAddressENS_12X86Registers10RegisterIDE
+__ZN3JSC3JIT22emit_op_push_new_scopeEPNS_11InstructionE
+__ZN3JSC3JIT18emit_op_jmp_scopesEPNS_11InstructionE
+__ZN3JSC3JIT17emit_op_pop_scopeEPNS_11InstructionE
+__ZN3WTF6VectorIN3JSC32CallReturnOffsetToBytecodeOffsetELm0EE15reserveCapacityEm
+_JSObjectDeletePrivateProperty
+__ZN3WTF6VectorIjLm16EE6resizeEm
+__ZN3WTFL7multaddERNS_6BigIntEii
+__ZN3WTFL4multERNS_6BigIntERKS0_
+__ZN3WTF6VectorIjLm16EEaSERKS1_
+__ZN3JSC4Yarr22YarrPatternConstructor23setupDisjunctionOffsetsEPNS0_18PatternDisjunctionEjj
+__ZN3JSC23MacroAssemblerX86Common4jumpEv
__ZN3WTF6VectorIN3JSC4Yarr11PatternTermELm0EE14expandCapacityEmPKS3_
-__ZN3WTF6VectorIN3JSC4Yarr11PatternTermELm0EE14expandCapacityEm
-__ZN3JSC4Yarr6ParserINS0_23RegexPatternConstructorEE11parseEscapeILb0ES2_EEbRT0_
-__ZN3JSC4Yarr14RegexGenerator19generateDisjunctionEPNS0_18PatternDisjunctionE
-__ZN3JSC12X86Assembler7addl_irEiNS_12X86Registers10RegisterIDE
-__ZN3JSC23MacroAssemblerX86Common8branch32ENS0_9ConditionENS_12X86Registers10RegisterIDES3_
-__ZN3JSC4Yarr14RegexGenerator12generateTermERNS1_19TermGenerationStateE
-__ZN3JSC12X86Assembler23X86InstructionFormatter9oneByteOpENS0_15OneByteOpcodeIDEiNS_12X86Registers10RegisterIDES4_ii
-__ZN3JSC4Yarr14RegexGenerator19TermGenerationState15jumpToBacktrackENS_22AbstractMacroAssemblerINS_12X86AssemblerEE4JumpEPNS_14
-__ZN3JSC4Yarr14RegexGenerator19jumpIfCharNotEqualsEti
-__ZN3JSC12X86Assembler7subl_irEiNS_12X86Registers10RegisterIDE
-__ZN3JSC22AbstractMacroAssemblerINS_12X86AssemblerEE8JumpList4linkEPS2_
-__ZN3WTF15deleteAllValuesIPN3JSC4Yarr18PatternDisjunctionELm4EEEvRKNS_6VectorIT_XT0_EEE
-__ZN3WTF15deleteAllValuesIPN3JSC4Yarr14CharacterClassELm0EEEvRKNS_6VectorIT_XT0_EEE
-__ZN3JSC17BytecodeGenerator8emitLoadEPNS_10RegisterIDEPNS_6RegExpE
-__ZN3JSC12RegExpObjectC1EN3WTF17NonNullPassRefPtrINS_9StructureEEENS2_INS_6RegExpEEE
-__ZN3JSC12RegExpObjectC2EN3WTF17NonNullPassRefPtrINS_9StructureEEENS2_INS_6RegExpEEE
-__ZN3JSC4Yarr23RegexPatternConstructor30atomParenthesesSubpatternBeginEb
-__ZN3JSC4Yarr25CharacterClassConstructor7putCharEt
-__ZN3JSC4Yarr25CharacterClassConstructor9addSortedERN3WTF6VectorItLm0EEEt
-__ZN3WTF6VectorItLm0EE14expandCapacityEm
-__ZN3JSC4Yarr23RegexPatternConstructor21atomCharacterClassEndEv
-__ZN3WTF6VectorIPN3JSC4Yarr14CharacterClassELm0EE14expandCapacityEmPKS4_
-__ZN3WTF6VectorIPN3JSC4Yarr14CharacterClassELm0EE14expandCapacityEm
+__ZN3JSC4Yarr18PatternDisjunction17addNewAlternativeEv
+__ZN3JSC4Yarr22YarrPatternConstructor15copyDisjunctionEPNS0_18PatternDisjunctionEb
__ZN3WTF6VectorIPN3JSC4Yarr18PatternDisjunctionELm4EE14expandCapacityEm
-__ZN3JSC4Yarr23RegexPatternConstructor23setupDisjunctionOffsetsEPNS0_18PatternDisjunctionEjj
-__ZN3JSC4Yarr14RegexGenerator25generateParenthesesSingleERNS1_19TermGenerationStateE
-__ZN3JSC4Yarr14RegexGenerator30generateParenthesesDisjunctionERNS0_11PatternTermERNS1_19TermGenerationStateEj
-__ZN3WTF6VectorIN3JSC4Yarr14RegexGenerator26AlternativeBacktrackRecordELm0EE14expandCapacityEm
-__ZN3JSC4Yarr14RegexGenerator28generateCharacterClassGreedyERNS1_19TermGenerationStateE
-__ZN3JSC4Yarr14RegexGenerator19matchCharacterClassENS_12X86Registers10RegisterIDERNS_22AbstractMacroAssemblerINS_12X86Assembler
-__ZN3JSC23MacroAssemblerX86Common4jumpEv
-__ZN3JSC4Yarr14RegexGenerator13readCharacterEiNS_12X86Registers10RegisterIDE
-__ZN3JSC12StringObject3putEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueERNS_15PutPropertySlotE
-_JSContextGetGlobalObject
-__ZN3WTF13wtfThreadDataEv
-_JSClassCreate
-__ZN13OpaqueJSClass6createEPK17JSClassDefinition
-__ZN13OpaqueJSClassC2EPK17JSClassDefinitionPS_
-__ZN3WTF7Unicode18convertUTF8ToUTF16EPPKcS2_PPtS4_b
-_JSClassRetain
-_JSObjectMake
-__ZN3JSC16JSCallbackObjectINS_8JSObjectEE4initEPNS_9ExecStateE
-__ZN13OpaqueJSClass9prototypeEPN3JSC9ExecStateE
-__ZN13OpaqueJSClass11contextDataEPN3JSC9ExecStateE
-__ZN3WTF9HashTableIP13OpaqueJSClassSt4pairIS2_P24OpaqueJSClassContextDataENS_18PairFirstExtractorIS6_EENS_7PtrHashIS2_EENS_14Pa
-__ZN24OpaqueJSClassContextDataC2EP13OpaqueJSClass
-_JSStringCreateWithUTF8CString
-_JSObjectSetProperty
-__ZN3JSC12APIEntryShimC1EPNS_9ExecStateEb
-__ZNK14OpaqueJSString10identifierEPN3JSC12JSGlobalDataE
-_JSClassRelease
-_JSContextGetGlobalContext
-_JSGlobalContextRetain
-_JSObjectGetProperty
-_JSValueToObject
-_JSValueProtect
-_JSObjectIsFunction
-_JSObjectCallAsFunction
-__ZN3JSC4callEPNS_9ExecStateENS_7JSValueENS_8CallTypeERKNS_8CallDataES2_RKNS_7ArgListE
-__ZN3JSC10JSFunction4callEPNS_9ExecStateENS_7JSValueERKNS_7ArgListE
-__ZN3JSC11Interpreter7executeEPNS_18FunctionExecutableEPNS_9ExecStateEPNS_10JSFunctionEPNS_8JSObjectERKNS_7ArgListEPNS_14ScopeC
-__ZNK3JSC8NullNode6isNullEv
-__ZN3JSC3JIT16emit_op_neq_nullEPNS_11InstructionE
-__ZNK3JSC19JSStaticScopeObject14isDynamicScopeERb
-__ZN3JSC12RegExpObject18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
-__ZN3JSCL19regExpProtoFuncTestEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZNK3JSC12RegExpObject9classInfoEv
-__ZN3JSC12RegExpObject4testEPNS_9ExecStateERKNS_7ArgListE
-__ZN3JSC12RegExpObject5matchEPNS_9ExecStateERKNS_7ArgListE
-__ZN3JSC6RegExp5matchERKNS_7UStringEiPN3WTF6VectorIiLm32EEE
-__ZN3JSC9WhileNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC15StrictEqualNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC3JIT16emit_op_stricteqEPNS_11InstructionE
-__ZN3JSC3JIT17compileOpStrictEqEPNS_11InstructionENS0_21CompileOpStrictEqTypeE
-__ZN3JSC3JIT17emit_op_nstricteqEPNS_11InstructionE
-__ZN3JSC3JIT20emitSlow_op_stricteqEPNS_11InstructionERPNS_13SlowCaseEntryE
-__ZN3JSC3JIT21emitSlow_op_nstricteqEPNS_11InstructionERPNS_13SlowCaseEntryE
-__ZN3JSC12ContinueNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC17BytecodeGenerator14continueTargetERKNS_10IdentifierE
-__ZN3JSCL7dateNowEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-_cti_op_get_by_val
-__ZN7WebCore10StringImpl5upperEv
-_cti_op_get_by_id_generic
-_cti_op_put_by_id_fail
-__ZNK3JSC7UString8toUInt32EPbb
-__ZNK3JSC7UString8toDoubleEbb
-__ZNK3JSC7UString10UTF8StringEb
-__ZN3JSC18globalFuncParseIntEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC12nonInlineNaNEv
-__ZN3JSC15toInt32SlowCaseEdRb
-__ZN3JSCL8parseIntERKNS_7UStringEi
-__ZN3JSC15globalFuncIsNaNEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZNK7WebCore6String8toDoubleEPb
-__ZN7WebCore10StringImpl8toDoubleEPb
-__ZN3JSC4Yarr6ParserINS0_23RegexPatternConstructorEE11parseEscapeILb1ENS3_28CharacterClassParserDelegateEEEbRT0_
-__ZN3JSC4Yarr12spacesCreateEv
-__ZN3WTF6VectorIN3JSC4Yarr14CharacterRangeELm0EE14expandCapacityEmPKS3_
-__ZN3WTF6VectorIN3JSC4Yarr14CharacterRangeELm0EE14expandCapacityEm
-__ZN3JSC4Yarr25CharacterClassConstructor6appendEPKNS0_14CharacterClassE
-__ZN3JSC4Yarr25CharacterClassConstructor14addSortedRangeERN3WTF6VectorINS0_14CharacterRangeELm0EEEtt
-__ZN3JSC4Yarr6ParserINS0_23RegexPatternConstructorEE28CharacterClassParserDelegate20atomPatternCharacterEt
-__ZN3JSC4Yarr14RegexGenerator24matchCharacterClassRangeENS_12X86Registers10RegisterIDERNS_22AbstractMacroAssemblerINS_12X86Asse
-__ZN3WTF6VectorIN3JSC22AbstractMacroAssemblerINS1_12X86AssemblerEE4JumpELm16EED1Ev
-_cti_op_nstricteq
-__ZN3JSC27ctiPatchCallByReturnAddressEPNS_9CodeBlockENS_16ReturnAddressPtrENS_21MacroAssemblerCodePtrE
-__ZNK3JSC8JSString9toBooleanEPNS_9ExecStateE
-_cti_op_is_string
-__ZN3JSCL16mathProtoFuncPowEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-_cti_op_get_by_id_proto_list_full
-_cti_op_put_by_id_transition_realloc
-_cti_timeout_check
-__ZN3JSC14TimeoutChecker10didTimeOutEPNS_9ExecStateE
-_cti_op_mul
-__ZN3JSC4Yarr23RegexPatternConstructor25atomBuiltInCharacterClassENS0_23BuiltInCharacterClassIDEb
-_cti_op_convert_this
-__ZNK3JSC8JSString12toThisObjectEPNS_9ExecStateE
-__ZN3JSC12StringObjectC1EN3WTF17NonNullPassRefPtrINS_9StructureEEEPNS_8JSStringE
-__ZN3JSCL22stringProtoFuncReplaceEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZNK3JSC7JSValue12toThisObjectEPNS_9ExecStateE
-__ZNK3JSC8JSObject8toStringEPNS_9ExecStateE
-__ZNK3JSC8JSObject11toPrimitiveEPNS_9ExecStateENS_22PreferredPrimitiveTypeE
-__ZNK3JSC8JSObject12defaultValueEPNS_9ExecStateENS_22PreferredPrimitiveTypeE
-__ZN3JSCL23stringProtoFuncToStringEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZNK3JSC12StringObject9classInfoEv
-__ZN7WebCore10StringImpl4costEv
-__ZN3JSC6JSCell11getCallDataERNS_8CallDataE
-__ZN3JSC24charCodeAtThunkGeneratorEPNS_12JSGlobalDataEPNS_14ExecutablePoolE
-__ZN3JSCL14stringCharLoadERNS_19SpecializedThunkJITE
-_cti_op_get_by_val_string
-_JSValueToBoolean
-_JSValueUnprotect
-_JSGlobalContextRelease
-__ZN3JSC4Heap17collectAllGarbageEv
-__ZN3JSC4Heap9markRootsEv
-__ZN3JSC4Heap30markStackObjectsConservativelyERNS_9MarkStackE
-__ZN3JSC4Heap31markCurrentThreadConservativelyERNS_9MarkStackE
-__ZN3JSC4Heap39markCurrentThreadConservativelyInternalERNS_9MarkStackE
-__ZN3JSC4Heap18markConservativelyERNS_9MarkStackEPvS3_
-__ZN3JSC9MarkStack12markChildrenEPNS_6JSCellE
-__ZN3JSC8JSObject12markChildrenERNS_9MarkStackE
-__ZN3JSC14JSGlobalObject12markChildrenERNS_9MarkStackE
-__ZN3JSCL12markIfNeededERNS_9MarkStackENS_7JSValueE
-__ZN3JSC10JSFunction12markChildrenERNS_9MarkStackE
-__ZN3JSC18FunctionExecutable13markAggregateERNS_9MarkStackE
-__ZN3JSC12JSActivation12markChildrenERNS_9MarkStackE
-__ZN3JSC15JSWrapperObject12markChildrenERNS_9MarkStackE
-__ZN3JSC7JSArray12markChildrenERNS_9MarkStackE
-__ZN3JSC18GlobalEvalFunction12markChildrenERNS_9MarkStackE
-__ZN3JSC9CodeBlock13markAggregateERNS_9MarkStackE
-__ZN3JSC16JSCallbackObjectINS_8JSObjectEE12markChildrenERNS_9MarkStackE
-__ZN3JSC19JSStaticScopeObject12markChildrenERNS_9MarkStackE
-__ZN3JSC9MarkStack12releaseStackEPvm
-__ZN3JSC4Heap20markProtectedObjectsERNS_9MarkStackE
-__ZN3JSC12SmallStrings12markChildrenERNS_9MarkStackE
-__ZN3JSC9MarkStack7compactEv
-__ZN3JSC4Heap5sweepEv
-__ZN3JSC12DateInstanceD1Ev
-__ZN3JSC9CodeBlock13unlinkCallersEv
-__ZN3JSC8JSObjectD1Ev
-__ZN3JSC12JSActivationD1Ev
-__ZN3JSC12JSActivationD2Ev
-__ZN3JSC12StringObjectD1Ev
-__ZN3JSC4Heap12resizeBlocksEv
-__ZN3WTF6VectorIPN3JSC14ExpressionNodeELm8EE14expandCapacityEm
-__ZN3WTF6VectorIPNS0_IN3JSC10RegisterIDELm32EEELm32EE14expandCapacityEmPKS4_
-__ZN3WTF6VectorIPNS0_IN3JSC10RegisterIDELm32EEELm32EE15reserveCapacityEm
-__ZN3JSC8VoidNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC4Yarr6ParserINS0_23RegexPatternConstructorEE15parseQuantifierEbjj
-__ZN3JSC4Yarr14RegexGenerator19TermGenerationState15jumpToBacktrackERNS_22AbstractMacroAssemblerINS_12X86AssemblerEE8JumpListEP
-__ZN3JSC4Yarr14wordcharCreateEv
-__ZN3JSC4Yarr12digitsCreateEv
-__ZN3JSC4Yarr14RegexGenerator30generatePatternCharacterGreedyERNS1_19TermGenerationStateE
-__ZN3WTF6VectorINS_6RefPtrIN3JSC10RegisterIDEEELm16EE14expandCapacityEm
-___initializeScavenger_block_invoke_1
-__Z22TCMalloc_SystemReleasePvm
-__Z21TCMalloc_SystemCommitPvm
-__ZNK3JSC7JSValue20toThisObjectSlowCaseEPNS_9ExecStateE
-__ZN3JSCL19mathProtoFuncRandomEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZNK3JSC7JSValue19synthesizePrototypeEPNS_9ExecStateE
-__ZN3JSCL23numberProtoFuncToStringEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC17NumberConstructor18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
-__ZN3JSCL25numberConstructorMaxValueEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
-__ZN3JSC18sqrtThunkGeneratorEPNS_12JSGlobalDataEPNS_14ExecutablePoolE
-__ZN3JSC3JIT26privateCompileGetByIdProtoEPNS_17StructureStubInfoEPNS_9StructureES4_RKNS_10IdentifierERKNS_12PropertySlotEmNS_16
-__ZN3JSC8JSObject3putEPNS_9ExecStateEjNS_7JSValueE
-__ZN3JSC10Identifier4fromEPNS_9ExecStateEj
-__ZN3JSC4Yarr13newlineCreateEv
-__ZN3JSC4Yarr14RegexGenerator29generateAssertionWordBoundaryERNS1_19TermGenerationStateE
-__ZN3JSC4Yarr14RegexGenerator22matchAssertionWordcharERNS1_19TermGenerationStateERNS_22AbstractMacroAssemblerINS_12X86Assembler
-__ZN3JSCL26stringProtoFuncToLowerCaseEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL22stringProtoFuncIndexOfEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZNK3JSC7UString4findERKS0_j
-__ZN3JSC17RegExpConstructor18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
-__ZN3JSC17RegExpConstructor16getConstructDataERNS_13ConstructDataE
-__ZN3JSCL30constructWithRegExpConstructorEPNS_9ExecStateEPNS_8JSObjectERKNS_7ArgListE
-__ZN3JSC15constructRegExpEPNS_9ExecStateERKNS_7ArgListE
-__ZNK3JSC6JSCell9classInfoEv
-__ZN3JSCL19regExpProtoFuncExecEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC12RegExpObject4execEPNS_9ExecStateERKNS_7ArgListE
+__ZN3WTF6VectorIN3JSC4Yarr13YarrGenerator17BacktrackingState19ReturnAddressRecordELm4EE14expandCapacityEm
+__ZN3JSCL19regExpProtoFuncExecEPNS_9ExecStateE
+__ZN3JSC12RegExpObject4execEPNS_9ExecStateE
__ZNK3JSC17RegExpConstructor14arrayOfMatchesEPNS_9ExecStateE
__ZN3JSC18RegExpMatchesArrayC2EPNS_9ExecStateEPNS_24RegExpConstructorPrivateE
-__ZN3JSC7JSArrayC2EN3WTF17NonNullPassRefPtrINS_9StructureEEEj
+__ZN3JSC7JSArrayC2ERNS_12JSGlobalDataEPNS_9StructureEjNS_17ArrayCreationModeE
__ZN3JSC7JSArray15setSubclassDataEPv
-__ZN3JSCL24regExpConstructorDollar1EPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
-__ZNK3JSC17RegExpConstructor10getBackrefEPNS_9ExecStateEj
-__ZN3JSC20globalFuncParseFloatEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-_cti_op_put_by_id_generic
-__ZN3JSC17BytecodeGenerator29uncheckedRegisterForArgumentsEv
-__ZN3JSC3JIT22emit_op_init_argumentsEPNS_11InstructionE
-__ZN3JSC3JIT24emit_op_create_argumentsEPNS_11InstructionE
-__ZN3JSC20MacroAssemblerX86_6413branchTestPtrENS_23MacroAssemblerX86Common9ConditionENS_22AbstractMacroAssemblerINS_12X86Assemb
-_cti_op_load_varargs
-__ZN3JSC3JIT19patchPutByIdReplaceEPNS_9CodeBlockEPNS_17StructureStubInfoEPNS_9StructureEmNS_16ReturnAddressPtrE
-__ZN3JSC21ThrowableBinaryOpNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSCL20stringProtoFuncSplitEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-_cti_op_in
-__ZN3JSCL19arrayProtoFuncShiftEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZNK3JSC7JSValue8toUInt32EPNS_9ExecStateE
-__ZN3JSC7JSArray18getOwnPropertySlotEPNS_9ExecStateEjRNS_12PropertySlotE
-__ZN3JSC7JSArray14deletePropertyEPNS_9ExecStateEj
-__ZN3JSC7JSArray3putEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueERNS_15PutPropertySlotE
-__ZN3JSC7JSArray9setLengthEj
-__ZN3JSC23CallFunctionCallDotNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC17BytecodeGenerator25emitJumpIfNotFunctionCallEPNS_10RegisterIDEPNS_5LabelE
-_cti_op_create_arguments
-__ZN3JSC9Arguments18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
-__ZN3JSC3JIT30privateCompileGetByIdProtoListEPNS_17StructureStubInfoEPNS_30PolymorphicAccessStructureListEiPNS_9StructureES6_RK
-__ZN3JSC9ForInNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC17BytecodeGenerator20emitGetPropertyNamesEPNS_10RegisterIDES2_S2_S2_PNS_5LabelE
-__ZN3WTF6VectorIN3JSC12ForInContextELm0EE15reserveCapacityEm
-__ZN3JSC17BytecodeGenerator20emitNextPropertyNameEPNS_10RegisterIDES2_S2_S2_S2_PNS_5LabelE
-__ZN3JSC3JIT18emit_op_get_pnamesEPNS_11InstructionE
-__ZN3JSC3JIT20emit_op_get_by_pnameEPNS_11InstructionE
-__ZN3JSC3JIT22compileGetDirectOffsetENS_12X86Registers10RegisterIDES2_S2_S2_S2_
-__ZN3JSC3JIT18emit_op_next_pnameEPNS_11InstructionE
-__ZN3JSC3JIT24emitSlow_op_get_by_pnameEPNS_11InstructionERPNS_13SlowCaseEntryE
-_cti_op_get_pnames
-__ZN3JSC22JSPropertyNameIterator6createEPNS_9ExecStateEPNS_8JSObjectE
-__ZN3JSC8JSObject16getPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayENS_15EnumerationModeE
-__ZN3JSC8JSObject19getOwnPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayENS_15EnumerationModeE
-__ZN3JSC9Structure16getPropertyNamesERNS_17PropertyNameArrayENS_15EnumerationModeE
-__ZN3JSCL29objectProtoFuncHasOwnPropertyEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZNK3JSC8JSObject14hasOwnPropertyEPNS_9ExecStateERKNS_10IdentifierE
-__ZN3JSC8JSObject18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
-_cti_op_typeof
-__ZN3JSC20jsTypeStringForValueEPNS_9ExecStateENS_7JSValueE
-__ZN3JSC9Structure27despecifyFunctionTransitionEPS0_RKNS_10IdentifierE
-_cti_has_property
-__ZN3JSC3JIT26emit_op_tear_off_argumentsEPNS_11InstructionE
-__ZN3JSCL19arrayProtoFuncSliceEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL11getPropertyEPNS_9ExecStateEPNS_8JSObjectEj
-__ZN3JSC9Arguments18getOwnPropertySlotEPNS_9ExecStateEjRNS_12PropertySlotE
-_cti_op_tear_off_arguments
-__ZN3JSC10JSFunction19getOwnPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayENS_15EnumerationModeE
-__ZNK3JSC10JSFunction9classInfoEv
-__ZN3JSC17DeleteBracketNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC17BytecodeGenerator15emitDeleteByValEPNS_10RegisterIDES2_S2_
-__ZN3JSC8JSObject18getOwnPropertySlotEPNS_9ExecStateEjRNS_12PropertySlotE
-_cti_op_del_by_val
-__ZN3JSC8JSObject14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE
-_cti_op_is_boolean
-__ZN3JSC10SwitchNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC13CaseBlockNode20emitBytecodeForBlockERNS_17BytecodeGeneratorEPNS_10RegisterIDES4_
-__ZN3JSC13CaseBlockNode18tryOptimizedSwitchERN3WTF6VectorIPNS_14ExpressionNodeELm8EEERiS7_
-__ZN3JSCL17processClauseListEPNS_14ClauseListNodeERN3WTF6VectorIPNS_14ExpressionNodeELm8EEERNS_10SwitchKindERbRiSB_
-__ZN3JSC17BytecodeGenerator11beginSwitchEPNS_10RegisterIDENS_10SwitchInfo10SwitchTypeE
-__ZN3WTF6VectorIN3JSC10SwitchInfoELm0EE14expandCapacityEm
-__ZN3JSC17BytecodeGenerator9endSwitchEjPN3WTF6RefPtrINS_5LabelEEEPPNS_14ExpressionNodeEPS3_ii
-__ZN3WTF6VectorIN3JSC15SimpleJumpTableELm0EE14expandCapacityEm
-__ZNK3JSC5Label4bindEii
-__ZN3JSC3JIT18emit_op_switch_immEPNS_11InstructionE
-__ZN3WTF6VectorIN3JSC12SwitchRecordELm0EE14expandCapacityEm
-__ZN3WTF6VectorIN3JSC17CodeLocationLabelELm0EE4growEm
-_cti_op_switch_imm
-__ZN3JSC4Yarr23RegexPatternConstructor8copyTermERNS0_11PatternTermE
-__ZL14compileBracketiPiPPhPPKtS3_P9ErrorCodeiS_S_R11CompileData
-__ZL32branchFindFirstAssertedCharacterPKhb
-__ZL20branchNeedsLineStartPKhjj
-__ZL17bracketIsAnchoredPKh
-_cti_op_get_by_id_array_fail
-__ZN3JSC17PropertyNameArray3addEPN7WebCore10StringImplE
-__ZN3WTF7HashSetIPN7WebCore10StringImplENS_7PtrHashIS3_EENS_10HashTraitsIS3_EEE3addERKS3_
-__ZN3WTF9HashTableIPN7WebCore10StringImplES3_NS_17IdentityExtractorIS3_EENS_7PtrHashIS3_EENS_10HashTraitsIS3_EES9_E6rehashEi
-__ZN3WTF6VectorIN3JSC10IdentifierELm20EE14expandCapacityEm
-__ZN3JSCL28numberConstructorPosInfinityEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
-__ZN3JSCL28numberConstructorNegInfinityEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
-__ZN3JSC4Heap5resetEv
-__ZN3JSC9Arguments12markChildrenERNS_9MarkStackE
-__ZN3JSC22JSPropertyNameIterator12markChildrenERNS_9MarkStackE
-__ZN3JSC3JIT10unlinkCallEPNS_12CallLinkInfoE
-__ZN3JSC9LabelNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC18RegExpMatchesArray18getOwnPropertySlotEPNS_9ExecStateEjRNS_12PropertySlotE
+__ZNK3JSC7JSArray12subclassDataEv
+__ZN3JSC18RegExpMatchesArray17fillArrayInstanceEPNS_9ExecStateE
+__ZN3JSCL20stringProtoFuncMatchEPNS_9ExecStateE
+__ZN3JSC4Yarr22YarrPatternConstructor25atomBuiltInCharacterClassENS0_23BuiltInCharacterClassIDEb
+__ZN3JSC4Yarr12spacesCreateEv
+__ZN3JSC28globalFuncDecodeURIComponentEPNS_9ExecStateE
+__ZN3JSCL6decodeEPNS_9ExecStateEPKcb
+__ZN3WTF6VectorItLm64EE9tryAppendItEEbPKT_m
+__ZN3WTF7Unicode18UTF8SequenceLengthEc
+__ZN3WTF7Unicode18decodeUTF8SequenceEPKc
+__ZN3WTF6VectorItLm64EE18tryReserveCapacityEm
+__ZN3JSCL24stringProtoFuncSubstringEPNS_9ExecStateE
+__ZN3JSC16globalFuncEscapeEPNS_9ExecStateE
+__ZN3JSC16ArrayConstructor16getConstructDataERNS_13ConstructDataE
+__ZN3JSCL29constructWithArrayConstructorEPNS_9ExecStateE
+__ZN3JSCL27constructArrayWithSizeQuirkEPNS_9ExecStateERKNS_7ArgListE
+__ZN3JSC13PrefixDotNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC17BytecodeGenerator11emitPostDecEPNS_10RegisterIDES2_
+__ZN3JSC3JIT16emit_op_post_decEPNS_11InstructionE
+__ZN3JSC3JIT20emitSlow_op_post_decEPNS_11InstructionERPNS_13SlowCaseEntryE
+__ZN3JSC3JIT22emit_op_loop_if_lesseqEPNS_11InstructionE
+__ZN3JSC3JIT26emitSlow_op_loop_if_lesseqEPNS_11InstructionERPNS_13SlowCaseEntryE
+_cti_op_pre_dec
+__ZN3JSC7JSArray19getOwnPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayENS_15EnumerationModeE
+__ZN3JSC10Identifier4fromEPNS_9ExecStateEj
+__ZN3JSC7UString6numberEj
+__ZN3JSC17PropertyNameArray3addEPN3WTF10StringImplE
+__ZN3JSC9ExecState19arrayPrototypeTableEPS0_
+__ZN3JSC3JIT22emit_op_put_scoped_varEPNS_11InstructionE
+__ZN3JSC12JSGlobalData15getHostFunctionEPFPvPNS_9ExecStateEEPFNS_21MacroAssemblerCodePtrEPS0_PNS_14ExecutablePoolEE
+__ZN3JSC9JITThunks16hostFunctionStubEPNS_12JSGlobalDataEPFPvPNS_9ExecStateEEPFNS_21MacroAssemblerCodePtrES2_PNS_14ExecutablePoolEE
+__ZN3JSC20charAtThunkGeneratorEPNS_12JSGlobalDataEPNS_14ExecutablePoolE
+__ZN3JSCL14stringCharLoadERNS_19SpecializedThunkJITE
+__ZN3JSCL12charToStringERNS_19SpecializedThunkJITEPNS_12JSGlobalDataENS_12X86Registers10RegisterIDES5_S5_
+__ZN3JSC19SpecializedThunkJIT8finalizeENS_21MacroAssemblerCodePtrE
+__ZN3JSC10JSFunctionC1EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureEiRKNS_10IdentifierEPNS_16NativeExecutableE
+__ZN3JSC10JSFunctionC2EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureEiRKNS_10IdentifierEPNS_16NativeExecutableE
+__ZN3JSCL21stringProtoFuncCharAtEPNS_9ExecStateE
+__ZN3WTF14FastMallocZone9forceLockEP14_malloc_zone_t
+__ZN3WTF14FastMallocZone11forceUnlockEP14_malloc_zone_t
+__ZN3WTF6VectorIPN3JSC9StructureELm8EE14expandCapacityEm
+__ZN3JSCL21stringProtoFuncSearchEPNS_9ExecStateE
+__ZN3JSC3JIT30privateCompileGetByIdProtoListEPNS_17StructureStubInfoEPNS_30PolymorphicAccessStructureListEiPNS_9StructureES6_RKNS_10IdentifierERKNS_12PropertySlotEmPNS_9ExecStateE
+__ZN3WTF6VectorItLm0EE14expandCapacityEmPKt
+__ZN3JSC4Yarr13YarrGenerator24matchCharacterClassRangeENS_12X86Registers10RegisterIDERNS_22AbstractMacroAssemblerINS_12X86AssemblerEE8JumpListES8_PKNS0_14CharacterRangeEjPjPKtj
+__ZN3JSC12X86Assembler23X86InstructionFormatter11memoryModRMEiNS_12X86Registers10RegisterIDES3_ii
+__ZN3JSC23MacroAssemblerX86Common8branch32ENS0_19RelationalConditionENS_12X86Registers10RegisterIDES3_
+__ZN3JSC4Yarr13YarrGenerator17BacktrackingState24takeBacktracksToJumpListERNS_22AbstractMacroAssemblerINS_12X86AssemblerEE8JumpListEPNS_14MacroAssemblerE
+_cti_op_get_by_id_proto_list_full
+__ZN3WTF6VectorIN3JSC4Yarr13YarrGenerator6YarrOpELm128EE14expandCapacityEmPKS4_
+__ZN3WTF6VectorIN3JSC4Yarr13YarrGenerator6YarrOpELm128EE15reserveCapacityEm
+__ZN3JSCL26stringProtoFuncLastIndexOfEPNS_9ExecStateE
+__ZNK3JSC7JSValue20toIntegerPreserveNaNEPNS_9ExecStateE
+__ZN3JSC17RegExpConstructor16getConstructDataERNS_13ConstructDataE
+__ZN3JSCL30constructWithRegExpConstructorEPNS_9ExecStateE
+__ZN3JSC15constructRegExpEPNS_9ExecStateEPNS_14JSGlobalObjectERKNS_7ArgListE
+__ZNK3JSC7JSValue19synthesizePrototypeEPNS_9ExecStateE
+__ZN3JSC16BooleanPrototype18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
+__ZN3JSC3JIT22compileGetDirectOffsetENS_12X86Registers10RegisterIDES2_PNS_9StructureEm
+__ZN3JSC3JIT15emit_op_resolveEPNS_11InstructionE
+_JSWeakObjectMapRemove
+__ZN3WTF7HashMapIPvPN3JSC7JSValueENS_7PtrHashIS1_EENS_10HashTraitsIS1_EENS7_IS4_EEE4takeERKS1_
+_JSObjectSetPrivate
+_cti_op_put_by_id_fail
+__ZN3JSC4Heap16allocateSlowCaseEm
+__ZN3JSC9CodeBlock14visitAggregateERNS_9MarkStackE
+__ZN3JSC13EvalCodeCache14visitAggregateERNS_9MarkStackE
+__ZN3JSC17StructureStubInfo14visitAggregateERNS_9MarkStackE
+__ZN3JSC14StructureChain13visitChildrenERNS_9MarkStackE
+__ZN3JSC12JSActivation13visitChildrenERNS_9MarkStackE
+__ZN3JSC15WeakHandleOwner26isReachableFromOpaqueRootsENS_6HandleINS_7UnknownEEEPvRNS_9MarkStackE
+__ZN3JSC9WeakGCMapIPvNS_8JSObjectENS_33DefaultWeakGCMapFinalizerCallbackIS1_S2_EEN3WTF7PtrHashIS1_EENS5_10HashTraitsIS1_EEE8finalizeENS_6HandleINS_7UnknownEEES1_
+__ZN3JSC20JSCallbackObjectData8finalizeENS_6HandleINS_7UnknownEEEPv
+__ZN3WTF7HashMapISt4pairINS_6RefPtrINS_10StringImplEEEjEPN3JSC7JSValueENS6_24StructureTransitionTable4HashENS9_10HashTraitsENS_10HashTraitsIS8_EEE4takeERKS5_
__ZN3JSC12RegExpObjectD1Ev
+__ZN3JSC12JSActivationD1Ev
+__ZN3JSC16JSCallbackObjectINS_24JSObjectWithGlobalObjectEED1Ev
+__ZN3JSC20JSCallbackObjectDataD0Ev
+_JSClassRelease
+__ZN3JSC15WeakHandleOwnerD2Ev
+__ZN3JSC14ExecutablePool13systemReleaseERNS0_10AllocationE
+__ZN3WTF11OSAllocator8decommitEPvm
__ZN3JSC18RegExpMatchesArrayD1Ev
-__ZNK3JSC7JSArray12subclassDataEv
-__ZN3JSC15ObjectPrototype18getOwnPropertySlotEPNS_9ExecStateEjRNS_12PropertySlotE
__ZN3JSC22JSPropertyNameIteratorD1Ev
-__ZN3JSC22JSPropertyNameIteratorD2Ev
-__ZNK3JSC7JSArray9classInfoEv
-__ZN3JSC7JSArray15copyToRegistersEPNS_9ExecStateEPNS_8RegisterEj
+__ZN3JSC14StructureChainD1Ev
+__ZN3JSC18JSCallbackFunctionD1Ev
+__ZN3JSC9WeakGCMapISt4pairIN3WTF6RefPtrINS2_10StringImplEEEjENS_9StructureENS_24StructureTransitionTable26WeakGCMapFinalizerCallbackENS8_4HashENS8_10HashTraitsEE8finalizeENS_6HandleINS_7UnknownEEEPv
+__ZN3JSC9WeakGCMapISt4pairIN3WTF6RefPtrINS2_10StringImplEEEjENS_9StructureENS_24StructureTransitionTable26WeakGCMapFinalizerCallbackENS8_4HashENS8_10HashTraitsEED0Ev
+__ZN3JSC9WeakGCMapISt4pairIN3WTF6RefPtrINS2_10StringImplEEEjENS_9StructureENS_24StructureTransitionTable26WeakGCMapFinalizerCallbackENS8_4HashENS8_10HashTraitsEED1Ev
+__ZN3JSC18FunctionExecutableD1Ev
+_cti_op_put_by_id_transition_realloc
+__ZN3JSC22createNotAnObjectErrorEPNS_9ExecStateENS_7JSValueE
+__ZN3JSC11makeUStringIPKcNS_7UStringES2_EES3_T_T0_T1_
+__ZN3WTF13tryMakeStringIPKcN3JSC7UStringES2_EENS_10PassRefPtrINS_10StringImplEEET_T0_T1_
+__ZN3JSC15createTypeErrorEPNS_9ExecStateERKNS_7UStringE
+__ZN3JSC13ErrorInstance6createEPNS_12JSGlobalDataEPNS_9StructureERKNS_7UStringE
+__ZN3JSC13ErrorInstanceC2EPNS_12JSGlobalDataEPNS_9StructureERKNS_7UStringE
+__ZN3JSC10throwErrorEPNS_9ExecStateEPNS_8JSObjectE
+__ZN3JSC13JSNotAnObject18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
+__ZN3JSCL23returnToThrowTrampolineEPNS_12JSGlobalDataENS_16ReturnAddressPtrERS2_
+_ctiVMThrowTrampoline
+_cti_vm_throw
+__ZN3JSC11Interpreter14throwExceptionERPNS_9ExecStateERNS_7JSValueEj
+__ZNK3JSC13ErrorInstance15isErrorInstanceEv
+__ZNK3JSC8JSObject13exceptionTypeEv
+__ZN3JSC9CodeBlock24handlerForBytecodeOffsetEj
+__ZN3JSC11Interpreter15unwindCallFrameERPNS_9ExecStateENS_7JSValueERjRPNS_9CodeBlockE
+_ctiOpThrowNotCaught
+__ZN3JSC14ErrorPrototype18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
+__ZN3JSCL22errorProtoFuncToStringEPNS_9ExecStateE
+__ZN3WTF13tryMakeStringIN3JSC7UStringEPKcS2_EENS_10PassRefPtrINS_10StringImplEEET_T0_T1_
+__ZN3JSC13JSNotAnObjectD1Ev
+__ZN3JSC13ErrorInstanceD1Ev
+__ZN3WTF10StringImpl16findIgnoringCaseEPKcj
+_cti_op_is_undefined
+__ZN3JSC21ReadModifyResolveNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC17NumberConstructor18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
+__ZN3JSC13jsAddSlowCaseEPNS_9ExecStateENS_7JSValueES2_
+__ZNK3JSC8JSString11toPrimitiveEPNS_9ExecStateENS_22PreferredPrimitiveTypeE
+__ZN3JSC3JIT19patchPutByIdReplaceEPNS_9CodeBlockEPNS_17StructureStubInfoEPNS_9StructureEmNS_16ReturnAddressPtrEb
+_cti_op_get_by_id_getter_stub
+__ZN3JSC10ASTBuilder11makeDivNodeEPNS_14ExpressionNodeES2_b
+__ZN3JSC3JIT11emit_op_divEPNS_11InstructionE
+__ZN3JSC3JIT15emitSlow_op_divEPNS_11InstructionERPNS_13SlowCaseEntryE
+_cti_op_lesseq
+__ZN3JSC9Structure24removePropertyTransitionERNS_12JSGlobalDataEPS0_RKNS_10IdentifierERm
+__ZN3JSC9Structure6removeERKNS_10IdentifierE
+__ZN3WTF6VectorIjLm0EE14expandCapacityEm
+__ZN3JSC9Structure31removePropertyWithoutTransitionERNS_12JSGlobalDataERKNS_10IdentifierE
+__ZN3JSC12GetterSetter13visitChildrenERNS_9MarkStackE
+__ZN3JSC9Arguments13visitChildrenERNS_9MarkStackE
+__ZN3JSC14JSGlobalObject17WeakMapsFinalizer8finalizeENS_6HandleINS_7UnknownEEEPv
+__ZN3JSC12StringObjectD1Ev
__ZN3JSC9ArgumentsD1Ev
__ZN3JSC9ArgumentsD2Ev
-__ZN3JSC7UString4fromEd
-__ZN3WTF32doubleToStringInJavaScriptFormatEdPcPj
-__ZN3WTF4dtoaEPcdiPiS1_PS0_
-__ZN3JSC10Identifier11addSlowCaseEPNS_12JSGlobalDataEPN7WebCore10StringImplE
-__ZN3WTF6VectorIPN3JSC9StructureELm8EE14expandCapacityEm
-_cti_op_resolve_base
-__ZN3JSC12JSActivation18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
-__ZN3JSC20charAtThunkGeneratorEPNS_12JSGlobalDataEPNS_14ExecutablePoolE
-__ZN3JSCL21stringProtoFuncCharAtEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC17PrefixBracketNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC14PostfixDotNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC17BytecodeGenerator11emitPostIncEPNS_10RegisterIDES2_
-__ZN3JSC3JIT16emit_op_post_incEPNS_11InstructionE
-__ZN3JSC3JIT20emitSlow_op_post_incEPNS_11InstructionERPNS_13SlowCaseEntryE
-__ZN3JSC18PostfixBracketNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC17BytecodeGenerator18pushFinallyContextEPNS_5LabelEPNS_10RegisterIDE
-__ZN3JSC17BytecodeGenerator17popFinallyContextEv
-__ZN3JSC17BytecodeGenerator19highestUsedRegisterEv
-__ZN3JSC17BytecodeGenerator18emitJumpSubroutineEPNS_10RegisterIDEPNS_5LabelE
-__ZN3JSC17BytecodeGenerator20emitSubroutineReturnEPNS_10RegisterIDE
-__ZN3JSC3JIT11emit_op_jsrEPNS_11InstructionE
-__ZN3WTF6VectorIN3JSC3JIT7JSRInfoELm0EE14expandCapacityEm
+__ZN3JSC19SourceProviderCacheD1Ev
+__ZN3WTF20deleteAllPairSecondsIPN3JSC23SourceProviderCacheItemEKNS_7HashMapIiS3_NS_7IntHashIjEENS_10HashTraitsIiEENS7_IS3_EEEEEEvRT0_
+__ZN3WTF6VectorIN3JSC8LineInfoELm0EE14expandCapacityEm
+__ZN3WTF6VectorIN3JSC19ExpressionRangeInfoELm0EE14expandCapacityEm
+__ZNK3WTF6String8toDoubleEPbS1_
+__ZN3WTF6String6appendEc
+__ZN3WTF6String6numberEt
+__ZNK3WTF6String8foldCaseEv
+__ZN3WTF10StringImpl8foldCaseEv
+__ZN3JSC15NumberPrototype18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
+__ZN3JSCL23numberProtoFuncToStringEPNS_9ExecStateE
+__ZN3JSC3JIT20emit_op_resolve_skipEPNS_11InstructionE
+_cti_op_resolve_skip
+__ZN3JSC19SourceProviderCache5clearEv
+__ZN3WTF11OSAllocator18releaseDecommittedEPvm
+__ZN3WTFeqERKNS_12AtomicStringEPKc
+_JSStringIsEqualToUTF8CString
+__ZN3JSC12RegisterFile17GlobalObjectOwner8finalizeENS_6HandleINS_7UnknownEEEPv
+__ZN3JSC12GetterSetterD1Ev
+__ZN3WTF6VectorIPNS0_IN3JSC10IdentifierELm64EEELm32EE14expandCapacityEm
+__ZNK3WTF6String18simplifyWhiteSpaceEv
+__ZN3WTF10StringImpl18simplifyWhiteSpaceEv
+__ZN3JSC22JSPropertyNameIterator13visitChildrenERNS_9MarkStackE
+__ZN3WTFL43initializeMainThreadToProcessMainThreadOnceEv
+__ZN3WTF47initializeMainThreadToProcessMainThreadPlatformEv
+__ZN3WTF6String6numberEd
+__ZN3WTF10StringImpl5upperEv
+__ZN3WTF6String6removeEji
+__ZN3WTF6String6insertERKS0_j
+__ZN3WTF6String6insertEPKtjj
+__ZN3WTF10StringImpl7replaceEPS0_S1_
+__ZNK3WTF6String5splitEtbRNS_6VectorIS0_Lm0EEE
+__ZN3JSC12JSGlobalData18createContextGroupENS_15ThreadStackTypeE
+__ZN3JSC12JSGlobalData22clearBuiltinStructuresEv
+__ZN3JSC4Heap7destroyEv
+__ZN3JSC9JITThunks22clearHostFunctionStubsEv
+__ZN3JSC11MarkedSpace7destroyEv
+__ZN3JSC12JSGlobalDataD1Ev
+__ZN3JSC12JSGlobalDataD2Ev
+__ZN3JSC12RegisterFileD1Ev
+__ZN3JSC12RegisterFileD2Ev
+__ZNK3JSC9HashTable11deleteTableEv
+__ZN3JSC5LexerD1Ev
+__ZN3WTF20deleteAllPairSecondsIP24OpaqueJSClassContextDataKNS_7HashMapIP13OpaqueJSClassS2_NS_7PtrHashIS5_EENS_10HashTraitsIS5_EENS8_IS2_EEEEEEvRT0_
+__ZN24OpaqueJSClassContextDataD1Ev
+__ZN24OpaqueJSClassContextDataD2Ev
+__ZN3JSC17CommonIdentifiersD2Ev
+__ZN3JSC21deleteIdentifierTableEPNS_15IdentifierTableE
+__ZN3JSC15IdentifierTableD2Ev
+__ZN3JSC4HeapD1Ev
+__ZN3JSC4HeapD2Ev
+__ZN3JSC14MachineThreadsD1Ev
+__ZN3JSC14MachineThreadsD2Ev
+__ZN3JSC25DefaultGCActivityCallbackD0Ev
+__ZN3JSC9JITThunksD1Ev
+__ZN3JSC12SmallStringsD1Ev
+__ZN13OpaqueJSClass26createNoAutomaticPrototypeEPK17JSClassDefinition
+__ZN3JSC16JSCallbackObjectINS_14JSGlobalObjectEEC2ERNS_12JSGlobalDataEP13OpaqueJSClassPNS_9StructureE
+__ZN3JSC16JSCallbackObjectINS_14JSGlobalObjectEE4initEPNS_9ExecStateE
+__ZN3JSC16JSCallbackObjectINS_14JSGlobalObjectEE18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
+__ZN13OpaqueJSClass12staticValuesEPN3JSC9ExecStateE
+__ZN13OpaqueJSClass15staticFunctionsEPN3JSC9ExecStateE
+__ZN3JSC14JSGlobalObject14resetPrototypeERNS_12JSGlobalDataENS_7JSValueE
+_JSReportExtraMemoryCost
+_JSValueIsObject
+_JSValueMakeNull
+_JSObjectSetPrototype
+_JSStringCreateWithCharacters
+_JSValueGetType
+__ZN3JSC16JSCallbackObjectINS_14JSGlobalObjectEE3putEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueERNS_15PutPropertySlotE
+_JSGarbageCollect
+__ZN3JSC16JSCallbackObjectINS_14JSGlobalObjectEE13visitChildrenERNS_9MarkStackE
+__ZN3JSC11makeUStringINS_7UStringES1_EES1_T_T0_
+__ZN3WTF13tryMakeStringIN3JSC7UStringES2_EENS_10PassRefPtrINS_10StringImplEEET_T0_
+__ZN3WTF13StringBuilder6appendEc
+_JSEvaluateScript
+__ZNK3JSC14JSGlobalObject17supportsProfilingEv
+__ZNK3JSC14JSGlobalObject22supportsRichSourceInfoEv
+__ZN3JSC8JSParser19parseThrowStatementINS_10ASTBuilderEEENT_9StatementERS3_
+__ZN3JSC9ThrowNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
__ZN3JSC3JIT13emit_op_throwEPNS_11InstructionE
-__ZN3JSC3JIT12emit_op_sretEPNS_11InstructionE
-__ZN3JSC21ReadModifyBracketNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-_cti_op_lesseq
-__ZN3JSCL20stringProtoFuncMatchEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC18RegExpMatchesArray18getOwnPropertySlotEPNS_9ExecStateEjRNS_12PropertySlotE
-__ZN3JSC18RegExpMatchesArray17fillArrayInstanceEPNS_9ExecStateE
-__ZN3JSC14jsReplaceRangeEPNS_9ExecStateERKNS_7UStringEiiS4_
-__ZN3JSC18RegExpMatchesArray18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
-__ZNK3JSC8JSObject11hasPropertyEPNS_9ExecStateEj
-__ZN3JSCL24stringProtoFuncSubstringEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-_cti_op_create_arguments_no_params
-__ZN3JSCL21arrayProtoFuncUnShiftEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-_cti_op_pre_dec
-_cti_op_is_undefined
-__ZN3JSC13DeleteDotNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC17BytecodeGenerator14emitDeleteByIdEPNS_10RegisterIDES2_RKNS_10IdentifierE
-__ZN3JSC23FunctionCallBracketNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC3JIT17emit_op_del_by_idEPNS_11InstructionE
-_cti_op_del_by_id
-__ZN3WTF37parseDateFromNullTerminatedCharactersEPKc
-__ZN3WTFL37parseDateFromNullTerminatedCharactersEPKcRbRi
-_cti_op_get_by_id_proto_fail
-__ZN3JSC17constructFunctionEPNS_9ExecStateERKNS_7ArgListERKNS_10IdentifierERKNS_7UStringEi
-__ZN3WTF6VectorItLm64EE15reserveCapacityEm
+_cti_op_throw
+__ZNK3JSC7JSValue16toObjectSlowCaseEPNS_9ExecStateEPNS_14JSGlobalObjectE
+__ZNK3JSC8JSObject8toNumberEPNS_9ExecStateE
+_JSValueIsEqual
+__ZN3JSC7JSValue13equalSlowCaseEPNS_9ExecStateES0_S0_
+__ZN3JSC8JSObject18getOwnPropertySlotEPNS_9ExecStateEjRNS_12PropertySlotE
+__ZN3JSC10throwErrorEPNS_9ExecStateENS_7JSValueE
+__ZNK3JSC8JSString8toNumberEPNS_9ExecStateE
+__ZN3JSC10jsToNumberERKNS_7UStringE
+_JSStringGetLength
+_JSStringGetCharactersPtr
+_JSStringGetMaximumUTF8CStringSize
+_JSStringGetUTF8CString
+_JSValueIsStrictEqual
+__ZN3JSC21UStringSourceProviderD0Ev
+_JSCheckScriptSyntax
+__ZN3JSC11checkSyntaxEPNS_9ExecStateERKNS_10SourceCodeE
+__ZN3JSC17ProgramExecutable11checkSyntaxEPNS_9ExecStateE
+__ZN3WTF6VectorIN3JSC9LabelInfoELm0EE14expandCapacityEmPKS2_
+__ZN3WTF6VectorIN3JSC9LabelInfoELm0EE15reserveCapacityEm
+__ZN3JSC17createSyntaxErrorEPNS_14JSGlobalObjectERKNS_7UStringE
+__ZN3JSC12addErrorInfoEPNS_12JSGlobalDataEPNS_8JSObjectEiRKNS_10SourceCodeE
+__ZN3JSC8JSObject17putWithAttributesEPNS_12JSGlobalDataERKNS_10IdentifierENS_7JSValueEj
+_JSObjectCallAsConstructor
+__ZN3JSC9constructEPNS_9ExecStateENS_7JSValueENS_13ConstructTypeERKNS_13ConstructDataERKNS_7ArgListE
+__ZN3JSC11Interpreter16executeConstructEPNS_9ExecStateEPNS_8JSObjectENS_13ConstructTypeERKNS_13ConstructDataERKNS_7ArgListE
+__ZN3JSC15ObjectPrototype18getOwnPropertySlotEPNS_9ExecStateEjRNS_12PropertySlotE
+_JSObjectSetPropertyAtIndex
+_JSObjectMakeFunction
+__ZN3JSC17constructFunctionEPNS_9ExecStateEPNS_14JSGlobalObjectERKNS_7ArgListERKNS_10IdentifierERKNS_7UStringEi
+__ZN3JSC8JSParser8popScopeERNS0_15AutoPopScopeRefEb
+__ZN3JSCL25functionProtoFuncToStringEPNS_9ExecStateE
+__ZNK3JSC21UStringSourceProvider8getRangeEii
+__ZNK3JSC18FunctionExecutable11paramStringEv
+__ZN3WTF13tryMakeStringIPKcN3JSC7UStringES2_S4_S2_S4_EENS_10PassRefPtrINS_10StringImplEEET_T0_T1_T2_T3_T4_
+_JSObjectMakeFunctionWithCallback
+_JSObjectMakeConstructor
+__ZN3JSC21JSCallbackConstructorC1EPNS_14JSGlobalObjectEPNS_9StructureEP13OpaqueJSClassPFP13OpaqueJSValuePK15OpaqueJSContextS8_mPKPKS7_PSD_E
+_JSPropertyNameArrayGetNameAtIndex
+_JSObjectMakeDate
+__ZN3JSC13constructDateEPNS_9ExecStateEPNS_14JSGlobalObjectERKNS_7ArgListE
+__ZN3JSC12DateInstanceC1EPNS_9ExecStateEPNS_9StructureEd
+__ZN3WTF8timeClipEd
+__ZN3JSC13DatePrototype18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
+__ZN3JSCL21dateProtoFuncToStringEPNS_9ExecStateE
+__ZNK3JSC12DateInstance26calculateGregorianDateTimeEPNS_9ExecStateE
+__ZN3JSC21msToGregorianDateTimeEPNS_9ExecStateEdbRNS_17GregorianDateTimeE
+__ZN3JSCL12getDSTOffsetEPNS_9ExecStateEdd
+__ZN3WTF18calculateDSTOffsetEdd
+__ZN3WTF18dateToDaysFrom1970Eiii
+__ZN3JSC10formatDateERKNS_17GregorianDateTimeERA100_c
+__ZN3JSC10formatTimeERKNS_17GregorianDateTimeERA100_c
+__ZN3WTF13tryMakeStringIPcPKcS1_EENS_10PassRefPtrINS_10StringImplEEET_T0_T1_
+_JSObjectMakeError
+__ZN3JSC13ErrorInstance6createEPNS_9ExecStateEPNS_9StructureENS_7JSValueE
+_JSObjectMakeRegExp
+__ZN3JSCL23regExpProtoFuncToStringEPNS_9ExecStateE
+__ZN3JSCL18regExpObjectGlobalEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
+__ZN3JSCL22regExpObjectIgnoreCaseEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
+__ZN3JSCL21regExpObjectMultilineEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
+__ZN3JSCL18regExpObjectSourceEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
+__ZN3WTF13tryMakeStringIPKcN3JSC7UStringEPcEENS_10PassRefPtrINS_10StringImplEEET_T0_T1_
+__ZN13OpaqueJSClassD1Ev
+__ZN13OpaqueJSClassD2Ev
__ZN3JSC20EvalFunctionCallNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC17BytecodeGenerator12emitCallEvalEPNS_10RegisterIDES2_S2_PNS_13ArgumentsNodeEjjj
+__ZN3JSC17BytecodeGenerator12emitCallEvalEPNS_10RegisterIDES2_RNS_13CallArgumentsEjjj
+__ZN3JSC3JIT25emit_op_resolve_with_baseEPNS_11InstructionE
__ZN3JSC3JIT17emit_op_call_evalEPNS_11InstructionE
__ZN3JSC3JIT21emitSlow_op_call_evalEPNS_11InstructionERPNS_13SlowCaseEntryE
-_cti_op_resolve
+_cti_op_resolve_with_base
+__ZN3JSC12JSActivation18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
_cti_op_call_eval
-__ZN3JSC11Interpreter8callEvalEPNS_9ExecStateEPNS_12RegisterFileEPNS_8RegisterEiiRNS_7JSValueE
-__ZN3JSC13LiteralParser5Lexer3lexERNS1_18LiteralParserTokenE
-__ZN3JSC13LiteralParser5parseENS0_11ParserStateE
-__ZN3JSC14EvalExecutable7compileEPNS_9ExecStateEPNS_14ScopeChainNodeE
-__ZN3JSC6Parser5parseINS_8EvalNodeEEEN3WTF10PassRefPtrIT_EEPNS_12JSGlobalDataEPNS_8DebuggerEPNS_9ExecStateERKNS_10SourceCodeEPi
-__ZN3JSC8EvalNode6createEPNS_12JSGlobalDataEPNS_14SourceElementsEPN3WTF6VectorISt4pairIPKNS_10IdentifierEjELm0EEEPNS6_IPNS_16Fu
-__ZNK3JSC10ScopeChain10localDepthEv
-__ZNK3JSC12JSActivation9classInfoEv
-__ZN3JSC17BytecodeGeneratorC1EPNS_8EvalNodeEPKNS_8DebuggerERKNS_10ScopeChainEPN3WTF7HashMapINS9_6RefPtrIN7WebCore10StringImplEE
-__ZN3JSC17BytecodeGeneratorC2EPNS_8EvalNodeEPKNS_8DebuggerERKNS_10ScopeChainEPN3WTF7HashMapINS9_6RefPtrIN7WebCore10StringImplEE
+__ZN3JSC11Interpreter8callEvalEPNS_9ExecStateEPNS_12RegisterFileEPNS_8RegisterEii
+__ZN3JSC14EvalExecutableC1EPNS_9ExecStateERKNS_10SourceCodeEb
+__ZN3JSC14EvalExecutable15compileInternalEPNS_9ExecStateEPNS_14ScopeChainNodeE
+__ZN3JSC6Parser5parseINS_8EvalNodeEEEN3WTF10PassRefPtrIT_EEPNS_14JSGlobalObjectEPNS_8DebuggerEPNS_9ExecStateERKNS_10SourceCodeEPNS_18FunctionParametersENS_18JSParserStrictnessEPPNS_8JSObjectE
+__ZN3JSCL19isNonASCIIIdentPartEi
+__ZN3JSC8EvalNode6createEPNS_12JSGlobalDataEPNS_14SourceElementsEPN3WTF6VectorISt4pairIPKNS_10IdentifierEjELm0EEEPNS6_IPNS_16FunctionBodyNodeELm0EEERNS5_7HashSetINS5_6RefPtrINS5_10StringImplEEENS_17IdentifierRepHashENS5_10HashTraitsISL_EEEERKNS_10SourceCodeEji
+__ZN3JSC14ScopeChainNode10localDepthEv
+__ZN3JSC17BytecodeGeneratorC1EPNS_8EvalNodeEPNS_14ScopeChainNodeEPN3WTF7HashMapINS5_6RefPtrINS5_10StringImplEEENS_16SymbolTableEntryENS_17IdentifierRepHashENS5_10HashTraitsIS9_EENS_26SymbolTableIndexHashTraitsEEEPNS_13EvalCodeBlockE
+__ZN3JSC17BytecodeGeneratorC2EPNS_8EvalNodeEPNS_14ScopeChainNodeEPN3WTF7HashMapINS5_6RefPtrINS5_10StringImplEEENS_16SymbolTableEntryENS_17IdentifierRepHashENS5_10HashTraitsIS9_EENS_26SymbolTableIndexHashTraitsEEEPNS_13EvalCodeBlockE
__ZN3JSC8EvalNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
__ZThn16_N3JSC8EvalNodeD0Ev
__ZN3JSC8EvalNodeD0Ev
-__ZN3WTF9HashTableINS_6RefPtrIN7WebCore10StringImplEEESt4pairIS4_NS1_IN3JSC14EvalExecutableEEEENS_18PairFirstExtractorIS9_EENS2
-__ZN3JSC9ExecState9thisValueEv
-__ZN3JSC11Interpreter7executeEPNS_14EvalExecutableEPNS_9ExecStateEPNS_8JSObjectEiPNS_14ScopeChainNodeEPNS_7JSValueE
-__ZN3JSC14EvalExecutable15generateJITCodeEPNS_9ExecStateEPNS_14ScopeChainNodeE
-__ZN3JSC9ThrowNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-_cti_op_throw
-__ZN3JSC9CodeBlock34reparseForExceptionInfoIfNecessaryEPNS_9ExecStateE
-__ZN3JSC18FunctionExecutable20reparseExceptionInfoEPNS_12JSGlobalDataEPNS_14ScopeChainNodeEPNS_9CodeBlockE
-__ZN3JSC11Interpreter14throwExceptionERPNS_9ExecStateERNS_7JSValueEjb
-__ZN3JSC9CodeBlock24handlerForBytecodeOffsetEj
-__ZN3JSC11Interpreter15unwindCallFrameERPNS_9ExecStateENS_7JSValueERjRPNS_9CodeBlockE
-__ZN3JSC9CodeBlock36hasGlobalResolveInfoAtBytecodeOffsetEj
+__ZN3WTF7HashMapINS_6RefPtrINS_10StringImplEEEN3JSC12WriteBarrierINS4_14EvalExecutableEEENS_10StringHashENS_10HashTraitsIS3_EENS9_IS7_EEE3setEPS2_RKS7_
+__ZN3WTF9HashTableINS_6RefPtrINS_10StringImplEEESt4pairIS3_N3JSC12WriteBarrierINS5_14EvalExecutableEEEENS_18PairFirstExtractorIS9_EENS_10StringHashENS_14PairHashTraitsINS_10HashTraitsIS3_EENSE_IS8_EEEESF_E6expandEv
+__ZN3JSC11Interpreter7executeEPNS_14EvalExecutableEPNS_9ExecStateEPNS_8JSObjectEiPNS_14ScopeChainNodeE
+__ZN3JSC16JSCallbackObjectINS_14JSGlobalObjectEE20staticFunctionGetterEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
+__ZN3JSC17ProgramExecutable13visitChildrenERNS_9MarkStackE
+__ZN3JSC19JSStaticScopeObject13visitChildrenERNS_9MarkStackE
+__ZN3JSC14EvalExecutableD1Ev
+__ZN3JSC13EvalCodeBlockD0Ev
+__ZN3JSC12DateInstanceD1Ev
+__ZN3JSC21JSCallbackConstructorD1Ev
+__ZN3JSC17TypeOfResolveNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC3JIT20emit_op_resolve_baseEPNS_11InstructionE
+__ZNK3JSC7JSValue20toThisObjectSlowCaseEPNS_9ExecStateE
+_cti_op_resolve
+__ZN3JSC16JSCallbackObjectINS_14JSGlobalObjectEE17staticValueGetterEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
+_cti_op_resolve_base
+_cti_op_typeof
+__ZN3JSC20jsTypeStringForValueEPNS_9ExecStateENS_7JSValueE
+__ZN3JSC16JSCallbackObjectINS_24JSObjectWithGlobalObjectEE11getCallDataERNS_8CallDataE
+__ZN3JSC16JSCallbackObjectINS_24JSObjectWithGlobalObjectEE14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE
_cti_op_push_new_scope
-__ZN3WTF7HashMapINS_6RefPtrIN7WebCore10StringImplEEEN3JSC16SymbolTableEntryENS5_17IdentifierRepHashENS_10HashTraitsIS4_EENS5_26
__ZN3JSC19JSStaticScopeObject18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
__ZN3JSC12JSActivation3putEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueERNS_15PutPropertySlotE
_cti_op_pop_scope
-_cti_op_is_number
-__ZN3JSCL20arrayProtoFuncConcatEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-_cti_op_stricteq
-__ZN3JSCL20arrayProtoFuncSpliceEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZNK3JSC11Interpreter18retrieveLastCallerEPNS_9ExecStateERiRlRNS_7UStringERNS_7JSValueE
-__ZN3JSC9CodeBlock27lineNumberForBytecodeOffsetEPNS_9ExecStateEj
-__ZN3JSC8RopeImpl20destructNonRecursiveEv
-__ZN3JSC8RopeImpl23derefFibersNonRecursiveERN3WTF6VectorIPS0_Lm32EEE
-__ZN3JSCL17arrayProtoFuncPopEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC7JSArray3popEv
-__ZN7WebCore6String6numberEd
-__ZN3JSC10Identifier5equalEPKN7WebCore10StringImplEPKc
-__ZNK3JSC9Arguments9classInfoEv
-__ZN3JSC9Arguments15copyToRegistersEPNS_9ExecStateEPNS_8RegisterEj
-__ZN3JSC14InstanceOfNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC17BytecodeGenerator14emitInstanceOfEPNS_10RegisterIDES2_S2_S2_
-__ZN3JSC3JIT18emit_op_instanceofEPNS_11InstructionE
-__ZN3JSC3JIT22emitSlow_op_instanceofEPNS_11InstructionERPNS_13SlowCaseEntryE
-__ZN3JSC17BytecodeGenerator11emitPostDecEPNS_10RegisterIDES2_
-__ZN3JSC3JIT16emit_op_post_decEPNS_11InstructionE
-__ZN3JSC3JIT20emitSlow_op_post_decEPNS_11InstructionERPNS_13SlowCaseEntryE
-_cti_op_less
-__ZN3JSC13PrefixDotNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-_cti_op_call_NotJSFunction
+__ZN3JSCL20isNonASCIIIdentStartEi
+__ZN3JSC16JSCallbackObjectINS_24JSObjectWithGlobalObjectEE4callEPNS_9ExecStateE
+__ZN3JSC16JSCallbackObjectINS_24JSObjectWithGlobalObjectEE16getConstructDataERNS_13ConstructDataE
+__ZN3JSC16JSCallbackObjectINS_24JSObjectWithGlobalObjectEE9constructEPNS_9ExecStateE
+_cti_op_instanceof
+__ZN3JSC16JSCallbackObjectINS_24JSObjectWithGlobalObjectEE11hasInstanceEPNS_9ExecStateENS_7JSValueES5_
+__ZN3JSC16JSCallbackObjectINS_24JSObjectWithGlobalObjectEE19getOwnPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayENS_15EnumerationModeE
+_JSPropertyNameAccumulatorAddName
+__ZN3JSC17ObjectConstructor18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
+__ZN3JSCL41objectConstructorGetOwnPropertyDescriptorEPNS_9ExecStateE
+__ZN3JSC16JSCallbackObjectINS_24JSObjectWithGlobalObjectEE24getOwnPropertyDescriptorEPNS_9ExecStateERKNS_10IdentifierERNS_18PropertyDescriptorE
+__ZN3JSC18PropertyDescriptor15setConfigurableEb
+__ZN3JSC18PropertyDescriptor13setEnumerableEb
+__ZNK3JSC18PropertyDescriptor20isAccessorDescriptorEv
+__ZNK3JSC18PropertyDescriptor8writableEv
+__ZNK3JSC18PropertyDescriptor10enumerableEv
+__ZNK3JSC18PropertyDescriptor12configurableEv
+__ZN3JSC20createReferenceErrorEPNS_9ExecStateERKNS_7UStringE
+__ZN3JSC12hasErrorInfoEPNS_9ExecStateEPNS_8JSObjectE
+__ZN3JSC9CodeBlock27lineNumberForBytecodeOffsetEj
+__ZN3JSC12addErrorInfoEPNS_9ExecStateEPNS_8JSObjectEiRKNS_10SourceCodeE
+__ZN3JSC8JSObject24getOwnPropertyDescriptorEPNS_9ExecStateERKNS_10IdentifierERNS_18PropertyDescriptorE
+__ZN3JSC15constructNumberEPNS_9ExecStateEPNS_14JSGlobalObjectENS_7JSValueE
+__ZN3JSC3JIT19emit_op_to_jsnumberEPNS_11InstructionE
+__ZN3JSC3JIT23emitSlow_op_to_jsnumberEPNS_11InstructionERPNS_13SlowCaseEntryE
+_cti_op_to_jsnumber
+__ZNK3JSC16JSCallbackObjectINS_24JSObjectWithGlobalObjectEE8toNumberEPNS_9ExecStateE
+__ZN3JSC23objectProtoFuncToStringEPNS_9ExecStateE
+__ZNK3JSC16JSCallbackObjectINS_24JSObjectWithGlobalObjectEE9classNameEv
__ZN3JSC17StringConstructor11getCallDataERNS_8CallDataE
-__ZN3JSCL21callStringConstructorEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZNK3JSC8JSString8toNumberEPNS_9ExecStateE
-__ZNK3JSC7UString8toDoubleEv
+__ZN3JSCL21callStringConstructorEPNS_9ExecStateE
+__ZNK3JSC16JSCallbackObjectINS_24JSObjectWithGlobalObjectEE8toStringEPNS_9ExecStateE
+_cti_op_sub
+__ZN3JSC21JSCallbackConstructor16getConstructDataERNS_13ConstructDataE
+__ZN3JSCL19constructJSCallbackEPNS_9ExecStateE
+_cti_op_to_primitive
+__ZN3JSCL22objectProtoFuncValueOfEPNS_9ExecStateE
+_cti_op_jmp_scopes
+__ZN3JSC24createStackOverflowErrorEPNS_9ExecStateE
+__ZN3JSC16createRangeErrorEPNS_9ExecStateERKNS_7UStringE
+__ZN3JSC9Structure27despecifyFunctionTransitionERNS_12JSGlobalDataEPS0_RKNS_10IdentifierE
+__ZN3JSC13PropertyTableC2ERNS_12JSGlobalDataEPNS_6JSCellERKS0_
+_cti_op_mul
+__ZNK3JSC8JSObject9classNameEv
+__ZN3JSC12RegisterFile21releaseExcessCapacityEv
+__ZN3JSC16JSCallbackObjectINS_14JSGlobalObjectEED1Ev
+__ZN3JSC19JSStaticScopeObjectD1Ev
+__ZN3JSC12NumberObjectD1Ev
+_JSObjectHasProperty
+_JSObjectGetPrototype
+__ZN3JSC8JSObject15unwrappedObjectEv
+__ZN3JSC11createErrorEPNS_9ExecStateERKNS_7UStringE
+__ZN3JSC12JSGlobalData6createENS_15ThreadStackTypeE
+__ZN3JSC8JSObject17putDirectFunctionEPNS_9ExecStateEPNS_10JSFunctionEj
+__ZNK3JSC7UString4utf8Eb
+__ZN3JSC12JSGlobalData13startSamplingEv
+__ZN3JSC11Interpreter13startSamplingEv
+__ZN3JSC15DateConstructor16getConstructDataERNS_13ConstructDataE
+__ZN3JSCL28constructWithDateConstructorEPNS_9ExecStateE
+__ZN3JSC21gregorianDateTimeToMSEPNS_9ExecStateERKNS_17GregorianDateTimeEdb
+__ZN3JSCL30dateProtoFuncGetTimezoneOffsetEPNS_9ExecStateE
+_cti_op_negate
+__ZN3JSC12JSGlobalData12stopSamplingEv
+__ZN3JSC11Interpreter12stopSamplingEv
+__ZN3JSC17BytecodeGenerator11emitPostIncEPNS_10RegisterIDES2_
+__ZN3JSC3JIT16emit_op_post_incEPNS_11InstructionE
+__ZN3JSC3JIT20emitSlow_op_post_incEPNS_11InstructionERPNS_13SlowCaseEntryE
+__ZN3JSC10MathObject18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
+__ZN3JSC17powThunkGeneratorEPNS_12JSGlobalDataEPNS_14ExecutablePoolE
+__ZN3JSC12X86Assembler7cmpl_imEiiNS_12X86Registers10RegisterIDE
+__ZN3JSC23MacroAssemblerX86Common26branchConvertDoubleToInt32ENS_12X86Registers13XMMRegisterIDENS1_10RegisterIDERNS_22AbstractMacroAssemblerINS_12X86AssemblerEE8JumpListES2_
+__ZN3JSC19SpecializedThunkJIT11returnInt32ENS_12X86Registers10RegisterIDE
+__ZN3JSC19SpecializedThunkJIT12returnDoubleENS_12X86Registers13XMMRegisterIDE
+__ZN3JSC19SpecializedThunkJITD1Ev
+__ZN3WTF9HashTableIjSt4pairIjN3JSC12WriteBarrierINS2_7UnknownEEEENS_18PairFirstExtractorIS6_EENS_7IntHashIjEENS_14PairHashTraitsINS_10HashTraitsIjEENSC_IS5_EEEESD_E6rehashEi
+__ZN3JSC3JIT11emit_op_neqEPNS_11InstructionE
+__ZN3JSC3JIT15emitSlow_op_neqEPNS_11InstructionERPNS_13SlowCaseEntryE
+__ZN3JSC12JSGlobalData14dumpSampleDataEPNS_9ExecStateE
+__ZN3JSC11Interpreter14dumpSampleDataEPNS_9ExecStateE
+__ZN3JSCL22arrayProtoFuncToStringEPNS_9ExecStateE
+__ZN3JSC16ArrayConstructor11getCallDataERNS_8CallDataE
+__ZN3JSCL20callArrayConstructorEPNS_9ExecStateE
+__ZN3JSC10ASTBuilder11makeModNodeEPNS_14ExpressionNodeES2_b
+__ZN3JSC3JIT11emit_op_modEPNS_11InstructionE
+__ZN3JSC3JIT15emitSlow_op_modEPNS_11InstructionERPNS_13SlowCaseEntryE
+__ZN3JSC17NumberConstructor11getCallDataERNS_8CallDataE
+__ZN3JSCL21callNumberConstructorEPNS_9ExecStateE
+__ZN3JSCL16mathProtoFuncAbsEPNS_9ExecStateE
+__ZN3JSCL28numberConstructorPosInfinityEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
+__ZN3JSCL18mathProtoFuncFloorEPNS_9ExecStateE
+_cti_op_mod
+_cti_timeout_check
+__ZN3JSC14TimeoutChecker10didTimeOutEPNS_9ExecStateE
+__ZN3WTF6VectorINS_6RefPtrIN3JSC10RegisterIDEEELm16EE14expandCapacityEm
+__ZN3WTF6VectorIPNS0_IN3JSC10RegisterIDELm32EEELm32EE14expandCapacityEmPKS4_
+__ZN3WTF6VectorIPNS0_IN3JSC10RegisterIDELm32EEELm32EE15reserveCapacityEm
+__ZN3JSC3JIT13linkConstructEPNS_10JSFunctionEPNS_9CodeBlockES4_NS_21MacroAssemblerCodePtrEPNS_12CallLinkInfoEiPNS_12JSGlobalDataE
+__ZN3JSC14EvalExecutable13visitChildrenERNS_9MarkStackE
+__ZN3JSC17NumberConstructor16getConstructDataERNS_13ConstructDataE
+__ZN3JSCL30constructWithNumberConstructorEPNS_9ExecStateE
+__ZN3JSC12NumberObjectC1ERNS_12JSGlobalDataEPNS_9StructureE
+__ZN3JSC18BooleanConstructor16getConstructDataERNS_13ConstructDataE
+__ZN3JSCL31constructWithBooleanConstructorEPNS_9ExecStateE
+__ZN3JSC16constructBooleanEPNS_9ExecStateERKNS_7ArgListE
+__ZN3JSC13BooleanObjectC1ERNS_12JSGlobalDataEPNS_9StructureE
+__ZN3JSC13BooleanObjectD1Ev
+__ZN3JSC9ExecState21arrayConstructorTableEPS0_
+__ZN3JSC17FunctionPrototype11getCallDataERNS_8CallDataE
+__ZN3JSC16InternalFunction4nameEPNS_9ExecStateE
+__ZN3JSC8VoidNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSCL25numberConstructorNaNValueEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
+__ZN3JSCL28numberConstructorNegInfinityEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
__ZN3JSC18BooleanConstructor11getCallDataERNS_8CallDataE
-__ZN3JSCL22callBooleanConstructorEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC7JSArray19getOwnPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayENS_15EnumerationModeE
-__ZN3JSC9ExecState10arrayTableEPS0_
-__ZN3JSC17DeleteResolveNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSCL18arrayProtoFuncSortEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
+__ZN3JSCL22callBooleanConstructorEPNS_9ExecStateE
+__ZN3JSC8JSString17substringFromRopeEPNS_9ExecStateEjj
+__ZN3WTF6VectorIN3JSC8JSString12RopeIterator8WorkItemELm16EE14expandCapacityEmPKS4_
+__ZN3WTF6VectorIN3JSC8JSString12RopeIterator8WorkItemELm16EE15reserveCapacityEm
+__ZN3JSC10JSFunction14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE
+__ZN3JSCL24booleanProtoFuncToStringEPNS_9ExecStateE
+__ZN3JSC18globalFuncUnescapeEPNS_9ExecStateE
+__ZN3WTF6VectorItLm64EE17tryExpandCapacityEm
+__ZNK3WTF13DecimalNumber19toStringExponentialEPtj
+__ZN3JSC8JSObject3putEPNS_9ExecStateEjNS_7JSValueE
+__ZN3JSCL21arrayProtoFuncReverseEPNS_9ExecStateE
+__ZN3JSC9CommaNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC9CommaNodeD1Ev
+__ZN3JSC7JSArray14deletePropertyEPNS_9ExecStateEj
+__ZN3JSC19FunctionConstructor16getConstructDataERNS_13ConstructDataE
+__ZN3JSCL32constructWithFunctionConstructorEPNS_9ExecStateE
+__ZN3JSC17constructFunctionEPNS_9ExecStateEPNS_14JSGlobalObjectERKNS_7ArgListE
+__ZN3JSC17StringConstructor16getConstructDataERNS_13ConstructDataE
+__ZN3JSCL30constructWithStringConstructorEPNS_9ExecStateE
+__ZN3JSC12StringObjectC1EPNS_9ExecStateEPNS_9StructureERKNS_7UStringE
+__ZN3JSC12StringObjectC2EPNS_9ExecStateEPNS_9StructureERKNS_7UStringE
+__ZN3JSCL22numberProtoFuncValueOfEPNS_9ExecStateE
+__ZN3JSC12NumberObject11getJSNumberEv
+__ZN3JSC11makeUStringINS_7UStringEPKcS1_EES1_T_T0_T1_
+__ZN3JSCL23booleanProtoFuncValueOfEPNS_9ExecStateE
+__ZN3JSC21ReadModifyBracketNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC26fromCharCodeThunkGeneratorEPNS_12JSGlobalDataEPNS_14ExecutablePoolE
+__ZN3JSCL18stringFromCharCodeEPNS_9ExecStateE
+__ZN3JSCL18arrayProtoFuncSortEPNS_9ExecStateE
+__ZN3JSC7JSArray4sortEPNS_9ExecStateE
+__ZN3JSC7JSArray17compactForSortingEv
+__ZN3JSC4Heap18pushTempSortVectorEPN3WTF6VectorISt4pairINS_7JSValueENS_7UStringEELm0EEE
+__ZN3WTF6VectorIPNS0_ISt4pairIN3JSC7JSValueENS2_7UStringEELm0EEELm0EE15reserveCapacityEm
+__ZN3JSC4Heap17popTempSortVectorEPN3WTF6VectorISt4pairINS_7JSValueENS_7UStringEELm0EEE
+__ZN3JSCltERKNS_7UStringES2_
+__ZN3JSCL27compareByStringPairForQSortEPKvS1_
+__ZN3WTF16codePointCompareEPKNS_10StringImplES2_
__ZN3JSC7JSArray4sortEPNS_9ExecStateENS_7JSValueENS_8CallTypeERKNS_8CallDataE
-__ZN3WTF6VectorIN3JSC26AVLTreeNodeForArrayCompareELm0EE14expandCapacityEm
-__ZN3JSC11Interpreter20prepareForRepeatCallEPNS_18FunctionExecutableEPNS_9ExecStateEPNS_10JSFunctionEiPNS_14ScopeChainNodeEPNS_
+__ZN3JSC11Interpreter20prepareForRepeatCallEPNS_18FunctionExecutableEPNS_9ExecStateEPNS_10JSFunctionEiPNS_14ScopeChainNodeE
__ZN3WTF7AVLTreeIN3JSC32AVLTreeAbstractorForArrayCompareELj44ENS_18AVLTreeDefaultBSetILj44EEEE6insertEi
-__ZN3JSC11Interpreter7executeERNS_16CallFrameClosureEPNS_7JSValueE
-__ZN3WTF7AVLTreeIN3JSC32AVLTreeAbstractorForArrayCompareELj44ENS_18AVLTreeDefaultBSetILj44EEEE7balanceEi
__ZN3JSC11Interpreter13endRepeatCallERNS_16CallFrameClosureE
-__ZN3JSCL16mathProtoFuncExpEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL17mathProtoFuncATanEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZL17makeLeftShiftNodePN3JSC12JSGlobalDataEPNS_14ExpressionNodeES3_b
-__ZN3JSC3JIT14emit_op_lshiftEPNS_11InstructionE
-__ZN3JSC3JIT14emit_op_bitandEPNS_11InstructionE
-__ZN3JSC3JIT14emit_op_rshiftEPNS_11InstructionE
-__ZN3JSC3JIT18emitSlow_op_lshiftEPNS_11InstructionERPNS_13SlowCaseEntryE
-__ZN3JSC3JIT18emitSlow_op_bitandEPNS_11InstructionERPNS_13SlowCaseEntryE
-__ZN3JSC3JIT18emitSlow_op_rshiftEPNS_11InstructionERPNS_13SlowCaseEntryE
-__ZN3JSC32jsSpliceSubstringsWithSeparatorsEPNS_9ExecStateEPNS_8JSStringERKNS_7UStringEPKNS_11StringRangeEiPS5_i
-__ZN3JSCL26stringProtoFuncLastIndexOfEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZNK3JSC7JSValue20toIntegerPreserveNaNEPNS_9ExecStateE
-__ZNK3JSC7UString5rfindERKS0_j
-__ZN3WTF6VectorIiLm0EE15reserveCapacityEm
-__ZN3WTF6VectorINS_6RefPtrIN3JSC5LabelEEELm8EE15reserveCapacityEm
-__ZN3WTF6VectorISt4pairIiiELm8EE14expandCapacityEm
-__ZN3JSC11DoWhileNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC3JIT19emit_op_switch_charEPNS_11InstructionE
-_cti_op_switch_char
-__ZN3JSCL21stringProtoFuncSearchEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3WTF10RefCountedIN3JSC6RegExpEE5derefEv
-__ZN3JSC14JSGlobalObjectD2Ev
-__ZN3JSC12RegisterFile17clearGlobalObjectEPNS_14JSGlobalObjectE
-__ZN3JSC17FunctionPrototypeD1Ev
-__ZN3JSC15ObjectPrototypeD1Ev
-__ZN3JSC14ArrayPrototypeD1Ev
-__ZN3JSC15StringPrototypeD1Ev
-__ZN3JSC16BooleanPrototypeD1Ev
-__ZN3JSC15NumberPrototypeD1Ev
-__ZN3JSC13DatePrototypeD1Ev
-__ZN3JSC15RegExpPrototypeD1Ev
-__ZN3JSC14ErrorPrototypeD1Ev
-__ZN3JSC20NativeErrorPrototypeD1Ev
-__ZN3JSC17ObjectConstructorD1Ev
-__ZN3JSC19FunctionConstructorD1Ev
-__ZN3JSC16ArrayConstructorD1Ev
-__ZN3JSC17StringConstructorD1Ev
-__ZN3JSC18BooleanConstructorD1Ev
-__ZN3JSC17NumberConstructorD1Ev
-__ZN3JSC15DateConstructorD1Ev
-__ZN3JSC17RegExpConstructorD1Ev
-__ZN3JSC16ErrorConstructorD1Ev
-__ZN3JSC22NativeErrorConstructorD1Ev
-__ZN3JSC10MathObjectD1Ev
-__ZN3JSC10JSONObjectD1Ev
-__ZN3JSC18GlobalEvalFunctionD1Ev
-__ZN3JSC19JSStaticScopeObjectD1Ev
-__ZN3JSC19JSStaticScopeObjectD2Ev
-__ZN3WTF6VectorIPvLm0EE14expandCapacityEmPKS1_
-__ZN3WTF6VectorIPvLm0EE15reserveCapacityEm
-__ZN3JSC16JSCallbackObjectINS_8JSObjectEED1Ev
-__ZL25clearReferenceToPrototypeP13OpaqueJSValue
-_JSObjectGetPrivate
-__ZNK3JSC16JSCallbackObjectINS_8JSObjectEE9classInfoEv
-__ZN3JSC28globalFuncEncodeURIComponentEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL6encodeEPNS_9ExecStateERKNS_7ArgListEPKc
-__ZN3WTF6VectorItLm64EE9tryAppendItEEbPKT_m
-__ZN3WTF6VectorItLm64EE18tryReserveCapacityEm
-__ZN3JSC28globalFuncDecodeURIComponentEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL6decodeEPNS_9ExecStateERKNS_7ArgListEPKcb
-__ZN3WTF7Unicode18UTF8SequenceLengthEc
-__ZN3WTF7Unicode18decodeUTF8SequenceEPKc
-__ZN3JSC18EmptyStatementNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSCltERKNS_7UStringES2_
-__ZN3WTF6VectorItLm0EE14expandCapacityEmPKt
-__ZN3WTF6VectorItLm0EE15reserveCapacityEm
-__ZN3JSC18RegExpMatchesArray3putEPNS_9ExecStateEjNS_7JSValueE
-__ZN3JSC18RegExpMatchesArray14deletePropertyEPNS_9ExecStateEj
-__ZN3JSC18RegExpMatchesArray3putEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueERNS_15PutPropertySlotE
-__ZN3JSC14EvalExecutableD0Ev
-__ZN3JSC13EvalCodeBlockD0Ev
-__ZN3JSC3JIT30emit_op_resolve_global_dynamicEPNS_11InstructionE
-__ZN3JSC3JIT34emitSlow_op_resolve_global_dynamicEPNS_11InstructionERPNS_13SlowCaseEntryE
-__ZN3JSC19FunctionConstructor16getConstructDataERNS_13ConstructDataE
-__ZN3JSCL32constructWithFunctionConstructorEPNS_9ExecStateEPNS_8JSObjectERKNS_7ArgListE
-__ZN3JSC17constructFunctionEPNS_9ExecStateERKNS_7ArgListE
-__ZN3JSC3JIT18emit_op_jmp_scopesEPNS_11InstructionE
+__ZN3JSC11Interpreter7executeERNS_16CallFrameClosureE
+__ZN3WTF7AVLTreeIN3JSC32AVLTreeAbstractorForArrayCompareELj44ENS_18AVLTreeDefaultBSetILj44EEEE7balanceEi
+__ZNK3JSC14ExpressionNode11isCommaNodeEv
+__ZNK3JSC7SubNode10isSubtractEv
+__ZN3JSC17BytecodeGenerator17argumentNumberForERKNS_10IdentifierE
+__ZN3JSC17BytecodeGenerator27setIsNumericCompareFunctionEb
+__ZN3JSC7JSArray11sortNumericEPNS_9ExecStateENS_7JSValueENS_8CallTypeERKNS_8CallDataE
+__ZN3JSCL20dateProtoFuncGetTimeEPNS_9ExecStateE
+__ZN3JSC8JSObject18getPrimitiveNumberEPNS_9ExecStateERdRNS_7JSValueE
+__ZN3JSC24charCodeAtThunkGeneratorEPNS_12JSGlobalDataEPNS_14ExecutablePoolE
+__ZN3JSC7JSArray14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE
+__ZNK3JSC8NullNode6isNullEv
+__ZN3JSC3JIT15emit_op_eq_nullEPNS_11InstructionE
+_cti_op_is_number
+__ZNK3JSC7JSValue16synthesizeObjectEPNS_9ExecStateE
+__ZN3JSC36constructBooleanFromImmediateBooleanEPNS_9ExecStateEPNS_14JSGlobalObjectENS_7JSValueE
+__ZN3JSC14throwTypeErrorEPNS_9ExecStateE
+__ZN3JSCL27dateProtoFuncGetUTCFullYearEPNS_9ExecStateE
+__ZNK3JSC12DateInstance29calculateGregorianDateTimeUTCEPNS_9ExecStateE
+__ZN3JSC23MacroAssemblerX86Common4moveENS_22AbstractMacroAssemblerINS_12X86AssemblerEE13TrustedImmPtrENS_12X86Registers10RegisterIDE
+__ZN3JSCL24dateProtoFuncGetUTCMonthEPNS_9ExecStateE
+__ZN3JSCL23dateProtoFuncGetUTCDateEPNS_9ExecStateE
+__ZN3JSCL22dateProtoFuncGetUTCDayEPNS_9ExecStateE
+__ZN3JSCL24dateProtoFuncGetUTCHoursEPNS_9ExecStateE
+__ZN3JSCL26dateProtoFuncGetUTCMinutesEPNS_9ExecStateE
+__ZN3JSCL26dateProtoFuncGetUTCSecondsEPNS_9ExecStateE
+__ZN3JSCL31dateProtoFuncGetUTCMillisecondsEPNS_9ExecStateE
+__ZN3JSCL24dateProtoFuncGetFullYearEPNS_9ExecStateE
+__ZN3JSCL21dateProtoFuncGetMonthEPNS_9ExecStateE
+__ZN3JSCL20dateProtoFuncGetDateEPNS_9ExecStateE
+__ZN3JSCL19dateProtoFuncGetDayEPNS_9ExecStateE
+__ZN3JSCL21dateProtoFuncGetHoursEPNS_9ExecStateE
+__ZN3JSCL23dateProtoFuncGetMinutesEPNS_9ExecStateE
+__ZN3JSCL23dateProtoFuncGetSecondsEPNS_9ExecStateE
+__ZN3JSCL28dateProtoFuncGetMilliSecondsEPNS_9ExecStateE
+__ZN3JSC9parseDateEPNS_9ExecStateERKNS_7UStringE
+__ZN3WTF40parseES5DateFromNullTerminatedCharactersEPKc
+__ZN3JSC37parseDateFromNullTerminatedCharactersEPNS_9ExecStateEPKc
+__ZN3WTFL37parseDateFromNullTerminatedCharactersEPKcRbRi
+__ZN3JSCL24dateProtoFuncToUTCStringEPNS_9ExecStateE
+__ZN3JSC20formatDateUTCVariantERKNS_17GregorianDateTimeERA100_c
+__ZN3JSC13formatTimeUTCERKNS_17GregorianDateTimeERA100_c
+__ZN3JSCL24dateProtoFuncToGMTStringEPNS_9ExecStateE
+__ZN3JSC15DateConstructor18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
+__ZN3JSCL9dateParseEPNS_9ExecStateE
+__ZN3JSCL7dateUTCEPNS_9ExecStateE
+__ZN3JSC15globalFuncIsNaNEPNS_9ExecStateE
+_cti_op_is_object
+__ZN3JSC14jsIsObjectTypeENS_7JSValueE
+_cti_op_less
+__ZN3JSCL19jsStrDecimalLiteralERPKtS1_
+__ZN3WTF6VectorIcLm32EE14expandCapacityEm
+__ZN3JSCL20dateProtoFuncGetYearEPNS_9ExecStateE
+_cti_op_pre_inc
+__ZN3JSCL20dateProtoFuncSetTimeEPNS_9ExecStateE
+__ZN3JSCL28dateProtoFuncSetMilliSecondsEPNS_9ExecStateE
+__ZN3JSCL23setNewValueFromTimeArgsEPNS_9ExecStateEib
+__ZN3JSCL31dateProtoFuncSetUTCMillisecondsEPNS_9ExecStateE
+__ZN3JSCL23dateProtoFuncSetSecondsEPNS_9ExecStateE
+__ZN3JSCL23dateProtoFuncSetMinutesEPNS_9ExecStateE
+__ZN3JSCL26dateProtoFuncSetUTCMinutesEPNS_9ExecStateE
+__ZN3JSCL21dateProtoFuncSetHoursEPNS_9ExecStateE
+__ZN3JSCL24dateProtoFuncSetUTCHoursEPNS_9ExecStateE
+__ZN3JSCL20dateProtoFuncSetDateEPNS_9ExecStateE
+__ZN3JSCL23setNewValueFromDateArgsEPNS_9ExecStateEib
+__ZN3JSCL23dateProtoFuncSetUTCDateEPNS_9ExecStateE
+__ZN3JSCL21dateProtoFuncSetMonthEPNS_9ExecStateE
+__ZN3JSCL24dateProtoFuncSetUTCMonthEPNS_9ExecStateE
+__ZN3JSCL24dateProtoFuncSetFullYearEPNS_9ExecStateE
+__ZN3JSCL27dateProtoFuncSetUTCFullYearEPNS_9ExecStateE
+__ZN3JSC8JSParser18parseWithStatementINS_13SyntaxCheckerEEENT_9StatementERS3_
+_cti_op_construct_arityCheck
+__ZN3JSC8JSParser18parseWithStatementINS_10ASTBuilderEEENT_9StatementERS3_
__ZN3JSC8WithNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
__ZN3JSC17BytecodeGenerator13emitPushScopeEPNS_10RegisterIDE
__ZN3JSC3JIT18emit_op_push_scopeEPNS_11InstructionE
_cti_op_push_scope
-_cti_op_jmp_scopes
-__ZN3WTF6VectorIN3JSC14ExecutablePool10AllocationELm2EE14expandCapacityEm
-__ZN3JSCL26stringProtoFuncToUpperCaseEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL21arrayProtoFuncIndexOfEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL16mathProtoFuncCosEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL17mathProtoFuncASinEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-_cti_op_loop_if_lesseq
-__ZN3JSC7JSArray4sortEPNS_9ExecStateE
-__ZN3JSC7JSArray17compactForSortingEv
-__ZL18makeRightShiftNodePN3JSC12JSGlobalDataEPNS_14ExpressionNodeES3_b
+__ZN3JSC17DeleteResolveNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC3JIT17emit_op_jneq_nullEPNS_11InstructionE
+__ZN3JSC3JIT26emit_op_ret_object_or_thisEPNS_11InstructionE
+__ZN3JSC16JSVariableObject19getOwnPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayENS_15EnumerationModeE
+__ZN3WTF9HashTableIPNS_10StringImplES2_NS_17IdentityExtractorIS2_EENS_7PtrHashIS2_EENS_10HashTraitsIS2_EES8_E6expandEv
+__ZN3WTF6VectorIN3JSC10IdentifierELm20EE15reserveCapacityEm
+__ZN3JSC9ExecState17globalObjectTableEPS0_
+__ZNK3JSC8JSObject16isVariableObjectEv
+__ZN3JSC17ObjectConstructor11getCallDataERNS_8CallDataE
+__ZN3JSC19FunctionConstructor11getCallDataERNS_8CallDataE
+__ZN3JSC15DateConstructor11getCallDataERNS_8CallDataE
+__ZN3JSCL25numberConstructorMaxValueEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
+__ZN3JSCL25numberConstructorMinValueEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
+__ZN3JSC18sqrtThunkGeneratorEPNS_12JSGlobalDataEPNS_14ExecutablePoolE
+__ZN3JSC9CodeBlock32expressionRangeForBytecodeOffsetEjRiS1_S1_
+__ZN3JSC11makeUStringINS_7UStringEPKcS1_S3_EES1_T_T0_T1_T2_
+__ZN3WTF13tryMakeStringIN3JSC7UStringEPKcS2_S4_EENS_10PassRefPtrINS_10StringImplEEET_T0_T1_T2_
+__ZN3JSC6JSCell16getConstructDataERNS_13ConstructDataE
+__ZN3JSC26createNotAConstructorErrorEPNS_9ExecStateENS_7JSValueE
+_cti_op_post_inc
+_cti_op_post_dec
+__ZN3JSC16JSVariableObject14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE
+__ZN3JSC10ASTBuilder18makeBitwiseNotNodeEPNS_14ExpressionNodeE
+__ZN3JSC3JIT14emit_op_bitnotEPNS_11InstructionE
+__ZN3JSC3JIT18emitSlow_op_bitnotEPNS_11InstructionERPNS_13SlowCaseEntryE
+_cti_op_jlesseq
+_cti_op_bitnot
+__ZN3JSC12StringObjectC1EPNS_9ExecStateEPNS_9StructureE
+__ZN3WTF6VectorIjLm16EE15reserveCapacityEm
+__ZNK3JSC8JSString8toObjectEPNS_9ExecStateEPNS_14JSGlobalObjectE
+__ZN3JSC10ASTBuilder17makeLeftShiftNodeEPNS_14ExpressionNodeES2_b
+__ZN3JSC3JIT14emit_op_lshiftEPNS_11InstructionE
+__ZN3JSC3JIT18emitSlow_op_lshiftEPNS_11InstructionERPNS_13SlowCaseEntryE
+_cti_op_lshift
+__ZN3JSC10ASTBuilder18makeRightShiftNodeEPNS_14ExpressionNodeES2_b
+__ZN3JSC3JIT14emit_op_rshiftEPNS_11InstructionE
+__ZN3JSC3JIT18emitSlow_op_rshiftEPNS_11InstructionERPNS_13SlowCaseEntryE
+_cti_op_rshift
+__ZN3JSC10ASTBuilder19makeURightShiftNodeEPNS_14ExpressionNodeES2_b
+__ZN3JSC3JIT15emit_op_urshiftEPNS_11InstructionE
+__ZN3JSC3JIT19emitSlow_op_urshiftEPNS_11InstructionERPNS_13SlowCaseEntryE
+__ZN3WTF6VectorIPNS_14StringImplBaseELm32EE14expandCapacityEm
+_cti_op_urshift
+__ZN3JSC3JIT16emit_op_neq_nullEPNS_11InstructionE
+__ZN3JSC10ASTBuilder14makeBitAndNodeEPNS_14ExpressionNodeES2_b
+__ZN3JSC3JIT14emit_op_bitandEPNS_11InstructionE
+__ZN3JSC3JIT18emitSlow_op_bitandEPNS_11InstructionERPNS_13SlowCaseEntryE
+_cti_op_bitand
+__ZN3JSC10ASTBuilder13makeBitOrNodeEPNS_14ExpressionNodeES2_b
__ZN3JSC3JIT13emit_op_bitorEPNS_11InstructionE
__ZN3JSC3JIT17emitSlow_op_bitorEPNS_11InstructionERPNS_13SlowCaseEntryE
-__ZN3WTF6VectorIN3JSC11StringRangeELm16EE14expandCapacityEm
-__ZN3WTF6VectorIN3JSC7UStringELm16EE14expandCapacityEmPKS2_
-__ZN3WTF6VectorIN3JSC7UStringELm16EE15reserveCapacityEm
-__ZNK3JSC8JSString8toObjectEPNS_9ExecStateE
-__ZN3JSC12StringObject14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE
-_cti_op_post_dec
+_cti_op_bitor
+__ZN3JSC10ASTBuilder14makeBitXOrNodeEPNS_14ExpressionNodeES2_b
__ZN3JSC3JIT14emit_op_bitxorEPNS_11InstructionE
__ZN3JSC3JIT18emitSlow_op_bitxorEPNS_11InstructionERPNS_13SlowCaseEntryE
-_cti_op_bitand
-_cti_op_bitor
-__ZN7WebCore10StringImpl18simplifyWhiteSpaceEv
-_cti_op_is_object
-__ZN3JSC14jsIsObjectTypeENS_7JSValueE
-__ZN3JSC17PrototypeFunction11getCallDataERNS_8CallDataE
-__ZN3JSC14globalFuncEvalEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL19isNonASCIIIdentPartEi
-__ZN3JSC11Interpreter7executeEPNS_14EvalExecutableEPNS_9ExecStateEPNS_8JSObjectEPNS_14ScopeChainNodeEPNS_7JSValueE
-_cti_op_mod
-__ZN7WebCore6String6appendEc
-__ZN7WebCore6String6appendEPKtj
-__ZN3JSC16globalFuncEscapeEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZNK7WebCore6String8foldCaseEv
-__ZN7WebCore10StringImpl8foldCaseEv
+_cti_op_bitxor
+_cti_op_div
+__ZN3JSCL23callFunctionConstructorEPNS_9ExecStateE
+__ZN3JSC10JSFunction12lengthGetterEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
__ZN3JSC10JSFunction15argumentsGetterEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
__ZNK3JSC11Interpreter17retrieveArgumentsEPNS_9ExecStateEPNS_10JSFunctionE
-__ZN3WTF6VectorIPN3JSC14ExpressionNodeELm16EE14expandCapacityEm
-__ZN3WTF6VectorINS_6RefPtrIN3JSC10RegisterIDEEELm16EE15reserveCapacityEm
-__ZN3WTF6VectorIN7WebCore6StringELm0EE14expandCapacityEm
-__ZN3JSC8JSObject14deletePropertyEPNS_9ExecStateEj
-__ZN3JSC18globalFuncUnescapeEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3WTF6VectorItLm64EE14expandCapacityEm
-__ZN3JSC3JIT16emit_op_jeq_nullEPNS_11InstructionE
-__ZN3WTF7CStringC1EPKc
-__ZN3WTFeqERKNS_7CStringES2_
-__ZN7WebCore17equalIgnoringCaseEPKtPKcj
-__ZNK7WebCore6String6toUIntEPb
-__ZN7WebCore10StringImpl6toUIntEPb
-__ZN7WebCore16charactersToUIntEPKtmPb
-__ZN7WebCore10StringImpl11reverseFindEti
-__ZN3WTF23waitForThreadCompletionEjPPv
-__ZN3WTF14FastMallocZone10statisticsEP14_malloc_zone_tP19malloc_statistics_t
-__ZNK7WebCore6String18simplifyWhiteSpaceEv
-__ZN7WebCore10StringImpl23defaultWritingDirectionEv
-__ZN3JSCL20dateProtoFuncSetTimeEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL21dateProtoFuncGetMonthEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZNK3JSC12DateInstance26calculateGregorianDateTimeEPNS_9ExecStateE
-__ZN3JSC21msToGregorianDateTimeEPNS_9ExecStateEdbRNS_17GregorianDateTimeE
-__ZN3WTFL18calculateDSTOffsetEdd
-__ZN3JSCL20dateProtoFuncGetDateEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZNK3JSC7JSValue8inheritsEPKNS_9ClassInfoE
-__ZN3JSCL20dateProtoFuncGetYearEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL21dateProtoFuncGetHoursEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL23dateProtoFuncGetMinutesEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC3JIT17emit_op_jneq_nullEPNS_11InstructionE
-__ZN3JSCL20dateProtoFuncSetYearEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZNK3JSC7JSValue7toInt32EPNS_9ExecStateERb
-__ZN3JSC21gregorianDateTimeToMSEPNS_9ExecStateERKNS_17GregorianDateTimeEdb
-__ZN3WTF18dateToDaysFrom1970Eiii
-__ZN3JSCL21dateProtoFuncSetMonthEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL23setNewValueFromDateArgsEPNS_9ExecStateENS_7JSValueERKNS_7ArgListEib
-__ZN3JSCL20dateProtoFuncSetDateEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL24dateProtoFuncToGMTStringEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZNK3JSC12DateInstance29calculateGregorianDateTimeUTCEPNS_9ExecStateE
-__ZN3JSC20formatDateUTCVariantERKNS_17GregorianDateTimeERA100_c
-__ZN3JSC13formatTimeUTCERKNS_17GregorianDateTimeERA100_c
-__ZN3JSC13tryMakeStringIPcPKcS1_EEN3WTF10PassRefPtrIN7WebCore10StringImplEEET_T0_T1_
-__ZN3JSC9parseDateEPNS_9ExecStateERKNS_7UStringE
-__ZN3JSC37parseDateFromNullTerminatedCharactersEPNS_9ExecStateEPKc
-__ZN3JSC16ArrayConstructor16getConstructDataERNS_13ConstructDataE
-__ZN3JSCL29constructWithArrayConstructorEPNS_9ExecStateEPNS_8JSObjectERKNS_7ArgListE
-__ZN3JSCL27constructArrayWithSizeQuirkEPNS_9ExecStateERKNS_7ArgListE
-__ZN3JSC7JSArrayC1EN3WTF17NonNullPassRefPtrINS_9StructureEEEj
-__ZN3JSC17StringConstructor16getConstructDataERNS_13ConstructDataE
-__ZN3JSCL30constructWithStringConstructorEPNS_9ExecStateEPNS_8JSObjectERKNS_7ArgListE
-__ZN3JSC12StringObjectC1EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEERKNS_7UStringE
-__ZN3JSC12StringObjectC2EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEERKNS_7UStringE
-_cti_op_pre_inc
-__ZN3JSCL23dateProtoFuncGetSecondsEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN7WebCore6String6removeEji
-__ZN3JSC23MacroAssemblerX86Common12branchTest32ENS0_9ConditionENS_22AbstractMacroAssemblerINS_12X86AssemblerEE7AddressENS4_5Imm
-__ZN3JSC23MacroAssemblerX86Common8branch32ENS0_9ConditionENS_22AbstractMacroAssemblerINS_12X86AssemblerEE7AddressENS4_5Imm32E
-__ZN3JSC12X86Assembler23X86InstructionFormatter9twoByteOpENS0_15TwoByteOpcodeIDEiNS_12X86Registers10RegisterIDEi
-__ZNK3JSC7UStringixEj
-__ZN3JSC3JIT19emit_op_to_jsnumberEPNS_11InstructionE
-__ZN3JSC3JIT23emitSlow_op_to_jsnumberEPNS_11InstructionERPNS_13SlowCaseEntryE
-_cti_op_to_jsnumber
-__ZN3JSCL30dateProtoFuncGetTimezoneOffsetEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC5Error6createEPNS_9ExecStateENS_9ErrorTypeERKNS_7UStringEilS6_
-__ZN3JSC22NativeErrorConstructor16getConstructDataERNS_13ConstructDataE
-__ZN3JSC9constructEPNS_9ExecStateENS_7JSValueENS_13ConstructTypeERKNS_13ConstructDataERKNS_7ArgListE
-__ZN3JSCL35constructWithNativeErrorConstructorEPNS_9ExecStateEPNS_8JSObjectERKNS_7ArgListE
-__ZN3JSC22NativeErrorConstructor9constructEPNS_9ExecStateERKNS_7ArgListE
-__ZN3JSC13ErrorInstanceC1EN3WTF17NonNullPassRefPtrINS_9StructureEEE
-__ZN3JSC8JSObject17putWithAttributesEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueEj
-__ZNK3JSC8JSObject13exceptionTypeEv
-__ZN3JSCL22errorProtoFuncToStringEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC13tryMakeStringINS_7UStringEPKcS1_EEN3WTF10PassRefPtrIN7WebCore10StringImplEEET_T0_T1_
-__ZN3JSC13ErrorInstanceD1Ev
-__ZN3JSC4Heap9freeBlockEm
-__ZN3JSC4Heap12freeBlockPtrEPNS_14CollectorBlockE
-__ZN3JSC28createUndefinedVariableErrorEPNS_9ExecStateERKNS_10IdentifierEjPNS_9CodeBlockE
-__ZN3JSC9CodeBlock32expressionRangeForBytecodeOffsetEPNS_9ExecStateEjRiS3_S3_
-__ZN3JSC10makeStringIPKcNS_7UStringEEES3_T_T0_
-__ZN3JSC13tryMakeStringIPKcNS_7UStringEEEN3WTF10PassRefPtrIN7WebCore10StringImplEEET_T0_
-__ZN3JSCL23returnToThrowTrampolineEPNS_12JSGlobalDataENS_16ReturnAddressPtrERS2_
-_ctiVMThrowTrampoline
-_cti_vm_throw
-__ZNK3JSC8JSObject22isNotAnObjectErrorStubEv
-__ZNK3JSC7UString5asciiEv
-__ZN3JSC6JSLock12DropAllLocksC1ENS_14JSLockBehaviorE
-__ZN3JSCL17createJSLockCountEv
-__ZN3JSC6JSLock12DropAllLocksD1Ev
-__ZNK7WebCore6String5upperEv
-__ZN3JSC4Yarr23RegexPatternConstructor31atomParentheticalAssertionBeginEb
-__ZN3JSC4Yarr14RegexGenerator30generateParentheticalAssertionERNS1_19TermGenerationStateE
-__ZNK3JSC8JSObject8toNumberEPNS_9ExecStateE
-__ZN3WTF6VectorIPN3JSC4Yarr18PatternDisjunctionELm4EE14expandCapacityEmPKS4_
-__ZN3JSCL18regExpObjectSourceEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
-__ZN3JSC17RegExpConstructor11getCallDataERNS_8CallDataE
-__ZN3JSCL21callRegExpConstructorEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC23objectProtoFuncToStringEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZNK3JSC8JSObject9classNameEv
-__ZN3JSC13tryMakeStringIPKcNS_7UStringES2_EEN3WTF10PassRefPtrIN7WebCore10StringImplEEET_T0_T1_
-__ZN3JSC16JSVariableObject14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE
-__ZN3JSC9Structure27despecifyDictionaryFunctionERKNS_10IdentifierE
-__ZN3JSC36constructBooleanFromImmediateBooleanEPNS_9ExecStateENS_7JSValueE
-__ZN3JSC13BooleanObjectC1EN3WTF17NonNullPassRefPtrINS_9StructureEEE
-__ZN3JSC17ObjectConstructor16getConstructDataERNS_13ConstructDataE
-__ZN3JSCL30constructWithObjectConstructorEPNS_9ExecStateEPNS_8JSObjectERKNS_7ArgListE
-__ZNK3JSC9ArrayNode13isSimpleArrayEv
-__ZN3JSC7JSArray14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE
-__ZN3JSCL27compareByStringPairForQSortEPKvS1_
-__ZN3JSC7compareERKNS_7UStringES2_
-__ZN3JSCL24dateProtoFuncToUTCStringEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC17NumberConstructor16getConstructDataERNS_13ConstructDataE
-__ZN3JSCL30constructWithNumberConstructorEPNS_9ExecStateEPNS_8JSObjectERKNS_7ArgListE
-__ZN3JSC12NumberObjectC1EN3WTF17NonNullPassRefPtrINS_9StructureEEE
-__ZN3JSCL20isNonASCIIIdentStartEi
-__ZN3JSC9Arguments3putEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueERNS_15PutPropertySlotE
-__ZN3JSC14MacroAssembler4peekENS_12X86Registers10RegisterIDEi
-__ZN3JSC4Yarr14RegexGenerator12atEndOfInputEv
-__ZN3JSC14MacroAssembler8branch32ENS_23MacroAssemblerX86Common9ConditionENS_12X86Registers10RegisterIDENS_22AbstractMacroAssemb
-__ZN3JSC22AbstractMacroAssemblerINS_12X86AssemblerEE8JumpList6linkToENS2_5LabelEPS2_
-__ZN3JSC14MacroAssembler4pokeENS_12X86Registers10RegisterIDEi
-__ZN3JSCL28substituteBackreferencesSlowERKNS_7UStringES2_PKiPNS_6RegExpEj
-__ZN3WTF6VectorItLm0EE6appendItEEvPKT_m
-_cti_op_to_primitive
-__ZN3JSC15constructNumberEPNS_9ExecStateENS_7JSValueE
-__ZNK3JSC12NumberObject9classInfoEv
-__Z12jsRegExpFreeP8JSRegExp
-__ZN3JSC13BooleanObjectD1Ev
-__ZN3JSCL18stringFromCharCodeEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC10makeStringIPKcNS_7UStringES2_EES3_T_T0_T1_
-__ZN3JSCL19dateProtoFuncGetDayEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC14EvalExecutable20reparseExceptionInfoEPNS_12JSGlobalDataEPNS_14ScopeChainNodeEPNS_9CodeBlockE
-__ZN3JSCL22objectProtoFuncValueOfEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC8JSObject18getPrimitiveNumberEPNS_9ExecStateERdRNS_7JSValueE
-__ZN3JSCL24dateProtoFuncGetFullYearEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC12RegExpObject3putEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueERNS_15PutPropertySlotE
-__ZN3JSCL24setRegExpObjectLastIndexEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueE
-__Z15jsc_pcre_xclassiPKh
-__ZN3JSCL28regExpConstructorLeftContextEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
-__ZNK3JSC17RegExpConstructor14getLeftContextEPNS_9ExecStateE
+__ZN3JSCL21callFunctionPrototypeEPNS_9ExecStateE
+__ZNK3JSC14ExpressionNode10isLocationEv
+__ZN3JSC21FunctionCallValueNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC23createNotAFunctionErrorEPNS_9ExecStateENS_7JSValueE
+__ZN3JSC10JSFunction19getOwnPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayENS_15EnumerationModeE
+__ZNK3JSC9CommaNode11isCommaNodeEv
+__ZN3JSC20globalFuncParseFloatEPNS_9ExecStateE
+__ZN3WTF6VectorIN3JSC15SimpleJumpTableELm0EE14expandCapacityEm
+__ZNK3JSC5Label4bindEii
+__ZN3WTF6VectorIiLm0EEC2ERKS1_
+__ZN3JSC3JIT18emit_op_switch_immEPNS_11InstructionE
+__ZN3WTF6VectorIN3JSC17CodeLocationLabelELm0EE14expandCapacityEm
+_cti_op_switch_imm
+__ZN3JSC18globalFuncIsFiniteEPNS_9ExecStateE
+__ZN3JSC28createUndefinedVariableErrorEPNS_9ExecStateERKNS_10IdentifierE
+__ZN3JSC11makeUStringIPKcNS_7UStringEEES3_T_T0_
+__ZN3WTF13tryMakeStringIPKcN3JSC7UStringEEENS_10PassRefPtrINS_10StringImplEEET_T0_
+__ZN3JSC15AssignErrorNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC17BytecodeGenerator23emitThrowReferenceErrorERKNS_7UStringE
+__ZN3JSC3JIT29emit_op_throw_reference_errorEPNS_11InstructionE
+_cti_op_throw_reference_error
+__ZN3JSC16parseIntOverflowEPKcii
+__ZN3JSC9ExecState9mathTableEPS0_
+__ZN3JSCL17mathProtoFuncACosEPNS_9ExecStateE
+__ZN3JSCL17mathProtoFuncASinEPNS_9ExecStateE
+__ZN3JSCL17mathProtoFuncATanEPNS_9ExecStateE
+__ZN3JSCL18mathProtoFuncATan2EPNS_9ExecStateE
+__ZN3JSCL17mathProtoFuncCeilEPNS_9ExecStateE
+__ZN3JSCL16mathProtoFuncCosEPNS_9ExecStateE
+__ZN3JSCL16mathProtoFuncExpEPNS_9ExecStateE
+__ZN3JSCL16mathProtoFuncLogEPNS_9ExecStateE
+__ZN3JSCL16mathProtoFuncMaxEPNS_9ExecStateE
+__ZN3JSCL16mathProtoFuncMinEPNS_9ExecStateE
+__ZN3JSCL16mathProtoFuncPowEPNS_9ExecStateE
+__ZN3JSCL19mathProtoFuncRandomEPNS_9ExecStateE
+__ZN3JSCL18mathProtoFuncRoundEPNS_9ExecStateE
+__ZN3JSCL16mathProtoFuncSinEPNS_9ExecStateE
+__ZN3JSCL17mathProtoFuncSqrtEPNS_9ExecStateE
+__ZN3JSCL16mathProtoFuncTanEPNS_9ExecStateE
+__ZN3JSC9ExecState22numberConstructorTableEPS0_
+__ZN3JSC6JSCell11getJSNumberEv
+__ZN3JSCL21callObjectConstructorEPNS_9ExecStateE
+__ZN3JSC9ExecState22objectConstructorTableEPS0_
_cti_to_object
-__ZNK3JSC7JSValue16toObjectSlowCaseEPNS_9ExecStateE
-_cti_op_sub
-__ZN3JSC17NumberConstructor11getCallDataERNS_8CallDataE
-__ZN3JSCL21callNumberConstructorEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-_cti_op_bitxor
-_cti_op_is_function
-__ZN3JSC16jsIsFunctionTypeENS_7JSValueE
-__ZN3JSC12NumberObjectD1Ev
-__ZN3WTF6VectorIN3JSC22AbstractMacroAssemblerINS1_12X86AssemblerEE4JumpELm16EE14expandCapacityEm
-__ZN3JSC8JSString18getPrimitiveNumberEPNS_9ExecStateERdRNS_7JSValueE
-__ZN7WebCore6String26fromUTF8WithLatin1FallbackEPKcm
-__ZN7WebCore6String8fromUTF8EPKcm
-__ZN3WTF10fastStrDupEPKc
-__ZN3JSC10throwErrorEPNS_9ExecStateENS_9ErrorTypeE
-__ZN3WTF6VectorIN3JSC15StringJumpTableELm0EE14expandCapacityEm
-__ZN3WTF9HashTableINS_6RefPtrIN7WebCore10StringImplEEESt4pairIS4_N3JSC14OffsetLocationEENS_18PairFirstExtractorIS8_EENS2_10Stri
-__ZN3JSC3JIT21emit_op_switch_stringEPNS_11InstructionE
-__ZN3JSC13LiteralParser5Lexer9lexNumberERNS1_18LiteralParserTokenE
-__ZN3WTF6VectorIPNS_14StringImplBaseELm32EE14expandCapacityEm
-__ZN3JSC4Yarr17nonwordcharCreateEv
-__ZN3JSC3JIT15emit_op_eq_nullEPNS_11InstructionE
-_cti_op_switch_string
-__ZN3JSC12X86Assembler23X86InstructionFormatter15emitRexIfNeededEiii
-__ZN3JSC12X86Assembler23X86InstructionFormatter11memoryModRMEiNS_12X86Registers10RegisterIDES3_ii
-__ZN3JSC4Yarr6ParserINS0_23RegexPatternConstructorEE28CharacterClassParserDelegate25atomBuiltInCharacterClassENS0_23BuiltInChar
+__ZN3JSC9ExecState20numberPrototypeTableEPS0_
+__ZNK3JSC15DotAccessorNode17isDotAccessorNodeEv
+__ZN3JSC10Identifier11addSlowCaseEPNS_12JSGlobalDataEPN3WTF10StringImplE
+__ZNK3JSC14ExpressionNode17isDotAccessorNodeEv
+__ZN3JSC9ExecState22stringConstructorTableEPS0_
+__ZN3JSCL26stringFromCharCodeSlowCaseEPNS_9ExecStateE
+__ZN3JSCL25stringProtoFuncCharCodeAtEPNS_9ExecStateE
+__ZNK3JSC12JSActivation12toThisObjectEPNS_9ExecStateE
+__ZN3JSCL26stringProtoFuncToLowerCaseEPNS_9ExecStateE
+__ZN3JSCL26stringProtoFuncToUpperCaseEPNS_9ExecStateE
+__ZN3JSC12StringObject19getOwnPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayENS_15EnumerationModeE
+__ZN3JSC9ExecState11stringTableEPS0_
+__ZN3JSC12StringObject14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE
+__ZN3JSC17BytecodeGenerator18pushFinallyContextEPNS_5LabelEPNS_10RegisterIDE
+__ZN3JSC17BytecodeGenerator17popFinallyContextEv
+__ZN3JSC17BytecodeGenerator19highestUsedRegisterEv
+__ZN3JSC17BytecodeGenerator18emitJumpSubroutineEPNS_10RegisterIDEPNS_5LabelE
+__ZN3JSC17BytecodeGenerator20emitSubroutineReturnEPNS_10RegisterIDE
+__ZN3JSC3JIT11emit_op_jsrEPNS_11InstructionE
+__ZN3WTF6VectorIN3JSC3JIT7JSRInfoELm0EE14expandCapacityEm
+__ZN3JSC3JIT12emit_op_sretEPNS_11InstructionE
+_cti_op_check_has_instance
+__ZN3JSC23createInvalidParamErrorEPNS_9ExecStateEPKcNS_7JSValueE
+__ZN3JSC11makeUStringIPKcNS_7UStringES2_S2_S2_EES3_T_T0_T1_T2_T3_
+__ZN3WTF13tryMakeStringIPKcN3JSC7UStringES2_S2_S2_EENS_10PassRefPtrINS_10StringImplEEET_T0_T1_T2_T3_
+_cti_op_is_string
+__ZN3JSC17RegExpConstructor18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
+__ZN3JSC12RegExpObject3putEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueERNS_15PutPropertySlotE
+__ZN3JSCL21regExpObjectLastIndexEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
+__ZN3JSC4Yarr12digitsCreateEv
+__ZN3WTF6VectorIN3JSC4Yarr12ByteCompiler21ParenthesesStackEntryELm0EE14expandCapacityEm
+__ZN3JSC4Yarr12ByteCompiler16closeAlternativeEi
+__ZN3WTF6VectorIN3JSC4Yarr8ByteTermELm0EE14expandCapacityEmPKS3_
+__ZN3WTF6VectorIPN3JSC4Yarr15ByteDisjunctionELm0EE14expandCapacityEm
+__ZN3JSC3JIT16emit_op_jeq_nullEPNS_11InstructionE
+__ZN3JSC18RegExpMatchesArray18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
+__ZN3JSC4Yarr11Interpreter20backtrackParenthesesERNS0_8ByteTermEPNS1_18DisjunctionContextE
+__ZN3JSC4Yarr11YarrPattern21newlineCharacterClassEv
+__ZN3JSC4Yarr6ParserINS0_22YarrPatternConstructorEE28CharacterClassParserDelegate25atomBuiltInCharacterClassENS0_23BuiltInCharacterClassIDEb
+__ZN3WTF6VectorIPN3JSC4Yarr14CharacterClassELm0EE14expandCapacityEmPKS4_
+__ZN3JSC4Yarr25CharacterClassConstructor6appendEPKNS0_14CharacterClassE
__ZN3JSC4Yarr15nonspacesCreateEv
-__ZN3JSCL25functionProtoFuncToStringEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZNK3JSC21UStringSourceProvider8getRangeEii
-__ZNK3JSC7UString6substrEjj
-__ZN3JSC10makeStringINS_7UStringEPKcS1_EES1_T_T0_T1_
-__ZNK3JSC18FunctionExecutable11paramStringEv
-__ZN3WTF6VectorItLm64EE6appendItEEvPKT_m
-__ZN3JSC13tryMakeStringIPKcNS_7UStringES2_S3_S2_S3_EEN3WTF10PassRefPtrIN7WebCore10StringImplEEET_T0_T1_T2_T3_T4_
-__ZN3JSC17RegExpConstructor3putEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueERNS_15PutPropertySlotE
-__ZN3JSCL21arrayProtoFuncForEachEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC10JSFunction14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE
-__ZN3JSCL22arrayProtoFuncToStringEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
+__ZN3WTF6VectorIN3JSC22AbstractMacroAssemblerINS1_12X86AssemblerEE4JumpELm16EE14expandCapacityEmPKS5_
+__ZN3WTF6VectorIN3JSC22AbstractMacroAssemblerINS1_12X86AssemblerEE4JumpELm16EE14expandCapacityEm
+__ZN3JSC4Yarr15nondigitsCreateEv
+__ZN3JSC4Yarr13YarrGenerator29generateAssertionWordBoundaryEm
+__ZN3JSCL24setRegExpObjectLastIndexEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueE
+__ZN3JSC9ExecState11regExpTableEPS0_
+__ZN3JSC9ExecState20regExpPrototypeTableEPS0_
+__ZN3JSC8JSParser21parseDoWhileStatementINS_13SyntaxCheckerEEENT_9StatementERS3_
+__ZN3JSC9LabelNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC14PostfixDotNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3WTF6VectorIiLm0EE15reserveCapacityEm
+__ZN3JSC3JIT19emit_op_switch_charEPNS_11InstructionE
+_cti_op_switch_char
+__ZN3JSC22AbstractMacroAssemblerINS_12X86AssemblerEE8JumpList6appendERS3_
+__ZNK3WTF9HashTableIPN3JSC20MarkedArgumentBufferES3_NS_17IdentityExtractorIS3_EENS_7PtrHashIS3_EENS_10HashTraitsIS3_EES9_E4findIS3_NS_22IdentityHashTranslatorIS3_S3_S7_EEEENS_22HashTableConstIteratorIS3_S3_S5_S7_S9_S9_EERKT_
+__ZN3JSCL20stringProtoFuncSliceEPNS_9ExecStateE
+_cti_op_get_by_id_proto_fail
+__ZN3JSCL28arrayProtoFuncToLocaleStringEPNS_9ExecStateE
+__ZN3JSCL17arrayProtoFuncPopEPNS_9ExecStateE
+__ZN3JSC7JSArray3popEv
__ZN3JSC16ErrorConstructor16getConstructDataERNS_13ConstructDataE
-__ZN3JSCL29constructWithErrorConstructorEPNS_9ExecStateEPNS_8JSObjectERKNS_7ArgListE
-__ZN3JSC14constructErrorEPNS_9ExecStateERKNS_7ArgListE
-_cti_op_instanceof
-__ZN3JSC6RegExp6createEPNS_12JSGlobalDataERKNS_7UStringE
-__ZN3WTF9HashTableIPN7WebCore10StringImplES3_NS_17IdentityExtractorIS3_EENS_7PtrHashIS3_EENS_10HashTraitsIS3_EES9_E4findIS3_NS_
-_cti_op_get_by_id_string_fail
-__ZN3JSCL20stringProtoFuncSliceEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC14MacroAssembler4jumpENS_22AbstractMacroAssemblerINS_12X86AssemblerEE5LabelE
-__ZN3JSCL23regExpProtoFuncToStringEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL18regExpObjectGlobalEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
-__ZN3JSCL22regExpObjectIgnoreCaseEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
-__ZN3JSCL21regExpObjectMultilineEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
-__ZN3JSC13tryMakeStringIPKcNS_7UStringEPcEEN3WTF10PassRefPtrIN7WebCore10StringImplEEET_T0_T1_
-__ZN3JSC12JSActivation14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE
-__ZN3WTFL10timerFiredEP16__CFRunLoopTimerPv
-__ZN7WebCore22charactersToUIntStrictEPKtmPbi
-__ZN3WTF9HashTableIjSt4pairIjN3JSC7JSValueEENS_18PairFirstExtractorIS4_EENS_7IntHashIjEENS_14PairHashTraitsINS_10HashTraitsIjEE
-__ZN3JSCL23dateProtoFuncSetMinutesEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL23setNewValueFromTimeArgsEPNS_9ExecStateENS_7JSValueERKNS_7ArgListEib
-__ZN3JSCL23dateProtoFuncSetSecondsEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL28dateProtoFuncSetMilliSecondsEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL9dateParseEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL21dateProtoFuncToStringEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC10formatDateERKNS_17GregorianDateTimeERA100_c
-__ZN3JSC10formatTimeERKNS_17GregorianDateTimeERA100_c
-__ZN3JSC19globalFuncEncodeURIEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC13UnaryPlusNode14stripUnaryPlusEv
-__ZN3JSCL20arrayProtoFuncFilterEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL27objectProtoFuncLookupGetterEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC8JSObject12lookupGetterEPNS_9ExecStateERKNS_10IdentifierE
-__ZNK3JSC6JSCell14isGetterSetterEv
-__ZN3JSCL27objectProtoFuncDefineSetterEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC8JSObject12defineSetterEPNS_9ExecStateERKNS_10IdentifierEPS0_j
-__ZN3JSCL27objectProtoFuncDefineGetterEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC8JSObject12defineGetterEPNS_9ExecStateERKNS_10IdentifierEPS0_j
-__ZNK3JSC12GetterSetter14isGetterSetterEv
-__ZN3JSC8JSObject15unwrappedObjectEv
-__ZN3JSC10JSFunction12callerGetterEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
-__ZNK3JSC11Interpreter14retrieveCallerEPNS_9ExecStateEPNS_16InternalFunctionE
-__ZN3JSC16toUInt32SlowCaseEdRb
-__ZN3JSC8JSObject22fillGetterPropertySlotERNS_12PropertySlotEPNS_7JSValueE
-__ZNK3JSC12PropertySlot14functionGetterEPNS_9ExecStateE
-_cti_op_get_by_id_getter_stub
-__ZN3JSC12GetterSetter12markChildrenERNS_9MarkStackE
-__ZN3JSCL17mathProtoFuncACosEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3WTF13tryFastCallocEmm
-__ZN3JSC3JIT20emit_op_resolve_skipEPNS_11InstructionE
-_cti_op_resolve_skip
-__ZN3JSC3JIT15emit_op_urshiftEPNS_11InstructionE
-__ZN3JSC3JIT19emitSlow_op_urshiftEPNS_11InstructionERPNS_13SlowCaseEntryE
-__ZN3JSCL25stringProtoFuncCharCodeAtEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3WTF6VectorIcLm0EE14expandCapacityEm
-__ZN3JSC15AssignErrorNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC23ThrowableExpressionData14emitThrowErrorERNS_17BytecodeGeneratorENS_9ErrorTypeEPKc
-__ZN3JSC17BytecodeGenerator12emitNewErrorEPNS_10RegisterIDENS_9ErrorTypeENS_7JSValueE
-__ZN3JSC3JIT17emit_op_new_errorEPNS_11InstructionE
-__ZN3JSCL27objectProtoFuncLookupSetterEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC8JSObject12lookupSetterEPNS_9ExecStateERKNS_10IdentifierE
-__ZN3JSC26createNotAnObjectErrorStubEPNS_9ExecStateEb
-__ZN3JSC13JSNotAnObject18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
-__ZNK3JSC22JSNotAnObjectErrorStub22isNotAnObjectErrorStubEv
-__ZN3JSC22createNotAnObjectErrorEPNS_9ExecStateEPNS_22JSNotAnObjectErrorStubEjPNS_9CodeBlockE
-__ZN3JSC9CodeBlock37getByIdExceptionInfoForBytecodeOffsetEPNS_9ExecStateEjRNS_8OpcodeIDE
-__ZN3JSCL18createErrorMessageEPNS_9ExecStateEPNS_9CodeBlockEiiiNS_7JSValueENS_7UStringE
-__ZN3JSC10makeStringIPKcNS_7UStringES2_S3_S2_S3_S2_EES3_T_T0_T1_T2_T3_T4_T5_
-__ZN3JSC13tryMakeStringIPKcNS_7UStringES2_S3_S2_S3_S2_EEN3WTF10PassRefPtrIN7WebCore10StringImplEEET_T0_T1_T2_T3_T4_T5_
-__ZN3JSC22JSNotAnObjectErrorStubD1Ev
-__ZN3JSC13JSNotAnObjectD1Ev
-__ZN3JSC12GetterSetterD1Ev
-__ZN3JSC20FixedVMPoolAllocator17coalesceFreeSpaceEv
-__ZN3WTF6VectorIPN3JSC13FreeListEntryELm0EE15reserveCapacityEm
-__ZN3JSCL35reverseSortFreeListEntriesByPointerEPKvS1_
-__ZN3JSCL33reverseSortCommonSizedAllocationsEPKvS1_
-__ZN7WebCore20equalIgnoringNullityEPNS_10StringImplES1_
-__ZN3JSC19globalFuncDecodeURIEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
+__ZN3JSCL29constructWithErrorConstructorEPNS_9ExecStateE
+__ZN3JSCL22compareNumbersForQSortEPKvS1_
+__ZN3JSCL25dateProtoFuncToDateStringEPNS_9ExecStateE
+__ZN3JSCL25dateProtoFuncToTimeStringEPNS_9ExecStateE
+_cti_op_get_by_val_string
+__ZN3JSCL27dateProtoFuncToLocaleStringEPNS_9ExecStateE
+__ZN3JSCL16formatLocaleDateEPNS_9ExecStateEPNS_12DateInstanceEdNS_20LocaleDateTimeFormatE
+__ZN3JSCL31dateProtoFuncToLocaleDateStringEPNS_9ExecStateE
__ZN3JSC16ErrorConstructor11getCallDataERNS_8CallDataE
-__ZN3JSCL20callErrorConstructorEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL22functionProtoFuncApplyEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC9Arguments11fillArgListEPNS_9ExecStateERNS_20MarkedArgumentBufferE
-__ZN3JSCL21functionProtoFuncCallEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC10JSONObject18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
-_cti_op_lshift
+__ZN3JSCL20callErrorConstructorEPNS_9ExecStateE
+__ZN3JSC17RegExpConstructor11getCallDataERNS_8CallDataE
+__ZN3JSCL21callRegExpConstructorEPNS_9ExecStateE
+__ZNK3JSC8JSObject15isErrorInstanceEv
+__ZN3JSC3JIT26emit_op_tear_off_argumentsEPNS_11InstructionE
+__ZN3JSC8jsStringEPNS_9ExecStateERKNS_7UStringE
+__ZN3JSC12JSActivation14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE
+__ZN3JSC17BytecodeGenerator14emitPutByIndexEPNS_10RegisterIDEjS2_
+__ZN3JSC3JIT20emit_op_put_by_indexEPNS_11InstructionE
+_cti_op_put_by_index
+__ZN3JSC18EmptyStatementNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC9Arguments14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE
+__ZN3JSC17DeleteBracketNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC17BytecodeGenerator15emitDeleteByValEPNS_10RegisterIDES2_S2_
+_cti_op_del_by_val
+__ZN3JSC9Arguments14deletePropertyEPNS_9ExecStateEj
+__ZN3JSC14LogicalNotNode30emitBytecodeInConditionContextERNS_17BytecodeGeneratorEPNS_5LabelES4_b
+_cti_op_tear_off_arguments
+__ZN3JSC9Arguments3putEPNS_9ExecStateEjNS_7JSValueE
+__ZN3JSCL29objectProtoFuncHasOwnPropertyEPNS_9ExecStateE
+__ZNK3JSC8JSObject14hasOwnPropertyEPNS_9ExecStateERKNS_10IdentifierE
+__ZN3JSCL22numberProtoFuncToFixedEPNS_9ExecStateE
+__ZN3WTF11dtoaRoundDPEPcdiRbRiRj
+__ZN3WTF4dtoaILb0ELb0ELb1ELb0EEEvPcdiRbRiRj
+__ZN3JSCL28numberProtoFuncToExponentialEPNS_9ExecStateE
+__ZN3WTF11dtoaRoundSFEPcdiRbRiRj
+__ZN3WTF4dtoaILb0ELb1ELb0ELb0EEEvPcdiRbRiRj
+__ZN3JSCL26numberProtoFuncToPrecisionEPNS_9ExecStateE
+__ZN3JSC22NativeErrorConstructor16getConstructDataERNS_13ConstructDataE
+__ZN3JSCL35constructWithNativeErrorConstructorEPNS_9ExecStateE
+__ZN3JSC23MacroAssemblerX86Common8branch16ENS0_19RelationalConditionENS_22AbstractMacroAssemblerINS_12X86AssemblerEE9BaseIndexENS4_12TrustedImm32E
+__ZN3JSC4Yarr17nonwordcharCreateEv
+__ZN3JSC12X86Assembler23X86InstructionFormatter15emitRexIfNeededEiii
+__ZN3JSC8JSString18getPrimitiveNumberEPNS_9ExecStateERdRNS_7JSValueE
+__ZN3JSCL28substituteBackreferencesSlowERKNS_7UStringES2_PKiPNS_6RegExpEm
+__ZN3WTF6VectorItLm0EE6appendItEEvPKT_m
+__ZN3JSC17createSyntaxErrorEPNS_9ExecStateERKNS_7UStringE
+__ZN3JSCL26regExpConstructorLastMatchEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
+__ZNK3JSC17RegExpConstructor10getBackrefEPNS_9ExecStateEj
+__ZN3JSCL28regExpConstructorLeftContextEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
+__ZNK3JSC17RegExpConstructor14getLeftContextEPNS_9ExecStateE
__ZN3JSCL29regExpConstructorRightContextEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
__ZNK3JSC17RegExpConstructor15getRightContextEPNS_9ExecStateE
-__ZN3JSC20MarkedArgumentBuffer10slowAppendENS_7JSValueE
-__ZN3WTF9HashTableIPN3JSC20MarkedArgumentBufferES3_NS_17IdentityExtractorIS3_EENS_7PtrHashIS3_EENS_10HashTraitsIS3_EES9_E6expan
-__ZN3WTF6VectorIN3JSC8RegisterELm8EE15reserveCapacityEm
-__ZN3WTF9HashTableIPN3JSC20MarkedArgumentBufferES3_NS_17IdentityExtractorIS3_EENS_7PtrHashIS3_EENS_10HashTraitsIS3_EES9_E4findI
-__ZN3JSCL26stringFromCharCodeSlowCaseEPNS_9ExecStateERKNS_7ArgListE
-__ZN3JSC4Yarr12RegexPattern21newlineCharacterClassEv
-__ZN3JSC10JSFunction12lengthGetterEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
-__ZN3JSC18globalFuncIsFiniteEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC16ArrayConstructor11getCallDataERNS_8CallDataE
-__ZN3JSCL20callArrayConstructorEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL19stringProtoFuncTrimEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC15isStrWhiteSpaceEt
-__ZN3JSC6JSCell9getObjectEv
-_ctiOpThrowNotCaught
-__ZN3JSCL22numberProtoFuncValueOfEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC12NumberObject11getJSNumberEv
-__ZN7WebCore10StringImpl6secureEt
-__ZN3JSC23createNotAFunctionErrorEPNS_9ExecStateENS_7JSValueEjPNS_9CodeBlockE
-_cti_op_rshift
-__ZN3JSC13JSNotAnObject18getOwnPropertySlotEPNS_9ExecStateEjRNS_12PropertySlotE
-__ZN3WTF6VectorIN3JSC22AbstractMacroAssemblerINS1_12X86AssemblerEE4JumpELm16EEC2ERKS6_
-__ZN3JSCL21arrayProtoFuncReverseEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3WTF21CrossThreadRefCountedINS_16OwnFastMallocPtrIKtEEE5derefEv
-_cti_op_post_inc
-__ZN3JSCL21regExpObjectLastIndexEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
-__ZN3JSC3JIT14emit_op_bitnotEPNS_11InstructionE
-__ZN3JSC3JIT18emitSlow_op_bitnotEPNS_11InstructionERPNS_13SlowCaseEntryE
-_cti_op_bitnot
-__ZNK3JSC10JSONObject9classInfoEv
-_JSGlobalContextCreate
-_JSGlobalContextCreateInGroup
-__ZN3JSC12JSGlobalData18createContextGroupENS_15ThreadStackTypeE
-__ZN3JSC21createIdentifierTableEv
-__ZN3JSC4Heap29makeUsableFromMultipleThreadsEv
-__ZN3JSC6JSLock6unlockENS_14JSLockBehaviorE
-_JSValueMakeFromJSONString
-_JSValueIsNull
-_JSValueIsUndefined
-_JSValueIsBoolean
-_JSValueIsNumber
-_JSValueIsString
-__ZN3JSC14JSGlobalObject18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
-_JSValueIsInstanceOfConstructor
-__ZN3JSC8JSObject11hasInstanceEPNS_9ExecStateENS_7JSValueES3_
-_JSValueToNumber
-_JSObjectGetPropertyAtIndex
-_JSValueToStringCopy
-__ZN14OpaqueJSString6createERKN3JSC7UStringE
-_JSStringCopyCFString
-__ZN3JSC4Heap7destroyEv
-__ZN3JSC4Heap10freeBlocksEv
-__ZN3JSC14JSGlobalObjectD1Ev
-__ZN3JSC14JSGlobalObject25destroyJSGlobalObjectDataEPv
-__ZN3JSC12JSGlobalDataD1Ev
-__ZN3JSC12JSGlobalDataD2Ev
-__ZN3JSC12RegisterFileD1Ev
-__ZNK3JSC9HashTable11deleteTableEv
-__ZN3JSC5LexerD1Ev
-__ZN3WTF20deleteAllPairSecondsIP24OpaqueJSClassContextDataKNS_7HashMapIP13OpaqueJSClassS2_NS_7PtrHashIS5_EENS_10HashTraitsIS5_E
-__ZN3JSC17CommonIdentifiersD2Ev
-__ZN3JSC21deleteIdentifierTableEPNS_15IdentifierTableE
-__ZN3JSC15IdentifierTableD2Ev
-__ZN3JSC4HeapD1Ev
-__ZN3JSC9JITThunksD1Ev
-__ZN3JSC16NativeExecutableD0Ev
-__ZN3JSC12SmallStringsD1Ev
-__ZN3JSC14JSGlobalObject17putWithAttributesEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueEj
-__ZN3JSC17ObjectConstructor11getCallDataERNS_8CallDataE
-__ZN3JSCL21callObjectConstructorEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC9Arguments14deletePropertyEPNS_9ExecStateEj
-__ZN3JSCL18JSONProtoFuncParseEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC7JSArray11fillArgListEPNS_9ExecStateERNS_20MarkedArgumentBufferE
-__ZN3JSCL17arrayProtoFuncMapEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC12StringObjectC1EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEE
-__ZN3JSC23MacroAssemblerX86Common9urshift32ENS_12X86Registers10RegisterIDES2_
-_cti_op_urshift
-__ZN3JSC15ObjectPrototype3putEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueERNS_15PutPropertySlotE
-__ZN3JSCL21stringProtoFuncConcatEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
+__ZN3WTF6VectorIiLm32EE15reserveCapacityEm
+__ZN3WTF6VectorIN3JSC11StringRangeELm16EE14expandCapacityEmPKS2_
+__ZN3WTF6VectorIN3JSC11StringRangeELm16EE15reserveCapacityEm
+__ZN3WTF6VectorIN3JSC7UStringELm16EE14expandCapacityEmPKS2_
+__ZN3WTF6VectorIN3JSC7UStringELm16EE15reserveCapacityEm
+__ZN3JSCL24regExpConstructorDollar1EPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
__ZN3JSCL24regExpConstructorDollar2EPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
+__ZN3WTF6VectorIPNS0_IN3JSC5LabelELm32EEELm32EE14expandCapacityEmPKS4_
+__ZN3WTF6VectorIPNS0_IN3JSC5LabelELm32EEELm32EE15reserveCapacityEm
+__ZN3JSC8JSString16replaceCharacterEPNS_9ExecStateEtRKNS_7UStringE
+__ZN3JSCL19arrayProtoFuncShiftEPNS_9ExecStateE
+__ZN3JSC7JSArray10shiftCountEPNS_9ExecStateEi
+__ZN3JSCL21arrayProtoFuncUnShiftEPNS_9ExecStateE
+__ZN3JSC7JSArray12unshiftCountEPNS_9ExecStateEi
+__ZN3JSC7JSArray26increaseVectorPrefixLengthEj
+__ZN3WTF6VectorIPN3JSC14ExpressionNodeELm16EE14expandCapacityEm
+__ZN3JSCL21stringProtoFuncConcatEPNS_9ExecStateE
__ZN3JSCL24regExpConstructorDollar3EPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
__ZN3JSCL24regExpConstructorDollar4EPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
-__ZN3JSC20MarkedArgumentBuffer9markListsERNS_9MarkStackERN3WTF7HashSetIPS0_NS3_7PtrHashIS5_EENS3_10HashTraitsIS5_EEEE
-__ZN3JSCL22numberProtoFuncToFixedEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL16integerPartNoExpEd
-__ZN3JSC10makeStringINS_7UStringES1_PKcS1_EES1_T_T0_T1_T2_
-__ZN3JSC13tryMakeStringINS_7UStringES1_PKcS1_EEN3WTF10PassRefPtrIN7WebCore10StringImplEEET_T0_T1_T2_
-__ZN3JSCL26numberProtoFuncToPrecisionEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL12charSequenceEci
-__ZN3JSC13tryMakeStringINS_7UStringEPKcS1_S1_EEN3WTF10PassRefPtrIN7WebCore10StringImplEEET_T0_T1_T2_
-__ZN3JSCL24booleanProtoFuncToStringEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZNK3JSC12JSActivation12toThisObjectEPNS_9ExecStateE
-_cti_op_div
-__ZN3JSC17BytecodeGenerator21emitComplexJumpScopesEPNS_5LabelEPNS_18ControlFlowContextES4_
-__ZN7WebCore10StringImpl7replaceEjjPS0_
-__ZN3JSC12RegExpObject11getCallDataERNS_8CallDataE
-__ZN3JSC12StringObject19getOwnPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayENS_15EnumerationModeE
-__ZN3JSC9ExecState11stringTableEPS0_
-__ZNK3JSC7JSValue16synthesizeObjectEPNS_9ExecStateE
-__ZN3JSC13JSNotAnObject3putEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueERNS_15PutPropertySlotE
-__ZN3JSCL35objectProtoFuncPropertyIsEnumerableEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
+__ZN3JSCL24regExpConstructorDollar5EPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
+__ZN3JSCL24regExpConstructorDollar6EPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
+__ZN3JSCL24regExpConstructorDollar7EPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
+__ZN3JSCL24regExpConstructorDollar8EPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
+__ZN3JSCL24regExpConstructorDollar9EPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
+__ZN3JSC17RegExpConstructor3putEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueERNS_15PutPropertySlotE
+__ZN3JSCL25setRegExpConstructorInputEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueE
+__ZN3JSCL22regExpConstructorInputEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
+__ZN3JSCL26regExpConstructorLastParenEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
+__ZNK3JSC17RegExpConstructor12getLastParenEPNS_9ExecStateE
+__ZN3JSCL26regExpConstructorMultilineEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
+__ZN3JSCL29setRegExpConstructorMultilineEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueE
+__ZN3JSCL22regExpProtoFuncCompileEPNS_9ExecStateE
+__ZN3JSC14globalFuncEvalEPNS_9ExecStateE
+__ZN3JSC11Interpreter7executeEPNS_14EvalExecutableEPNS_9ExecStateEPNS_8JSObjectEPNS_14ScopeChainNodeE
+__ZNK3JSC19JSStaticScopeObject14isDynamicScopeERb
+__ZN3JSC9Arguments3putEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueERNS_15PutPropertySlotE
+__ZN3JSC17ConservativeRoots4growEv
+__ZN3JSCL27objectProtoFuncDefineSetterEPNS_9ExecStateE
+__ZN3JSC15ObjectPrototype3putEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueERNS_15PutPropertySlotE
+__ZN3JSCL27objectProtoFuncLookupSetterEPNS_9ExecStateE
+__ZN3JSC8JSObject12lookupSetterEPNS_9ExecStateERKNS_10IdentifierE
+__ZN3JSCL27objectProtoFuncLookupGetterEPNS_9ExecStateE
+__ZN3JSC8JSObject12lookupGetterEPNS_9ExecStateERKNS_10IdentifierE
+__ZN3JSCL21stringProtoFuncAnchorEPNS_9ExecStateE
+__ZN3WTF13tryMakeStringIPKcN3JSC7UStringES2_S4_S2_EENS_10PassRefPtrINS_10StringImplEEET_T0_T1_T2_T3_
+__ZN3JSCL18stringProtoFuncBigEPNS_9ExecStateE
+__ZN3JSCL20stringProtoFuncBlinkEPNS_9ExecStateE
+__ZN3JSC22jsMakeNontrivialStringIPKcNS_7UStringES2_EENS_7JSValueEPNS_9ExecStateET_T0_T1_
+__ZN3JSCL19stringProtoFuncBoldEPNS_9ExecStateE
+__ZN3JSCL22stringProtoFuncItalicsEPNS_9ExecStateE
+__ZN3JSCL20stringProtoFuncFixedEPNS_9ExecStateE
+__ZN3JSCL24stringProtoFuncFontcolorEPNS_9ExecStateE
+__ZN3JSCL23stringProtoFuncFontsizeEPNS_9ExecStateE
+__ZN3JSCL19stringProtoFuncLinkEPNS_9ExecStateE
+__ZN3JSCL20stringProtoFuncSmallEPNS_9ExecStateE
+__ZN3JSCL21stringProtoFuncStrikeEPNS_9ExecStateE
+__ZN3JSCL18stringProtoFuncSubEPNS_9ExecStateE
+__ZN3JSCL18stringProtoFuncSupEPNS_9ExecStateE
+__ZN3JSC18PostfixBracketNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3JSC19globalFuncEncodeURIEPNS_9ExecStateE
+__ZN3JSCL6encodeEPNS_9ExecStateEPKc
+__ZN3JSC8JSString18getOwnPropertySlotEPNS_9ExecStateEjRNS_12PropertySlotE
+__ZN3JSCL35objectProtoFuncPropertyIsEnumerableEPNS_9ExecStateE
__ZNK3JSC8JSObject20propertyIsEnumerableEPNS_9ExecStateERKNS_10IdentifierE
-__ZN3JSC7JSArray24getOwnPropertyDescriptorEPNS_9ExecStateERKNS_10IdentifierERNS_18PropertyDescriptorE
+__ZN3JSC14JSGlobalObject24getOwnPropertyDescriptorEPNS_9ExecStateERKNS_10IdentifierERNS_18PropertyDescriptorE
+__ZN3JSC16JSVariableObject14symbolTableGetERKNS_10IdentifierERNS_18PropertyDescriptorE
__ZN3JSC18PropertyDescriptor13setDescriptorENS_7JSValueEj
-__ZNK3JSC18PropertyDescriptor10enumerableEv
-__ZN3JSCL22JSONProtoFuncStringifyEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC11StringifierC2EPNS_9ExecStateENS_7JSValueES3_
-__ZN3JSC11Stringifier9stringifyENS_7JSValueE
-__ZN3JSC11Stringifier22appendStringifiedValueERNS_13StringBuilderENS_7JSValueEPNS_8JSObjectERKNS_27PropertyNameForFunctionCallE
-__ZNK3JSC6JSCell9getStringEPNS_9ExecStateERNS_7UStringE
-__ZN3JSC11Stringifier6Holder18appendNextPropertyERS0_RNS_13StringBuilderE
-__ZN3JSC11Stringifier18appendQuotedStringERNS_13StringBuilderERKNS_7UStringE
-__ZN3JSC11StringifierD2Ev
-__ZN3JSC5Lexer19copyCodeWithoutBOMsEv
-__ZN3JSCL21dateProtoFuncSetHoursEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC17FunctionPrototype11getCallDataERNS_8CallDataE
-__ZN3JSCL28dateProtoFuncGetMilliSecondsEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC10makeStringINS_7UStringES1_EES1_T_T0_
-__ZN3JSC13tryMakeStringINS_7UStringES1_EEN3WTF10PassRefPtrIN7WebCore10StringImplEEET_T0_
-__ZN3JSC23MacroAssemblerX86Common8branch16ENS0_9ConditionENS_22AbstractMacroAssemblerINS_12X86AssemblerEE9BaseIndexENS4_5Imm32E
-__Z22jsc_pcre_ucp_othercasej
-__ZN3JSC8JSString18getOwnPropertySlotEPNS_9ExecStateEjRNS_12PropertySlotE
-__ZN3JSCL24dateProtoFuncSetUTCHoursEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL26dateProtoFuncSetUTCMinutesEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL26dateProtoFuncSetUTCSecondsEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL23dateProtoFuncGetUTCDateEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL23dateProtoFuncSetUTCDateEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL24dateProtoFuncGetUTCHoursEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL26dateProtoFuncGetUTCMinutesEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL26dateProtoFuncGetUTCSecondsEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL24dateProtoFuncSetFullYearEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3WTF6VectorIiLm32EE15reserveCapacityEm
-__ZN3JSCL22regExpProtoFuncCompileEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZNK3JSC27PropertyNameForFunctionCall5valueEPNS_9ExecStateE
-_cti_op_new_error
-__ZN7WebCore6String6numberEj
-__ZN3JSCL27dateProtoFuncGetUTCFullYearEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL24dateProtoFuncGetUTCMonthEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL31dateProtoFuncToLocaleDateStringEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL16formatLocaleDateEPNS_9ExecStateEPNS_12DateInstanceEdNS_20LocaleDateTimeFormatERKNS_7ArgListE
-__ZN3JSC10throwErrorEPNS_9ExecStateENS_9ErrorTypeEPKc
-__ZN3JSCL23throwStackOverflowErrorEPNS_9ExecStateEPNS_12JSGlobalDataENS_16ReturnAddressPtrERS4_
-__ZN3JSC24createStackOverflowErrorEPNS_9ExecStateE
-__ZN3JSC12RegisterFile21releaseExcessCapacityEv
+__ZN3JSC19globalFuncDecodeURIEPNS_9ExecStateE
+__ZN3JSC14createURIErrorEPNS_9ExecStateERKNS_7UStringE
+__ZN3WTF6VectorISt4pairIPN3JSC14ExpressionNodeENS2_10ASTBuilder12BinaryOpInfoEELm10EE14expandCapacityEmPKS7_
+__ZN3WTF6VectorISt4pairIPN3JSC14ExpressionNodeENS2_10ASTBuilder12BinaryOpInfoEELm10EE15reserveCapacityEm
+__ZN3WTF6VectorISt4pairIiiELm10EE14expandCapacityEm
+__ZN3JSC29callHostFunctionAsConstructorEPNS_9ExecStateE
+__ZN3JSC3JIT30emit_op_resolve_global_dynamicEPNS_11InstructionE
+__ZN3JSC3JIT34emitSlow_op_resolve_global_dynamicEPNS_11InstructionERPNS_13SlowCaseEntryE
+__ZNK3JSC9ArrayNode13isSimpleArrayEv
+__ZN3JSCL17arrayProtoFuncMapEPNS_9ExecStateE
+__ZN3JSCL21arrayProtoFuncForEachEPNS_9ExecStateE
+__ZN3JSCL20arrayProtoFuncFilterEPNS_9ExecStateE
+__ZN3JSCL19arrayProtoFuncEveryEPNS_9ExecStateE
+__ZN3JSCL18arrayProtoFuncSomeEPNS_9ExecStateE
+__ZN3JSCL21arrayProtoFuncIndexOfEPNS_9ExecStateE
__ZN3JSC12StringObject18getOwnPropertySlotEPNS_9ExecStateEjRNS_12PropertySlotE
-__ZN3JSC19FunctionConstructor11getCallDataERNS_8CallDataE
-__ZN7WebCore6String8fromUTF8EPKc
-__ZN3JSCL27dateProtoFuncToLocaleStringEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC18BooleanConstructor16getConstructDataERNS_13ConstructDataE
-__ZN3JSCL31constructWithBooleanConstructorEPNS_9ExecStateEPNS_8JSObjectERKNS_7ArgListE
-__ZN3JSC16constructBooleanEPNS_9ExecStateERKNS_7ArgListE
-__ZN3JSC7JSArray11sortNumericEPNS_9ExecStateENS_7JSValueENS_8CallTypeERKNS_8CallDataE
-__ZN3JSCL22compareNumbersForQSortEPKvS1_
-__ZN3WTF6VectorIjLm16EE15reserveCapacityEm
-__ZN3JSC8JSString16getIndexSlowCaseEPNS_9ExecStateEj
-__ZN3JSCL25numberConstructorNaNValueEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
-__ZN3JSC6JSCell3putEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueERNS_15PutPropertySlotE
-__ZN3JSC4Yarr15nondigitsCreateEv
-__ZN3JSCL7dateUTCEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZNK3JSC7ArgList2atEm
-__ZN3JSCL16mathProtoFuncTanEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZNK3JSC8JSObject16isVariableObjectEv
-__ZN7WebCore6String6insertERKS0_j
-__ZN7WebCore6String6insertEPKtjj
-__ZN7WebCore10StringImpl37createStrippingNullCharactersSlowCaseEPKtj
-__ZN3JSCL31dateProtoFuncToLocaleTimeStringEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3WTF7CString11mutableDataEv
-__ZN3WTF7CString18copyBufferIfNeededEv
-__ZN3JSCL18arrayProtoFuncSomeEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC21DebuggerStatementNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSCL31dateProtoFuncGetUTCMillisecondsEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3WTF15ThreadConditionD1Ev
-__ZN3JSC18RegExpMatchesArray19getOwnPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayENS_15EnumerationModeE
-__ZN3WTF6VectorIPNS0_IN3JSC10IdentifierELm64EEELm32EE14expandCapacityEm
-__ZN3JSC15DateConstructor11getCallDataERNS_8CallDataE
-__ZN3JSCL8callDateEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL22dateProtoFuncGetUTCDayEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL25arrayProtoFuncLastIndexOfEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL19arrayProtoFuncEveryEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL23callFunctionConstructorEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL19stringProtoFuncLinkEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL25dateProtoFuncToDateStringEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC10throwErrorEPNS_9ExecStateEPNS_8JSObjectE
-__ZN3JSCL27dateProtoFuncSetUTCFullYearEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL24dateProtoFuncSetUTCMonthEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL31dateProtoFuncSetUTCMillisecondsEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN7WebCore6String6numberEx
-__ZNK3JSC17NumberConstructor9classInfoEv
-__ZNK3JSC17RegExpConstructor9classInfoEv
-__ZN3WTF9HashTableINS_6RefPtrIN7WebCore10StringImplEEESt4pairIS4_P19StaticFunctionEntryENS_18PairFirstExtractorIS8_EENS2_10Stri
-__ZN3WTF9HashTableINS_6RefPtrIN7WebCore10StringImplEEESt4pairIS4_P16StaticValueEntryENS_18PairFirstExtractorIS8_EENS2_10StringH
-__ZN3JSC16JSCallbackObjectINS_8JSObjectEE18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
-__ZN3JSC16JSCallbackObjectINS_8JSObjectEE20staticFunctionGetterEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
-__ZN3JSC18JSCallbackFunctionC1EPNS_9ExecStateEPFPK13OpaqueJSValuePK15OpaqueJSContextPS3_S9_mPKS5_PS5_ERKNS_10IdentifierE
-__ZN3JSC18JSCallbackFunction11getCallDataERNS_8CallDataE
-__ZN3JSC18JSCallbackFunction4callEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC6JSLock12DropAllLocksC1EPNS_9ExecStateE
-_JSValueMakeUndefined
-__ZN3JSC16JSCallbackObjectINS_8JSObjectEE17staticValueGetterEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
-_JSValueMakeString
-__ZN3JSC18JSCallbackFunctionD1Ev
-_JSValueMakeBoolean
-_JSStringCreateWithCharacters
-_JSValueMakeNumber
-__ZN3JSC4Heap6isBusyEv
-__ZN7WebCore10StringImpl7replaceEtPS0_
-__ZNK3JSC8JSObject14isGlobalObjectEv
-__ZNK7WebCore6String5splitEtbRN3WTF6VectorIS0_Lm0EEE
-__ZN7WebCore6String6appendEt
-__ZNK3JSC7UString8toUInt32EPb
-__ZN3WTF9ByteArray6createEm
-__ZN3JSC11JSByteArrayC1EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEPNS3_9ByteArrayEPKNS_9ClassInfoE
-__ZN3JSC11JSByteArrayC2EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEPNS3_9ByteArrayEPKNS_9ClassInfoE
+__ZN3JSC8JSObject14deletePropertyEPNS_9ExecStateEj
+__ZN3JSCL25arrayProtoFuncLastIndexOfEPNS_9ExecStateE
+__ZNK3WTF6String7toFloatEPbS1_
+__ZN3WTF10StringImpl7toFloatEPbS1_
+__ZN3WTF17charactersToFloatEPKtmPbS2_
+__ZNK3JSC7UString5asciiEv
+__ZN3JSC6JSLock12DropAllLocksC1ENS_14JSLockBehaviorE
+__ZN3WTF10StringImpl8toDoubleEPbS1_
+__ZN3JSCL21stringProtoFuncSubstrEPNS_9ExecStateE
+__ZN3WTF10StringImpl4findEPKcj
+__ZN3WTF6String26fromUTF8WithLatin1FallbackEPKcm
+__ZN3WTF10fastStrDupEPKc
+__ZN3WTF17equalIgnoringCaseEPKtPKcj
+__ZN3JSC10Identifier5equalEPKN3WTF10StringImplEPKc
+__ZN3JSC11JSByteArray15createStructureERNS_12JSGlobalDataENS_7JSValueEPKNS_9ClassInfoE
+__ZN3JSC11JSByteArrayC1EPNS_9ExecStateEPNS_9StructureEPN3WTF9ByteArrayE
+__ZN3JSC11JSByteArrayC2EPNS_9ExecStateEPNS_9StructureEPN3WTF9ByteArrayE
+__ZN3JSC11JSByteArrayD1Ev
+_cti_op_get_by_val_byte_array
__ZN3JSC11JSByteArray18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
__ZN3JSC11JSByteArray3putEPNS_9ExecStateEjNS_7JSValueE
+_cti_op_put_by_val_byte_array
+__ZN3JSC16throwSyntaxErrorEPNS_9ExecStateE
+__ZN3WTF10StringImpl16findIgnoringCaseEPS0_j
+__ZNK3WTF6String6toUIntEPb
+__ZN3WTF10StringImpl6toUIntEPb
+__ZN3WTF16charactersToUIntEPKtmPb
+__ZN3WTFeqERKNS_12AtomicStringERKNS_6VectorItLm0EEE
+__ZN3WTF12AtomicString16fromUTF8InternalEPKcS2_
+__ZN3WTF7Unicode36calculateStringHashAndLengthFromUTF8EPKcS2_RjS3_
+__ZNK3WTF6String5splitERKS0_RNS_6VectorIS0_Lm0EEE
+__ZN3WTF10StringImpl7replaceEtPS0_
+__ZN3WTFeqERKNS_7CStringES2_
+__ZN3WTF10StringImpl6secureEtNS0_21LastCharacterBehaviorE
+__ZNK3WTF6String5upperEv
+__ZNK3JSC11Interpreter18retrieveLastCallerEPNS_9ExecStateERiRlRNS_7UStringERNS_7JSValueE
+__ZNK3WTF6String6latin1Ev
+__ZN3WTF6VectorIN3JSC14ExecutablePool10AllocationELm2EE15reserveCapacityEm
+__ZN3WTF6String6numberEj
+__ZNK3JSC8JSObject14isGlobalObjectEv
+__ZN3WTF10StringImpl19characterStartingAtEj
+__ZN3WTF6String6appendEt
+__ZNK3WTF6String19characterStartingAtEj
__ZN3JSC11JSByteArray3putEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueERNS_15PutPropertySlotE
__ZN3JSC11JSByteArray18getOwnPropertySlotEPNS_9ExecStateEjRNS_12PropertySlotE
-_cti_op_get_by_val_byte_array
-_cti_op_put_by_val_byte_array
-_JSStringGetUTF8CString
-__ZN3JSC16JSVariableObject19getOwnPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayENS_15EnumerationModeE
-__ZNK3JSC22NativeErrorConstructor9classInfoEv
-__ZNK3JSC16JSCallbackObjectINS_8JSObjectEE9classNameEv
-__ZN3JSC6JSCell16getConstructDataERNS_13ConstructDataE
-__ZN3JSC26createNotAConstructorErrorEPNS_9ExecStateENS_7JSValueEjPNS_9CodeBlockE
-__ZNK3JSC4Heap11objectCountEv
-__ZN3JSC14JSGlobalObject12defineGetterEPNS_9ExecStateERKNS_10IdentifierEPNS_8JSObjectEj
-__ZN3JSC14JSGlobalObject12defineSetterEPNS_9ExecStateERKNS_10IdentifierEPNS_8JSObjectEj
-__ZN3JSC9Structure22getterSetterTransitionEPS0_
-__ZN3JSCL28objectProtoFuncIsPrototypeOfEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC16JSCallbackObjectINS_8JSObjectEE11getCallDataERNS_8CallDataE
-__ZN3JSCL23arrayConstructorIsArrayEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL21objectConstructorKeysEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC12DateInstanceC1EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEd
-__ZN3JSC12DateInstanceC2EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEd
-__ZN3JSCL24dateProtoFuncToISOStringEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC15createTypeErrorEPNS_9ExecStateEPKc
-__ZNK3JSC11JSByteArray9classInfoEv
-__ZN3JSC11JSByteArray19getOwnPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayENS_15EnumerationModeE
-__ZN3JSC22NativeErrorConstructor11getCallDataERNS_8CallDataE
-__ZN3JSCL36objectConstructorGetOwnPropertyNamesEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL41objectConstructorGetOwnPropertyDescriptorEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC16JSVariableObject14symbolTableGetERKNS_10IdentifierERNS_18PropertyDescriptorE
-__ZN3JSC8JSObject24getOwnPropertyDescriptorEPNS_9ExecStateERKNS_10IdentifierERNS_18PropertyDescriptorE
-__ZNK3JSC18PropertyDescriptor20isAccessorDescriptorEv
-__ZNK3JSC18PropertyDescriptor8writableEv
-__ZNK3JSC18PropertyDescriptor12configurableEv
-__ZN3JSC12JSGlobalData6createENS_15ThreadStackTypeE
+__ZN3WTF20equalIgnoringNullityEPNS_10StringImplES1_
+_cti_op_get_by_id_array_fail
+__ZN3JSC17PrefixBracketNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
+__ZN3WTF21CrossThreadRefCountedINS_16OwnFastMallocPtrIKtEEE5derefEv
__ZN3JSC12JSGlobalData10ClientDataD2Ev
+__ZN3JSC8DebuggerD2Ev
__ZN3WTF14ThreadSpecificINS_13WTFThreadDataEE7destroyEPv
__ZN3WTF13WTFThreadDataD1Ev
-__ZN7WebCore17AtomicStringTable7destroyEPS0_
+__ZN3WTF17AtomicStringTable7destroyEPS0_
__ZN3JSC15IdentifierTableD1Ev
-__ZN3WTF9dayInYearEdi
-__ZN3WTF18monthFromDayInYearEib
-__ZN3WTF23dayInMonthFromDayInYearEib
-__ZN3JSC6Walker4walkENS_7JSValueE
-__ZN3WTF9HashTableIPN7WebCore10StringImplES3_NS_17IdentityExtractorIS3_EENS_7PtrHashIS3_EENS_10HashTraitsIS3_EES9_EC2ERKSA_
-__ZN3WTF6VectorIPN3JSC7JSArrayELm16EE14expandCapacityEm
-__ZN3WTF6VectorIjLm16EE14expandCapacityEm
-__ZN3WTF6VectorIN3JSC11WalkerStateELm16EE14expandCapacityEm
-__ZL30makeGetterOrSetterPropertyNodePN3JSC12JSGlobalDataERKNS_10IdentifierES4_PNS_13ParameterNodeEPNS_16FunctionBodyNodeERKNS_1
-__ZN3JSC17BytecodeGenerator13emitPutGetterEPNS_10RegisterIDERKNS_10IdentifierES2_
-__ZN3JSC3JIT18emit_op_put_getterEPNS_11InstructionE
-_cti_op_put_getter
-__ZN3JSCL23booleanProtoFuncValueOfEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL19dateProtoFuncToJSONEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC9ExecState9dateTableEPS0_
-__ZN3JSC10Identifier4fromEPNS_9ExecStateEd
-__ZN3JSC13StringBuilder6appendEt
-__ZN3JSC17BytecodeGenerator13emitPutSetterEPNS_10RegisterIDERKNS_10IdentifierES2_
-__ZN3JSC3JIT18emit_op_put_setterEPNS_11InstructionE
-_cti_op_put_setter
-__ZN3JSCL23objectConstructorCreateEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL16definePropertiesEPNS_9ExecStateEPNS_8JSObjectES3_
-__ZN3JSCL20toPropertyDescriptorEPNS_9ExecStateENS_7JSValueERNS_18PropertyDescriptorE
-__ZN3JSC18PropertyDescriptor13setEnumerableEb
-__ZN3WTF6VectorIN3JSC18PropertyDescriptorELm0EE14expandCapacityEm
-__ZNK3JSC18PropertyDescriptor16isDataDescriptorEv
-__ZN3JSC8JSObject17defineOwnPropertyEPNS_9ExecStateERKNS_10IdentifierERNS_18PropertyDescriptorEb
-__ZN3JSCL13putDescriptorEPNS_9ExecStateEPNS_8JSObjectERKNS_10IdentifierERNS_18PropertyDescriptorEjNS_7JSValueE
-__ZNK3JSC18PropertyDescriptor19isGenericDescriptorEv
-__ZN3JSCL31objectConstructorGetPrototypeOfEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC18PropertyDescriptor9setGetterENS_7JSValueE
-__ZNK3JSC18PropertyDescriptor6getterEv
-__ZNK3JSC18PropertyDescriptor6setterEv
-__ZN3JSC18PropertyDescriptor15setConfigurableEb
-__ZN3JSC18PropertyDescriptor11setWritableEb
-__ZN3JSC18PropertyDescriptor9setSetterENS_7JSValueE
-__ZN3JSCL33objectConstructorDefinePropertiesEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZNK3JSC18PropertyDescriptor7equalToEPNS_9ExecStateERKS0_
-__ZNK3JSC18PropertyDescriptor15attributesEqualERKS0_
-__ZNK3JSC18PropertyDescriptor22attributesWithOverrideERKS0_
-__ZN3JSCL31objectConstructorDefinePropertyEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC9ExecState11regExpTableEPS0_
-__ZN3JSC9Arguments19getOwnPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayENS_15EnumerationModeE
-__ZN3JSC9ExecState11numberTableEPS0_
-__ZN3JSC9ExecState22regExpConstructorTableEPS0_
-__ZNK3JSC15RegExpPrototype9classInfoEv
-__ZNK3JSC10MathObject9classInfoEv
-__ZN3JSC9ExecState9mathTableEPS0_
-__ZN3JSC9ExecState9jsonTableEPS0_
-__ZN3JSCL20arrayProtoFuncReduceEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL25arrayProtoFuncReduceRightEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL28arrayProtoFuncToLocaleStringEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC19JSStaticScopeObject3putEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueERNS_15PutPropertySlotE
-__ZN3JSCL25dateProtoFuncToTimeStringEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC7JSValueC1EPNS_9ExecStateEd
-__ZN3JSC15DeleteValueNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC16PostfixErrorNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC23ThrowableExpressionData14emitThrowErrorERNS_17BytecodeGeneratorENS_9ErrorTypeEPKcRKNS_7UStringE
-__ZN3JSC10makeStringINS_7UStringES1_S1_EES1_T_T0_T1_
-__ZN3JSC13tryMakeStringINS_7UStringES1_S1_EEN3WTF10PassRefPtrIN7WebCore10StringImplEEET_T0_T1_
-__ZN3JSC15PrefixErrorNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE
-__ZN3JSC23createInvalidParamErrorEPNS_9ExecStateEPKcNS_7JSValueEjPNS_9CodeBlockE
-__ZN3JSC10makeStringIPKcS2_S2_EENS_7UStringET_T0_T1_
-__ZN3JSC13tryMakeStringIPKcS2_S2_EEN3WTF10PassRefPtrIN7WebCore10StringImplEEET_T0_T1_
-__ZNK3JSC15DotAccessorNode17isDotAccessorNodeEv
-__ZNK3JSC14ExpressionNode17isDotAccessorNodeEv
-__ZN3JSC13JSNotAnObject3putEPNS_9ExecStateEjNS_7JSValueE
-__ZN3JSC14ArrayPrototype24getOwnPropertyDescriptorEPNS_9ExecStateERKNS_10IdentifierERNS_18PropertyDescriptorE
-__ZN3JSC13DatePrototype24getOwnPropertyDescriptorEPNS_9ExecStateERKNS_10IdentifierERNS_18PropertyDescriptorE
-__ZN3JSC15StringPrototype24getOwnPropertyDescriptorEPNS_9ExecStateERKNS_10IdentifierERNS_18PropertyDescriptorE
-__ZN3JSC12StringObject24getOwnPropertyDescriptorEPNS_9ExecStateERKNS_10IdentifierERNS_18PropertyDescriptorE
-__ZN3JSC8JSString27getStringPropertyDescriptorEPNS_9ExecStateERKNS_10IdentifierERNS_18PropertyDescriptorE
-__ZN3JSC17NumberConstructor24getOwnPropertyDescriptorEPNS_9ExecStateERKNS_10IdentifierERNS_18PropertyDescriptorE
-__ZN3JSC17RegExpConstructor24getOwnPropertyDescriptorEPNS_9ExecStateERKNS_10IdentifierERNS_18PropertyDescriptorE
-__ZN3JSCL22regExpConstructorInputEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
-__ZN3JSC12RegExpObject24getOwnPropertyDescriptorEPNS_9ExecStateERKNS_10IdentifierERNS_18PropertyDescriptorE
-__ZN3JSC10MathObject24getOwnPropertyDescriptorEPNS_9ExecStateERKNS_10IdentifierERNS_18PropertyDescriptorE
-__ZN3JSC18RegExpMatchesArray24getOwnPropertyDescriptorEPNS_9ExecStateERKNS_10IdentifierERNS_18PropertyDescriptorE
-__ZN3JSC10JSFunction24getOwnPropertyDescriptorEPNS_9ExecStateERKNS_10IdentifierERNS_18PropertyDescriptorE
-__ZN3JSC11JSByteArray24getOwnPropertyDescriptorEPNS_9ExecStateERKNS_10IdentifierERNS_18PropertyDescriptorE
-__ZNK3JSC16JSCallbackObjectINS_8JSObjectEE8toStringEPNS_9ExecStateE
-__ZN3JSC10throwErrorEPNS_9ExecStateENS_9ErrorTypeERKNS_7UStringEilS5_
-__ZN3JSC17BytecodeGenerator35emitThrowExpressionTooDeepExceptionEv
-__ZN3JSCL25numberConstructorMinValueEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
-__ZN3JSCL18mathProtoFuncATan2EPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL28numberProtoFuncToExponentialEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC16parseIntOverflowEPKcii
-__ZN3JSCL29objectProtoFuncToLocaleStringEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL24regExpConstructorDollar5EPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
-__ZN3JSCL24regExpConstructorDollar6EPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
-__ZN3JSCL24regExpConstructorDollar7EPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
-__ZN3JSCL24regExpConstructorDollar8EPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
-__ZN3JSCL24regExpConstructorDollar9EPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
-__ZN3JSCL25setRegExpConstructorInputEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueE
-__ZN3JSCL26regExpConstructorLastMatchEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
-__ZN3JSCL26regExpConstructorLastParenEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
-__ZNK3JSC17RegExpConstructor12getLastParenEPNS_9ExecStateE
-__ZN3JSCL26regExpConstructorMultilineEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
-__ZN3JSCL29setRegExpConstructorMultilineEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueE
-__ZNK3JSC17RegExpConstructor5inputEv
-__ZN3JSC10makeStringIPKcS2_EENS_7UStringET_T0_
-__ZN3JSC13tryMakeStringIPKcS2_EEN3WTF10PassRefPtrIN7WebCore10StringImplEEET_T0_
-__ZN3JSC10throwErrorEPNS_9ExecStateENS_9ErrorTypeERKNS_7UStringE
-__ZNK3JSC19JSStaticScopeObject12toThisObjectEPNS_9ExecStateE
-__ZN3JSCL23stringProtoFuncTrimLeftEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL24stringProtoFuncTrimRightEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC12JSActivation18getArgumentsGetterEv
-__ZN3JSC12JSActivation15argumentsGetterEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
-__ZN3JSCL28stringProtoFuncLocaleCompareEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3WTF8Collator11userDefaultEv
-__ZNK3WTF8Collator7collateEPKtmS2_m
-__ZNK3WTF8Collator14createCollatorEv
-__ZN3WTF8CollatorD1Ev
-__ZN3WTF8Collator15releaseCollatorEv
-__ZN3JSC9Arguments14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE
-__ZN3JSCL26callNativeErrorConstructorEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSCL21callFunctionPrototypeEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3JSC6JSCell11getJSNumberEv
-__ZN3JSCL16callRegExpObjectEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE
-__ZN3WTF6VectorIN3JSC20FunctionRegisterInfoELm0EE14expandCapacityEm
-__ZN3JSC3JIT25emit_op_profile_will_callEPNS_11InstructionE
-__ZN3JSC3JIT24emit_op_profile_did_callEPNS_11InstructionE
-__ZN3JSC8Profiler8profilerEv
-__ZN3JSC8Profiler14startProfilingEPNS_9ExecStateERKNS_7UStringE
-__ZN3JSC16ProfileGenerator6createERKNS_7UStringEPNS_9ExecStateEj
-__ZN3JSC16ProfileGeneratorC2ERKNS_7UStringEPNS_9ExecStateEj
-__ZN3JSC7Profile6createERKNS_7UStringEj
-__ZN3JSC7ProfileC2ERKNS_7UStringEj
-__ZN3JSC11ProfileNodeC1ERKNS_14CallIdentifierEPS0_S4_
-__ZN3JSC16ProfileGenerator24addParentForConsoleStartEPNS_9ExecStateE
-__ZN3JSC8Profiler20createCallIdentifierEPNS_9ExecStateENS_7JSValueERKNS_7UStringEi
-__ZN3JSC16InternalFunction21calculatedDisplayNameEPNS_9ExecStateE
-__ZN3JSC16InternalFunction11displayNameEPNS_9ExecStateE
-__ZN3JSC11ProfileNode10insertNodeEN3WTF10PassRefPtrIS0_EE
-__ZN3WTF6VectorINS_6RefPtrIN3JSC11ProfileNodeEEELm0EE14expandCapacityEm
-__ZN3WTF6VectorINS_6RefPtrIN3JSC16ProfileGeneratorEEELm0EE15reserveCapacityEm
-_cti_op_profile_did_call
-__ZN3JSC8Profiler10didExecuteEPNS_9ExecStateENS_7JSValueE
-__ZN3JSC16ProfileGenerator10didExecuteERKNS_14CallIdentifierE
-__ZN3JSC11ProfileNode10didExecuteEv
-_cti_op_profile_will_call
-__ZN3JSC8Profiler11willExecuteEPNS_9ExecStateENS_7JSValueE
-__ZN3JSC16ProfileGenerator11willExecuteERKNS_14CallIdentifierE
-__ZN3JSC11ProfileNode11willExecuteERKNS_14CallIdentifierE
-__ZN3JSC8Profiler13stopProfilingEPNS_9ExecStateERKNS_7UStringE
-__ZN3JSC16ProfileGenerator13stopProfilingEv
-__ZN3JSC7Profile7forEachEMNS_11ProfileNodeEFvvE
-__ZNK3JSC11ProfileNode25traverseNextNodePostOrderEv
-__ZN3JSC11ProfileNode13stopProfilingEv
-__ZN3JSC11ProfileNode11removeChildEPS0_
-__ZN3JSC11ProfileNode8addChildEN3WTF10PassRefPtrIS0_EE
-__ZN3JSC8Debugger23recompileAllJSFunctionsEPNS_12JSGlobalDataE
-__ZN3JSC4Heap16primaryHeapBeginEv
-__ZN3JSC4Heap14primaryHeapEndEv
-__ZNK3JSC18JSCallbackFunction9classInfoEv
-__ZN3WTF7HashSetIPN3JSC18FunctionExecutableENS_7PtrHashIS3_EENS_10HashTraitsIS3_EEE3addERKS3_
-__ZN3WTF9HashTableIPN3JSC18FunctionExecutableES3_NS_17IdentityExtractorIS3_EENS_7PtrHashIS3_EENS_10HashTraitsIS3_EES9_E6expandE
-__ZN3JSC18FunctionExecutable9recompileEPNS_9ExecStateE
-__ZN3JSC8Profiler11willExecuteEPNS_9ExecStateERKNS_7UStringEi
-__ZN3JSC8Profiler10didExecuteEPNS_9ExecStateERKNS_7UStringEi
-__ZNK3JSC16ProfileGenerator5titleEv
-__ZN3JSC9CodeBlock33functionRegisterForBytecodeOffsetEjRi
-__ZN3JSC7ProfileD0Ev
-__ZN3WTF10RefCountedIN3JSC11ProfileNodeEE5derefEv
-__ZN3JSC34createTerminatedExecutionExceptionEPNS_12JSGlobalDataE
-__ZNK3JSC24TerminatedExecutionError13exceptionTypeEv
-__ZN3JSC24TerminatedExecutionErrorD1Ev
-__ZN3WTF8CollatorC1EPKc
-__ZN3WTF8Collator18setOrderLowerFirstEb
-_JSValueIsEqual
-__ZN3JSC7JSValue13equalSlowCaseEPNS_9ExecStateES0_S0_
-__ZNK3JSC14JSGlobalObject17supportsProfilingEv
-__ZNK7WebCore6String12toUIntStrictEPbi
-__ZN7WebCore10StringImpl12toUIntStrictEPbi
-__ZN3WTF12randomNumberEv
-__ZNK7WebCore6String8toUInt64EPb
-__ZN7WebCore10StringImpl8toUInt64EPb
-__ZN7WebCore18charactersToUInt64EPKtmPb
-_JSStringGetMaximumUTF8CStringSize
-__ZN3JSC16JSCallbackObjectINS_8JSObjectEE3putEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueERNS_15PutPropertySlotE
-__ZN7WebCore6String6numberEm
-__ZN3JSC4Heap17globalObjectCountEv
-__ZN3JSC4Heap20protectedObjectCountEv
-__ZN3JSC4Heap25protectedObjectTypeCountsEv
-__ZN3WTF9HashTableIPKcSt4pairIS2_jENS_18PairFirstExtractorIS4_EENS_7PtrHashIS2_EENS_14PairHashTraitsINS_10HashTraitsIS2_EENSA_I
-__ZNK3JSC6JSCell17isAPIValueWrapperEv
-__ZNK3JSC6JSCell22isPropertyNameIteratorEv
-__ZN3JSC4Heap16objectTypeCountsEv
-__ZNK3JSC22JSPropertyNameIterator22isPropertyNameIteratorEv
-__ZN3WTF20fastMallocStatisticsEv
-__ZNK3JSC4Heap10statisticsEv
-__ZN3WTF27releaseFastMallocFreeMemoryEv
-_JSStringIsEqualToUTF8CString
-__ZN3JSC16JSCallbackObjectINS_8JSObjectEE14callbackGetterEPNS_9ExecStateENS_7JSValueERKNS_10IdentifierE
-_JSObjectSetPrivate
-__ZN3JSC8Debugger6attachEPNS_14JSGlobalObjectE
-__ZN3WTF9HashTableIPN3JSC14JSGlobalObjectES3_NS_17IdentityExtractorIS3_EENS_7PtrHashIS3_EENS_10HashTraitsIS3_EES9_E6rehashEi
-__ZN3WTF9HashTableIPN3JSC14SourceProviderESt4pairIS3_PNS1_9ExecStateEENS_18PairFirstExtractorIS7_EENS_7PtrHashIS3_EENS_14PairHa
-__ZN3JSC7UString4fromEl
-__ZN3JSC3JIT13emit_op_debugEPNS_11InstructionE
-_cti_op_debug
-__ZN3JSC11Interpreter5debugEPNS_9ExecStateENS_11DebugHookIDEii
-__ZNK3JSC17DebuggerCallFrame4typeEv
-__ZNK3JSC17DebuggerCallFrame22calculatedFunctionNameEv
-__ZNK3JSC12JSActivation18isActivationObjectEv
-__ZNK3JSC17DebuggerCallFrame10thisObjectEv
-__ZN3WTF28setMainThreadCallbacksPausedEb
-__ZNK3JSC17DebuggerCallFrame8evaluateERKNS_7UStringERNS_7JSValueE
-__ZN3JSC8Debugger6detachEPNS_14JSGlobalObjectE
-_JSValueIsObjectOfClass
# JavaScriptCore - Qt4 build info
+
+include(../common.pri)
+
VPATH += $$PWD
-CONFIG(debug, debug|release) {
- # Output in JavaScriptCore/<config>
- JAVASCRIPTCORE_DESTDIR = debug
- # Use a config-specific target to prevent parallel builds file clashes on Mac
- JAVASCRIPTCORE_TARGET = jscored
-} else {
- JAVASCRIPTCORE_DESTDIR = release
- JAVASCRIPTCORE_TARGET = jscore
-}
+
+# Use a config-specific target to prevent parallel builds file clashes on Mac
+mac: CONFIG(debug, debug|release): JAVASCRIPTCORE_TARGET = jscored
+else: JAVASCRIPTCORE_TARGET = jscore
+
+# Output in JavaScriptCore/<config>
+CONFIG(debug, debug|release) : JAVASCRIPTCORE_DESTDIR = debug
+else: JAVASCRIPTCORE_DESTDIR = release
+
CONFIG(standalone_package) {
isEmpty(JSC_GENERATED_SOURCES_DIR):JSC_GENERATED_SOURCES_DIR = $$PWD/generated
} else {
- isEmpty(JSC_GENERATED_SOURCES_DIR):JSC_GENERATED_SOURCES_DIR = generated
-}
-
-CONFIG(standalone_package): DEFINES *= NDEBUG
-
-symbian: {
- # Need to guarantee this comes before system includes of /epoc32/include
- MMP_RULES += "USERINCLUDE ../JavaScriptCore/profiler"
- LIBS += -lhal
- # For hal.h
- INCLUDEPATH *= $$MW_LAYER_SYSTEMINCLUDE
+ isEmpty(JSC_GENERATED_SOURCES_DIR):JSC_GENERATED_SOURCES_DIR = $$OUTPUT_DIR/JavaScriptCore/generated
}
-INCLUDEPATH = \
+JAVASCRIPTCORE_INCLUDEPATH = \
$$PWD \
$$PWD/.. \
+ $$PWD/../ThirdParty \
$$PWD/assembler \
$$PWD/bytecode \
$$PWD/bytecompiler \
+ $$PWD/heap \
+ $$PWD/dfg \
$$PWD/debugger \
$$PWD/interpreter \
$$PWD/jit \
$$PWD/parser \
- $$PWD/pcre \
$$PWD/profiler \
$$PWD/runtime \
$$PWD/wtf \
+ $$PWD/wtf/gobject \
$$PWD/wtf/symbian \
$$PWD/wtf/unicode \
$$PWD/yarr \
$$PWD/API \
$$PWD/ForwardingHeaders \
- $$JSC_GENERATED_SOURCES_DIR \
- $$INCLUDEPATH
+ $$JSC_GENERATED_SOURCES_DIR
+
+symbian {
+ PREPEND_INCLUDEPATH = $$JAVASCRIPTCORE_INCLUDEPATH $$PREPEND_INCLUDEPATH
+} else {
+ INCLUDEPATH = $$JAVASCRIPTCORE_INCLUDEPATH $$INCLUDEPATH
+}
+
+symbian {
+ LIBS += -lhal
+ INCLUDEPATH *= $$MW_LAYER_SYSTEMINCLUDE
+}
win32-*: DEFINES += _HAS_TR1=0
-DEFINES += BUILDING_QT__ BUILDING_JavaScriptCore BUILDING_WTF
+DEFINES += BUILDING_JavaScriptCore BUILDING_WTF
-contains(JAVASCRIPTCORE_JIT,yes) {
- DEFINES+=ENABLE_JIT=1
- DEFINES+=ENABLE_YARR_JIT=1
- DEFINES+=ENABLE_YARR=1
-}
-contains(JAVASCRIPTCORE_JIT,no) {
- DEFINES+=ENABLE_JIT=0
- DEFINES+=ENABLE_YARR_JIT=0
- DEFINES+=ENABLE_YARR=0
+# CONFIG += text_breaking_with_icu
+
+contains (CONFIG, text_breaking_with_icu) {
+ DEFINES += WTF_USE_QT_ICU_TEXT_BREAKING=1
}
wince* {
INCLUDEPATH += $$QT_SOURCE_TREE/src/3rdparty/ce-compat
- DEFINES += WINCEBASIC
-
- INCLUDEPATH += $$PWD/../JavaScriptCore/os-wince
INCLUDEPATH += $$PWD/../JavaScriptCore/os-win32
}
-defineTest(addJavaScriptCoreLib) {
+defineTest(prependJavaScriptCoreLib) {
# Argument is the relative path to JavaScriptCore.pro's qmake output
pathToJavaScriptCoreOutput = $$ARGS/$$JAVASCRIPTCORE_DESTDIR
win32-msvc*|wince* {
- LIBS += -L$$pathToJavaScriptCoreOutput
- LIBS += -l$$JAVASCRIPTCORE_TARGET
+ LIBS = -l$$JAVASCRIPTCORE_TARGET $$LIBS
+ LIBS = -L$$pathToJavaScriptCoreOutput $$LIBS
POST_TARGETDEPS += $${pathToJavaScriptCoreOutput}$${QMAKE_DIR_SEP}$${JAVASCRIPTCORE_TARGET}.lib
} else:symbian {
- LIBS += -l$${JAVASCRIPTCORE_TARGET}.lib
+ LIBS = -l$${JAVASCRIPTCORE_TARGET}.lib $$LIBS
# The default symbian build system does not use library paths at all. However when building with
# qmake's symbian makespec that uses Makefiles
QMAKE_LIBDIR += $$pathToJavaScriptCoreOutput
# Make sure jscore will be early in the list of libraries to workaround a bug in MinGW
# that can't resolve symbols from QtCore if libjscore comes after.
QMAKE_LIBDIR = $$pathToJavaScriptCoreOutput $$QMAKE_LIBDIR
- LIBS += -l$$JAVASCRIPTCORE_TARGET
+ LIBS = -l$$JAVASCRIPTCORE_TARGET $$LIBS
POST_TARGETDEPS += $${pathToJavaScriptCoreOutput}$${QMAKE_DIR_SEP}lib$${JAVASCRIPTCORE_TARGET}.a
}
return(true)
}
+
contains(QT_CONFIG, embedded):CONFIG += embedded
-CONFIG(QTDIR_build) {
- # Make sure we compile both debug and release on mac when inside Qt.
- # This line was extracted from qbase.pri instead of including the whole file
- win32|mac:!macx-xcode:CONFIG += debug_and_release
-} else {
- CONFIG(debug, debug|release) {
- OBJECTS_DIR = obj/debug
- } else { # Release
- OBJECTS_DIR = obj/release
- }
- # Make sure that build_all follows the build_all config in WebCore
- mac:contains(QT_CONFIG, qt_framework):!CONFIG(webkit_no_framework):!build_pass:CONFIG += build_all
-}
-
# WebCore adds these config only when in a standalone build.
# qbase.pri takes care of that when in a QTDIR_build
# Here we add the config for both cases since we don't include qbase.pri
CONFIG += no_debug_info
}
-# Pick up 3rdparty libraries from INCLUDE/LIB just like with MSVC
-win32-g++ {
- TMPPATH = $$quote($$(INCLUDE))
- QMAKE_INCDIR_POST += $$split(TMPPATH,";")
- TMPPATH = $$quote($$(LIB))
- QMAKE_LIBDIR_POST += $$split(TMPPATH,";")
-}
-
*-g++*:QMAKE_CXXFLAGS_RELEASE -= -O2
*-g++*:QMAKE_CXXFLAGS_RELEASE += -O3
SOURCES += $$QT_SOURCE_TREE/src/3rdparty/ce-compat/ce_time.c
}
-include(pcre/pcre.pri)
+include(yarr/yarr.pri)
+include(wtf/wtf.pri)
+
+INSTALLDEPS += all
SOURCES += \
API/JSBase.cpp \
API/JSValueRef.cpp \
API/OpaqueJSString.cpp \
assembler/ARMAssembler.cpp \
+ assembler/ARMv7Assembler.cpp \
assembler/MacroAssemblerARM.cpp \
+ assembler/MacroAssemblerSH4.h \
+ assembler/MacroAssemblerSH4.cpp \
+ assembler/SH4Assembler.h \
bytecode/CodeBlock.cpp \
bytecode/JumpTable.cpp \
bytecode/Opcode.cpp \
bytecode/StructureStubInfo.cpp \
bytecompiler/BytecodeGenerator.cpp \
bytecompiler/NodesCodegen.cpp \
+ heap/ConservativeRoots.cpp \
+ heap/HandleHeap.cpp \
+ heap/HandleStack.cpp \
+ heap/Heap.cpp \
+ heap/MachineStackMarker.cpp \
+ heap/MarkStack.cpp \
+ heap/MarkStackPosix.cpp \
+ heap/MarkStackSymbian.cpp \
+ heap/MarkStackWin.cpp \
+ heap/MarkedBlock.cpp \
+ heap/MarkedSpace.cpp \
debugger/DebuggerActivation.cpp \
debugger/DebuggerCallFrame.cpp \
debugger/Debugger.cpp \
+ dfg/DFGByteCodeParser.cpp \
+ dfg/DFGGraph.cpp \
+ dfg/DFGJITCodeGenerator.cpp \
+ dfg/DFGJITCompiler.cpp \
+ dfg/DFGNonSpeculativeJIT.cpp \
+ dfg/DFGOperations.cpp \
+ dfg/DFGSpeculativeJIT.cpp \
interpreter/CallFrame.cpp \
interpreter/Interpreter.cpp \
interpreter/RegisterFile.cpp \
jit/ExecutableAllocatorFixedVMPool.cpp \
- jit/ExecutableAllocatorPosix.cpp \
- jit/ExecutableAllocatorSymbian.cpp \
- jit/ExecutableAllocatorWin.cpp \
jit/ExecutableAllocator.cpp \
jit/JITArithmetic.cpp \
jit/JITArithmetic32_64.cpp \
jit/JITCall.cpp \
+ jit/JITCall32_64.cpp \
jit/JIT.cpp \
jit/JITOpcodes.cpp \
jit/JITOpcodes32_64.cpp \
jit/JITPropertyAccess32_64.cpp \
jit/JITStubs.cpp \
jit/ThunkGenerators.cpp \
+ parser/JSParser.cpp \
parser/Lexer.cpp \
parser/Nodes.cpp \
parser/ParserArena.cpp \
parser/Parser.cpp \
+ parser/SourceProviderCache.cpp \
profiler/Profile.cpp \
profiler/ProfileGenerator.cpp \
profiler/ProfileNode.cpp \
runtime/BooleanObject.cpp \
runtime/BooleanPrototype.cpp \
runtime/CallData.cpp \
- runtime/Collector.cpp \
runtime/CommonIdentifiers.cpp \
runtime/Completion.cpp \
runtime/ConstructData.cpp \
runtime/Executable.cpp \
runtime/FunctionConstructor.cpp \
runtime/FunctionPrototype.cpp \
+ runtime/GCActivityCallback.cpp \
runtime/GetterSetter.cpp \
- runtime/GlobalEvalFunction.cpp \
runtime/Identifier.cpp \
runtime/InitializeThreading.cpp \
runtime/InternalFunction.cpp \
runtime/JSGlobalData.cpp \
runtime/JSGlobalObject.cpp \
runtime/JSGlobalObjectFunctions.cpp \
- runtime/JSImmediate.cpp \
runtime/JSLock.cpp \
runtime/JSNotAnObject.cpp \
- runtime/JSNumberCell.cpp \
runtime/JSObject.cpp \
+ runtime/JSObjectWithGlobalObject.cpp \
runtime/JSONObject.cpp \
runtime/JSPropertyNameIterator.cpp \
runtime/JSStaticScopeObject.cpp \
runtime/JSWrapperObject.cpp \
runtime/LiteralParser.cpp \
runtime/Lookup.cpp \
- runtime/MarkStackPosix.cpp \
- runtime/MarkStackSymbian.cpp \
- runtime/MarkStackWin.cpp \
- runtime/MarkStack.cpp \
runtime/MathObject.cpp \
runtime/NativeErrorConstructor.cpp \
runtime/NativeErrorPrototype.cpp \
runtime/PropertyDescriptor.cpp \
runtime/PropertyNameArray.cpp \
runtime/PropertySlot.cpp \
- runtime/PrototypeFunction.cpp \
runtime/RegExpConstructor.cpp \
runtime/RegExp.cpp \
runtime/RegExpObject.cpp \
runtime/RopeImpl.cpp \
runtime/ScopeChain.cpp \
runtime/SmallStrings.cpp \
+ runtime/StrictEvalActivation.cpp \
runtime/StringConstructor.cpp \
runtime/StringObject.cpp \
runtime/StringPrototype.cpp \
+ runtime/StringRecursionChecker.cpp \
runtime/StructureChain.cpp \
runtime/Structure.cpp \
runtime/TimeoutChecker.cpp \
runtime/UString.cpp \
- wtf/Assertions.cpp \
- wtf/ByteArray.cpp \
- wtf/CurrentTime.cpp \
- wtf/DateMath.cpp \
- wtf/dtoa.cpp \
- wtf/FastMalloc.cpp \
- wtf/HashTable.cpp \
- wtf/MD5.cpp \
- wtf/MainThread.cpp \
- wtf/qt/MainThreadQt.cpp \
- wtf/qt/StringQt.cpp \
- wtf/qt/ThreadingQt.cpp \
- wtf/RandomNumber.cpp \
- wtf/RefCountedLeakCounter.cpp \
- wtf/symbian/BlockAllocatorSymbian.cpp \
- wtf/ThreadingNone.cpp \
- wtf/Threading.cpp \
- wtf/TypeTraits.cpp \
- wtf/WTFThreadData.cpp \
- wtf/text/AtomicString.cpp \
- wtf/text/CString.cpp \
- wtf/text/StringImpl.cpp \
- wtf/text/StringStatics.cpp \
- wtf/text/WTFString.cpp \
- wtf/unicode/CollatorDefault.cpp \
- wtf/unicode/icu/CollatorICU.cpp \
- wtf/unicode/UTF8.cpp \
- yarr/RegexCompiler.cpp \
- yarr/RegexInterpreter.cpp \
- yarr/RegexJIT.cpp
+ yarr/YarrJIT.cpp \
+
+*sh4* {
+ QMAKE_CXXFLAGS += -mieee -w
+ QMAKE_CFLAGS += -mieee -w
+}
# Generated files, simply list them for JavaScriptCore
-SOURCES += \
- $${JSC_GENERATED_SOURCES_DIR}/Grammar.cpp
-!contains(DEFINES, USE_SYSTEM_MALLOC) {
- SOURCES += wtf/TCSystemAlloc.cpp
+symbian: {
+ symbian-abld|symbian-sbsv2 {
+ MMP_RULES += ALWAYS_BUILD_AS_ARM
+ } else {
+ QMAKE_CFLAGS -= --thumb
+ QMAKE_CXXFLAGS -= --thumb
+ }
+ QMAKE_CXXFLAGS.ARMCC += -OTime -O3
+}
+
+lessThan(QT_GCC_MAJOR_VERSION, 5):lessThan(QT_GCC_MINOR_VERSION, 6) {
+ # Disable C++0x mode in JSC for those who enabled it in their Qt's mkspec.
+ *-g++*:QMAKE_CXXFLAGS -= -std=c++0x -std=gnu++0x
}
-# Disable C++0x mode in JSC for those who enabled it in their Qt's mkspec
-*-g++*:QMAKE_CXXFLAGS -= -std=c++0x -std=gnu++0x
/* Work around bug with C++ library that screws up Objective-C++ when exception support is disabled. */
#undef try
#undef catch
+
--- /dev/null
+# Copyright (C) 2010 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import sys
+import string
+import operator
+
+keywordsText = open(sys.argv[1]).read()
+
+# Observed weights of the most common keywords, rounded to 2.s.d
+keyWordWeights = {
+ "catch": 0.01,
+ "try": 0.01,
+ "while": 0.01,
+ "case": 0.01,
+ "break": 0.01,
+ "new": 0.01,
+ "in": 0.01,
+ "typeof": 0.02,
+ "true": 0.02,
+ "false": 0.02,
+ "for": 0.03,
+ "null": 0.03,
+ "else": 0.03,
+ "return": 0.13,
+ "var": 0.13,
+ "if": 0.16,
+ "function": 0.18,
+ "this": 0.18,
+}
+
+
+def allWhitespace(str):
+ for c in str:
+ if not(c in string.whitespace):
+ return False
+ return True
+
+
+def parseKeywords(keywordsText):
+ lines = keywordsText.split("\n")
+ lines = [line.split("#")[0] for line in lines]
+ lines = [line for line in lines if (not allWhitespace(line))]
+ name = lines[0].split()
+ terminator = lines[-1]
+ if not name[0] == "@begin":
+ raise Exception("expected description beginning with @begin")
+ if not terminator == "@end":
+ raise Exception("expected description ending with @end")
+
+ lines = lines[1:-1] # trim off the old heading
+ return [line.split() for line in lines]
+
+
+def makePadding(size):
+ str = ""
+ for i in range(size):
+ str = str + " "
+ return str
+
+
+class Trie:
+ def __init__(self, prefix):
+ self.prefix = prefix
+ self.keys = {}
+ self.value = None
+
+ def insert(self, key, value):
+ if len(key) == 0:
+ self.value = value
+ return
+ if not (key[0] in self.keys):
+ self.keys[key[0]] = Trie(key[0])
+ self.keys[key[0]].insert(key[1:], value)
+
+ def coalesce(self):
+ keys = {}
+ for k, v in self.keys.items():
+ t = v.coalesce()
+ keys[t.prefix] = t
+ self.keys = keys
+ if self.value != None:
+ return self
+ if len(self.keys) != 1:
+ return self
+ (prefix, suffix) = self.keys.items()[0]
+ res = Trie(self.prefix + prefix)
+ res.value = suffix.value
+ res.keys = suffix.keys
+ return res
+
+ def fillOut(self, prefix=""):
+ self.fullPrefix = prefix + self.prefix
+ weight = 0
+ if self.fullPrefix in keyWordWeights:
+ weight = weight + keyWordWeights[self.fullPrefix]
+ self.selfWeight = weight
+ for trie in self.keys.values():
+ trie.fillOut(self.fullPrefix)
+ weight = weight + trie.weight
+ self.keys = [(trie.prefix, trie) for trie in sorted(self.keys.values(), key=operator.attrgetter('weight'), reverse=True)]
+ self.weight = weight
+
+ def printSubTreeAsC(self, indent):
+ str = makePadding(indent)
+
+ if self.value != None:
+ print(str + "if (!isIdentPart(code[%d])) {" % (len(self.fullPrefix)))
+ print(str + " internalShift<%d, DoNotBoundsCheck>();" % len(self.fullPrefix))
+ print(str + " if (shouldCreateIdentifier)")
+ print(str + (" data->ident = &m_globalData->propertyNames->%sKeyword;" % self.fullPrefix))
+ print(str + " return " + self.value + ";")
+ print(str + "}")
+ rootIndex = len(self.fullPrefix)
+ itemCount = 0
+ for k, trie in self.keys:
+ baseIndex = rootIndex
+ if (baseIndex > 0) and (len(k) == 3):
+ baseIndex = baseIndex - 1
+ k = trie.fullPrefix[baseIndex] + k
+ test = [("'%s'" % c) for c in k]
+ if len(test) == 1:
+ comparison = "code[%d] == %s" % (baseIndex, test[0])
+ else:
+ base = "code"
+ if baseIndex > 0:
+ base = "code + %d" % baseIndex
+ comparison = ("COMPARE_CHARACTERS%d(%s, " % (len(test), base)) + ", ".join(test) + ")"
+ if itemCount == 0:
+ print(str + "if (" + comparison + ") {")
+ else:
+ print(str + "else if (" + comparison + ") {")
+
+ trie.printSubTreeAsC(indent + 4)
+ itemCount = itemCount + 1
+ print(str + "}")
+
+ def maxLength(self):
+ max = len(self.fullPrefix)
+ for (_, trie) in self.keys:
+ l = trie.maxLength()
+ if l > max:
+ max = l
+ return max
+
+ def printAsC(self):
+ print("namespace JSC {")
+ print("static ALWAYS_INLINE bool isIdentPart(int c);")
+ # max length + 1 so we don't need to do any bounds checking at all
+ print("static const int maxTokenLength = %d;" % (self.maxLength() + 1))
+ print("template <bool shouldCreateIdentifier> ALWAYS_INLINE JSTokenType Lexer::parseKeyword(JSTokenData* data) {")
+ print(" ASSERT(m_codeEnd - m_code >= maxTokenLength);")
+ print(" const UChar* code = m_code;")
+ self.printSubTreeAsC(4)
+ print(" return IDENT;")
+ print("}")
+ print("}")
+
+keywords = parseKeywords(keywordsText)
+trie = Trie("")
+for k, v in keywords:
+ trie.insert(k, v)
+trie.coalesce()
+trie.fillOut()
+print("// This file was generated by KeywordLookupGenerator.py. Do not edit.")
+print("""
+
+#if CPU(NEEDS_ALIGNED_ACCESS)
+
+#define COMPARE_CHARACTERS2(address, char1, char2) \
+ (((address)[0] == char1) && ((address)[1] == char2))
+#define COMPARE_CHARACTERS4(address, char1, char2, char3, char4) \
+ (COMPARE_CHARACTERS2(address, char1, char2) && COMPARE_CHARACTERS2((address) + 2, char3, char4))
+
+#else
+
+#if CPU(BIG_ENDIAN)
+#define CHARPAIR_TOUINT32(a, b) ((((uint32_t)(a)) << 16) + (uint32_t)(b))
+#define CHARQUAD_TOUINT64(a, b, c, d) ((((uint64_t)(CHARPAIR_TOUINT32(a, b))) << 32) + CHARPAIR_TOUINT32(c, d))
+#else
+#define CHARPAIR_TOUINT32(a, b) ((((uint32_t)(b)) << 16) + (uint32_t)(a))
+#define CHARQUAD_TOUINT64(a, b, c, d) ((((uint64_t)(CHARPAIR_TOUINT32(c, d))) << 32) + CHARPAIR_TOUINT32(a, b))
+#endif
+
+#define COMPARE_CHARACTERS2(address, char1, char2) \
+ (((uint32_t*)(address))[0] == CHARPAIR_TOUINT32(char1, char2))
+#if CPU(X86_64)
+
+#define COMPARE_CHARACTERS4(address, char1, char2, char3, char4) \
+ (((uint64_t*)(address))[0] == CHARQUAD_TOUINT64(char1, char2, char3, char4))
+#else
+#define COMPARE_CHARACTERS4(address, char1, char2, char3, char4) \
+ (COMPARE_CHARACTERS2(address, char1, char2) && COMPARE_CHARACTERS2((address) + 2, char3, char4))
+#endif
+
+#endif
+
+#define COMPARE_CHARACTERS3(address, char1, char2, char3) \
+ (COMPARE_CHARACTERS2(address, char1, char2) && ((address)[2] == (char3)))
+#define COMPARE_CHARACTERS5(address, char1, char2, char3, char4, char5) \
+ (COMPARE_CHARACTERS4(address, char1, char2, char3, char4) && ((address)[4] == (char5)))
+#define COMPARE_CHARACTERS6(address, char1, char2, char3, char4, char5, char6) \
+ (COMPARE_CHARACTERS4(address, char1, char2, char3, char4) && COMPARE_CHARACTERS2(address + 4, char5, char6))
+#define COMPARE_CHARACTERS7(address, char1, char2, char3, char4, char5, char6, char7) \
+ (COMPARE_CHARACTERS4(address, char1, char2, char3, char4) && COMPARE_CHARACTERS4(address + 3, char4, char5, char6, char7))
+#define COMPARE_CHARACTERS8(address, char1, char2, char3, char4, char5, char6, char7, char8) \
+ (COMPARE_CHARACTERS4(address, char1, char2, char3, char4) && COMPARE_CHARACTERS4(address + 4, char5, char6, char7, char8))
+""")
+
+trie.printAsC()
-OTHER_OPTIONS = -target All
include ../Makefile.shared
add_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 12) | (10 << 8));
dtr_u(isLoad, srcDst, ARMRegisters::S0, (offset & 0xfff) | transferFlag);
} else {
- ARMWord reg = getImm(offset, ARMRegisters::S0);
- dtr_ur(isLoad, srcDst, base, reg | transferFlag);
+ moveImm(offset, ARMRegisters::S0);
+ dtr_ur(isLoad, srcDst, base, ARMRegisters::S0 | transferFlag);
}
} else {
offset = -offset;
sub_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 12) | (10 << 8));
dtr_d(isLoad, srcDst, ARMRegisters::S0, (offset & 0xfff) | transferFlag);
} else {
- ARMWord reg = getImm(offset, ARMRegisters::S0);
- dtr_dr(isLoad, srcDst, base, reg | transferFlag);
+ moveImm(offset, ARMRegisters::S0);
+ dtr_dr(isLoad, srcDst, base, ARMRegisters::S0 | transferFlag);
}
}
}
fdtr_u(isLoad, srcDst, ARMRegisters::S0, 0);
}
-void* ARMAssembler::executableCopy(ExecutablePool* allocator)
+void* ARMAssembler::executableCopy(JSGlobalData& globalData, ExecutablePool* allocator)
{
// 64-bit alignment is required for next constant pool and JIT code as well
m_buffer.flushWithoutBarrier(true);
- if (m_buffer.uncheckedSize() & 0x7)
+ if (!m_buffer.isAligned(8))
bkpt(0);
- char* data = reinterpret_cast<char*>(m_buffer.executableCopy(allocator));
+ char* data = reinterpret_cast<char*>(m_buffer.executableCopy(globalData, allocator));
for (Jumps::Iterator iter = m_jumps.begin(); iter != m_jumps.end(); ++iter) {
// The last bit is set if the constant must be placed on constant pool.
- int pos = (*iter) & (~0x1);
- ARMWord* ldrAddr = reinterpret_cast<ARMWord*>(data + pos);
+ int pos = (iter->m_offset) & (~0x1);
+ ARMWord* ldrAddr = reinterpret_cast_ptr<ARMWord*>(data + pos);
ARMWord* addr = getLdrImmAddress(ldrAddr);
if (*addr != InvalidBranchTarget) {
- if (!(*iter & 1)) {
- int diff = reinterpret_cast<ARMWord*>(data + *addr) - (ldrAddr + DefaultPrefetching);
+ if (!(iter->m_offset & 1)) {
+ int diff = reinterpret_cast_ptr<ARMWord*>(data + *addr) - (ldrAddr + DefaultPrefetching);
if ((diff <= BOFFSET_MAX && diff >= BOFFSET_MIN)) {
*ldrAddr = B | getConditionalField(*ldrAddr) | (diff & BRANCH_MASK);
r0 = 0,
r1,
r2,
- r3,
- S0 = r3,
+ r3, S0 = r3,
r4,
r5,
r6,
r7,
- r8,
- S1 = r8,
+ r8, S1 = r8,
r9,
r10,
r11,
r12,
- r13,
- sp = r13,
- r14,
- lr = r14,
- r15,
- pc = r15
+ r13, sp = r13,
+ r14, lr = r14,
+ r15, pc = r15
} RegisterID;
typedef enum {
d0,
d1,
d2,
- d3,
- SD0 = d3
+ d3, SD0 = d3,
+ d4,
+ d5,
+ d6,
+ d7,
+ d8,
+ d9,
+ d10,
+ d11,
+ d12,
+ d13,
+ d14,
+ d15,
+ d16,
+ d17,
+ d18,
+ d19,
+ d20,
+ d21,
+ d22,
+ d23,
+ d24,
+ d25,
+ d26,
+ d27,
+ d28,
+ d29,
+ d30,
+ d31
} FPRegisterID;
} // namespace ARMRegisters
typedef ARMRegisters::RegisterID RegisterID;
typedef ARMRegisters::FPRegisterID FPRegisterID;
typedef AssemblerBufferWithConstantPool<2048, 4, 4, ARMAssembler> ARMBuffer;
- typedef SegmentedVector<int, 64> Jumps;
+ typedef SegmentedVector<AssemblerLabel, 64> Jumps;
ARMAssembler() { }
MVN = (0xf << 21),
MUL = 0x00000090,
MULL = 0x00c00090,
- FADDD = 0x0e300b00,
- FDIVD = 0x0e800b00,
- FSUBD = 0x0e300b40,
- FMULD = 0x0e200b00,
- FCMPD = 0x0eb40b40,
- FSQRTD = 0x0eb10bc0,
+ VADD_F64 = 0x0e300b00,
+ VDIV_F64 = 0x0e800b00,
+ VSUB_F64 = 0x0e300b40,
+ VMUL_F64 = 0x0e200b00,
+ VCMP_F64 = 0x0eb40b40,
+ VSQRT_F64 = 0x0eb10bc0,
DTR = 0x05000000,
LDRH = 0x00100090,
STRH = 0x00000090,
#if WTF_ARM_ARCH_AT_LEAST(5) || defined(__ARM_ARCH_4T__)
BX = 0x012fff10,
#endif
- FMSR = 0x0e000a10,
- FMRS = 0x0e100a10,
- FSITOD = 0x0eb80bc0,
- FTOSID = 0x0ebd0b40,
- FMSTAT = 0x0ef1fa10,
+ VMOV_VFP = 0x0e000a10,
+ VMOV_ARM = 0x0e100a10,
+ VCVT_F64_S32 = 0x0eb80bc0,
+ VCVT_S32_F64 = 0x0ebd0b40,
+ VCVTR_S32_F64 = 0x0ebd0bc0,
+ VMRS_APSR = 0x0ef1fa10,
#if WTF_ARM_ARCH_AT_LEAST(5)
CLZ = 0x016f0f10,
- BKPT = 0xe120070,
+ BKPT = 0xe1200070,
BLX = 0x012fff30,
+ NOP_T2 = 0xf3af8000,
#endif
#if WTF_ARM_ARCH_AT_LEAST(7)
MOVW = 0x03000000,
enum {
padForAlign8 = 0x00,
padForAlign16 = 0x0000,
- padForAlign32 = 0xee120070,
+ padForAlign32 = 0xe12fff7f // 'bkpt 0xffff' instruction.
};
static const ARMWord INVALID_IMM = 0xf0000000;
static const ARMWord InvalidBranchTarget = 0xffffffff;
static const int DefaultPrefetching = 2;
- class JmpSrc {
- friend class ARMAssembler;
- public:
- JmpSrc()
- : m_offset(-1)
- {
- }
-
- private:
- JmpSrc(int offset)
- : m_offset(offset)
- {
- }
-
- int m_offset;
- };
-
- class JmpDst {
- friend class ARMAssembler;
- public:
- JmpDst()
- : m_offset(-1)
- , m_used(false)
- {
- }
-
- bool isUsed() const { return m_used; }
- void used() { m_used = true; }
- private:
- JmpDst(int offset)
- : m_offset(offset)
- , m_used(false)
- {
- ASSERT(m_offset == offset);
- }
-
- int m_offset : 31;
- int m_used : 1;
- };
-
// Instruction formating
void emitInst(ARMWord op, int rd, int rn, ARMWord op2)
{
- ASSERT ( ((op2 & ~OP2_IMM) <= 0xfff) || (((op2 & ~OP2_IMMh) <= 0xfff)) );
+ ASSERT(((op2 & ~OP2_IMM) <= 0xfff) || (((op2 & ~OP2_IMMh) <= 0xfff)));
m_buffer.putInt(op | RN(rn) | RD(rd) | op2);
}
+ void emitDoublePrecisionInst(ARMWord op, int dd, int dn, int dm)
+ {
+ ASSERT((dd >= 0 && dd <= 31) && (dn >= 0 && dn <= 31) && (dm >= 0 && dm <= 31));
+ m_buffer.putInt(op | ((dd & 0xf) << 12) | ((dd & 0x10) << (22 - 4))
+ | ((dn & 0xf) << 16) | ((dn & 0x10) << (7 - 4))
+ | (dm & 0xf) | ((dm & 0x10) << (5 - 4)));
+ }
+
+ void emitSinglePrecisionInst(ARMWord op, int sd, int sn, int sm)
+ {
+ ASSERT((sd >= 0 && sd <= 31) && (sn >= 0 && sn <= 31) && (sm >= 0 && sm <= 31));
+ m_buffer.putInt(op | ((sd >> 1) << 12) | ((sd & 0x1) << 22)
+ | ((sn >> 1) << 16) | ((sn & 0x1) << 7)
+ | (sm >> 1) | ((sm & 0x1) << 5));
+ }
+
void and_r(int rd, int rn, ARMWord op2, Condition cc = AL)
{
emitInst(static_cast<ARMWord>(cc) | AND, rd, rn, op2);
emitInst(static_cast<ARMWord>(cc) | CMP | SET_CC, 0, rn, op2);
}
+ void cmn_r(int rn, ARMWord op2, Condition cc = AL)
+ {
+ emitInst(static_cast<ARMWord>(cc) | CMN | SET_CC, 0, rn, op2);
+ }
+
void orr_r(int rd, int rn, ARMWord op2, Condition cc = AL)
{
emitInst(static_cast<ARMWord>(cc) | ORR, rd, rn, op2);
m_buffer.putInt(static_cast<ARMWord>(cc) | MULL | RN(rdhi) | RD(rdlo) | RS(rn) | RM(rm));
}
- void faddd_r(int dd, int dn, int dm, Condition cc = AL)
+ void vadd_f64_r(int dd, int dn, int dm, Condition cc = AL)
{
- emitInst(static_cast<ARMWord>(cc) | FADDD, dd, dn, dm);
+ emitDoublePrecisionInst(static_cast<ARMWord>(cc) | VADD_F64, dd, dn, dm);
}
- void fdivd_r(int dd, int dn, int dm, Condition cc = AL)
+ void vdiv_f64_r(int dd, int dn, int dm, Condition cc = AL)
{
- emitInst(static_cast<ARMWord>(cc) | FDIVD, dd, dn, dm);
+ emitDoublePrecisionInst(static_cast<ARMWord>(cc) | VDIV_F64, dd, dn, dm);
}
- void fsubd_r(int dd, int dn, int dm, Condition cc = AL)
+ void vsub_f64_r(int dd, int dn, int dm, Condition cc = AL)
{
- emitInst(static_cast<ARMWord>(cc) | FSUBD, dd, dn, dm);
+ emitDoublePrecisionInst(static_cast<ARMWord>(cc) | VSUB_F64, dd, dn, dm);
}
- void fmuld_r(int dd, int dn, int dm, Condition cc = AL)
+ void vmul_f64_r(int dd, int dn, int dm, Condition cc = AL)
{
- emitInst(static_cast<ARMWord>(cc) | FMULD, dd, dn, dm);
+ emitDoublePrecisionInst(static_cast<ARMWord>(cc) | VMUL_F64, dd, dn, dm);
}
- void fcmpd_r(int dd, int dm, Condition cc = AL)
+ void vcmp_f64_r(int dd, int dm, Condition cc = AL)
{
- emitInst(static_cast<ARMWord>(cc) | FCMPD, dd, 0, dm);
+ emitDoublePrecisionInst(static_cast<ARMWord>(cc) | VCMP_F64, dd, 0, dm);
}
- void fsqrtd_r(int dd, int dm, Condition cc = AL)
+ void vsqrt_f64_r(int dd, int dm, Condition cc = AL)
{
- emitInst(static_cast<ARMWord>(cc) | FSQRTD, dd, 0, dm);
+ emitDoublePrecisionInst(static_cast<ARMWord>(cc) | VSQRT_F64, dd, 0, dm);
}
void ldr_imm(int rd, ARMWord imm, Condition cc = AL)
dtr_u(true, reg, ARMRegisters::sp, 0, cc);
}
- void fmsr_r(int dd, int rn, Condition cc = AL)
+ void vmov_vfp_r(int sn, int rt, Condition cc = AL)
+ {
+ ASSERT(rt <= 15);
+ emitSinglePrecisionInst(static_cast<ARMWord>(cc) | VMOV_VFP, rt << 1, sn, 0);
+ }
+
+ void vmov_arm_r(int rt, int sn, Condition cc = AL)
{
- emitInst(static_cast<ARMWord>(cc) | FMSR, rn, dd, 0);
+ ASSERT(rt <= 15);
+ emitSinglePrecisionInst(static_cast<ARMWord>(cc) | VMOV_ARM, rt << 1, sn, 0);
}
- void fmrs_r(int rd, int dn, Condition cc = AL)
+ void vcvt_f64_s32_r(int dd, int sm, Condition cc = AL)
{
- emitInst(static_cast<ARMWord>(cc) | FMRS, rd, dn, 0);
+ ASSERT(!(sm & 0x1)); // sm must be divisible by 2
+ emitDoublePrecisionInst(static_cast<ARMWord>(cc) | VCVT_F64_S32, dd, 0, (sm >> 1));
}
- void fsitod_r(int dd, int dm, Condition cc = AL)
+ void vcvt_s32_f64_r(int sd, int dm, Condition cc = AL)
{
- emitInst(static_cast<ARMWord>(cc) | FSITOD, dd, 0, dm);
+ ASSERT(!(sd & 0x1)); // sd must be divisible by 2
+ emitDoublePrecisionInst(static_cast<ARMWord>(cc) | VCVT_S32_F64, (sd >> 1), 0, dm);
}
- void ftosid_r(int fd, int dm, Condition cc = AL)
+ void vcvtr_s32_f64_r(int sd, int dm, Condition cc = AL)
{
- emitInst(static_cast<ARMWord>(cc) | FTOSID, fd, 0, dm);
+ ASSERT(!(sd & 0x1)); // sd must be divisible by 2
+ emitDoublePrecisionInst(static_cast<ARMWord>(cc) | VCVTR_S32_F64, (sd >> 1), 0, dm);
}
- void fmstat(Condition cc = AL)
+ void vmrs_apsr(Condition cc = AL)
{
- m_buffer.putInt(static_cast<ARMWord>(cc) | FMSTAT);
+ m_buffer.putInt(static_cast<ARMWord>(cc) | VMRS_APSR);
}
#if WTF_ARM_ARCH_AT_LEAST(5)
dtr_dr(true, ARMRegisters::S0, ARMRegisters::S0, ARMRegisters::S0);
#endif
}
+
+ void nop()
+ {
+ m_buffer.putInt(OP_NOP_T2);
+ }
void bx(int rm, Condition cc = AL)
{
#endif
}
- JmpSrc blx(int rm, Condition cc = AL)
+ AssemblerLabel blx(int rm, Condition cc = AL)
{
#if WTF_ARM_ARCH_AT_LEAST(5)
- int s = m_buffer.uncheckedSize();
emitInst(static_cast<ARMWord>(cc) | BLX, 0, 0, RM(rm));
#else
ASSERT(rm != 14);
ensureSpace(2 * sizeof(ARMWord), 0);
mov_r(ARMRegisters::lr, ARMRegisters::pc, cc);
- int s = m_buffer.uncheckedSize();
bx(rm, cc);
#endif
- return JmpSrc(s);
+ return m_buffer.label();
}
static ARMWord lsl(int reg, ARMWord value)
// General helpers
- int size()
+ size_t codeSize() const
{
- return m_buffer.size();
+ return m_buffer.codeSize();
}
void ensureSpace(int insnSpace, int constSpace)
return m_buffer.sizeOfConstantPool();
}
- JmpDst label()
+ AssemblerLabel label()
{
- return JmpDst(m_buffer.size());
+ m_buffer.ensureSpaceForAnyOneInstruction();
+ return m_buffer.label();
}
- JmpDst align(int alignment)
+ AssemblerLabel align(int alignment)
{
while (!m_buffer.isAligned(alignment))
mov_r(ARMRegisters::r0, ARMRegisters::r0);
return label();
}
- JmpSrc loadBranchTarget(int rd, Condition cc = AL, int useConstantPool = 0)
+ AssemblerLabel loadBranchTarget(int rd, Condition cc = AL, int useConstantPool = 0)
{
ensureSpace(sizeof(ARMWord), sizeof(ARMWord));
- int s = m_buffer.uncheckedSize();
+ m_jumps.append(m_buffer.codeSize() | (useConstantPool & 0x1));
ldr_un_imm(rd, InvalidBranchTarget, cc);
- m_jumps.append(s | (useConstantPool & 0x1));
- return JmpSrc(s);
+ return m_buffer.label();
}
- JmpSrc jmp(Condition cc = AL, int useConstantPool = 0)
+ AssemblerLabel jmp(Condition cc = AL, int useConstantPool = 0)
{
return loadBranchTarget(ARMRegisters::pc, cc, useConstantPool);
}
- void* executableCopy(ExecutablePool* allocator);
+ void* executableCopy(JSGlobalData&, ExecutablePool* allocator);
+
+#ifndef NDEBUG
+ unsigned debugOffset() { return m_buffer.debugOffset(); }
+#endif
// Patching helpers
static void patchConstantPoolLoad(void* loadAddr, void* constPoolAddr);
+ // Read pointers
+ static void* readPointer(void* from)
+ {
+ ARMWord* insn = reinterpret_cast<ARMWord*>(from);
+ void* addr = reinterpret_cast<void*>(getLdrImmAddress(insn));
+ return *addr;
+ }
+
// Patch pointers
- static void linkPointer(void* code, JmpDst from, void* to)
+ static void linkPointer(void* code, AssemblerLabel from, void* to)
{
patchPointerInternal(reinterpret_cast<intptr_t>(code) + from.m_offset, to);
}
{
patchPointerInternal(reinterpret_cast<intptr_t>(from), reinterpret_cast<void*>(to));
}
+
+ static void repatchCompact(void* where, int32_t value)
+ {
+ repatchInt32(where, value);
+ }
static void repatchPointer(void* from, void* to)
{
patchPointerInternal(reinterpret_cast<intptr_t>(from), to);
}
- static void repatchLoadPtrToLEA(void* from)
+ // Linkers
+ static intptr_t getAbsoluteJumpAddress(void* base, int offset = 0)
{
- // On arm, this is a patch from LDR to ADD. It is restricted conversion,
- // from special case to special case, altough enough for its purpose
- ARMWord* insn = reinterpret_cast<ARMWord*>(from);
- ASSERT((*insn & 0x0ff00f00) == 0x05900000);
-
- *insn = (*insn & 0xf00ff0ff) | 0x02800000;
- ExecutableAllocator::cacheFlush(insn, sizeof(ARMWord));
+ return reinterpret_cast<intptr_t>(base) + offset - sizeof(ARMWord);
}
- // Linkers
-
- void linkJump(JmpSrc from, JmpDst to)
+ void linkJump(AssemblerLabel from, AssemblerLabel to)
{
- ARMWord* insn = reinterpret_cast<ARMWord*>(m_buffer.data()) + (from.m_offset / sizeof(ARMWord));
+ ARMWord* insn = reinterpret_cast<ARMWord*>(getAbsoluteJumpAddress(m_buffer.data(), from.m_offset));
ARMWord* addr = getLdrImmAddressOnPool(insn, m_buffer.poolAddress());
*addr = static_cast<ARMWord>(to.m_offset);
}
- static void linkJump(void* code, JmpSrc from, void* to)
+ static void linkJump(void* code, AssemblerLabel from, void* to)
{
- patchPointerInternal(reinterpret_cast<intptr_t>(code) + from.m_offset, to);
+ patchPointerInternal(getAbsoluteJumpAddress(code, from.m_offset), to);
}
static void relinkJump(void* from, void* to)
{
- patchPointerInternal(reinterpret_cast<intptr_t>(from) - sizeof(ARMWord), to);
+ patchPointerInternal(getAbsoluteJumpAddress(from), to);
}
- static void linkCall(void* code, JmpSrc from, void* to)
+ static void linkCall(void* code, AssemblerLabel from, void* to)
{
- patchPointerInternal(reinterpret_cast<intptr_t>(code) + from.m_offset, to);
+ patchPointerInternal(getAbsoluteJumpAddress(code, from.m_offset), to);
}
static void relinkCall(void* from, void* to)
{
- patchPointerInternal(reinterpret_cast<intptr_t>(from) - sizeof(ARMWord), to);
+ patchPointerInternal(getAbsoluteJumpAddress(from), to);
}
// Address operations
- static void* getRelocatedAddress(void* code, JmpSrc jump)
- {
- return reinterpret_cast<void*>(reinterpret_cast<ARMWord*>(code) + jump.m_offset / sizeof(ARMWord) + 1);
- }
-
- static void* getRelocatedAddress(void* code, JmpDst label)
+ static void* getRelocatedAddress(void* code, AssemblerLabel label)
{
- return reinterpret_cast<void*>(reinterpret_cast<ARMWord*>(code) + label.m_offset / sizeof(ARMWord));
+ return reinterpret_cast<void*>(reinterpret_cast<char*>(code) + label.m_offset);
}
// Address differences
- static int getDifferenceBetweenLabels(JmpDst from, JmpSrc to)
+ static int getDifferenceBetweenLabels(AssemblerLabel a, AssemblerLabel b)
{
- return (to.m_offset + sizeof(ARMWord)) - from.m_offset;
+ return b.m_offset - a.m_offset;
}
- static int getDifferenceBetweenLabels(JmpDst from, JmpDst to)
+ static unsigned getCallReturnOffset(AssemblerLabel call)
{
- return to.m_offset - from.m_offset;
- }
-
- static unsigned getCallReturnOffset(JmpSrc call)
- {
- return call.m_offset + sizeof(ARMWord);
+ return call.m_offset;
}
// Handle immediates
void moveImm(ARMWord imm, int dest);
ARMWord encodeComplexImm(ARMWord imm, int dest);
+ ARMWord getOffsetForHalfwordDataTransfer(ARMWord imm, int tmpReg)
+ {
+ // Encode immediate data in the instruction if it is possible
+ if (imm <= 0xff)
+ return getOp2Byte(imm);
+ // Otherwise, store the data in a temporary register
+ return encodeComplexImm(imm, tmpReg);
+ }
+
// Memory load/store helpers
void dataTransfer32(bool isLoad, RegisterID srcDst, RegisterID base, int32_t offset, bool bytes = false);
namespace JSC {
-const int ARMv7Assembler::JumpSizes[] = { 0xffffffff, sizeof(uint16_t), sizeof(uint16_t),
- 2 * sizeof(uint16_t), 2 * sizeof(uint16_t), 3 * sizeof(uint16_t), 5 * sizeof(uint16_t), 6 * sizeof(uint16_t) };
-const int ARMv7Assembler::JumpPaddingSizes[] = { 0, 5 * sizeof(uint16_t), 6 * sizeof(uint16_t),
- 5 * sizeof(uint16_t), 6 * sizeof(uint16_t) };
-
}
#endif
return m_type != TypeInvalid;
}
+ uint16_t asUInt16() const { return m_value.asInt; }
+
// These methods rely on the format of encoded byte values.
bool isUInt3() { return !(m_value.asInt & 0xfff8); }
bool isUInt4() { return !(m_value.asInt & 0xfff0); }
uint8_t getUInt6() { ASSERT(isUInt6()); return m_value.asInt; }
uint8_t getUInt7() { ASSERT(isUInt7()); return m_value.asInt; }
uint8_t getUInt8() { ASSERT(isUInt8()); return m_value.asInt; }
- uint8_t getUInt9() { ASSERT(isUInt9()); return m_value.asInt; }
- uint8_t getUInt10() { ASSERT(isUInt10()); return m_value.asInt; }
+ uint16_t getUInt9() { ASSERT(isUInt9()); return m_value.asInt; }
+ uint16_t getUInt10() { ASSERT(isUInt10()); return m_value.asInt; }
uint16_t getUInt12() { ASSERT(isUInt12()); return m_value.asInt; }
uint16_t getUInt16() { ASSERT(isUInt16()); return m_value.asInt; }
ThumbImmediateValue m_value;
};
-class VFPImmediate {
-public:
- VFPImmediate(double d)
- : m_value(-1)
- {
- union {
- uint64_t i;
- double d;
- } u;
-
- u.d = d;
-
- int sign = static_cast<int>(u.i >> 63);
- int exponent = static_cast<int>(u.i >> 52) & 0x7ff;
- uint64_t mantissa = u.i & 0x000fffffffffffffull;
-
- if ((exponent >= 0x3fc) && (exponent <= 0x403) && !(mantissa & 0x0000ffffffffffffull))
- m_value = (sign << 7) | ((exponent & 7) << 4) | (int)(mantissa >> 48);
- }
-
- bool isValid()
- {
- return m_value != -1;
- }
-
- uint8_t value()
- {
- return (uint8_t)m_value;
- }
-
-private:
- int m_value;
-};
-
typedef enum {
SRType_LSL,
SRType_LSR,
SRType_RRX = SRType_ROR
} ARMShiftType;
-class ARMv7Assembler;
class ShiftTypeAndAmount {
friend class ARMv7Assembler;
typedef enum {
ConditionEQ,
ConditionNE,
- ConditionHS,
- ConditionLO,
+ ConditionHS, ConditionCS = ConditionHS,
+ ConditionLO, ConditionCC = ConditionLO,
ConditionMI,
ConditionPL,
ConditionVS,
ConditionGT,
ConditionLE,
ConditionAL,
-
- ConditionCS = ConditionHS,
- ConditionCC = ConditionLO,
+ ConditionInvalid
} Condition;
- enum JumpType { JumpFixed, JumpNoCondition, JumpCondition, JumpNoConditionFixedSize, JumpConditionFixedSize, JumpTypeCount };
- enum JumpLinkType { LinkInvalid, LinkJumpT1, LinkJumpT2, LinkJumpT3,
- LinkJumpT4, LinkConditionalJumpT4, LinkBX, LinkConditionalBX, JumpLinkTypeCount };
- static const int JumpSizes[JumpLinkTypeCount];
- static const int JumpPaddingSizes[JumpTypeCount];
+#define JUMP_ENUM_WITH_SIZE(index, value) (((value) << 3) | (index))
+#define JUMP_ENUM_SIZE(jump) ((jump) >> 3)
+ enum JumpType { JumpFixed = JUMP_ENUM_WITH_SIZE(0, 0),
+ JumpNoCondition = JUMP_ENUM_WITH_SIZE(1, 5 * sizeof(uint16_t)),
+ JumpCondition = JUMP_ENUM_WITH_SIZE(2, 6 * sizeof(uint16_t)),
+ JumpNoConditionFixedSize = JUMP_ENUM_WITH_SIZE(3, 5 * sizeof(uint16_t)),
+ JumpConditionFixedSize = JUMP_ENUM_WITH_SIZE(4, 6 * sizeof(uint16_t))
+ };
+ enum JumpLinkType {
+ LinkInvalid = JUMP_ENUM_WITH_SIZE(0, 0),
+ LinkJumpT1 = JUMP_ENUM_WITH_SIZE(1, sizeof(uint16_t)),
+ LinkJumpT2 = JUMP_ENUM_WITH_SIZE(2, sizeof(uint16_t)),
+ LinkJumpT3 = JUMP_ENUM_WITH_SIZE(3, 2 * sizeof(uint16_t)),
+ LinkJumpT4 = JUMP_ENUM_WITH_SIZE(4, 2 * sizeof(uint16_t)),
+ LinkConditionalJumpT4 = JUMP_ENUM_WITH_SIZE(5, 3 * sizeof(uint16_t)),
+ LinkBX = JUMP_ENUM_WITH_SIZE(6, 5 * sizeof(uint16_t)),
+ LinkConditionalBX = JUMP_ENUM_WITH_SIZE(7, 6 * sizeof(uint16_t))
+ };
+
class LinkRecord {
public:
LinkRecord(intptr_t from, intptr_t to, JumpType type, Condition condition)
private:
intptr_t m_from : 31;
intptr_t m_to : 31;
- JumpType m_type : 3;
- JumpLinkType m_linkType : 4;
- Condition m_condition : 16;
- };
-
- class JmpSrc {
- friend class ARMv7Assembler;
- friend class ARMInstructionFormatter;
- friend class LinkBuffer;
- public:
- JmpSrc()
- : m_offset(-1)
- {
- }
-
- private:
- JmpSrc(int offset, JumpType type)
- : m_offset(offset)
- , m_condition(0xffff)
- , m_type(type)
- {
- ASSERT(m_type == JumpFixed || m_type == JumpNoCondition || m_type == JumpNoConditionFixedSize);
- }
-
- JmpSrc(int offset, JumpType type, Condition condition)
- : m_offset(offset)
- , m_condition(condition)
- , m_type(type)
- {
- ASSERT(m_type == JumpFixed || m_type == JumpCondition || m_type == JumpConditionFixedSize);
- }
-
- int m_offset;
+ JumpType m_type : 8;
+ JumpLinkType m_linkType : 8;
Condition m_condition : 16;
- JumpType m_type : 16;
-
- };
-
- class JmpDst {
- friend class ARMv7Assembler;
- friend class ARMInstructionFormatter;
- friend class LinkBuffer;
- public:
- JmpDst()
- : m_offset(-1)
- , m_used(false)
- {
- }
-
- bool isUsed() const { return m_used; }
- void used() { m_used = true; }
- private:
- JmpDst(int offset)
- : m_offset(offset)
- , m_used(false)
- {
- ASSERT(m_offset == offset);
- }
-
- int m_offset : 31;
- int m_used : 1;
};
private:
OP_LSR_reg_T2 = 0xFA20,
OP_ASR_reg_T2 = 0xFA40,
OP_ROR_reg_T2 = 0xFA60,
+ OP_CLZ = 0xFAB0,
OP_SMULL_T1 = 0xFB80,
} OpcodeID1;
if (rn == ARMRegisters::sp) {
if (!(rd & 8) && imm.isUInt10()) {
- m_formatter.oneWordOp5Reg3Imm8(OP_ADD_SP_imm_T1, rd, imm.getUInt10() >> 2);
+ m_formatter.oneWordOp5Reg3Imm8(OP_ADD_SP_imm_T1, rd, static_cast<uint8_t>(imm.getUInt10() >> 2));
return;
} else if ((rd == ARMRegisters::sp) && imm.isUInt9()) {
- m_formatter.oneWordOp9Imm7(OP_ADD_SP_imm_T2, imm.getUInt9() >> 2);
+ m_formatter.oneWordOp9Imm7(OP_ADD_SP_imm_T2, static_cast<uint8_t>(imm.getUInt9() >> 2));
return;
}
} else if (!((rd | rn) & 8)) {
}
}
- void add(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
+ ALWAYS_INLINE void add(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
{
ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
ASSERT(rd != ARMRegisters::pc);
}
// NOTE: In an IT block, add doesn't modify the flags register.
- void add(RegisterID rd, RegisterID rn, RegisterID rm)
+ ALWAYS_INLINE void add(RegisterID rd, RegisterID rn, RegisterID rm)
{
if (rd == rn)
m_formatter.oneWordOp8RegReg143(OP_ADD_reg_T2, rm, rd);
}
// Not allowed in an IT (if then) block.
- void add_S(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
+ ALWAYS_INLINE void add_S(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
{
// Rd can only be SP if Rn is also SP.
ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
}
// Not allowed in an IT (if then) block?
- void add_S(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
+ ALWAYS_INLINE void add_S(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
{
ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
ASSERT(rd != ARMRegisters::pc);
}
// Not allowed in an IT (if then) block.
- void add_S(RegisterID rd, RegisterID rn, RegisterID rm)
+ ALWAYS_INLINE void add_S(RegisterID rd, RegisterID rn, RegisterID rm)
{
if (!((rd | rn | rm) & 8))
m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_reg_T1, rm, rn, rd);
add_S(rd, rn, rm, ShiftTypeAndAmount());
}
- void ARM_and(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
+ ALWAYS_INLINE void ARM_and(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
{
ASSERT(!BadReg(rd));
ASSERT(!BadReg(rn));
m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_AND_imm_T1, rn, rd, imm);
}
- void ARM_and(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
+ ALWAYS_INLINE void ARM_and(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
{
ASSERT(!BadReg(rd));
ASSERT(!BadReg(rn));
m_formatter.twoWordOp12Reg4FourFours(OP_AND_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
}
- void ARM_and(RegisterID rd, RegisterID rn, RegisterID rm)
+ ALWAYS_INLINE void ARM_and(RegisterID rd, RegisterID rn, RegisterID rm)
{
if ((rd == rn) && !((rd | rm) & 8))
m_formatter.oneWordOp10Reg3Reg3(OP_AND_reg_T1, rm, rd);
ARM_and(rd, rn, rm, ShiftTypeAndAmount());
}
- void asr(RegisterID rd, RegisterID rm, int32_t shiftAmount)
+ ALWAYS_INLINE void asr(RegisterID rd, RegisterID rm, int32_t shiftAmount)
{
ASSERT(!BadReg(rd));
ASSERT(!BadReg(rm));
m_formatter.twoWordOp16FourFours(OP_ASR_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm));
}
- void asr(RegisterID rd, RegisterID rn, RegisterID rm)
+ ALWAYS_INLINE void asr(RegisterID rd, RegisterID rn, RegisterID rm)
{
ASSERT(!BadReg(rd));
ASSERT(!BadReg(rn));
}
// Only allowed in IT (if then) block if last instruction.
- JmpSrc b(JumpType type)
+ ALWAYS_INLINE AssemblerLabel b()
{
m_formatter.twoWordOp16Op16(OP_B_T4a, OP_B_T4b);
- return JmpSrc(m_formatter.size(), type);
+ return m_formatter.label();
}
// Only allowed in IT (if then) block if last instruction.
- JmpSrc blx(RegisterID rm, JumpType type)
+ ALWAYS_INLINE AssemblerLabel blx(RegisterID rm)
{
ASSERT(rm != ARMRegisters::pc);
m_formatter.oneWordOp8RegReg143(OP_BLX, rm, (RegisterID)8);
- return JmpSrc(m_formatter.size(), type);
+ return m_formatter.label();
}
// Only allowed in IT (if then) block if last instruction.
- JmpSrc bx(RegisterID rm, JumpType type, Condition condition)
+ ALWAYS_INLINE AssemblerLabel bx(RegisterID rm)
{
m_formatter.oneWordOp8RegReg143(OP_BX, rm, (RegisterID)0);
- return JmpSrc(m_formatter.size(), type, condition);
+ return m_formatter.label();
}
- JmpSrc bx(RegisterID rm, JumpType type)
+ void bkpt(uint8_t imm=0)
{
- m_formatter.oneWordOp8RegReg143(OP_BX, rm, (RegisterID)0);
- return JmpSrc(m_formatter.size(), type);
+ m_formatter.oneWordOp8Imm8(OP_BKPT, imm);
}
- void bkpt(uint8_t imm=0)
+ ALWAYS_INLINE void clz(RegisterID rd, RegisterID rm)
{
- m_formatter.oneWordOp8Imm8(OP_BKPT, imm);
+ ASSERT(!BadReg(rd));
+ ASSERT(!BadReg(rm));
+ m_formatter.twoWordOp12Reg4FourFours(OP_CLZ, rm, FourFours(0xf, rd, 8, rm));
}
- void cmn(RegisterID rn, ARMThumbImmediate imm)
+ ALWAYS_INLINE void cmn(RegisterID rn, ARMThumbImmediate imm)
{
ASSERT(rn != ARMRegisters::pc);
ASSERT(imm.isEncodedImm());
m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_CMN_imm, rn, (RegisterID)0xf, imm);
}
- void cmp(RegisterID rn, ARMThumbImmediate imm)
+ ALWAYS_INLINE void cmp(RegisterID rn, ARMThumbImmediate imm)
{
ASSERT(rn != ARMRegisters::pc);
ASSERT(imm.isEncodedImm());
m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_CMP_imm_T2, rn, (RegisterID)0xf, imm);
}
- void cmp(RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
+ ALWAYS_INLINE void cmp(RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
{
ASSERT(rn != ARMRegisters::pc);
ASSERT(!BadReg(rm));
m_formatter.twoWordOp12Reg4FourFours(OP_CMP_reg_T2, rn, FourFours(shift.hi4(), 0xf, shift.lo4(), rm));
}
- void cmp(RegisterID rn, RegisterID rm)
+ ALWAYS_INLINE void cmp(RegisterID rn, RegisterID rm)
{
if ((rn | rm) & 8)
cmp(rn, rm, ShiftTypeAndAmount());
}
// xor is not spelled with an 'e'. :-(
- void eor(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
+ ALWAYS_INLINE void eor(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
{
ASSERT(!BadReg(rd));
ASSERT(!BadReg(rn));
}
// xor is not spelled with an 'e'. :-(
- void eor(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
+ ALWAYS_INLINE void eor(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
{
ASSERT(!BadReg(rd));
ASSERT(!BadReg(rn));
eor(rd, rn, rm, ShiftTypeAndAmount());
}
- void it(Condition cond)
+ ALWAYS_INLINE void it(Condition cond)
{
m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond));
}
- void it(Condition cond, bool inst2if)
+ ALWAYS_INLINE void it(Condition cond, bool inst2if)
{
m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond, inst2if));
}
- void it(Condition cond, bool inst2if, bool inst3if)
+ ALWAYS_INLINE void it(Condition cond, bool inst2if, bool inst3if)
{
m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond, inst2if, inst3if));
}
- void it(Condition cond, bool inst2if, bool inst3if, bool inst4if)
+ ALWAYS_INLINE void it(Condition cond, bool inst2if, bool inst3if, bool inst4if)
{
m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond, inst2if, inst3if, inst4if));
}
// rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
- void ldr(RegisterID rt, RegisterID rn, ARMThumbImmediate imm)
+ ALWAYS_INLINE void ldr(RegisterID rt, RegisterID rn, ARMThumbImmediate imm)
{
ASSERT(rn != ARMRegisters::pc); // LDR (literal)
ASSERT(imm.isUInt12());
if (!((rt | rn) & 8) && imm.isUInt7())
m_formatter.oneWordOp5Imm5Reg3Reg3(OP_LDR_imm_T1, imm.getUInt7() >> 2, rn, rt);
else if ((rn == ARMRegisters::sp) && !(rt & 8) && imm.isUInt10())
- m_formatter.oneWordOp5Reg3Imm8(OP_LDR_imm_T2, rt, imm.getUInt10() >> 2);
+ m_formatter.oneWordOp5Reg3Imm8(OP_LDR_imm_T2, rt, static_cast<uint8_t>(imm.getUInt10() >> 2));
else
m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDR_imm_T3, rn, rt, imm.getUInt12());
}
+ ALWAYS_INLINE void ldrCompact(RegisterID rt, RegisterID rn, ARMThumbImmediate imm)
+ {
+ ASSERT(rn != ARMRegisters::pc); // LDR (literal)
+ ASSERT(imm.isUInt7());
+ ASSERT(!((rt | rn) & 8));
+ m_formatter.oneWordOp5Imm5Reg3Reg3(OP_LDR_imm_T1, imm.getUInt7() >> 2, rn, rt);
+ }
+
// If index is set, this is a regular offset or a pre-indexed load;
// if index is not set then is is a post-index load.
//
// _tmp = _reg + offset
// MEM[index ? _tmp : _reg] = REG[rt]
// if (wback) REG[rn] = _tmp
- void ldr(RegisterID rt, RegisterID rn, int offset, bool index, bool wback)
+ ALWAYS_INLINE void ldr(RegisterID rt, RegisterID rn, int offset, bool index, bool wback)
{
ASSERT(rt != ARMRegisters::pc);
ASSERT(rn != ARMRegisters::pc);
}
// rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
- void ldr(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift=0)
+ ALWAYS_INLINE void ldr(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift = 0)
{
ASSERT(rn != ARMRegisters::pc); // LDR (literal)
ASSERT(!BadReg(rm));
}
// rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
- void ldrh(RegisterID rt, RegisterID rn, ARMThumbImmediate imm)
+ ALWAYS_INLINE void ldrh(RegisterID rt, RegisterID rn, ARMThumbImmediate imm)
{
ASSERT(rn != ARMRegisters::pc); // LDR (literal)
ASSERT(imm.isUInt12());
// _tmp = _reg + offset
// MEM[index ? _tmp : _reg] = REG[rt]
// if (wback) REG[rn] = _tmp
- void ldrh(RegisterID rt, RegisterID rn, int offset, bool index, bool wback)
+ ALWAYS_INLINE void ldrh(RegisterID rt, RegisterID rn, int offset, bool index, bool wback)
{
ASSERT(rt != ARMRegisters::pc);
ASSERT(rn != ARMRegisters::pc);
m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDRH_imm_T3, rn, rt, offset);
}
- void ldrh(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift=0)
+ ALWAYS_INLINE void ldrh(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift = 0)
{
ASSERT(!BadReg(rt)); // Memory hint
ASSERT(rn != ARMRegisters::pc); // LDRH (literal)
m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDRB_imm_T3, rn, rt, offset);
}
- void ldrb(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift = 0)
+ ALWAYS_INLINE void ldrb(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift = 0)
{
ASSERT(rn != ARMRegisters::pc); // LDR (literal)
ASSERT(!BadReg(rm));
m_formatter.twoWordOp16FourFours(OP_LSL_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm));
}
- void lsl(RegisterID rd, RegisterID rn, RegisterID rm)
+ ALWAYS_INLINE void lsl(RegisterID rd, RegisterID rn, RegisterID rm)
{
ASSERT(!BadReg(rd));
ASSERT(!BadReg(rn));
m_formatter.twoWordOp12Reg4FourFours(OP_LSL_reg_T2, rn, FourFours(0xf, rd, 0, rm));
}
- void lsr(RegisterID rd, RegisterID rm, int32_t shiftAmount)
+ ALWAYS_INLINE void lsr(RegisterID rd, RegisterID rm, int32_t shiftAmount)
{
ASSERT(!BadReg(rd));
ASSERT(!BadReg(rm));
m_formatter.twoWordOp16FourFours(OP_LSR_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm));
}
- void lsr(RegisterID rd, RegisterID rn, RegisterID rm)
+ ALWAYS_INLINE void lsr(RegisterID rd, RegisterID rn, RegisterID rm)
{
ASSERT(!BadReg(rd));
ASSERT(!BadReg(rn));
m_formatter.twoWordOp12Reg4FourFours(OP_LSR_reg_T2, rn, FourFours(0xf, rd, 0, rm));
}
- void movT3(RegisterID rd, ARMThumbImmediate imm)
+ ALWAYS_INLINE void movT3(RegisterID rd, ARMThumbImmediate imm)
{
ASSERT(imm.isValid());
ASSERT(!imm.isEncodedImm());
m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOV_imm_T3, imm.m_value.imm4, rd, imm);
}
- void mov(RegisterID rd, ARMThumbImmediate imm)
+ ALWAYS_INLINE void mov(RegisterID rd, ARMThumbImmediate imm)
{
ASSERT(imm.isValid());
ASSERT(!BadReg(rd));
movT3(rd, imm);
}
- void mov(RegisterID rd, RegisterID rm)
+ ALWAYS_INLINE void mov(RegisterID rd, RegisterID rm)
{
m_formatter.oneWordOp8RegReg143(OP_MOV_reg_T1, rm, rd);
}
- void movt(RegisterID rd, ARMThumbImmediate imm)
+ ALWAYS_INLINE void movt(RegisterID rd, ARMThumbImmediate imm)
{
ASSERT(imm.isUInt16());
ASSERT(!BadReg(rd));
m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOVT, imm.m_value.imm4, rd, imm);
}
- void mvn(RegisterID rd, ARMThumbImmediate imm)
+ ALWAYS_INLINE void mvn(RegisterID rd, ARMThumbImmediate imm)
{
ASSERT(imm.isEncodedImm());
ASSERT(!BadReg(rd));
m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MVN_imm, 0xf, rd, imm);
}
- void mvn(RegisterID rd, RegisterID rm, ShiftTypeAndAmount shift)
+ ALWAYS_INLINE void mvn(RegisterID rd, RegisterID rm, ShiftTypeAndAmount shift)
{
ASSERT(!BadReg(rd));
ASSERT(!BadReg(rm));
m_formatter.twoWordOp16FourFours(OP_MVN_reg_T2, FourFours(shift.hi4(), rd, shift.lo4(), rm));
}
- void mvn(RegisterID rd, RegisterID rm)
+ ALWAYS_INLINE void mvn(RegisterID rd, RegisterID rm)
{
if (!((rd | rm) & 8))
m_formatter.oneWordOp10Reg3Reg3(OP_MVN_reg_T1, rm, rd);
mvn(rd, rm, ShiftTypeAndAmount());
}
- void neg(RegisterID rd, RegisterID rm)
+ ALWAYS_INLINE void neg(RegisterID rd, RegisterID rm)
{
ARMThumbImmediate zero = ARMThumbImmediate::makeUInt12(0);
sub(rd, zero, rm);
}
- void orr(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
+ ALWAYS_INLINE void orr(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
{
ASSERT(!BadReg(rd));
ASSERT(!BadReg(rn));
m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ORR_imm_T1, rn, rd, imm);
}
- void orr(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
+ ALWAYS_INLINE void orr(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
{
ASSERT(!BadReg(rd));
ASSERT(!BadReg(rn));
orr(rd, rn, rm, ShiftTypeAndAmount());
}
- void orr_S(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
+ ALWAYS_INLINE void orr_S(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
{
ASSERT(!BadReg(rd));
ASSERT(!BadReg(rn));
orr_S(rd, rn, rm, ShiftTypeAndAmount());
}
- void ror(RegisterID rd, RegisterID rm, int32_t shiftAmount)
+ ALWAYS_INLINE void ror(RegisterID rd, RegisterID rm, int32_t shiftAmount)
{
ASSERT(!BadReg(rd));
ASSERT(!BadReg(rm));
m_formatter.twoWordOp16FourFours(OP_ROR_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm));
}
- void ror(RegisterID rd, RegisterID rn, RegisterID rm)
+ ALWAYS_INLINE void ror(RegisterID rd, RegisterID rn, RegisterID rm)
{
ASSERT(!BadReg(rd));
ASSERT(!BadReg(rn));
m_formatter.twoWordOp12Reg4FourFours(OP_ROR_reg_T2, rn, FourFours(0xf, rd, 0, rm));
}
- void smull(RegisterID rdLo, RegisterID rdHi, RegisterID rn, RegisterID rm)
+ ALWAYS_INLINE void smull(RegisterID rdLo, RegisterID rdHi, RegisterID rn, RegisterID rm)
{
ASSERT(!BadReg(rdLo));
ASSERT(!BadReg(rdHi));
}
// rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
- void str(RegisterID rt, RegisterID rn, ARMThumbImmediate imm)
+ ALWAYS_INLINE void str(RegisterID rt, RegisterID rn, ARMThumbImmediate imm)
{
ASSERT(rt != ARMRegisters::pc);
ASSERT(rn != ARMRegisters::pc);
if (!((rt | rn) & 8) && imm.isUInt7())
m_formatter.oneWordOp5Imm5Reg3Reg3(OP_STR_imm_T1, imm.getUInt7() >> 2, rn, rt);
else if ((rn == ARMRegisters::sp) && !(rt & 8) && imm.isUInt10())
- m_formatter.oneWordOp5Reg3Imm8(OP_STR_imm_T2, rt, imm.getUInt10() >> 2);
+ m_formatter.oneWordOp5Reg3Imm8(OP_STR_imm_T2, rt, static_cast<uint8_t>(imm.getUInt10() >> 2));
else
m_formatter.twoWordOp12Reg4Reg4Imm12(OP_STR_imm_T3, rn, rt, imm.getUInt12());
}
// _tmp = _reg + offset
// MEM[index ? _tmp : _reg] = REG[rt]
// if (wback) REG[rn] = _tmp
- void str(RegisterID rt, RegisterID rn, int offset, bool index, bool wback)
+ ALWAYS_INLINE void str(RegisterID rt, RegisterID rn, int offset, bool index, bool wback)
{
ASSERT(rt != ARMRegisters::pc);
ASSERT(rn != ARMRegisters::pc);
}
// rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
- void str(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift=0)
+ ALWAYS_INLINE void str(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift = 0)
{
ASSERT(rn != ARMRegisters::pc);
ASSERT(!BadReg(rm));
m_formatter.twoWordOp12Reg4FourFours(OP_STR_reg_T2, rn, FourFours(rt, 0, shift, rm));
}
- void sub(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
+ ALWAYS_INLINE void sub(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
{
// Rd can only be SP if Rn is also SP.
ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
ASSERT(imm.isValid());
if ((rn == ARMRegisters::sp) && (rd == ARMRegisters::sp) && imm.isUInt9()) {
- m_formatter.oneWordOp9Imm7(OP_SUB_SP_imm_T1, imm.getUInt9() >> 2);
+ m_formatter.oneWordOp9Imm7(OP_SUB_SP_imm_T1, static_cast<uint8_t>(imm.getUInt9() >> 2));
return;
} else if (!((rd | rn) & 8)) {
if (imm.isUInt3()) {
}
}
- void sub(RegisterID rd, ARMThumbImmediate imm, RegisterID rn)
+ ALWAYS_INLINE void sub(RegisterID rd, ARMThumbImmediate imm, RegisterID rn)
{
ASSERT(rd != ARMRegisters::pc);
ASSERT(rn != ARMRegisters::pc);
m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_RSB_imm_T2, rn, rd, imm);
}
- void sub(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
+ ALWAYS_INLINE void sub(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
{
ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
ASSERT(rd != ARMRegisters::pc);
}
// NOTE: In an IT block, add doesn't modify the flags register.
- void sub(RegisterID rd, RegisterID rn, RegisterID rm)
+ ALWAYS_INLINE void sub(RegisterID rd, RegisterID rn, RegisterID rm)
{
if (!((rd | rn | rm) & 8))
m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_reg_T1, rm, rn, rd);
ASSERT(imm.isValid());
if ((rn == ARMRegisters::sp) && (rd == ARMRegisters::sp) && imm.isUInt9()) {
- m_formatter.oneWordOp9Imm7(OP_SUB_SP_imm_T1, imm.getUInt9() >> 2);
+ m_formatter.oneWordOp9Imm7(OP_SUB_SP_imm_T1, static_cast<uint8_t>(imm.getUInt9() >> 2));
return;
} else if (!((rd | rn) & 8)) {
if (imm.isUInt3()) {
}
// Not allowed in an IT (if then) block?
- void sub_S(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
+ ALWAYS_INLINE void sub_S(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
{
ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
ASSERT(rd != ARMRegisters::pc);
}
// Not allowed in an IT (if then) block.
- void sub_S(RegisterID rd, RegisterID rn, RegisterID rm)
+ ALWAYS_INLINE void sub_S(RegisterID rd, RegisterID rn, RegisterID rm)
{
if (!((rd | rn | rm) & 8))
m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_reg_T1, rm, rn, rd);
sub_S(rd, rn, rm, ShiftTypeAndAmount());
}
- void tst(RegisterID rn, ARMThumbImmediate imm)
+ ALWAYS_INLINE void tst(RegisterID rn, ARMThumbImmediate imm)
{
ASSERT(!BadReg(rn));
ASSERT(imm.isEncodedImm());
m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_TST_imm, rn, (RegisterID)0xf, imm);
}
- void tst(RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
+ ALWAYS_INLINE void tst(RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
{
ASSERT(!BadReg(rn));
ASSERT(!BadReg(rm));
m_formatter.twoWordOp12Reg4FourFours(OP_TST_reg_T2, rn, FourFours(shift.hi4(), 0xf, shift.lo4(), rm));
}
- void tst(RegisterID rn, RegisterID rm)
+ ALWAYS_INLINE void tst(RegisterID rn, RegisterID rm)
{
if ((rn | rm) & 8)
tst(rn, rm, ShiftTypeAndAmount());
m_formatter.vfpOp(OP_VSUB_T2, OP_VSUB_T2b, true, rn, rd, rm);
}
- JmpDst label()
+ void nop()
{
- return JmpDst(m_formatter.size());
+ m_formatter.oneWordOp8Imm8(OP_NOP_T1, 0);
}
-
- JmpDst align(int alignment)
- {
- while (!m_formatter.isAligned(alignment))
- bkpt();
- return label();
- }
-
- static void* getRelocatedAddress(void* code, JmpSrc jump)
+ AssemblerLabel label()
{
- ASSERT(jump.m_offset != -1);
-
- return reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(code) + jump.m_offset);
+ return m_formatter.label();
}
- static void* getRelocatedAddress(void* code, JmpDst destination)
+ AssemblerLabel align(int alignment)
{
- ASSERT(destination.m_offset != -1);
+ while (!m_formatter.isAligned(alignment))
+ bkpt();
- return reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(code) + destination.m_offset);
- }
-
- static int getDifferenceBetweenLabels(JmpDst src, JmpDst dst)
- {
- return dst.m_offset - src.m_offset;
+ return label();
}
- static int getDifferenceBetweenLabels(JmpDst src, JmpSrc dst)
+ static void* getRelocatedAddress(void* code, AssemblerLabel label)
{
- return dst.m_offset - src.m_offset;
+ ASSERT(label.isSet());
+ return reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(code) + label.m_offset);
}
- static int getDifferenceBetweenLabels(JmpSrc src, JmpDst dst)
+ static int getDifferenceBetweenLabels(AssemblerLabel a, AssemblerLabel b)
{
- return dst.m_offset - src.m_offset;
+ return b.m_offset - a.m_offset;
}
int executableOffsetFor(int location)
return static_cast<int32_t*>(m_formatter.data())[location / sizeof(int32_t) - 1];
}
- int jumpSizeDelta(JumpType jumpType, JumpLinkType jumpLinkType) { return JumpPaddingSizes[jumpType] - JumpSizes[jumpLinkType]; }
+ int jumpSizeDelta(JumpType jumpType, JumpLinkType jumpLinkType) { return JUMP_ENUM_SIZE(jumpType) - JUMP_ENUM_SIZE(jumpLinkType); }
// Assembler admin methods:
- size_t size() const
- {
- return m_formatter.size();
- }
-
- static bool linkRecordSourceComparator(const LinkRecord& a, const LinkRecord& b)
+ static ALWAYS_INLINE bool linkRecordSourceComparator(const LinkRecord& a, const LinkRecord& b)
{
return a.from() < b.from();
}
if (jumpType == JumpConditionFixedSize)
return LinkConditionalBX;
- const int paddingSize = JumpPaddingSizes[jumpType];
+ const int paddingSize = JUMP_ENUM_SIZE(jumpType);
bool mayTriggerErrata = false;
if (jumpType == JumpCondition) {
// 2-byte conditional T1
- const uint16_t* jumpT1Location = reinterpret_cast<const uint16_t*>(from - (paddingSize - JumpSizes[LinkJumpT1]));
+ const uint16_t* jumpT1Location = reinterpret_cast<const uint16_t*>(from - (paddingSize - JUMP_ENUM_SIZE(LinkJumpT1)));
if (canBeJumpT1(jumpT1Location, to))
return LinkJumpT1;
// 4-byte conditional T3
- const uint16_t* jumpT3Location = reinterpret_cast<const uint16_t*>(from - (paddingSize - JumpSizes[LinkJumpT3]));
+ const uint16_t* jumpT3Location = reinterpret_cast<const uint16_t*>(from - (paddingSize - JUMP_ENUM_SIZE(LinkJumpT3)));
if (canBeJumpT3(jumpT3Location, to, mayTriggerErrata)) {
if (!mayTriggerErrata)
return LinkJumpT3;
}
// 4-byte conditional T4 with IT
const uint16_t* conditionalJumpT4Location =
- reinterpret_cast<const uint16_t*>(from - (paddingSize - JumpSizes[LinkConditionalJumpT4]));
+ reinterpret_cast<const uint16_t*>(from - (paddingSize - JUMP_ENUM_SIZE(LinkConditionalJumpT4)));
if (canBeJumpT4(conditionalJumpT4Location, to, mayTriggerErrata)) {
if (!mayTriggerErrata)
return LinkConditionalJumpT4;
}
} else {
// 2-byte unconditional T2
- const uint16_t* jumpT2Location = reinterpret_cast<const uint16_t*>(from - (paddingSize - JumpSizes[LinkJumpT2]));
+ const uint16_t* jumpT2Location = reinterpret_cast<const uint16_t*>(from - (paddingSize - JUMP_ENUM_SIZE(LinkJumpT2)));
if (canBeJumpT2(jumpT2Location, to))
return LinkJumpT2;
// 4-byte unconditional T4
- const uint16_t* jumpT4Location = reinterpret_cast<const uint16_t*>(from - (paddingSize - JumpSizes[LinkJumpT4]));
+ const uint16_t* jumpT4Location = reinterpret_cast<const uint16_t*>(from - (paddingSize - JUMP_ENUM_SIZE(LinkJumpT4)));
if (canBeJumpT4(jumpT4Location, to, mayTriggerErrata)) {
if (!mayTriggerErrata)
return LinkJumpT4;
return m_jumpsToLink;
}
- void link(LinkRecord& record, uint8_t* from, uint8_t* to)
+ void ALWAYS_INLINE link(LinkRecord& record, uint8_t* from, uint8_t* to)
{
switch (record.linkType()) {
case LinkJumpT1:
}
void* unlinkedCode() { return m_formatter.data(); }
-
- static unsigned getCallReturnOffset(JmpSrc call)
+ size_t codeSize() const { return m_formatter.codeSize(); }
+
+ static unsigned getCallReturnOffset(AssemblerLabel call)
{
- ASSERT(call.m_offset >= 0);
+ ASSERT(call.isSet());
return call.m_offset;
}
// writable region of memory; to modify the code in an execute-only execuable
// pool the 'repatch' and 'relink' methods should be used.
- void linkJump(JmpSrc from, JmpDst to)
+ void linkJump(AssemblerLabel from, AssemblerLabel to, JumpType type, Condition condition)
{
- ASSERT(to.m_offset != -1);
- ASSERT(from.m_offset != -1);
- m_jumpsToLink.append(LinkRecord(from.m_offset, to.m_offset, from.m_type, from.m_condition));
+ ASSERT(to.isSet());
+ ASSERT(from.isSet());
+ m_jumpsToLink.append(LinkRecord(from.m_offset, to.m_offset, type, condition));
}
- static void linkJump(void* code, JmpSrc from, void* to)
+ static void linkJump(void* code, AssemblerLabel from, void* to)
{
- ASSERT(from.m_offset != -1);
+ ASSERT(from.isSet());
uint16_t* location = reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
linkJumpAbsolute(location, to);
}
- // bah, this mathod should really be static, since it is used by the LinkBuffer.
- // return a bool saying whether the link was successful?
- static void linkCall(void* code, JmpSrc from, void* to)
+ static void linkCall(void* code, AssemblerLabel from, void* to)
{
ASSERT(!(reinterpret_cast<intptr_t>(code) & 1));
- ASSERT(from.m_offset != -1);
+ ASSERT(from.isSet());
ASSERT(reinterpret_cast<intptr_t>(to) & 1);
setPointer(reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(code) + from.m_offset) - 1, to);
}
- static void linkPointer(void* code, JmpDst where, void* value)
+ static void linkPointer(void* code, AssemblerLabel where, void* value)
{
setPointer(reinterpret_cast<char*>(code) + where.m_offset, value);
}
setInt32(where, value);
}
+
+ static void repatchCompact(void* where, int32_t value)
+ {
+ ASSERT(value >= 0);
+ ASSERT(ARMThumbImmediate::makeUInt12(value).isUInt7());
+ setUInt7ForLoad(where, ARMThumbImmediate::makeUInt12(value));
+ }
static void repatchPointer(void* where, void* value)
{
setPointer(where, value);
}
- static void repatchLoadPtrToLEA(void* where)
+ static void* readPointer(void* where)
{
- ASSERT(!(reinterpret_cast<intptr_t>(where) & 1));
- uint16_t* loadOp = reinterpret_cast<uint16_t*>(where) + 4;
-
- ASSERT((loadOp[0] & 0xfff0) == OP_LDR_reg_T2);
- ASSERT((loadOp[1] & 0x0ff0) == 0);
- int rn = loadOp[0] & 0xf;
- int rt = loadOp[1] >> 12;
- int rm = loadOp[1] & 0xf;
-
- loadOp[0] = OP_ADD_reg_T3 | rn;
- loadOp[1] = rt << 8 | rm;
- ExecutableAllocator::cacheFlush(loadOp, sizeof(uint32_t));
+ return reinterpret_cast<void*>(readInt32(where));
}
private:
ExecutableAllocator::cacheFlush(location - 4, 4 * sizeof(uint16_t));
}
+
+ static int32_t readInt32(void* code)
+ {
+ uint16_t* location = reinterpret_cast<uint16_t*>(code);
+ ASSERT(isMOV_imm_T3(location - 4) && isMOVT(location - 2));
+
+ ARMThumbImmediate lo16;
+ ARMThumbImmediate hi16;
+ decodeTwoWordOp5i6Imm4Reg4EncodedImmFirst(lo16, location[-4]);
+ decodeTwoWordOp5i6Imm4Reg4EncodedImmSecond(lo16, location[-3]);
+ decodeTwoWordOp5i6Imm4Reg4EncodedImmFirst(hi16, location[-2]);
+ decodeTwoWordOp5i6Imm4Reg4EncodedImmSecond(hi16, location[-1]);
+ uint32_t result = hi16.asUInt16();
+ result <<= 16;
+ result |= lo16.asUInt16();
+ return static_cast<int32_t>(result);
+ }
+
+ static void setUInt7ForLoad(void* code, ARMThumbImmediate imm)
+ {
+ // Requires us to have planted a LDR_imm_T1
+ ASSERT(imm.isValid());
+ ASSERT(imm.isUInt7());
+ uint16_t* location = reinterpret_cast<uint16_t*>(code);
+ location[0] |= (imm.getUInt7() >> 2) << 6;
+ ExecutableAllocator::cacheFlush(location, sizeof(uint16_t));
+ }
static void setPointer(void* code, void* value)
{
return op | (imm.m_value.i << 10) | imm.m_value.imm4;
}
+ static void decodeTwoWordOp5i6Imm4Reg4EncodedImmFirst(ARMThumbImmediate& result, uint16_t value)
+ {
+ result.m_value.i = (value >> 10) & 1;
+ result.m_value.imm4 = value & 15;
+ }
+
static uint16_t twoWordOp5i6Imm4Reg4EncodedImmSecond(uint16_t rd, ARMThumbImmediate imm)
{
return (imm.m_value.imm3 << 12) | (rd << 8) | imm.m_value.imm8;
}
+ static void decodeTwoWordOp5i6Imm4Reg4EncodedImmSecond(ARMThumbImmediate& result, uint16_t value)
+ {
+ result.m_value.imm3 = (value >> 12) & 7;
+ result.m_value.imm8 = value & 255;
+ }
+
class ARMInstructionFormatter {
public:
- void oneWordOp5Reg3Imm8(OpcodeID op, RegisterID rd, uint8_t imm)
+ ALWAYS_INLINE void oneWordOp5Reg3Imm8(OpcodeID op, RegisterID rd, uint8_t imm)
{
m_buffer.putShort(op | (rd << 8) | imm);
}
- void oneWordOp5Imm5Reg3Reg3(OpcodeID op, uint8_t imm, RegisterID reg1, RegisterID reg2)
+ ALWAYS_INLINE void oneWordOp5Imm5Reg3Reg3(OpcodeID op, uint8_t imm, RegisterID reg1, RegisterID reg2)
{
m_buffer.putShort(op | (imm << 6) | (reg1 << 3) | reg2);
}
- void oneWordOp7Reg3Reg3Reg3(OpcodeID op, RegisterID reg1, RegisterID reg2, RegisterID reg3)
+ ALWAYS_INLINE void oneWordOp7Reg3Reg3Reg3(OpcodeID op, RegisterID reg1, RegisterID reg2, RegisterID reg3)
{
m_buffer.putShort(op | (reg1 << 6) | (reg2 << 3) | reg3);
}
- void oneWordOp8Imm8(OpcodeID op, uint8_t imm)
+ ALWAYS_INLINE void oneWordOp8Imm8(OpcodeID op, uint8_t imm)
{
m_buffer.putShort(op | imm);
}
- void oneWordOp8RegReg143(OpcodeID op, RegisterID reg1, RegisterID reg2)
+ ALWAYS_INLINE void oneWordOp8RegReg143(OpcodeID op, RegisterID reg1, RegisterID reg2)
{
m_buffer.putShort(op | ((reg2 & 8) << 4) | (reg1 << 3) | (reg2 & 7));
}
- void oneWordOp9Imm7(OpcodeID op, uint8_t imm)
+
+ ALWAYS_INLINE void oneWordOp9Imm7(OpcodeID op, uint8_t imm)
{
m_buffer.putShort(op | imm);
}
- void oneWordOp10Reg3Reg3(OpcodeID op, RegisterID reg1, RegisterID reg2)
+ ALWAYS_INLINE void oneWordOp10Reg3Reg3(OpcodeID op, RegisterID reg1, RegisterID reg2)
{
m_buffer.putShort(op | (reg1 << 3) | reg2);
}
- void twoWordOp12Reg4FourFours(OpcodeID1 op, RegisterID reg, FourFours ff)
+ ALWAYS_INLINE void twoWordOp12Reg4FourFours(OpcodeID1 op, RegisterID reg, FourFours ff)
{
m_buffer.putShort(op | reg);
m_buffer.putShort(ff.m_u.value);
}
- void twoWordOp16FourFours(OpcodeID1 op, FourFours ff)
+ ALWAYS_INLINE void twoWordOp16FourFours(OpcodeID1 op, FourFours ff)
{
m_buffer.putShort(op);
m_buffer.putShort(ff.m_u.value);
}
- void twoWordOp16Op16(OpcodeID1 op1, OpcodeID2 op2)
+ ALWAYS_INLINE void twoWordOp16Op16(OpcodeID1 op1, OpcodeID2 op2)
{
m_buffer.putShort(op1);
m_buffer.putShort(op2);
}
- void twoWordOp5i6Imm4Reg4EncodedImm(OpcodeID1 op, int imm4, RegisterID rd, ARMThumbImmediate imm)
+ ALWAYS_INLINE void twoWordOp5i6Imm4Reg4EncodedImm(OpcodeID1 op, int imm4, RegisterID rd, ARMThumbImmediate imm)
{
ARMThumbImmediate newImm = imm;
newImm.m_value.imm4 = imm4;
m_buffer.putShort(ARMv7Assembler::twoWordOp5i6Imm4Reg4EncodedImmSecond(rd, newImm));
}
- void twoWordOp12Reg4Reg4Imm12(OpcodeID1 op, RegisterID reg1, RegisterID reg2, uint16_t imm)
+ ALWAYS_INLINE void twoWordOp12Reg4Reg4Imm12(OpcodeID1 op, RegisterID reg1, RegisterID reg2, uint16_t imm)
{
m_buffer.putShort(op | reg1);
m_buffer.putShort((reg2 << 12) | imm);
// 111111111B11aaaa:bbbb222SA2C2cccc
// Where 1s in the pattern come from op1, 2s in the pattern come from op2, S is the provided size bit.
// Operands provide 5 bit values of the form Aaaaa, Bbbbb, Ccccc.
- void vfpOp(OpcodeID1 op1, OpcodeID2 op2, bool size, VFPOperand a, VFPOperand b, VFPOperand c)
+ ALWAYS_INLINE void vfpOp(OpcodeID1 op1, OpcodeID2 op2, bool size, VFPOperand a, VFPOperand b, VFPOperand c)
{
ASSERT(!(op1 & 0x004f));
ASSERT(!(op2 & 0xf1af));
// Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
// (i.e. +/-(0..255) 32-bit words)
- void vfpMemOp(OpcodeID1 op1, OpcodeID2 op2, bool size, RegisterID rn, VFPOperand rd, int32_t imm)
+ ALWAYS_INLINE void vfpMemOp(OpcodeID1 op1, OpcodeID2 op2, bool size, RegisterID rn, VFPOperand rd, int32_t imm)
{
bool up = true;
if (imm < 0) {
// Administrative methods:
- size_t size() const { return m_buffer.size(); }
+ size_t codeSize() const { return m_buffer.codeSize(); }
+ AssemblerLabel label() const { return m_buffer.label(); }
bool isAligned(int alignment) const { return m_buffer.isAligned(alignment); }
void* data() const { return m_buffer.data(); }
- void* executableCopy(ExecutablePool* allocator) { return m_buffer.executableCopy(allocator); }
+
+#ifndef NDEBUG
+ unsigned debugOffset() { return m_buffer.debugOffset(); }
+#endif
private:
AssemblerBuffer m_buffer;
#ifndef AbstractMacroAssembler_h
#define AbstractMacroAssembler_h
-#include <MacroAssemblerCodeRef.h>
-#include <CodeLocation.h>
+#include "CodeLocation.h"
+#include "MacroAssemblerCodeRef.h"
#include <wtf/Noncopyable.h>
#include <wtf/UnusedParam.h>
template <class AssemblerType>
class AbstractMacroAssembler {
public:
+ friend class JITWriteBarrierBase;
typedef AssemblerType AssemblerType_T;
typedef MacroAssemblerCodePtr CodePtr;
class Jump;
typedef typename AssemblerType::RegisterID RegisterID;
- typedef typename AssemblerType::JmpSrc JmpSrc;
- typedef typename AssemblerType::JmpDst JmpDst;
-
// Section 1: MacroAssembler operand types
//
// Describes an memory operand given by a pointer. For regular load & store
// operations an unwrapped void* will be used, rather than using this.
struct AbsoluteAddress {
- explicit AbsoluteAddress(void* ptr)
+ explicit AbsoluteAddress(const void* ptr)
: m_ptr(ptr)
{
}
- void* m_ptr;
+ const void* m_ptr;
};
- // ImmPtr:
+ // TrustedImmPtr:
//
// A pointer sized immediate operand to an instruction - this is wrapped
// in a class requiring explicit construction in order to differentiate
// from pointers used as absolute addresses to memory operations
- struct ImmPtr {
- explicit ImmPtr(const void* value)
+ struct TrustedImmPtr {
+ explicit TrustedImmPtr(const void* value)
: m_value(value)
{
}
const void* m_value;
};
- // Imm32:
+ struct ImmPtr : public TrustedImmPtr {
+ explicit ImmPtr(const void* value)
+ : TrustedImmPtr(value)
+ {
+ }
+ };
+
+ // TrustedImm32:
//
// A 32bit immediate operand to an instruction - this is wrapped in a
// class requiring explicit construction in order to prevent RegisterIDs
// (which are implemented as an enum) from accidentally being passed as
// immediate values.
- struct Imm32 {
- explicit Imm32(int32_t value)
+ struct TrustedImm32 {
+ explicit TrustedImm32(int32_t value)
: m_value(value)
#if CPU(ARM) || CPU(MIPS)
, m_isPointer(false)
}
#if !CPU(X86_64)
- explicit Imm32(ImmPtr ptr)
+ explicit TrustedImm32(TrustedImmPtr ptr)
: m_value(ptr.asIntptr())
#if CPU(ARM) || CPU(MIPS)
, m_isPointer(true)
};
+ struct Imm32 : public TrustedImm32 {
+ explicit Imm32(int32_t value)
+ : TrustedImm32(value)
+ {
+ }
+#if !CPU(X86_64)
+ explicit Imm32(TrustedImmPtr ptr)
+ : TrustedImm32(ptr)
+ {
+ }
+#endif
+ };
+
// Section 2: MacroAssembler code buffer handles
//
// The following types are used to reference items in the code buffer
{
}
- bool isUsed() const { return m_label.isUsed(); }
- void used() { m_label.used(); }
+ bool isSet() const { return m_label.isSet(); }
private:
- JmpDst m_label;
+ AssemblerLabel m_label;
};
// DataLabelPtr:
{
}
+ bool isSet() const { return m_label.isSet(); }
+
private:
- JmpDst m_label;
+ AssemblerLabel m_label;
};
// DataLabel32:
{
}
+ AssemblerLabel label() const { return m_label; }
+
+ private:
+ AssemblerLabel m_label;
+ };
+
+ // DataLabelCompact:
+ //
+ // A DataLabelCompact is used to refer to a location in the code containing a
+ // compact immediate to be patched after the code has been generated.
+ class DataLabelCompact {
+ template<class TemplateAssemblerType>
+ friend class AbstractMacroAssembler;
+ friend class LinkBuffer;
+ public:
+ DataLabelCompact()
+ {
+ }
+
+ DataLabelCompact(AbstractMacroAssembler<AssemblerType>* masm)
+ : m_label(masm->m_assembler.label())
+ {
+ }
+
+ DataLabelCompact(AssemblerLabel label)
+ : m_label(label)
+ {
+ }
+
private:
- JmpDst m_label;
+ AssemblerLabel m_label;
};
// Call:
{
}
- Call(JmpSrc jmp, Flags flags)
+ Call(AssemblerLabel jmp, Flags flags)
: m_jmp(jmp)
, m_flags(flags)
{
return Call(jump.m_jmp, Linkable);
}
- JmpSrc m_jmp;
+ AssemblerLabel m_jmp;
private:
Flags m_flags;
};
{
}
- Jump(JmpSrc jmp)
+#if CPU(ARM_THUMB2)
+ // Fixme: this information should be stored in the instruction stream, not in the Jump object.
+ Jump(AssemblerLabel jmp, ARMv7Assembler::JumpType type, ARMv7Assembler::Condition condition = ARMv7Assembler::ConditionInvalid)
: m_jmp(jmp)
+ , m_type(type)
+ , m_condition(condition)
{
}
-
- void link(AbstractMacroAssembler<AssemblerType>* masm)
+#else
+ Jump(AssemblerLabel jmp)
+ : m_jmp(jmp)
+ {
+ }
+#endif
+
+ void link(AbstractMacroAssembler<AssemblerType>* masm) const
{
+#if CPU(ARM_THUMB2)
+ masm->m_assembler.linkJump(m_jmp, masm->m_assembler.label(), m_type, m_condition);
+#else
masm->m_assembler.linkJump(m_jmp, masm->m_assembler.label());
+#endif
}
- void linkTo(Label label, AbstractMacroAssembler<AssemblerType>* masm)
+ void linkTo(Label label, AbstractMacroAssembler<AssemblerType>* masm) const
{
+#if CPU(ARM_THUMB2)
+ masm->m_assembler.linkJump(m_jmp, label.m_label, m_type, m_condition);
+#else
masm->m_assembler.linkJump(m_jmp, label.m_label);
+#endif
}
+ bool isSet() const { return m_jmp.isSet(); }
+
private:
- JmpSrc m_jmp;
+ AssemblerLabel m_jmp;
+#if CPU(ARM_THUMB2)
+ ARMv7Assembler::JumpType m_type;
+ ARMv7Assembler::Condition m_condition;
+#endif
};
// JumpList:
return !m_jumps.size();
}
+ void clear()
+ {
+ m_jumps.clear();
+ }
+
const JumpVector& jumps() { return m_jumps; }
private:
// Section 3: Misc admin methods
- size_t size()
- {
- return m_assembler.size();
- }
-
Label label()
{
return Label(this);
{
return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
}
+
+ ptrdiff_t differenceBetween(Label from, DataLabelCompact to)
+ {
+ return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
+ }
ptrdiff_t differenceBetween(DataLabelPtr from, Jump to)
{
{
return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp);
}
-
+
+ // Temporary interface; likely to be removed, since may be hard to port to all architectures.
+#if CPU(X86) || CPU(X86_64)
+ void rewindToLabel(Label rewindTo) { m_assembler.rewindToLabel(rewindTo.m_label); }
+#endif
+
void beginUninterruptedSequence() { }
void endUninterruptedSequence() { }
+#ifndef NDEBUG
+ unsigned debugOffset() { return m_assembler.debugOffset(); }
+#endif
+
protected:
AssemblerType m_assembler;
AssemblerType::linkJump(code, jump.m_jmp, target.dataLocation());
}
- static void linkPointer(void* code, typename AssemblerType::JmpDst label, void* value)
+ static void linkPointer(void* code, AssemblerLabel label, void* value)
{
AssemblerType::linkPointer(code, label, value);
}
- static void* getLinkerAddress(void* code, typename AssemblerType::JmpSrc label)
- {
- return AssemblerType::getRelocatedAddress(code, label);
- }
-
- static void* getLinkerAddress(void* code, typename AssemblerType::JmpDst label)
+ static void* getLinkerAddress(void* code, AssemblerLabel label)
{
return AssemblerType::getRelocatedAddress(code, label);
}
AssemblerType::relinkCall(nearCall.dataLocation(), destination.executableAddress());
}
+ static void repatchCompact(CodeLocationDataLabelCompact dataLabelCompact, int32_t value)
+ {
+ AssemblerType::repatchCompact(dataLabelCompact.dataLocation(), value);
+ }
+
static void repatchInt32(CodeLocationDataLabel32 dataLabel32, int32_t value)
{
AssemblerType::repatchInt32(dataLabel32.dataLocation(), value);
{
AssemblerType::repatchPointer(dataLabelPtr.dataLocation(), value);
}
-
- static void repatchLoadPtrToLEA(CodeLocationInstruction instruction)
+
+ static void* readPointer(CodeLocationDataLabelPtr dataLabelPtr)
{
- AssemblerType::repatchLoadPtrToLEA(instruction.dataLocation());
+ return AssemblerType::readPointer(dataLabelPtr.dataLocation());
}
};
#include <jit/ExecutableAllocator.h>
#include <wtf/Assertions.h>
#include <wtf/FastMalloc.h>
+#include <wtf/StdLibExtras.h>
namespace JSC {
- class AssemblerBuffer {
- static const int inlineCapacity = 256;
- public:
- AssemblerBuffer()
- : m_buffer(m_inlineBuffer)
- , m_capacity(inlineCapacity)
- , m_size(0)
+ struct AssemblerLabel {
+ AssemblerLabel()
+ : m_offset(std::numeric_limits<uint32_t>::max())
{
}
- ~AssemblerBuffer()
+ explicit AssemblerLabel(uint32_t offset)
+ : m_offset(offset)
{
- if (m_buffer != m_inlineBuffer)
- fastFree(m_buffer);
}
- void ensureSpace(int space)
- {
- if (m_size > m_capacity - space)
- grow();
- }
+ bool isSet() const { return (m_offset != std::numeric_limits<uint32_t>::max()); }
- bool isAligned(int alignment) const
+ AssemblerLabel labelAtOffset(int offset) const
{
- return !(m_size & (alignment - 1));
+ return AssemblerLabel(m_offset + offset);
}
- void putByteUnchecked(int value)
+ uint32_t m_offset;
+ };
+
+ class AssemblerBuffer {
+ static const int inlineCapacity = 128;
+ public:
+ AssemblerBuffer()
+ : m_storage(inlineCapacity)
+ , m_buffer(m_storage.begin())
+ , m_capacity(inlineCapacity)
+ , m_index(0)
{
- ASSERT(!(m_size > m_capacity - 4));
- m_buffer[m_size] = value;
- m_size++;
}
- void putByte(int value)
+ ~AssemblerBuffer()
{
- if (m_size > m_capacity - 4)
- grow();
- putByteUnchecked(value);
}
- void putShortUnchecked(int value)
+ bool isAvailable(int space)
{
- ASSERT(!(m_size > m_capacity - 4));
- *reinterpret_cast<short*>(&m_buffer[m_size]) = value;
- m_size += 2;
+ return m_index + space <= m_capacity;
}
- void putShort(int value)
+ void ensureSpace(int space)
{
- if (m_size > m_capacity - 4)
+ if (!isAvailable(space))
grow();
- putShortUnchecked(value);
}
- void putIntUnchecked(int value)
+ bool isAligned(int alignment) const
{
- ASSERT(!(m_size > m_capacity - 4));
- *reinterpret_cast<int*>(&m_buffer[m_size]) = value;
- m_size += 4;
+ return !(m_index & (alignment - 1));
}
- void putInt64Unchecked(int64_t value)
+ template<typename IntegralType>
+ void putIntegral(IntegralType value)
{
- ASSERT(!(m_size > m_capacity - 8));
- *reinterpret_cast<int64_t*>(&m_buffer[m_size]) = value;
- m_size += 8;
+ ensureSpace(sizeof(IntegralType));
+ putIntegralUnchecked(value);
}
- void putInt(int value)
+ template<typename IntegralType>
+ void putIntegralUnchecked(IntegralType value)
{
- if (m_size > m_capacity - 4)
- grow();
- putIntUnchecked(value);
+ ASSERT(isAvailable(sizeof(IntegralType)));
+ *reinterpret_cast_ptr<IntegralType*>(m_buffer + m_index) = value;
+ m_index += sizeof(IntegralType);
}
+ void putByteUnchecked(int8_t value) { putIntegralUnchecked(value); }
+ void putByte(int8_t value) { putIntegral(value); }
+ void putShortUnchecked(int16_t value) { putIntegralUnchecked(value); }
+ void putShort(int16_t value) { putIntegral(value); }
+ void putIntUnchecked(int32_t value) { putIntegralUnchecked(value); }
+ void putInt(int32_t value) { putIntegral(value); }
+ void putInt64Unchecked(int64_t value) { putIntegralUnchecked(value); }
+ void putInt64(int64_t value) { putIntegral(value); }
+
void* data() const
{
return m_buffer;
}
- int size() const
+ size_t codeSize() const
{
- return m_size;
+ return m_index;
}
- void* executableCopy(ExecutablePool* allocator)
+ AssemblerLabel label() const
{
- if (!m_size)
+ return AssemblerLabel(m_index);
+ }
+
+ void* executableCopy(JSGlobalData& globalData, ExecutablePool* allocator)
+ {
+ if (!m_index)
return 0;
- void* result = allocator->alloc(m_size);
+ void* result = allocator->alloc(globalData, m_index);
if (!result)
return 0;
- ExecutableAllocator::makeWritable(result, m_size);
+ ExecutableAllocator::makeWritable(result, m_index);
- return memcpy(result, m_buffer, m_size);
+ return memcpy(result, m_buffer, m_index);
}
+ void rewindToLabel(AssemblerLabel label)
+ {
+ m_index = label.m_offset;
+ }
+
+#ifndef NDEBUG
+ unsigned debugOffset() { return m_index; }
+#endif
+
protected:
void append(const char* data, int size)
{
- if (m_size > m_capacity - size)
+ if (!isAvailable(size))
grow(size);
- memcpy(m_buffer + m_size, data, size);
- m_size += size;
+ memcpy(m_buffer + m_index, data, size);
+ m_index += size;
}
void grow(int extraCapacity = 0)
{
m_capacity += m_capacity / 2 + extraCapacity;
- if (m_buffer == m_inlineBuffer) {
- char* newBuffer = static_cast<char*>(fastMalloc(m_capacity));
- m_buffer = static_cast<char*>(memcpy(newBuffer, m_buffer, m_size));
- } else
- m_buffer = static_cast<char*>(fastRealloc(m_buffer, m_capacity));
+ m_storage.grow(m_capacity);
+ m_buffer = m_storage.begin();
}
- char m_inlineBuffer[inlineCapacity];
+ private:
+ Vector<char, inlineCapacity> m_storage;
char* m_buffer;
int m_capacity;
- int m_size;
+ int m_index;
};
} // namespace JSC
template <int maxPoolSize, int barrierSize, int maxInstructionSize, class AssemblerType>
class AssemblerBufferWithConstantPool: public AssemblerBuffer {
typedef SegmentedVector<uint32_t, 512> LoadOffsets;
+ using AssemblerBuffer::putIntegral;
+ using AssemblerBuffer::putIntegralUnchecked;
public:
+ typedef struct {
+ short high;
+ short low;
+ } TwoShorts;
+
enum {
UniqueConst,
ReusableConst,
AssemblerBuffer::ensureSpace(insnSpace);
}
+ void ensureSpaceForAnyOneInstruction()
+ {
+ flushIfNoSpaceFor(maxInstructionSize, sizeof(uint64_t));
+ }
+
bool isAligned(int alignment)
{
flushIfNoSpaceFor(alignment);
correctDeltas(8);
}
- int size()
+ void putIntegral(TwoShorts value)
{
- flushIfNoSpaceFor(maxInstructionSize, sizeof(uint64_t));
- return AssemblerBuffer::size();
+ putIntegral(value.high);
+ putIntegral(value.low);
}
- int uncheckedSize()
+ void putIntegralUnchecked(TwoShorts value)
{
- return AssemblerBuffer::size();
+ putIntegralUnchecked(value.high);
+ putIntegralUnchecked(value.low);
}
- void* executableCopy(ExecutablePool* allocator)
+ void* executableCopy(JSGlobalData& globalData, ExecutablePool* allocator)
{
flushConstantPool(false);
- return AssemblerBuffer::executableCopy(allocator);
+ return AssemblerBuffer::executableCopy(globalData, allocator);
}
- void putIntWithConstantInt(uint32_t insn, uint32_t constant, bool isReusable = false)
+ void putShortWithConstantInt(uint16_t insn, uint32_t constant, bool isReusable = false)
{
- flushIfNoSpaceFor(4, 4);
-
- m_loadOffsets.append(AssemblerBuffer::size());
- if (isReusable)
- for (int i = 0; i < m_numConsts; ++i) {
- if (m_mask[i] == ReusableConst && m_pool[i] == constant) {
- AssemblerBuffer::putInt(AssemblerType::patchConstantPoolLoad(insn, i));
- correctDeltas(4);
- return;
- }
- }
-
- m_pool[m_numConsts] = constant;
- m_mask[m_numConsts] = static_cast<char>(isReusable ? ReusableConst : UniqueConst);
-
- AssemblerBuffer::putInt(AssemblerType::patchConstantPoolLoad(insn, m_numConsts));
- ++m_numConsts;
+ putIntegralWithConstantInt(insn, constant, isReusable);
+ }
- correctDeltas(4, 4);
+ void putIntWithConstantInt(uint32_t insn, uint32_t constant, bool isReusable = false)
+ {
+ putIntegralWithConstantInt(insn, constant, isReusable);
}
// This flushing mechanism can be called after any unconditional jumps.
m_lastConstDelta = constSize;
}
+ template<typename IntegralType>
+ void putIntegralWithConstantInt(IntegralType insn, uint32_t constant, bool isReusable)
+ {
+ if (!m_numConsts)
+ m_maxDistance = maxPoolSize;
+ flushIfNoSpaceFor(sizeof(IntegralType), 4);
+
+ m_loadOffsets.append(codeSize());
+ if (isReusable) {
+ for (int i = 0; i < m_numConsts; ++i) {
+ if (m_mask[i] == ReusableConst && m_pool[i] == constant) {
+ putIntegral(static_cast<IntegralType>(AssemblerType::patchConstantPoolLoad(insn, i)));
+ correctDeltas(sizeof(IntegralType));
+ return;
+ }
+ }
+ }
+
+ m_pool[m_numConsts] = constant;
+ m_mask[m_numConsts] = static_cast<char>(isReusable ? ReusableConst : UniqueConst);
+
+ putIntegral(static_cast<IntegralType>(AssemblerType::patchConstantPoolLoad(insn, m_numConsts)));
+ ++m_numConsts;
+
+ correctDeltas(sizeof(IntegralType), 4);
+ }
+
void flushConstantPool(bool useBarrier = true)
{
if (m_numConsts == 0)
return;
- int alignPool = (AssemblerBuffer::size() + (useBarrier ? barrierSize : 0)) & (sizeof(uint64_t) - 1);
+ int alignPool = (codeSize() + (useBarrier ? barrierSize : 0)) & (sizeof(uint64_t) - 1);
if (alignPool)
alignPool = sizeof(uint64_t) - alignPool;
// Callback to protect the constant pool from execution
if (useBarrier)
- AssemblerBuffer::putInt(AssemblerType::placeConstantPoolBarrier(m_numConsts * sizeof(uint32_t) + alignPool));
+ putIntegral(AssemblerType::placeConstantPoolBarrier(m_numConsts * sizeof(uint32_t) + alignPool));
if (alignPool) {
if (alignPool & 1)
AssemblerBuffer::putInt(AssemblerType::padForAlign32);
}
- int constPoolOffset = AssemblerBuffer::size();
+ int constPoolOffset = codeSize();
append(reinterpret_cast<char*>(m_pool), m_numConsts * sizeof(uint32_t));
// Patch each PC relative load
for (LoadOffsets::Iterator iter = m_loadOffsets.begin(); iter != m_loadOffsets.end(); ++iter) {
- void* loadAddr = reinterpret_cast<void*>(m_buffer + *iter);
- AssemblerType::patchConstantPoolLoad(loadAddr, reinterpret_cast<void*>(m_buffer + constPoolOffset));
+ void* loadAddr = reinterpret_cast<char*>(data()) + *iter;
+ AssemblerType::patchConstantPoolLoad(loadAddr, reinterpret_cast<char*>(data()) + constPoolOffset);
}
m_loadOffsets.clear();
m_numConsts = 0;
- m_maxDistance = maxPoolSize;
}
void flushIfNoSpaceFor(int nextInsnSize)
#ifndef CodeLocation_h
#define CodeLocation_h
-
-#include <MacroAssemblerCodeRef.h>
+#include "MacroAssemblerCodeRef.h"
#if ENABLE(ASSEMBLER)
class CodeLocationJump;
class CodeLocationCall;
class CodeLocationNearCall;
+class CodeLocationDataLabelCompact;
class CodeLocationDataLabel32;
class CodeLocationDataLabelPtr;
CodeLocationNearCall nearCallAtOffset(int offset);
CodeLocationDataLabelPtr dataLabelPtrAtOffset(int offset);
CodeLocationDataLabel32 dataLabel32AtOffset(int offset);
+ CodeLocationDataLabelCompact dataLabelCompactAtOffset(int offset);
protected:
CodeLocationCommon()
: CodeLocationCommon(MacroAssemblerCodePtr(location)) {}
};
+class CodeLocationDataLabelCompact : public CodeLocationCommon {
+public:
+ CodeLocationDataLabelCompact() { }
+ explicit CodeLocationDataLabelCompact(MacroAssemblerCodePtr location)
+ : CodeLocationCommon(location) { }
+ explicit CodeLocationDataLabelCompact(void* location)
+ : CodeLocationCommon(MacroAssemblerCodePtr(location)) { }
+};
+
class CodeLocationDataLabelPtr : public CodeLocationCommon {
public:
CodeLocationDataLabelPtr() {}
return CodeLocationDataLabel32(reinterpret_cast<char*>(dataLocation()) + offset);
}
+inline CodeLocationDataLabelCompact CodeLocationCommon::dataLabelCompactAtOffset(int offset)
+{
+ ASSERT_VALID_CODE_OFFSET(offset);
+ return CodeLocationDataLabelCompact(reinterpret_cast<char*>(dataLocation()) + offset);
+}
+
} // namespace JSC
#endif // ENABLE(ASSEMBLER)
#if ENABLE(ASSEMBLER)
+#define DUMP_LINK_STATISTICS 0
+#define DUMP_CODE 0
+
#include <MacroAssembler.h>
#include <wtf/Noncopyable.h>
namespace JSC {
+class JSGlobalData;
+
// LinkBuffer:
//
// This class assists in linking code generated by the macro assembler, once code generation
// * The address of a Label pointing into the code may be resolved.
// * The value referenced by a DataLabel may be set.
//
-class LinkBuffer : public Noncopyable {
+class LinkBuffer {
+ WTF_MAKE_NONCOPYABLE(LinkBuffer);
typedef MacroAssemblerCodeRef CodeRef;
typedef MacroAssemblerCodePtr CodePtr;
typedef MacroAssembler::Label Label;
typedef MacroAssembler::Jump Jump;
typedef MacroAssembler::JumpList JumpList;
typedef MacroAssembler::Call Call;
+ typedef MacroAssembler::DataLabelCompact DataLabelCompact;
typedef MacroAssembler::DataLabel32 DataLabel32;
typedef MacroAssembler::DataLabelPtr DataLabelPtr;
- typedef MacroAssembler::JmpDst JmpDst;
#if ENABLE(BRANCH_COMPACTION)
typedef MacroAssembler::LinkRecord LinkRecord;
typedef MacroAssembler::JumpLinkType JumpLinkType;
#endif
public:
- // Note: Initialization sequence is significant, since executablePool is a PassRefPtr.
- // First, executablePool is copied into m_executablePool, then the initialization of
- // m_code uses m_executablePool, *not* executablePool, since this is no longer valid.
- // The linkOffset parameter should only be non-null when recompiling for exception info
- LinkBuffer(MacroAssembler* masm, PassRefPtr<ExecutablePool> executablePool, void* linkOffset)
+ LinkBuffer(JSGlobalData& globalData, MacroAssembler* masm, PassRefPtr<ExecutablePool> executablePool)
: m_executablePool(executablePool)
, m_size(0)
, m_code(0)
, m_assembler(masm)
+ , m_globalData(&globalData)
+#ifndef NDEBUG
+ , m_completed(false)
+#endif
+ {
+ linkCode();
+ }
+
+ LinkBuffer(JSGlobalData& globalData, MacroAssembler* masm, ExecutableAllocator& allocator)
+ : m_executablePool(allocator.poolForSize(globalData, masm->m_assembler.codeSize()))
+ , m_size(0)
+ , m_code(0)
+ , m_assembler(masm)
+ , m_globalData(&globalData)
#ifndef NDEBUG
, m_completed(false)
#endif
{
- linkCode(linkOffset);
+ linkCode();
}
~LinkBuffer()
void patch(DataLabelPtr label, void* value)
{
- JmpDst target = applyOffset(label.m_label);
+ AssemblerLabel target = applyOffset(label.m_label);
MacroAssembler::linkPointer(code(), target, value);
}
void patch(DataLabelPtr label, CodeLocationLabel value)
{
- JmpDst target = applyOffset(label.m_label);
+ AssemblerLabel target = applyOffset(label.m_label);
MacroAssembler::linkPointer(code(), target, value.executableAddress());
}
{
return CodeLocationDataLabel32(MacroAssembler::getLinkerAddress(code(), applyOffset(label.m_label)));
}
+
+ CodeLocationDataLabelCompact locationOf(DataLabelCompact label)
+ {
+ return CodeLocationDataLabelCompact(MacroAssembler::getLinkerAddress(code(), applyOffset(label.m_label)));
+ }
// This method obtains the return address of the call, given as an offset from
// the start of the code.
return CodePtr(MacroAssembler::AssemblerType_T::getRelocatedAddress(code(), applyOffset(label.m_label)));
}
+#ifndef NDEBUG
+ void* debugAddress()
+ {
+ return m_code;
+ }
+#endif
+
private:
template <typename T> T applyOffset(T src)
{
return m_code;
}
- void linkCode(void* linkOffset)
+ void linkCode()
{
- UNUSED_PARAM(linkOffset);
ASSERT(!m_code);
#if !ENABLE(BRANCH_COMPACTION)
- m_code = m_assembler->m_assembler.executableCopy(m_executablePool.get());
- m_size = m_assembler->size();
+ m_code = m_assembler->m_assembler.executableCopy(*m_globalData, m_executablePool.get());
+ m_size = m_assembler->m_assembler.codeSize();
+ ASSERT(m_code);
#else
- size_t initialSize = m_assembler->size();
- m_code = (uint8_t*)m_executablePool->alloc(initialSize);
+ size_t initialSize = m_assembler->m_assembler.codeSize();
+ m_code = (uint8_t*)m_executablePool->alloc(*m_globalData, initialSize);
if (!m_code)
return;
- ExecutableAllocator::makeWritable(m_code, m_assembler->size());
+ ExecutableAllocator::makeWritable(m_code, initialSize);
uint8_t* inData = (uint8_t*)m_assembler->unlinkedCode();
uint8_t* outData = reinterpret_cast<uint8_t*>(m_code);
- const uint8_t* linkBase = linkOffset ? reinterpret_cast<uint8_t*>(linkOffset) : outData;
int readPtr = 0;
int writePtr = 0;
Vector<LinkRecord>& jumpsToLink = m_assembler->jumpsToLink();
// Copy the instructions from the last jump to the current one.
size_t regionSize = jumpsToLink[i].from() - readPtr;
- memcpy(outData + writePtr, inData + readPtr, regionSize);
+ uint16_t* copySource = reinterpret_cast<uint16_t*>(inData + readPtr);
+ uint16_t* copyEnd = reinterpret_cast<uint16_t*>(inData + readPtr + regionSize);
+ uint16_t* copyDst = reinterpret_cast<uint16_t*>(outData + writePtr);
+ ASSERT(!(regionSize % 2));
+ ASSERT(!(readPtr % 2));
+ ASSERT(!(writePtr % 2));
+ while (copySource != copyEnd)
+ *copyDst++ = *copySource++;
m_assembler->recordLinkOffsets(readPtr, jumpsToLink[i].from(), offset);
readPtr += regionSize;
writePtr += regionSize;
// branches we need to be precise, forward branches we are pessimistic
const uint8_t* target;
if (jumpsToLink[i].to() >= jumpsToLink[i].from())
- target = linkBase + jumpsToLink[i].to() - offset; // Compensate for what we have collapsed so far
+ target = outData + jumpsToLink[i].to() - offset; // Compensate for what we have collapsed so far
else
- target = linkBase + jumpsToLink[i].to() - m_assembler->executableOffsetFor(jumpsToLink[i].to());
+ target = outData + jumpsToLink[i].to() - m_assembler->executableOffsetFor(jumpsToLink[i].to());
- JumpLinkType jumpLinkType = m_assembler->computeJumpType(jumpsToLink[i], linkBase + writePtr, target);
+ JumpLinkType jumpLinkType = m_assembler->computeJumpType(jumpsToLink[i], outData + writePtr, target);
// Compact branch if we can...
if (m_assembler->canCompact(jumpsToLink[i].type())) {
// Step back in the write stream
jumpsToLink[i].setFrom(writePtr);
}
// Copy everything after the last jump
- memcpy(outData + writePtr, inData + readPtr, m_assembler->size() - readPtr);
- m_assembler->recordLinkOffsets(readPtr, m_assembler->size(), readPtr - writePtr);
+ memcpy(outData + writePtr, inData + readPtr, initialSize - readPtr);
+ m_assembler->recordLinkOffsets(readPtr, initialSize, readPtr - writePtr);
- // Actually link everything (don't link if we've be given a linkoffset as it's a
- // waste of time: linkOffset is used for recompiling to get exception info)
- if (!linkOffset) {
- for (unsigned i = 0; i < jumpCount; ++i) {
- uint8_t* location = outData + jumpsToLink[i].from();
- uint8_t* target = outData + jumpsToLink[i].to() - m_assembler->executableOffsetFor(jumpsToLink[i].to());
- m_assembler->link(jumpsToLink[i], location, target);
- }
+ for (unsigned i = 0; i < jumpCount; ++i) {
+ uint8_t* location = outData + jumpsToLink[i].from();
+ uint8_t* target = outData + jumpsToLink[i].to() - m_assembler->executableOffsetFor(jumpsToLink[i].to());
+ m_assembler->link(jumpsToLink[i], location, target);
}
jumpsToLink.clear();
- m_size = writePtr + m_assembler->size() - readPtr;
+ m_size = writePtr + initialSize - readPtr;
m_executablePool->tryShrink(m_code, initialSize, m_size);
+
+#if DUMP_LINK_STATISTICS
+ dumpLinkStatistics(m_code, initialSize, m_size);
+#endif
+#if DUMP_CODE
+ dumpCode(m_code, m_size);
+#endif
#endif
}
ExecutableAllocator::cacheFlush(code(), m_size);
}
+#if DUMP_LINK_STATISTICS
+ static void dumpLinkStatistics(void* code, size_t initialSize, size_t finalSize)
+ {
+ static unsigned linkCount = 0;
+ static unsigned totalInitialSize = 0;
+ static unsigned totalFinalSize = 0;
+ linkCount++;
+ totalInitialSize += initialSize;
+ totalFinalSize += finalSize;
+ printf("link %p: orig %u, compact %u (delta %u, %.2f%%)\n",
+ code, static_cast<unsigned>(initialSize), static_cast<unsigned>(finalSize),
+ static_cast<unsigned>(initialSize - finalSize),
+ 100.0 * (initialSize - finalSize) / initialSize);
+ printf("\ttotal %u: orig %u, compact %u (delta %u, %.2f%%)\n",
+ linkCount, totalInitialSize, totalFinalSize, totalInitialSize - totalFinalSize,
+ 100.0 * (totalInitialSize - totalFinalSize) / totalInitialSize);
+ }
+#endif
+
+#if DUMP_CODE
+ static void dumpCode(void* code, size_t size)
+ {
+#if CPU(ARM_THUMB2)
+ // Dump the generated code in an asm file format that can be assembled and then disassembled
+ // for debugging purposes. For example, save this output as jit.s:
+ // gcc -arch armv7 -c jit.s
+ // otool -tv jit.o
+ static unsigned codeCount = 0;
+ unsigned short* tcode = static_cast<unsigned short*>(code);
+ size_t tsize = size / sizeof(short);
+ char nameBuf[128];
+ snprintf(nameBuf, sizeof(nameBuf), "_jsc_jit%u", codeCount++);
+ printf("\t.syntax unified\n"
+ "\t.section\t__TEXT,__text,regular,pure_instructions\n"
+ "\t.globl\t%s\n"
+ "\t.align 2\n"
+ "\t.code 16\n"
+ "\t.thumb_func\t%s\n"
+ "# %p\n"
+ "%s:\n", nameBuf, nameBuf, code, nameBuf);
+
+ for (unsigned i = 0; i < tsize; i++)
+ printf("\t.short\t0x%x\n", tcode[i]);
+#endif
+ }
+#endif
+
RefPtr<ExecutablePool> m_executablePool;
size_t m_size;
void* m_code;
MacroAssembler* m_assembler;
+ JSGlobalData* m_globalData;
#ifndef NDEBUG
bool m_completed;
#endif
public:
typedef MIPSRegisters::RegisterID RegisterID;
typedef MIPSRegisters::FPRegisterID FPRegisterID;
- typedef SegmentedVector<int, 64> Jumps;
+ typedef SegmentedVector<AssemblerLabel, 64> Jumps;
MIPSAssembler()
{
OP_SH_FT = 16
};
- class JmpSrc {
- friend class MIPSAssembler;
- public:
- JmpSrc()
- : m_offset(-1)
- {
- }
-
- private:
- JmpSrc(int offset)
- : m_offset(offset)
- {
- }
-
- int m_offset;
- };
-
- class JmpDst {
- friend class MIPSAssembler;
- public:
- JmpDst()
- : m_offset(-1)
- , m_used(false)
- {
- }
-
- bool isUsed() const { return m_used; }
- void used() { m_used = true; }
- private:
- JmpDst(int offset)
- : m_offset(offset)
- , m_used(false)
- {
- ASSERT(m_offset == offset);
- }
-
- int m_offset : 31;
- int m_used : 1;
- };
-
void emitInst(MIPSWord op)
{
void* oldBase = m_buffer.data();
emitInst(0x00000018 | (rs << OP_SH_RS) | (rt << OP_SH_RT));
}
+ void div(RegisterID rs, RegisterID rt)
+ {
+ emitInst(0x0000001a | (rs << OP_SH_RS) | (rt << OP_SH_RT));
+ }
+
void mfhi(RegisterID rd)
{
emitInst(0x00000010 | (rd << OP_SH_RD));
| (rs << OP_SH_RS));
}
+ void srl(RegisterID rd, RegisterID rt, int shamt)
+ {
+ emitInst(0x00000002 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
+ | ((shamt & 0x1f) << OP_SH_SHAMT));
+ }
+
+ void srlv(RegisterID rd, RegisterID rt, RegisterID rs)
+ {
+ emitInst(0x00000006 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
+ | (rs << OP_SH_RS));
+ }
+
void lbu(RegisterID rt, RegisterID rs, int offset)
{
emitInst(0x90000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
emitInst(0x45000000);
}
- JmpSrc newJmpSrc()
- {
- return JmpSrc(m_buffer.size());
- }
-
void appendJump()
{
- m_jumps.append(m_buffer.size());
+ m_jumps.append(m_buffer.label());
}
void addd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
| (ft << OP_SH_FT));
}
+ void divd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
+ {
+ emitInst(0x46200003 | (fd << OP_SH_FD) | (fs << OP_SH_FS)
+ | (ft << OP_SH_FT));
+ }
+
void lwc1(FPRegisterID ft, RegisterID rs, int offset)
{
emitInst(0xc4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS)
copDelayNop();
}
+ void mthc1(RegisterID rt, FPRegisterID fs)
+ {
+ emitInst(0x44e00000 | (fs << OP_SH_FS) | (rt << OP_SH_RT));
+ copDelayNop();
+ }
+
void mfc1(RegisterID rt, FPRegisterID fs)
{
emitInst(0x44000000 | (fs << OP_SH_FS) | (rt << OP_SH_RT));
copDelayNop();
}
+ void sqrtd(FPRegisterID fd, FPRegisterID fs)
+ {
+ emitInst(0x46200004 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
+ }
+
void truncwd(FPRegisterID fd, FPRegisterID fs)
{
emitInst(0x4620000d | (fd << OP_SH_FD) | (fs << OP_SH_FS));
emitInst(0x46800021 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
}
+ void cvtwd(FPRegisterID fd, FPRegisterID fs)
+ {
+ emitInst(0x46200024 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
+ }
+
void ceqd(FPRegisterID fs, FPRegisterID ft)
{
emitInst(0x46200032 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
// General helpers
- JmpDst label()
+ AssemblerLabel label()
{
- return JmpDst(m_buffer.size());
+ return m_buffer.label();
}
- JmpDst align(int alignment)
+ AssemblerLabel align(int alignment)
{
while (!m_buffer.isAligned(alignment))
bkpt();
return label();
}
- static void* getRelocatedAddress(void* code, JmpSrc jump)
+ static void* getRelocatedAddress(void* code, AssemblerLabel label)
{
- ASSERT(jump.m_offset != -1);
- void* b = reinterpret_cast<void*>((reinterpret_cast<intptr_t>(code)) + jump.m_offset);
- return b;
+ return reinterpret_cast<void*>(reinterpret_cast<char*>(code) + label.m_offset);
}
- static void* getRelocatedAddress(void* code, JmpDst label)
+ static int getDifferenceBetweenLabels(AssemblerLabel a, AssemblerLabel b)
{
- void* b = reinterpret_cast<void*>((reinterpret_cast<intptr_t>(code)) + label.m_offset);
- return b;
- }
-
- static int getDifferenceBetweenLabels(JmpDst from, JmpDst to)
- {
- return to.m_offset - from.m_offset;
- }
-
- static int getDifferenceBetweenLabels(JmpDst from, JmpSrc to)
- {
- return to.m_offset - from.m_offset;
- }
-
- static int getDifferenceBetweenLabels(JmpSrc from, JmpDst to)
- {
- return to.m_offset - from.m_offset;
+ return b.m_offset - a.m_offset;
}
// Assembler admin methods:
- size_t size() const
+ size_t codeSize() const
{
- return m_buffer.size();
+ return m_buffer.codeSize();
}
- void* executableCopy(ExecutablePool* allocator)
+ void* executableCopy(JSGlobalData& globalData, ExecutablePool* allocator)
{
- void *result = m_buffer.executableCopy(allocator);
+ void *result = m_buffer.executableCopy(globalData, allocator);
if (!result)
return 0;
return result;
}
- static unsigned getCallReturnOffset(JmpSrc call)
+#ifndef NDEBUG
+ unsigned debugOffset() { return m_buffer.debugOffset(); }
+#endif
+
+ static unsigned getCallReturnOffset(AssemblerLabel call)
{
// The return address is after a call and a delay slot instruction
return call.m_offset;
// writable region of memory; to modify the code in an execute-only execuable
// pool the 'repatch' and 'relink' methods should be used.
- void linkJump(JmpSrc from, JmpDst to)
+ void linkJump(AssemblerLabel from, AssemblerLabel to)
{
- ASSERT(to.m_offset != -1);
- ASSERT(from.m_offset != -1);
+ ASSERT(to.isSet());
+ ASSERT(from.isSet());
MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(m_buffer.data()) + from.m_offset);
MIPSWord* toPos = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(m_buffer.data()) + to.m_offset);
linkWithOffset(insn, toPos);
}
- static void linkJump(void* code, JmpSrc from, void* to)
+ static void linkJump(void* code, AssemblerLabel from, void* to)
{
- ASSERT(from.m_offset != -1);
+ ASSERT(from.isSet());
MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
ASSERT(!(*(insn - 1)) && !(*(insn - 2)) && !(*(insn - 3)) && !(*(insn - 5)));
linkWithOffset(insn, to);
}
- static void linkCall(void* code, JmpSrc from, void* to)
+ static void linkCall(void* code, AssemblerLabel from, void* to)
{
MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
linkCallInternal(insn, to);
}
- static void linkPointer(void* code, JmpDst from, void* to)
+ static void linkPointer(void* code, AssemblerLabel from, void* to)
{
MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
ExecutableAllocator::cacheFlush(insn, 2 * sizeof(MIPSWord));
}
+ static int32_t readInt32(void* from)
+ {
+ MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
+ ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
+ int32_t result = (*insn & 0x0000ffff) << 16;
+ insn++;
+ ASSERT((*insn & 0xfc000000) == 0x34000000); // ori
+ result |= *insn & 0x0000ffff
+ }
+
+ static void repatchCompact(void* where, int32_t value)
+ {
+ repatchInt32(where, value);
+ }
+
static void repatchPointer(void* from, void* to)
{
repatchInt32(from, reinterpret_cast<int32_t>(to));
}
- static void repatchLoadPtrToLEA(void* from)
+ static void* readPointer(void* from)
{
- MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
- insn = insn + 3;
- ASSERT((*insn & 0xfc000000) == 0x8c000000); // lw
- /* lw -> addiu */
- *insn = 0x24000000 | (*insn & 0x03ffffff);
-
- ExecutableAllocator::cacheFlush(insn, sizeof(MIPSWord));
+ return static_cast<void*>(readInt32(from));
}
private:
-
/* Update each jump in the buffer of newBase. */
void relocateJumps(void* oldBase, void* newBase)
{
// Check each jump
for (Jumps::Iterator iter = m_jumps.begin(); iter != m_jumps.end(); ++iter) {
- int pos = *iter;
+ int pos = iter->m_offset;
MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(newBase) + pos);
insn = insn + 2;
// Need to make sure we have 5 valid instructions after pos
- if ((unsigned int)pos >= m_buffer.size() - 5 * sizeof(MIPSWord))
+ if ((unsigned int)pos >= m_buffer.codeSize() - 5 * sizeof(MIPSWord))
continue;
if ((*insn & 0xfc000000) == 0x08000000) { // j
#include "MacroAssemblerX86_64.h"
namespace JSC { typedef MacroAssemblerX86_64 MacroAssemblerBase; };
+#elif CPU(SH4)
+#include "MacroAssemblerSH4.h"
+namespace JSC {
+typedef MacroAssemblerSH4 MacroAssemblerBase;
+};
+
#else
#error "The MacroAssembler is not supported on this platform."
#endif
// described in terms of other macro assembly methods.
void pop()
{
- addPtr(Imm32(sizeof(void*)), stackPointerRegister);
+ addPtr(TrustedImm32(sizeof(void*)), stackPointerRegister);
}
void peek(RegisterID dest, int index = 0)
storePtr(src, Address(stackPointerRegister, (index * sizeof(void*))));
}
- void poke(Imm32 value, int index = 0)
+ void poke(TrustedImm32 value, int index = 0)
{
store32(value, Address(stackPointerRegister, (index * sizeof(void*))));
}
- void poke(ImmPtr imm, int index = 0)
+ void poke(TrustedImmPtr imm, int index = 0)
{
storePtr(imm, Address(stackPointerRegister, (index * sizeof(void*))));
}
// Backwards banches, these are currently all implemented using existing forwards branch mechanisms.
- void branchPtr(Condition cond, RegisterID op1, ImmPtr imm, Label target)
+ void branchPtr(RelationalCondition cond, RegisterID op1, TrustedImmPtr imm, Label target)
{
branchPtr(cond, op1, imm).linkTo(target, this);
}
- void branch32(Condition cond, RegisterID op1, RegisterID op2, Label target)
+ void branch32(RelationalCondition cond, RegisterID op1, RegisterID op2, Label target)
{
branch32(cond, op1, op2).linkTo(target, this);
}
- void branch32(Condition cond, RegisterID op1, Imm32 imm, Label target)
+ void branch32(RelationalCondition cond, RegisterID op1, TrustedImm32 imm, Label target)
{
branch32(cond, op1, imm).linkTo(target, this);
}
- void branch32(Condition cond, RegisterID left, Address right, Label target)
+ void branch32(RelationalCondition cond, RegisterID left, Address right, Label target)
{
branch32(cond, left, right).linkTo(target, this);
}
- void branch16(Condition cond, BaseIndex left, RegisterID right, Label target)
+ void branch16(RelationalCondition cond, BaseIndex left, RegisterID right, Label target)
{
branch16(cond, left, right).linkTo(target, this);
}
- void branchTestPtr(Condition cond, RegisterID reg, Label target)
+ void branchTestPtr(ResultCondition cond, RegisterID reg, Label target)
{
branchTestPtr(cond, reg).linkTo(target, this);
}
add32(src, dest);
}
- void addPtr(Imm32 imm, RegisterID srcDest)
+ void addPtr(TrustedImm32 imm, RegisterID srcDest)
{
add32(imm, srcDest);
}
- void addPtr(ImmPtr imm, RegisterID dest)
+ void addPtr(TrustedImmPtr imm, RegisterID dest)
{
- add32(Imm32(imm), dest);
+ add32(TrustedImm32(imm), dest);
}
- void addPtr(Imm32 imm, RegisterID src, RegisterID dest)
+ void addPtr(TrustedImm32 imm, RegisterID src, RegisterID dest)
{
add32(imm, src, dest);
}
and32(src, dest);
}
- void andPtr(Imm32 imm, RegisterID srcDest)
+ void andPtr(TrustedImm32 imm, RegisterID srcDest)
{
and32(imm, srcDest);
}
or32(src, dest);
}
- void orPtr(ImmPtr imm, RegisterID dest)
+ void orPtr(TrustedImmPtr imm, RegisterID dest)
{
- or32(Imm32(imm), dest);
+ or32(TrustedImm32(imm), dest);
}
- void orPtr(Imm32 imm, RegisterID dest)
+ void orPtr(TrustedImm32 imm, RegisterID dest)
{
or32(imm, dest);
}
sub32(src, dest);
}
- void subPtr(Imm32 imm, RegisterID dest)
+ void subPtr(TrustedImm32 imm, RegisterID dest)
{
sub32(imm, dest);
}
- void subPtr(ImmPtr imm, RegisterID dest)
+ void subPtr(TrustedImmPtr imm, RegisterID dest)
{
- sub32(Imm32(imm), dest);
+ sub32(TrustedImm32(imm), dest);
}
void xorPtr(RegisterID src, RegisterID dest)
xor32(src, dest);
}
- void xorPtr(Imm32 imm, RegisterID srcDest)
+ void xorPtr(TrustedImm32 imm, RegisterID srcDest)
{
xor32(imm, srcDest);
}
{
return load32WithAddressOffsetPatch(address, dest);
}
+
+ DataLabelCompact loadPtrWithCompactAddressOffsetPatch(Address address, RegisterID dest)
+ {
+ return load32WithCompactAddressOffsetPatch(address, dest);
+ }
- void setPtr(Condition cond, RegisterID left, Imm32 right, RegisterID dest)
+ void comparePtr(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
{
- set32(cond, left, right, dest);
+ compare32(cond, left, right, dest);
}
void storePtr(RegisterID src, ImplicitAddress address)
store32(src, address);
}
- void storePtr(ImmPtr imm, ImplicitAddress address)
+ void storePtr(TrustedImmPtr imm, ImplicitAddress address)
{
- store32(Imm32(imm), address);
+ store32(TrustedImm32(imm), address);
}
- void storePtr(ImmPtr imm, void* address)
+ void storePtr(TrustedImmPtr imm, void* address)
{
- store32(Imm32(imm), address);
+ store32(TrustedImm32(imm), address);
}
DataLabel32 storePtrWithAddressOffsetPatch(RegisterID src, Address address)
}
- Jump branchPtr(Condition cond, RegisterID left, RegisterID right)
+ Jump branchPtr(RelationalCondition cond, RegisterID left, RegisterID right)
{
return branch32(cond, left, right);
}
- Jump branchPtr(Condition cond, RegisterID left, ImmPtr right)
+ Jump branchPtr(RelationalCondition cond, RegisterID left, TrustedImmPtr right)
{
- return branch32(cond, left, Imm32(right));
+ return branch32(cond, left, TrustedImm32(right));
}
- Jump branchPtr(Condition cond, RegisterID left, Address right)
+ Jump branchPtr(RelationalCondition cond, RegisterID left, Address right)
{
return branch32(cond, left, right);
}
- Jump branchPtr(Condition cond, Address left, RegisterID right)
+ Jump branchPtr(RelationalCondition cond, Address left, RegisterID right)
{
return branch32(cond, left, right);
}
- Jump branchPtr(Condition cond, AbsoluteAddress left, RegisterID right)
+ Jump branchPtr(RelationalCondition cond, AbsoluteAddress left, RegisterID right)
{
return branch32(cond, left, right);
}
- Jump branchPtr(Condition cond, Address left, ImmPtr right)
+ Jump branchPtr(RelationalCondition cond, Address left, TrustedImmPtr right)
{
- return branch32(cond, left, Imm32(right));
+ return branch32(cond, left, TrustedImm32(right));
}
- Jump branchPtr(Condition cond, AbsoluteAddress left, ImmPtr right)
+ Jump branchPtr(RelationalCondition cond, AbsoluteAddress left, TrustedImmPtr right)
{
- return branch32(cond, left, Imm32(right));
+ return branch32(cond, left, TrustedImm32(right));
}
- Jump branchTestPtr(Condition cond, RegisterID reg, RegisterID mask)
+ Jump branchTestPtr(ResultCondition cond, RegisterID reg, RegisterID mask)
{
return branchTest32(cond, reg, mask);
}
- Jump branchTestPtr(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1))
+ Jump branchTestPtr(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
{
return branchTest32(cond, reg, mask);
}
- Jump branchTestPtr(Condition cond, Address address, Imm32 mask = Imm32(-1))
+ Jump branchTestPtr(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
{
return branchTest32(cond, address, mask);
}
- Jump branchTestPtr(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1))
+ Jump branchTestPtr(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
{
return branchTest32(cond, address, mask);
}
- Jump branchAddPtr(Condition cond, RegisterID src, RegisterID dest)
+ Jump branchAddPtr(ResultCondition cond, RegisterID src, RegisterID dest)
{
return branchAdd32(cond, src, dest);
}
- Jump branchSubPtr(Condition cond, Imm32 imm, RegisterID dest)
+ Jump branchSubPtr(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
{
return branchSub32(cond, imm, dest);
}
using MacroAssemblerBase::branchTest8;
- Jump branchTest8(Condition cond, ExtendedAddress address, Imm32 mask = Imm32(-1))
+ Jump branchTest8(ResultCondition cond, ExtendedAddress address, TrustedImm32 mask = TrustedImm32(-1))
{
return MacroAssemblerBase::branchTest8(cond, Address(address.base, address.offset), mask);
}
}
#endif
+#if (COMPILER(RVCT) && defined(__TARGET_FPU_VFP)) || (COMPILER(GCC) && defined(__VFP_FP__))
+ return true;
+#else
return false;
+#endif
}
const bool MacroAssemblerARM::s_isVFPPresent = isVFPPresent();
COMPILE_ASSERT(!(DoubleConditionBitSpecial & DoubleConditionMask), DoubleConditionBitSpecial_should_not_interfere_with_ARMAssembler_Condition_codes);
public:
typedef ARMRegisters::FPRegisterID FPRegisterID;
+ static const int MaximumCompactPtrAlignedAddressOffset = 0x7FFFFFFF;
- enum Condition {
+ enum RelationalCondition {
Equal = ARMAssembler::EQ,
NotEqual = ARMAssembler::NE,
Above = ARMAssembler::HI,
GreaterThan = ARMAssembler::GT,
GreaterThanOrEqual = ARMAssembler::GE,
LessThan = ARMAssembler::LT,
- LessThanOrEqual = ARMAssembler::LE,
+ LessThanOrEqual = ARMAssembler::LE
+ };
+
+ enum ResultCondition {
Overflow = ARMAssembler::VS,
Signed = ARMAssembler::MI,
Zero = ARMAssembler::EQ,
m_assembler.adds_r(dest, dest, src);
}
- void add32(Imm32 imm, Address address)
+ void add32(TrustedImm32 imm, Address address)
{
load32(address, ARMRegisters::S1);
add32(imm, ARMRegisters::S1);
store32(ARMRegisters::S1, address);
}
- void add32(Imm32 imm, RegisterID dest)
+ void add32(TrustedImm32 imm, RegisterID dest)
{
m_assembler.adds_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
}
m_assembler.ands_r(dest, dest, src);
}
- void and32(Imm32 imm, RegisterID dest)
+ void and32(TrustedImm32 imm, RegisterID dest)
{
ARMWord w = m_assembler.getImm(imm.m_value, ARMRegisters::S0, true);
if (w & ARMAssembler::OP2_INV_IMM)
m_assembler.movs_r(dest, m_assembler.lsl_r(dest, ARMRegisters::S0));
}
- void lshift32(Imm32 imm, RegisterID dest)
+ void lshift32(TrustedImm32 imm, RegisterID dest)
{
m_assembler.movs_r(dest, m_assembler.lsl(dest, imm.m_value & 0x1f));
}
m_assembler.muls_r(dest, dest, src);
}
- void mul32(Imm32 imm, RegisterID src, RegisterID dest)
+ void mul32(TrustedImm32 imm, RegisterID src, RegisterID dest)
{
move(imm, ARMRegisters::S0);
m_assembler.muls_r(dest, src, ARMRegisters::S0);
m_assembler.orrs_r(dest, dest, src);
}
- void or32(Imm32 imm, RegisterID dest)
+ void or32(TrustedImm32 imm, RegisterID dest)
{
m_assembler.orrs_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
}
m_assembler.movs_r(dest, m_assembler.asr_r(dest, ARMRegisters::S0));
}
- void rshift32(Imm32 imm, RegisterID dest)
+ void rshift32(TrustedImm32 imm, RegisterID dest)
{
m_assembler.movs_r(dest, m_assembler.asr(dest, imm.m_value & 0x1f));
}
m_assembler.movs_r(dest, m_assembler.lsr_r(dest, ARMRegisters::S0));
}
- void urshift32(Imm32 imm, RegisterID dest)
+ void urshift32(TrustedImm32 imm, RegisterID dest)
{
m_assembler.movs_r(dest, m_assembler.lsr(dest, imm.m_value & 0x1f));
}
m_assembler.subs_r(dest, dest, src);
}
- void sub32(Imm32 imm, RegisterID dest)
+ void sub32(TrustedImm32 imm, RegisterID dest)
{
m_assembler.subs_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
}
- void sub32(Imm32 imm, Address address)
+ void sub32(TrustedImm32 imm, Address address)
{
load32(address, ARMRegisters::S1);
sub32(imm, ARMRegisters::S1);
m_assembler.eors_r(dest, dest, src);
}
- void xor32(Imm32 imm, RegisterID dest)
+ void xor32(TrustedImm32 imm, RegisterID dest)
{
m_assembler.eors_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
}
+ void countLeadingZeros32(RegisterID src, RegisterID dest)
+ {
+#if WTF_ARM_ARCH_AT_LEAST(5)
+ m_assembler.clz_r(dest, src);
+#else
+ UNUSED_PARAM(src);
+ UNUSED_PARAM(dest);
+ ASSERT_NOT_REACHED();
+#endif
+ }
+
void load8(ImplicitAddress address, RegisterID dest)
{
m_assembler.dataTransfer32(true, dest, address.base, address.offset, true);
m_assembler.dtr_ur(true, dest, address.base, ARMRegisters::S0);
return dataLabel;
}
-
- Label loadPtrWithPatchToLEA(Address address, RegisterID dest)
+
+ DataLabelCompact load32WithCompactAddressOffsetPatch(Address address, RegisterID dest)
{
- Label label(this);
- load32(address, dest);
- return label;
+ DataLabelCompact dataLabel(this);
+ load32WithAddressOffsetPatch(address, dest);
+ return dataLabel;
}
void load16(BaseIndex address, RegisterID dest)
{
- m_assembler.add_r(ARMRegisters::S0, address.base, m_assembler.lsl(address.index, address.scale));
- if (address.offset>=0)
- m_assembler.ldrh_u(dest, ARMRegisters::S0, ARMAssembler::getOp2Byte(address.offset));
- else
- m_assembler.ldrh_d(dest, ARMRegisters::S0, ARMAssembler::getOp2Byte(-address.offset));
+ m_assembler.add_r(ARMRegisters::S1, address.base, m_assembler.lsl(address.index, address.scale));
+ load16(Address(ARMRegisters::S1, address.offset), dest);
}
void load16(ImplicitAddress address, RegisterID dest)
{
if (address.offset >= 0)
- m_assembler.ldrh_u(dest, address.base, ARMAssembler::getOp2Byte(address.offset));
+ m_assembler.ldrh_u(dest, address.base, m_assembler.getOffsetForHalfwordDataTransfer(address.offset, ARMRegisters::S0));
else
- m_assembler.ldrh_d(dest, address.base, ARMAssembler::getOp2Byte(-address.offset));
+ m_assembler.ldrh_d(dest, address.base, m_assembler.getOffsetForHalfwordDataTransfer(-address.offset, ARMRegisters::S0));
}
DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
m_assembler.baseIndexTransfer32(false, src, address.base, address.index, static_cast<int>(address.scale), address.offset);
}
- void store32(Imm32 imm, ImplicitAddress address)
+ void store32(TrustedImm32 imm, ImplicitAddress address)
{
if (imm.m_isPointer)
m_assembler.ldr_un_imm(ARMRegisters::S1, imm.m_value);
m_assembler.dtr_u(false, src, ARMRegisters::S0, 0);
}
- void store32(Imm32 imm, void* address)
+ void store32(TrustedImm32 imm, void* address)
{
m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address));
if (imm.m_isPointer)
push(ARMRegisters::S1);
}
- void push(Imm32 imm)
+ void push(TrustedImm32 imm)
{
move(imm, ARMRegisters::S0);
push(ARMRegisters::S0);
}
- void move(Imm32 imm, RegisterID dest)
+ void move(TrustedImm32 imm, RegisterID dest)
{
if (imm.m_isPointer)
m_assembler.ldr_un_imm(dest, imm.m_value);
m_assembler.mov_r(dest, src);
}
- void move(ImmPtr imm, RegisterID dest)
+ void move(TrustedImmPtr imm, RegisterID dest)
{
- move(Imm32(imm), dest);
+ move(TrustedImm32(imm), dest);
}
void swap(RegisterID reg1, RegisterID reg2)
move(src, dest);
}
- Jump branch8(Condition cond, Address left, Imm32 right)
+ Jump branch8(RelationalCondition cond, Address left, TrustedImm32 right)
{
load8(left, ARMRegisters::S1);
return branch32(cond, ARMRegisters::S1, right);
}
- Jump branch32(Condition cond, RegisterID left, RegisterID right, int useConstantPool = 0)
+ Jump branch32(RelationalCondition cond, RegisterID left, RegisterID right, int useConstantPool = 0)
{
m_assembler.cmp_r(left, right);
return Jump(m_assembler.jmp(ARMCondition(cond), useConstantPool));
}
- Jump branch32(Condition cond, RegisterID left, Imm32 right, int useConstantPool = 0)
+ Jump branch32(RelationalCondition cond, RegisterID left, TrustedImm32 right, int useConstantPool = 0)
{
if (right.m_isPointer) {
m_assembler.ldr_un_imm(ARMRegisters::S0, right.m_value);
m_assembler.cmp_r(left, ARMRegisters::S0);
- } else
- m_assembler.cmp_r(left, m_assembler.getImm(right.m_value, ARMRegisters::S0));
+ } else {
+ ARMWord tmp = m_assembler.getOp2(-right.m_value);
+ if (tmp != ARMAssembler::INVALID_IMM)
+ m_assembler.cmn_r(left, tmp);
+ else
+ m_assembler.cmp_r(left, m_assembler.getImm(right.m_value, ARMRegisters::S0));
+ }
return Jump(m_assembler.jmp(ARMCondition(cond), useConstantPool));
}
- Jump branch32(Condition cond, RegisterID left, Address right)
+ Jump branch32(RelationalCondition cond, RegisterID left, Address right)
{
load32(right, ARMRegisters::S1);
return branch32(cond, left, ARMRegisters::S1);
}
- Jump branch32(Condition cond, Address left, RegisterID right)
+ Jump branch32(RelationalCondition cond, Address left, RegisterID right)
{
load32(left, ARMRegisters::S1);
return branch32(cond, ARMRegisters::S1, right);
}
- Jump branch32(Condition cond, Address left, Imm32 right)
+ Jump branch32(RelationalCondition cond, Address left, TrustedImm32 right)
{
load32(left, ARMRegisters::S1);
return branch32(cond, ARMRegisters::S1, right);
}
- Jump branch32(Condition cond, BaseIndex left, Imm32 right)
+ Jump branch32(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
{
load32(left, ARMRegisters::S1);
return branch32(cond, ARMRegisters::S1, right);
}
- Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right)
+ Jump branch32WithUnalignedHalfWords(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
{
load32WithUnalignedHalfWords(left, ARMRegisters::S1);
return branch32(cond, ARMRegisters::S1, right);
}
- Jump branch16(Condition cond, BaseIndex left, RegisterID right)
+ Jump branch16(RelationalCondition cond, BaseIndex left, RegisterID right)
{
UNUSED_PARAM(cond);
UNUSED_PARAM(left);
return jump();
}
- Jump branch16(Condition cond, BaseIndex left, Imm32 right)
+ Jump branch16(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
{
load16(left, ARMRegisters::S0);
move(right, ARMRegisters::S1);
return m_assembler.jmp(ARMCondition(cond));
}
- Jump branchTest8(Condition cond, Address address, Imm32 mask = Imm32(-1))
+ Jump branchTest8(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
{
load8(address, ARMRegisters::S1);
return branchTest32(cond, ARMRegisters::S1, mask);
}
- Jump branchTest32(Condition cond, RegisterID reg, RegisterID mask)
+ Jump branchTest32(ResultCondition cond, RegisterID reg, RegisterID mask)
{
ASSERT((cond == Zero) || (cond == NonZero));
m_assembler.tst_r(reg, mask);
return Jump(m_assembler.jmp(ARMCondition(cond)));
}
- Jump branchTest32(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1))
+ Jump branchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
{
ASSERT((cond == Zero) || (cond == NonZero));
ARMWord w = m_assembler.getImm(mask.m_value, ARMRegisters::S0, true);
return Jump(m_assembler.jmp(ARMCondition(cond)));
}
- Jump branchTest32(Condition cond, Address address, Imm32 mask = Imm32(-1))
+ Jump branchTest32(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
{
load32(address, ARMRegisters::S1);
return branchTest32(cond, ARMRegisters::S1, mask);
}
- Jump branchTest32(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1))
+ Jump branchTest32(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
{
load32(address, ARMRegisters::S1);
return branchTest32(cond, ARMRegisters::S1, mask);
load32(address, ARMRegisters::pc);
}
- Jump branchAdd32(Condition cond, RegisterID src, RegisterID dest)
+ Jump branchAdd32(ResultCondition cond, RegisterID src, RegisterID dest)
{
ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
add32(src, dest);
return Jump(m_assembler.jmp(ARMCondition(cond)));
}
- Jump branchAdd32(Condition cond, Imm32 imm, RegisterID dest)
+ Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
{
ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
add32(imm, dest);
m_assembler.cmp_r(ARMRegisters::S1, m_assembler.asr(dest, 31));
}
- Jump branchMul32(Condition cond, RegisterID src, RegisterID dest)
+ Jump branchMul32(ResultCondition cond, RegisterID src, RegisterID dest)
{
ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
if (cond == Overflow) {
return Jump(m_assembler.jmp(ARMCondition(cond)));
}
- Jump branchMul32(Condition cond, Imm32 imm, RegisterID src, RegisterID dest)
+ Jump branchMul32(ResultCondition cond, TrustedImm32 imm, RegisterID src, RegisterID dest)
{
ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
if (cond == Overflow) {
return Jump(m_assembler.jmp(ARMCondition(cond)));
}
- Jump branchSub32(Condition cond, RegisterID src, RegisterID dest)
+ Jump branchSub32(ResultCondition cond, RegisterID src, RegisterID dest)
{
ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
sub32(src, dest);
return Jump(m_assembler.jmp(ARMCondition(cond)));
}
- Jump branchSub32(Condition cond, Imm32 imm, RegisterID dest)
+ Jump branchSub32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
{
ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
sub32(imm, dest);
return Jump(m_assembler.jmp(ARMCondition(cond)));
}
- Jump branchNeg32(Condition cond, RegisterID srcDest)
+ Jump branchNeg32(ResultCondition cond, RegisterID srcDest)
{
ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
neg32(srcDest);
return Jump(m_assembler.jmp(ARMCondition(cond)));
}
- Jump branchOr32(Condition cond, RegisterID src, RegisterID dest)
+ Jump branchOr32(ResultCondition cond, RegisterID src, RegisterID dest)
{
ASSERT((cond == Signed) || (cond == Zero) || (cond == NonZero));
or32(src, dest);
Call call(RegisterID target)
{
- m_assembler.blx(target);
- JmpSrc jmpSrc;
- return Call(jmpSrc, Call::None);
+ return Call(m_assembler.blx(target), Call::None);
}
void call(Address address)
m_assembler.bx(linkRegister);
}
- void set32(Condition cond, RegisterID left, RegisterID right, RegisterID dest)
+ void compare32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID dest)
{
m_assembler.cmp_r(left, right);
m_assembler.mov_r(dest, ARMAssembler::getOp2(0));
m_assembler.mov_r(dest, ARMAssembler::getOp2(1), ARMCondition(cond));
}
- void set32(Condition cond, RegisterID left, Imm32 right, RegisterID dest)
+ void compare32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
{
m_assembler.cmp_r(left, m_assembler.getImm(right.m_value, ARMRegisters::S0));
m_assembler.mov_r(dest, ARMAssembler::getOp2(0));
m_assembler.mov_r(dest, ARMAssembler::getOp2(1), ARMCondition(cond));
}
- void set8(Condition cond, RegisterID left, RegisterID right, RegisterID dest)
- {
- // ARM doesn't have byte registers
- set32(cond, left, right, dest);
- }
-
- void set8(Condition cond, Address left, RegisterID right, RegisterID dest)
- {
- // ARM doesn't have byte registers
- load32(left, ARMRegisters::S1);
- set32(cond, ARMRegisters::S1, right, dest);
- }
-
- void set8(Condition cond, RegisterID left, Imm32 right, RegisterID dest)
+ void test32(ResultCondition cond, RegisterID reg, TrustedImm32 mask, RegisterID dest)
{
- // ARM doesn't have byte registers
- set32(cond, left, right, dest);
- }
-
- void setTest32(Condition cond, Address address, Imm32 mask, RegisterID dest)
- {
- load32(address, ARMRegisters::S1);
if (mask.m_value == -1)
- m_assembler.cmp_r(0, ARMRegisters::S1);
+ m_assembler.cmp_r(0, reg);
else
- m_assembler.tst_r(ARMRegisters::S1, m_assembler.getImm(mask.m_value, ARMRegisters::S0));
+ m_assembler.tst_r(reg, m_assembler.getImm(mask.m_value, ARMRegisters::S0));
m_assembler.mov_r(dest, ARMAssembler::getOp2(0));
m_assembler.mov_r(dest, ARMAssembler::getOp2(1), ARMCondition(cond));
}
- void setTest8(Condition cond, Address address, Imm32 mask, RegisterID dest)
+ void test32(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
+ {
+ load32(address, ARMRegisters::S1);
+ test32(cond, ARMRegisters::S1, mask, dest);
+ }
+
+ void test8(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
{
- // ARM doesn't have byte registers
- setTest32(cond, address, mask, dest);
+ load8(address, ARMRegisters::S1);
+ test32(cond, ARMRegisters::S1, mask, dest);
}
- void add32(Imm32 imm, RegisterID src, RegisterID dest)
+ void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
{
m_assembler.add_r(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
}
- void add32(Imm32 imm, AbsoluteAddress address)
+ void add32(TrustedImm32 imm, AbsoluteAddress address)
{
m_assembler.ldr_un_imm(ARMRegisters::S1, reinterpret_cast<ARMWord>(address.m_ptr));
m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0);
m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 0);
}
- void sub32(Imm32 imm, AbsoluteAddress address)
+ void sub32(TrustedImm32 imm, AbsoluteAddress address)
{
m_assembler.ldr_un_imm(ARMRegisters::S1, reinterpret_cast<ARMWord>(address.m_ptr));
m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0);
m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 0);
}
- void load32(void* address, RegisterID dest)
+ void load32(const void* address, RegisterID dest)
{
m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address));
m_assembler.dtr_u(true, dest, ARMRegisters::S0, 0);
}
- Jump branch32(Condition cond, AbsoluteAddress left, RegisterID right)
+ Jump branch32(RelationalCondition cond, AbsoluteAddress left, RegisterID right)
{
load32(left.m_ptr, ARMRegisters::S1);
return branch32(cond, ARMRegisters::S1, right);
}
- Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right)
+ Jump branch32(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right)
{
load32(left.m_ptr, ARMRegisters::S1);
return branch32(cond, ARMRegisters::S1, right);
}
+ void relativeTableJump(RegisterID index, int scale)
+ {
+ ASSERT(scale >= 0 && scale <= 31);
+ m_assembler.add_r(ARMRegisters::pc, ARMRegisters::pc, m_assembler.lsl(index, scale));
+
+ // NOP the default prefetching
+ m_assembler.mov_r(ARMRegisters::r0, ARMRegisters::r0);
+ }
+
Call call()
{
#if WTF_ARM_ARCH_AT_LEAST(5)
return Call::fromTailJump(oldJump);
}
- DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest)
+ DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
{
DataLabelPtr dataLabel(this);
m_assembler.ldr_un_imm(dest, reinterpret_cast<ARMWord>(initialValue.m_value));
return dataLabel;
}
- Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0))
+ Jump branchPtrWithPatch(RelationalCondition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
{
dataLabel = moveWithPatch(initialRightValue, ARMRegisters::S1);
Jump jump = branch32(cond, left, ARMRegisters::S1, true);
return jump;
}
- Jump branchPtrWithPatch(Condition cond, Address left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0))
+ Jump branchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
{
load32(left, ARMRegisters::S1);
dataLabel = moveWithPatch(initialRightValue, ARMRegisters::S0);
return jump;
}
- DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address)
+ DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
{
DataLabelPtr dataLabel = moveWithPatch(initialValue, ARMRegisters::S1);
store32(ARMRegisters::S1, address);
DataLabelPtr storePtrWithPatch(ImplicitAddress address)
{
- return storePtrWithPatch(ImmPtr(0), address);
+ return storePtrWithPatch(TrustedImmPtr(0), address);
}
// Floating point operators
bool supportsFloatingPointTruncate() const
{
- return false;
+ return s_isVFPPresent;
}
bool supportsFloatingPointSqrt() const
void addDouble(FPRegisterID src, FPRegisterID dest)
{
- m_assembler.faddd_r(dest, dest, src);
+ m_assembler.vadd_f64_r(dest, dest, src);
}
void addDouble(Address src, FPRegisterID dest)
void divDouble(FPRegisterID src, FPRegisterID dest)
{
- m_assembler.fdivd_r(dest, dest, src);
+ m_assembler.vdiv_f64_r(dest, dest, src);
}
void divDouble(Address src, FPRegisterID dest)
void subDouble(FPRegisterID src, FPRegisterID dest)
{
- m_assembler.fsubd_r(dest, dest, src);
+ m_assembler.vsub_f64_r(dest, dest, src);
}
void subDouble(Address src, FPRegisterID dest)
void mulDouble(FPRegisterID src, FPRegisterID dest)
{
- m_assembler.fmuld_r(dest, dest, src);
+ m_assembler.vmul_f64_r(dest, dest, src);
}
void mulDouble(Address src, FPRegisterID dest)
void sqrtDouble(FPRegisterID src, FPRegisterID dest)
{
- m_assembler.fsqrtd_r(dest, src);
+ m_assembler.vsqrt_f64_r(dest, src);
}
void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
{
- m_assembler.fmsr_r(dest, src);
- m_assembler.fsitod_r(dest, dest);
+ m_assembler.vmov_vfp_r(dest << 1, src);
+ m_assembler.vcvt_f64_s32_r(dest, dest << 1);
}
void convertInt32ToDouble(Address src, FPRegisterID dest)
Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
{
- m_assembler.fcmpd_r(left, right);
- m_assembler.fmstat();
+ m_assembler.vcmp_f64_r(left, right);
+ m_assembler.vmrs_apsr();
if (cond & DoubleConditionBitSpecial)
m_assembler.cmp_r(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::VS);
return Jump(m_assembler.jmp(static_cast<ARMAssembler::Condition>(cond & ~DoubleConditionMask)));
// Truncates 'src' to an integer, and places the resulting 'dest'.
// If the result is not representable as a 32 bit value, branch.
// May also branch for some values that are representable in 32 bits
- // (specifically, in this case, INT_MIN).
+ // (specifically, in this case, INT_MIN and INT_MAX).
Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest)
{
- UNUSED_PARAM(src);
- UNUSED_PARAM(dest);
- ASSERT_NOT_REACHED();
- return jump();
+ m_assembler.vcvtr_s32_f64_r(ARMRegisters::SD0 << 1, src);
+ // If VCVTR.S32.F64 can't fit the result into a 32-bit
+ // integer, it saturates at INT_MAX or INT_MIN. Testing this is
+ // probably quicker than testing FPSCR for exception.
+ m_assembler.vmov_arm_r(dest, ARMRegisters::SD0 << 1);
+ m_assembler.sub_r(ARMRegisters::S0, dest, ARMAssembler::getOp2(0x80000000));
+ m_assembler.cmn_r(ARMRegisters::S0, ARMAssembler::getOp2(1), ARMCondition(NotEqual));
+ return Jump(m_assembler.jmp(ARMCondition(Equal)));
}
// Convert 'src' to an integer, and places the resulting 'dest'.
// (specifically, in this case, 0).
void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID fpTemp)
{
- m_assembler.ftosid_r(ARMRegisters::SD0, src);
- m_assembler.fmrs_r(dest, ARMRegisters::SD0);
+ m_assembler.vcvt_s32_f64_r(ARMRegisters::SD0 << 1, src);
+ m_assembler.vmov_arm_r(dest, ARMRegisters::SD0 << 1);
// Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump.
- m_assembler.fsitod_r(ARMRegisters::SD0, ARMRegisters::SD0);
+ m_assembler.vcvt_f64_s32_r(ARMRegisters::SD0, ARMRegisters::SD0 << 1);
failureCases.append(branchDouble(DoubleNotEqualOrUnordered, src, ARMRegisters::SD0));
// If the result is zero, it might have been -0.0, and 0.0 equals to -0.0
return branchDouble(DoubleEqualOrUnordered, reg, scratch);
}
+ void nop()
+ {
+ m_assembler.nop();
+ }
+
protected:
- ARMAssembler::Condition ARMCondition(Condition cond)
+ ARMAssembler::Condition ARMCondition(RelationalCondition cond)
+ {
+ return static_cast<ARMAssembler::Condition>(cond);
+ }
+
+ ARMAssembler::Condition ARMCondition(ResultCondition cond)
{
return static_cast<ARMAssembler::Condition>(cond);
}
prepareCall();
m_assembler.dtr_u(true, targetReg, tmpReg, offset & 0xfff);
} else {
- ARMWord reg = m_assembler.getImm(offset, tmpReg);
+ m_assembler.moveImm(offset, tmpReg);
prepareCall();
- m_assembler.dtr_ur(true, targetReg, base, reg);
+ m_assembler.dtr_ur(true, targetReg, base, tmpReg);
}
} else {
offset = -offset;
prepareCall();
m_assembler.dtr_d(true, targetReg, tmpReg, offset & 0xfff);
} else {
- ARMWord reg = m_assembler.getImm(offset, tmpReg);
+ m_assembler.moveImm(offset, tmpReg);
prepareCall();
- m_assembler.dtr_dr(true, targetReg, base, reg);
+ m_assembler.dtr_dr(true, targetReg, base, tmpReg);
}
}
#if WTF_ARM_ARCH_AT_LEAST(5)
typedef ARMv7Assembler::LinkRecord LinkRecord;
typedef ARMv7Assembler::JumpType JumpType;
typedef ARMv7Assembler::JumpLinkType JumpLinkType;
+ // Magic number is the biggest useful offset we can get on ARMv7 with
+ // a LDR_imm_T2 encoding
+ static const int MaximumCompactPtrAlignedAddressOffset = 124;
MacroAssemblerARMv7()
: m_inUninterruptedSequence(false)
static const Scale ScalePtr = TimesFour;
- enum Condition {
+ enum RelationalCondition {
Equal = ARMv7Assembler::ConditionEQ,
NotEqual = ARMv7Assembler::ConditionNE,
Above = ARMv7Assembler::ConditionHI,
GreaterThan = ARMv7Assembler::ConditionGT,
GreaterThanOrEqual = ARMv7Assembler::ConditionGE,
LessThan = ARMv7Assembler::ConditionLT,
- LessThanOrEqual = ARMv7Assembler::ConditionLE,
+ LessThanOrEqual = ARMv7Assembler::ConditionLE
+ };
+
+ enum ResultCondition {
Overflow = ARMv7Assembler::ConditionVS,
Signed = ARMv7Assembler::ConditionMI,
Zero = ARMv7Assembler::ConditionEQ,
NonZero = ARMv7Assembler::ConditionNE
};
+
enum DoubleCondition {
// These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN.
DoubleEqual = ARMv7Assembler::ConditionEQ,
// Integer arithmetic operations:
//
// Operations are typically two operand - operation(source, srcDst)
- // For many operations the source may be an Imm32, the srcDst operand
+ // For many operations the source may be an TrustedImm32, the srcDst operand
// may often be a memory location (explictly described using an Address
// object).
m_assembler.add(dest, dest, src);
}
- void add32(Imm32 imm, RegisterID dest)
+ void add32(TrustedImm32 imm, RegisterID dest)
{
add32(imm, dest, dest);
}
- void add32(Imm32 imm, RegisterID src, RegisterID dest)
+ void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
{
ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
if (armImm.isValid())
}
}
- void add32(Imm32 imm, Address address)
+ void add32(TrustedImm32 imm, Address address)
{
load32(address, dataTempRegister);
add32(dataTempRegister, dest);
}
- void add32(Imm32 imm, AbsoluteAddress address)
+ void add32(TrustedImm32 imm, AbsoluteAddress address)
{
load32(address.m_ptr, dataTempRegister);
m_assembler.ARM_and(dest, dest, src);
}
- void and32(Imm32 imm, RegisterID dest)
+ void and32(TrustedImm32 imm, RegisterID dest)
{
ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
if (armImm.isValid())
}
}
+ void countLeadingZeros32(RegisterID src, RegisterID dest)
+ {
+ m_assembler.clz(dest, src);
+ }
+
void lshift32(RegisterID shift_amount, RegisterID dest)
{
// Clamp the shift to the range 0..31
m_assembler.lsl(dest, dest, dataTempRegister);
}
- void lshift32(Imm32 imm, RegisterID dest)
+ void lshift32(TrustedImm32 imm, RegisterID dest)
{
m_assembler.lsl(dest, dest, imm.m_value & 0x1f);
}
m_assembler.smull(dest, dataTempRegister, dest, src);
}
- void mul32(Imm32 imm, RegisterID src, RegisterID dest)
+ void mul32(TrustedImm32 imm, RegisterID src, RegisterID dest)
{
move(imm, dataTempRegister);
m_assembler.smull(dest, dataTempRegister, src, dataTempRegister);
m_assembler.orr(dest, dest, src);
}
- void or32(Imm32 imm, RegisterID dest)
+ void or32(TrustedImm32 imm, RegisterID dest)
{
ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
if (armImm.isValid())
m_assembler.asr(dest, dest, dataTempRegister);
}
- void rshift32(Imm32 imm, RegisterID dest)
+ void rshift32(TrustedImm32 imm, RegisterID dest)
{
m_assembler.asr(dest, dest, imm.m_value & 0x1f);
}
m_assembler.lsr(dest, dest, dataTempRegister);
}
- void urshift32(Imm32 imm, RegisterID dest)
+ void urshift32(TrustedImm32 imm, RegisterID dest)
{
m_assembler.lsr(dest, dest, imm.m_value & 0x1f);
}
m_assembler.sub(dest, dest, src);
}
- void sub32(Imm32 imm, RegisterID dest)
+ void sub32(TrustedImm32 imm, RegisterID dest)
{
ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
if (armImm.isValid())
}
}
- void sub32(Imm32 imm, Address address)
+ void sub32(TrustedImm32 imm, Address address)
{
load32(address, dataTempRegister);
sub32(dataTempRegister, dest);
}
- void sub32(Imm32 imm, AbsoluteAddress address)
+ void sub32(TrustedImm32 imm, AbsoluteAddress address)
{
load32(address.m_ptr, dataTempRegister);
m_assembler.eor(dest, dest, src);
}
- void xor32(Imm32 imm, RegisterID dest)
+ void xor32(TrustedImm32 imm, RegisterID dest)
{
ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
if (armImm.isValid())
// Memory access operations:
//
// Loads are of the form load(address, destination) and stores of the form
- // store(source, address). The source for a store may be an Imm32. Address
+ // store(source, address). The source for a store may be an TrustedImm32. Address
// operand objects to loads and store will be implicitly constructed if a
// register is passed.
load32(setupArmAddress(address), dest);
}
- void load32(void* address, RegisterID dest)
+ void load32(const void* address, RegisterID dest)
{
- move(ImmPtr(address), addressTempRegister);
+ move(TrustedImmPtr(address), addressTempRegister);
m_assembler.ldr(dest, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
}
DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest)
{
- DataLabel32 label = moveWithPatch(Imm32(address.offset), dataTempRegister);
+ DataLabel32 label = moveWithPatch(TrustedImm32(address.offset), dataTempRegister);
load32(ArmAddress(address.base, dataTempRegister), dest);
return label;
}
-
- Label loadPtrWithPatchToLEA(Address address, RegisterID dest)
+
+ DataLabelCompact load32WithCompactAddressOffsetPatch(Address address, RegisterID dest)
{
- Label label(this);
- moveFixedWidthEncoding(Imm32(address.offset), dataTempRegister);
- load32(ArmAddress(address.base, dataTempRegister), dest);
+ DataLabelCompact label(this);
+ ASSERT(address.offset >= 0);
+ ASSERT(address.offset <= MaximumCompactPtrAlignedAddressOffset);
+ ASSERT(ARMThumbImmediate::makeUInt12(address.offset).isUInt7());
+ m_assembler.ldrCompact(dest, address.base, ARMThumbImmediate::makeUInt12(address.offset));
return label;
}
if (armImm.isValid())
m_assembler.ldrh(dest, address.base, armImm);
else {
- move(Imm32(address.offset), dataTempRegister);
+ move(TrustedImm32(address.offset), dataTempRegister);
m_assembler.ldrh(dest, address.base, dataTempRegister);
}
}
DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
{
- DataLabel32 label = moveWithPatch(Imm32(address.offset), dataTempRegister);
+ DataLabel32 label = moveWithPatch(TrustedImm32(address.offset), dataTempRegister);
store32(src, ArmAddress(address.base, dataTempRegister));
return label;
}
store32(src, setupArmAddress(address));
}
- void store32(Imm32 imm, ImplicitAddress address)
+ void store32(TrustedImm32 imm, ImplicitAddress address)
{
move(imm, dataTempRegister);
store32(dataTempRegister, setupArmAddress(address));
}
- void store32(RegisterID src, void* address)
+ void store32(RegisterID src, const void* address)
{
- move(ImmPtr(address), addressTempRegister);
+ move(TrustedImmPtr(address), addressTempRegister);
m_assembler.str(src, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
}
- void store32(Imm32 imm, void* address)
+ void store32(TrustedImm32 imm, const void* address)
{
move(imm, dataTempRegister);
store32(dataTempRegister, address);
// Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
- add32(Imm32(offset), base, addressTempRegister);
+ add32(TrustedImm32(offset), base, addressTempRegister);
base = addressTempRegister;
offset = 0;
}
void loadDouble(const void* address, FPRegisterID dest)
{
- move(ImmPtr(address), addressTempRegister);
+ move(TrustedImmPtr(address), addressTempRegister);
m_assembler.vldr(dest, addressTempRegister, 0);
}
// Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
- add32(Imm32(offset), base, addressTempRegister);
+ add32(TrustedImm32(offset), base, addressTempRegister);
base = addressTempRegister;
offset = 0;
}
Jump notEqual = makeBranch(ARMv7Assembler::ConditionNE);
unordered.link(this);
// We get here if either unordered or equal.
- Jump result = makeJump();
+ Jump result = jump();
notEqual.link(this);
return result;
}
Jump notEqual = makeBranch(ARMv7Assembler::ConditionNE);
unordered.link(this);
// We get here if either unordered or equal.
- Jump result = makeJump();
+ Jump result = jump();
notEqual.link(this);
return result;
}
push(dataTempRegister);
}
- void push(Imm32 imm)
+ void push(TrustedImm32 imm)
{
move(imm, dataTempRegister);
push(dataTempRegister);
//
// Move values in registers.
- void move(Imm32 imm, RegisterID dest)
+ void move(TrustedImm32 imm, RegisterID dest)
{
uint32_t value = imm.m_value;
m_assembler.mov(dest, src);
}
- void move(ImmPtr imm, RegisterID dest)
+ void move(TrustedImmPtr imm, RegisterID dest)
{
- move(Imm32(imm), dest);
+ move(TrustedImm32(imm), dest);
}
void swap(RegisterID reg1, RegisterID reg2)
move(src, dest);
}
+ void nop()
+ {
+ m_assembler.nop();
+ }
// Forwards / external control flow operations:
//
// used (representing the names 'below' and 'above').
//
// Operands to the comparision are provided in the expected order, e.g.
- // jle32(reg1, Imm32(5)) will branch if the value held in reg1, when
+ // jle32(reg1, TrustedImm32(5)) will branch if the value held in reg1, when
// treated as a signed 32bit value, is less than or equal to 5.
//
// jz and jnz test whether the first operand is equal to zero, and take
private:
// Should we be using TEQ for equal/not-equal?
- void compare32(RegisterID left, Imm32 right)
+ void compare32(RegisterID left, TrustedImm32 right)
{
int32_t imm = right.m_value;
if (!imm)
else if ((armImm = ARMThumbImmediate::makeEncodedImm(-imm)).isValid())
m_assembler.cmn(left, armImm);
else {
- move(Imm32(imm), dataTempRegister);
+ move(TrustedImm32(imm), dataTempRegister);
m_assembler.cmp(left, dataTempRegister);
}
}
}
- void test32(RegisterID reg, Imm32 mask)
+ void test32(RegisterID reg, TrustedImm32 mask)
{
int32_t imm = mask.m_value;
}
public:
- Jump branch32(Condition cond, RegisterID left, RegisterID right)
+ Jump branch32(RelationalCondition cond, RegisterID left, RegisterID right)
{
m_assembler.cmp(left, right);
return Jump(makeBranch(cond));
}
- Jump branch32(Condition cond, RegisterID left, Imm32 right)
+ Jump branch32(RelationalCondition cond, RegisterID left, TrustedImm32 right)
{
compare32(left, right);
return Jump(makeBranch(cond));
}
- Jump branch32(Condition cond, RegisterID left, Address right)
+ Jump branch32(RelationalCondition cond, RegisterID left, Address right)
{
load32(right, dataTempRegister);
return branch32(cond, left, dataTempRegister);
}
- Jump branch32(Condition cond, Address left, RegisterID right)
+ Jump branch32(RelationalCondition cond, Address left, RegisterID right)
{
load32(left, dataTempRegister);
return branch32(cond, dataTempRegister, right);
}
- Jump branch32(Condition cond, Address left, Imm32 right)
+ Jump branch32(RelationalCondition cond, Address left, TrustedImm32 right)
{
// use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
load32(left, addressTempRegister);
return branch32(cond, addressTempRegister, right);
}
- Jump branch32(Condition cond, BaseIndex left, Imm32 right)
+ Jump branch32(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
{
// use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
load32(left, addressTempRegister);
return branch32(cond, addressTempRegister, right);
}
- Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right)
+ Jump branch32WithUnalignedHalfWords(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
{
// use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
load32WithUnalignedHalfWords(left, addressTempRegister);
return branch32(cond, addressTempRegister, right);
}
- Jump branch32(Condition cond, AbsoluteAddress left, RegisterID right)
+ Jump branch32(RelationalCondition cond, AbsoluteAddress left, RegisterID right)
{
load32(left.m_ptr, dataTempRegister);
return branch32(cond, dataTempRegister, right);
}
- Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right)
+ Jump branch32(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right)
{
// use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
load32(left.m_ptr, addressTempRegister);
return branch32(cond, addressTempRegister, right);
}
- Jump branch16(Condition cond, BaseIndex left, RegisterID right)
+ Jump branch16(RelationalCondition cond, BaseIndex left, RegisterID right)
{
load16(left, dataTempRegister);
m_assembler.lsl(addressTempRegister, right, 16);
return branch32(cond, dataTempRegister, addressTempRegister);
}
- Jump branch16(Condition cond, BaseIndex left, Imm32 right)
+ Jump branch16(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
{
// use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
load16(left, addressTempRegister);
m_assembler.lsl(addressTempRegister, addressTempRegister, 16);
- return branch32(cond, addressTempRegister, Imm32(right.m_value << 16));
+ return branch32(cond, addressTempRegister, TrustedImm32(right.m_value << 16));
}
- Jump branch8(Condition cond, RegisterID left, Imm32 right)
+ Jump branch8(RelationalCondition cond, RegisterID left, TrustedImm32 right)
{
compare32(left, right);
return Jump(makeBranch(cond));
}
- Jump branch8(Condition cond, Address left, Imm32 right)
+ Jump branch8(RelationalCondition cond, Address left, TrustedImm32 right)
{
// use addressTempRegister incase the branch8 we call uses dataTempRegister. :-/
load8(left, addressTempRegister);
return branch8(cond, addressTempRegister, right);
}
- Jump branchTest32(Condition cond, RegisterID reg, RegisterID mask)
+ Jump branchTest32(ResultCondition cond, RegisterID reg, RegisterID mask)
{
- ASSERT((cond == Zero) || (cond == NonZero));
m_assembler.tst(reg, mask);
return Jump(makeBranch(cond));
}
- Jump branchTest32(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1))
+ Jump branchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
{
- ASSERT((cond == Zero) || (cond == NonZero));
test32(reg, mask);
return Jump(makeBranch(cond));
}
- Jump branchTest32(Condition cond, Address address, Imm32 mask = Imm32(-1))
+ Jump branchTest32(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
{
- ASSERT((cond == Zero) || (cond == NonZero));
// use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/
load32(address, addressTempRegister);
return branchTest32(cond, addressTempRegister, mask);
}
- Jump branchTest32(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1))
+ Jump branchTest32(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
{
- ASSERT((cond == Zero) || (cond == NonZero));
// use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/
load32(address, addressTempRegister);
return branchTest32(cond, addressTempRegister, mask);
}
- Jump branchTest8(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1))
+ Jump branchTest8(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
{
- ASSERT((cond == Zero) || (cond == NonZero));
test32(reg, mask);
return Jump(makeBranch(cond));
}
- Jump branchTest8(Condition cond, Address address, Imm32 mask = Imm32(-1))
+ Jump branchTest8(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
{
- ASSERT((cond == Zero) || (cond == NonZero));
// use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/
load8(address, addressTempRegister);
return branchTest8(cond, addressTempRegister, mask);
}
- Jump jump()
- {
- return Jump(makeJump());
- }
-
void jump(RegisterID target)
{
- m_assembler.bx(target, ARMv7Assembler::JumpFixed);
+ m_assembler.bx(target);
}
// Address is a memory location containing the address to jump to
void jump(Address address)
{
load32(address, dataTempRegister);
- m_assembler.bx(dataTempRegister, ARMv7Assembler::JumpFixed);
+ m_assembler.bx(dataTempRegister);
}
// * jo operations branch if the (signed) arithmetic
// operation caused an overflow to occur.
- Jump branchAdd32(Condition cond, RegisterID src, RegisterID dest)
+ Jump branchAdd32(ResultCondition cond, RegisterID src, RegisterID dest)
{
- ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
m_assembler.add_S(dest, dest, src);
return Jump(makeBranch(cond));
}
- Jump branchAdd32(Condition cond, Imm32 imm, RegisterID dest)
+ Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
{
- ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
if (armImm.isValid())
m_assembler.add_S(dest, dest, armImm);
return Jump(makeBranch(cond));
}
- Jump branchMul32(Condition cond, RegisterID src, RegisterID dest)
+ Jump branchMul32(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest)
{
- ASSERT_UNUSED(cond, cond == Overflow);
- m_assembler.smull(dest, dataTempRegister, dest, src);
- m_assembler.asr(addressTempRegister, dest, 31);
- return branch32(NotEqual, addressTempRegister, dataTempRegister);
+ m_assembler.smull(dest, dataTempRegister, src1, src2);
+
+ if (cond == Overflow) {
+ m_assembler.asr(addressTempRegister, dest, 31);
+ return branch32(NotEqual, addressTempRegister, dataTempRegister);
+ }
+
+ return branchTest32(cond, dest);
}
- Jump branchMul32(Condition cond, Imm32 imm, RegisterID src, RegisterID dest)
+ Jump branchMul32(ResultCondition cond, RegisterID src, RegisterID dest)
+ {
+ return branchMul32(cond, src, dest, dest);
+ }
+
+ Jump branchMul32(ResultCondition cond, TrustedImm32 imm, RegisterID src, RegisterID dest)
{
- ASSERT_UNUSED(cond, cond == Overflow);
move(imm, dataTempRegister);
- m_assembler.smull(dest, dataTempRegister, src, dataTempRegister);
- m_assembler.asr(addressTempRegister, dest, 31);
- return branch32(NotEqual, addressTempRegister, dataTempRegister);
+ return branchMul32(cond, dataTempRegister, src, dest);
}
- Jump branchOr32(Condition cond, RegisterID src, RegisterID dest)
+ Jump branchOr32(ResultCondition cond, RegisterID src, RegisterID dest)
{
- ASSERT((cond == Signed) || (cond == Zero) || (cond == NonZero));
m_assembler.orr_S(dest, dest, src);
return Jump(makeBranch(cond));
}
- Jump branchSub32(Condition cond, RegisterID src, RegisterID dest)
+ Jump branchSub32(ResultCondition cond, RegisterID src, RegisterID dest)
{
- ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
m_assembler.sub_S(dest, dest, src);
return Jump(makeBranch(cond));
}
- Jump branchSub32(Condition cond, Imm32 imm, RegisterID dest)
+ Jump branchSub32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
{
- ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
if (armImm.isValid())
m_assembler.sub_S(dest, dest, armImm);
return Jump(makeBranch(cond));
}
+ void relativeTableJump(RegisterID index, int scale)
+ {
+ ASSERT(scale >= 0 && scale <= 31);
+
+ // dataTempRegister will point after the jump if index register contains zero
+ move(ARMRegisters::pc, dataTempRegister);
+ m_assembler.add(dataTempRegister, dataTempRegister, ARMThumbImmediate::makeEncodedImm(9));
+
+ ShiftTypeAndAmount shift(SRType_LSL, scale);
+ m_assembler.add(dataTempRegister, dataTempRegister, index, shift);
+ jump(dataTempRegister);
+ }
// Miscellaneous operations:
m_assembler.bkpt(0);
}
- Call nearCall()
+ ALWAYS_INLINE Call nearCall()
{
- moveFixedWidthEncoding(Imm32(0), dataTempRegister);
- return Call(m_assembler.blx(dataTempRegister, ARMv7Assembler::JumpFixed), Call::LinkableNear);
+ moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
+ return Call(m_assembler.blx(dataTempRegister), Call::LinkableNear);
}
- Call call()
+ ALWAYS_INLINE Call call()
{
- moveFixedWidthEncoding(Imm32(0), dataTempRegister);
- return Call(m_assembler.blx(dataTempRegister, ARMv7Assembler::JumpFixed), Call::Linkable);
+ moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
+ return Call(m_assembler.blx(dataTempRegister), Call::Linkable);
}
- Call call(RegisterID target)
+ ALWAYS_INLINE Call call(RegisterID target)
{
- return Call(m_assembler.blx(target, ARMv7Assembler::JumpFixed), Call::None);
+ return Call(m_assembler.blx(target), Call::None);
}
- Call call(Address address)
+ ALWAYS_INLINE Call call(Address address)
{
load32(address, dataTempRegister);
- return Call(m_assembler.blx(dataTempRegister, ARMv7Assembler::JumpFixed), Call::None);
+ return Call(m_assembler.blx(dataTempRegister), Call::None);
}
- void ret()
+ ALWAYS_INLINE void ret()
{
- m_assembler.bx(linkRegister, ARMv7Assembler::JumpFixed);
+ m_assembler.bx(linkRegister);
}
- void set32(Condition cond, RegisterID left, RegisterID right, RegisterID dest)
+ void compare32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID dest)
{
m_assembler.cmp(left, right);
m_assembler.it(armV7Condition(cond), false);
m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
}
- void set32(Condition cond, Address left, RegisterID right, RegisterID dest)
+ void compare32(RelationalCondition cond, Address left, RegisterID right, RegisterID dest)
{
load32(left, dataTempRegister);
- set32(cond, dataTempRegister, right, dest);
+ compare32(cond, dataTempRegister, right, dest);
}
- void set32(Condition cond, RegisterID left, Imm32 right, RegisterID dest)
+ void compare32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
{
compare32(left, right);
m_assembler.it(armV7Condition(cond), false);
m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
}
- void set8(Condition cond, RegisterID left, RegisterID right, RegisterID dest)
- {
- set32(cond, left, right, dest);
- }
-
- void set8(Condition cond, Address left, RegisterID right, RegisterID dest)
- {
- set32(cond, left, right, dest);
- }
-
- void set8(Condition cond, RegisterID left, Imm32 right, RegisterID dest)
- {
- set32(cond, left, right, dest);
- }
-
// FIXME:
// The mask should be optional... paerhaps the argument order should be
// dest-src, operations always have a dest? ... possibly not true, considering
// asm ops like test, or pseudo ops like pop().
- void setTest32(Condition cond, Address address, Imm32 mask, RegisterID dest)
+ void test32(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
{
load32(address, dataTempRegister);
test32(dataTempRegister, mask);
m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
}
- void setTest8(Condition cond, Address address, Imm32 mask, RegisterID dest)
+ void test8(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
{
load8(address, dataTempRegister);
test32(dataTempRegister, mask);
m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
}
- DataLabel32 moveWithPatch(Imm32 imm, RegisterID dst)
+ ALWAYS_INLINE DataLabel32 moveWithPatch(TrustedImm32 imm, RegisterID dst)
{
moveFixedWidthEncoding(imm, dst);
return DataLabel32(this);
}
- DataLabelPtr moveWithPatch(ImmPtr imm, RegisterID dst)
+ ALWAYS_INLINE DataLabelPtr moveWithPatch(TrustedImmPtr imm, RegisterID dst)
{
- moveFixedWidthEncoding(Imm32(imm), dst);
+ moveFixedWidthEncoding(TrustedImm32(imm), dst);
return DataLabelPtr(this);
}
- Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0))
+ ALWAYS_INLINE Jump branchPtrWithPatch(RelationalCondition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
{
dataLabel = moveWithPatch(initialRightValue, dataTempRegister);
return branch32(cond, left, dataTempRegister);
}
- Jump branchPtrWithPatch(Condition cond, Address left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0))
+ ALWAYS_INLINE Jump branchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
{
load32(left, addressTempRegister);
dataLabel = moveWithPatch(initialRightValue, dataTempRegister);
return branch32(cond, addressTempRegister, dataTempRegister);
}
- DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address)
+ ALWAYS_INLINE DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
{
DataLabelPtr label = moveWithPatch(initialValue, dataTempRegister);
store32(dataTempRegister, address);
return label;
}
- DataLabelPtr storePtrWithPatch(ImplicitAddress address) { return storePtrWithPatch(ImmPtr(0), address); }
+ ALWAYS_INLINE DataLabelPtr storePtrWithPatch(ImplicitAddress address) { return storePtrWithPatch(TrustedImmPtr(0), address); }
- Call tailRecursiveCall()
+ ALWAYS_INLINE Call tailRecursiveCall()
{
// Like a normal call, but don't link.
- moveFixedWidthEncoding(Imm32(0), dataTempRegister);
- return Call(m_assembler.bx(dataTempRegister, ARMv7Assembler::JumpFixed), Call::Linkable);
+ moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
+ return Call(m_assembler.bx(dataTempRegister), Call::Linkable);
}
- Call makeTailRecursiveCall(Jump oldJump)
+ ALWAYS_INLINE Call makeTailRecursiveCall(Jump oldJump)
{
oldJump.link(this);
return tailRecursiveCall();
return m_inUninterruptedSequence;
}
- ARMv7Assembler::JmpSrc makeJump()
+ ALWAYS_INLINE Jump jump()
{
- moveFixedWidthEncoding(Imm32(0), dataTempRegister);
- return m_assembler.bx(dataTempRegister, inUninterruptedSequence() ? ARMv7Assembler::JumpNoConditionFixedSize : ARMv7Assembler::JumpNoCondition);
+ moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
+ return Jump(m_assembler.bx(dataTempRegister), inUninterruptedSequence() ? ARMv7Assembler::JumpNoConditionFixedSize : ARMv7Assembler::JumpNoCondition);
}
- ARMv7Assembler::JmpSrc makeBranch(ARMv7Assembler::Condition cond)
+ ALWAYS_INLINE Jump makeBranch(ARMv7Assembler::Condition cond)
{
m_assembler.it(cond, true, true);
- moveFixedWidthEncoding(Imm32(0), dataTempRegister);
- return m_assembler.bx(dataTempRegister, inUninterruptedSequence() ? ARMv7Assembler::JumpConditionFixedSize : ARMv7Assembler::JumpCondition, cond);
+ moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
+ return Jump(m_assembler.bx(dataTempRegister), inUninterruptedSequence() ? ARMv7Assembler::JumpConditionFixedSize : ARMv7Assembler::JumpCondition, cond);
}
- ARMv7Assembler::JmpSrc makeBranch(Condition cond) { return makeBranch(armV7Condition(cond)); }
- ARMv7Assembler::JmpSrc makeBranch(DoubleCondition cond) { return makeBranch(armV7Condition(cond)); }
+ ALWAYS_INLINE Jump makeBranch(RelationalCondition cond) { return makeBranch(armV7Condition(cond)); }
+ ALWAYS_INLINE Jump makeBranch(ResultCondition cond) { return makeBranch(armV7Condition(cond)); }
+ ALWAYS_INLINE Jump makeBranch(DoubleCondition cond) { return makeBranch(armV7Condition(cond)); }
ArmAddress setupArmAddress(BaseIndex address)
{
if (imm.isValid())
m_assembler.add(addressTempRegister, address.base, imm);
else {
- move(Imm32(address.offset), addressTempRegister);
+ move(TrustedImm32(address.offset), addressTempRegister);
m_assembler.add(addressTempRegister, addressTempRegister, address.base);
}
if ((address.offset >= -0xff) && (address.offset <= 0xfff))
return ArmAddress(address.base, address.offset);
- move(Imm32(address.offset), addressTempRegister);
+ move(TrustedImm32(address.offset), addressTempRegister);
return ArmAddress(address.base, addressTempRegister);
}
if ((address.offset >= -0xff) && (address.offset <= 0xfff))
return ArmAddress(address.base, address.offset);
- move(Imm32(address.offset), addressTempRegister);
+ move(TrustedImm32(address.offset), addressTempRegister);
return ArmAddress(address.base, addressTempRegister);
}
if (imm.isValid())
m_assembler.add(addressTempRegister, address.base, imm);
else {
- move(Imm32(address.offset), addressTempRegister);
+ move(TrustedImm32(address.offset), addressTempRegister);
m_assembler.add(addressTempRegister, addressTempRegister, address.base);
}
return addressTempRegister;
}
- void moveFixedWidthEncoding(Imm32 imm, RegisterID dst)
+ void moveFixedWidthEncoding(TrustedImm32 imm, RegisterID dst)
{
uint32_t value = imm.m_value;
m_assembler.movT3(dst, ARMThumbImmediate::makeUInt16(value & 0xffff));
m_assembler.movt(dst, ARMThumbImmediate::makeUInt16(value >> 16));
}
- ARMv7Assembler::Condition armV7Condition(Condition cond)
+ ARMv7Assembler::Condition armV7Condition(RelationalCondition cond)
+ {
+ return static_cast<ARMv7Assembler::Condition>(cond);
+ }
+
+ ARMv7Assembler::Condition armV7Condition(ResultCondition cond)
{
return static_cast<ARMv7Assembler::Condition>(cond);
}
{
}
+ template<typename returnType>
+ FunctionPtr(returnType(*value)())
+ : m_value((void*)value)
+ {
+ ASSERT_VALID_CODE_POINTER(m_value);
+ }
+
+ template<typename returnType, typename argType1>
+ FunctionPtr(returnType(*value)(argType1))
+ : m_value((void*)value)
+ {
+ ASSERT_VALID_CODE_POINTER(m_value);
+ }
+
+ template<typename returnType, typename argType1, typename argType2>
+ FunctionPtr(returnType(*value)(argType1, argType2))
+ : m_value((void*)value)
+ {
+ ASSERT_VALID_CODE_POINTER(m_value);
+ }
+
+ template<typename returnType, typename argType1, typename argType2, typename argType3>
+ FunctionPtr(returnType(*value)(argType1, argType2, argType3))
+ : m_value((void*)value)
+ {
+ ASSERT_VALID_CODE_POINTER(m_value);
+ }
+
+ template<typename returnType, typename argType1, typename argType2, typename argType3, typename argType4>
+ FunctionPtr(returnType(*value)(argType1, argType2, argType3, argType4))
+ : m_value((void*)value)
+ {
+ ASSERT_VALID_CODE_POINTER(m_value);
+ }
+
template<typename FunctionType>
explicit FunctionPtr(FunctionType* value)
-#if COMPILER(RVCT)
- // RVTC compiler needs C-style cast as it fails with the following error
- // Error: #694: reinterpret_cast cannot cast away const or other type qualifiers
- : m_value((void*)(value))
-#else
- : m_value(reinterpret_cast<void*>(value))
-#endif
+ // Using a C-ctyle cast here to avoid compiler error on RVTC:
+ // Error: #694: reinterpret_cast cannot cast away const or other type qualifiers
+ // (I guess on RVTC function pointers have a different constness to GCC/MSVC?)
+ : m_value((void*)value)
{
ASSERT_VALID_CODE_POINTER(m_value);
}
void* dataLocation() const { ASSERT_VALID_CODE_POINTER(m_value); return m_value; }
#endif
- bool operator!()
+ bool operator!() const
{
return !m_value;
}
#if ENABLE(ASSEMBLER) && CPU(MIPS)
-#include "AbstractMacroAssembler.h"
#include "MIPSAssembler.h"
+#include "AbstractMacroAssembler.h"
namespace JSC {
class MacroAssemblerMIPS : public AbstractMacroAssembler<MIPSAssembler> {
public:
+ typedef MIPSRegisters::FPRegisterID FPRegisterID;
MacroAssemblerMIPS()
: m_fixedWidth(false)
// FP temp register
static const FPRegisterID fpTempRegister = MIPSRegisters::f16;
- enum Condition {
+ static const int MaximumCompactPtrAlignedAddressOffset = 0x7FFFFFFF;
+
+ enum RelationalCondition {
Equal,
NotEqual,
Above,
GreaterThan,
GreaterThanOrEqual,
LessThan,
- LessThanOrEqual,
+ LessThanOrEqual
+ };
+
+ enum ResultCondition {
Overflow,
Signed,
Zero,
// Integer arithmetic operations:
//
// Operations are typically two operand - operation(source, srcDst)
- // For many operations the source may be an Imm32, the srcDst operand
+ // For many operations the source may be an TrustedImm32, the srcDst operand
// may often be a memory location (explictly described using an Address
// object).
m_assembler.addu(dest, dest, src);
}
- void add32(Imm32 imm, RegisterID dest)
+ void add32(TrustedImm32 imm, RegisterID dest)
{
add32(imm, dest, dest);
}
- void add32(Imm32 imm, RegisterID src, RegisterID dest)
+ void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
{
if (!imm.m_isPointer && imm.m_value >= -32768 && imm.m_value <= 32767
&& !m_fixedWidth) {
}
}
- void add32(Imm32 imm, Address address)
+ void add32(TrustedImm32 imm, Address address)
{
if (address.offset >= -32768 && address.offset <= 32767
&& !m_fixedWidth) {
}
}
- void add32(Imm32 imm, AbsoluteAddress address)
+ void add32(TrustedImm32 imm, AbsoluteAddress address)
{
/*
li addrTemp, address
addu dataTemp, dataTemp, immTemp
sw dataTemp, 0(addrTemp)
*/
- move(ImmPtr(address.m_ptr), addrTempRegister);
+ move(TrustedImmPtr(address.m_ptr), addrTempRegister);
m_assembler.lw(dataTempRegister, addrTempRegister, 0);
if (!imm.m_isPointer && imm.m_value >= -32768 && imm.m_value <= 32767
&& !m_fixedWidth)
m_assembler.andInsn(dest, dest, src);
}
- void and32(Imm32 imm, RegisterID dest)
+ void and32(TrustedImm32 imm, RegisterID dest)
{
if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth)
move(MIPSRegisters::zero, dest);
}
}
- void lshift32(Imm32 imm, RegisterID dest)
+ void lshift32(TrustedImm32 imm, RegisterID dest)
{
m_assembler.sll(dest, dest, imm.m_value);
}
m_assembler.mul(dest, dest, src);
}
- void mul32(Imm32 imm, RegisterID src, RegisterID dest)
+ void mul32(TrustedImm32 imm, RegisterID src, RegisterID dest)
{
if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth)
move(MIPSRegisters::zero, dest);
}
}
+ void neg32(RegisterID srcDest)
+ {
+ m_assembler.subu(srcDest, MIPSRegisters::zero, srcDest);
+ }
+
void not32(RegisterID srcDest)
{
m_assembler.nor(srcDest, srcDest, MIPSRegisters::zero);
m_assembler.orInsn(dest, dest, src);
}
- void or32(Imm32 imm, RegisterID dest)
+ void or32(TrustedImm32 imm, RegisterID dest)
{
if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth)
return;
m_assembler.srav(dest, dest, shiftAmount);
}
- void rshift32(Imm32 imm, RegisterID dest)
+ void rshift32(TrustedImm32 imm, RegisterID dest)
{
m_assembler.sra(dest, dest, imm.m_value);
}
+ void urshift32(RegisterID shiftAmount, RegisterID dest)
+ {
+ m_assembler.srlv(dest, dest, shiftAmount);
+ }
+
+ void urshift32(TrustedImm32 imm, RegisterID dest)
+ {
+ m_assembler.srl(dest, dest, imm.m_value);
+ }
+
void sub32(RegisterID src, RegisterID dest)
{
m_assembler.subu(dest, dest, src);
}
- void sub32(Imm32 imm, RegisterID dest)
+ void sub32(TrustedImm32 imm, RegisterID dest)
{
if (!imm.m_isPointer && imm.m_value >= -32767 && imm.m_value <= 32768
&& !m_fixedWidth) {
}
}
- void sub32(Imm32 imm, Address address)
+ void sub32(TrustedImm32 imm, Address address)
{
if (address.offset >= -32768 && address.offset <= 32767
&& !m_fixedWidth) {
sub32(dataTempRegister, dest);
}
- void sub32(Imm32 imm, AbsoluteAddress address)
+ void sub32(TrustedImm32 imm, AbsoluteAddress address)
{
/*
li addrTemp, address
subu dataTemp, dataTemp, immTemp
sw dataTemp, 0(addrTemp)
*/
- move(ImmPtr(address.m_ptr), addrTempRegister);
+ move(TrustedImmPtr(address.m_ptr), addrTempRegister);
m_assembler.lw(dataTempRegister, addrTempRegister, 0);
if (!imm.m_isPointer && imm.m_value >= -32767 && imm.m_value <= 32768
m_assembler.xorInsn(dest, dest, src);
}
- void xor32(Imm32 imm, RegisterID dest)
+ void xor32(TrustedImm32 imm, RegisterID dest)
{
/*
li immTemp, imm
m_assembler.xorInsn(dest, dest, immTempRegister);
}
+ void sqrtDouble(FPRegisterID src, FPRegisterID dst)
+ {
+ m_assembler.sqrtd(dst, src);
+ }
+
// Memory access operations:
//
// Loads are of the form load(address, destination) and stores of the form
- // store(source, address). The source for a store may be an Imm32. Address
+ // store(source, address). The source for a store may be an TrustedImm32. Address
// operand objects to loads and store will be implicitly constructed if a
// register is passed.
}
}
- void load32(void* address, RegisterID dest)
+ void load32(const void* address, RegisterID dest)
{
/*
li addrTemp, address
lw dest, 0(addrTemp)
*/
- move(ImmPtr(address), addrTempRegister);
+ move(TrustedImmPtr(address), addrTempRegister);
m_assembler.lw(dest, addrTempRegister, 0);
}
lw dest, 0(addrTemp)
*/
DataLabel32 dataLabel(this);
- move(Imm32(address.offset), addrTempRegister);
+ move(TrustedImm32(address.offset), addrTempRegister);
m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
m_assembler.lw(dest, addrTempRegister, 0);
m_fixedWidth = false;
return dataLabel;
}
-
- Label loadPtrWithPatchToLEA(Address address, RegisterID dest)
+
+ DataLabelCompact load32WithCompactAddressOffsetPatch(Address address, RegisterID dest)
{
- m_fixedWidth = true;
- /*
- lui addrTemp, address.offset >> 16
- ori addrTemp, addrTemp, address.offset & 0xffff
- addu addrTemp, addrTemp, address.base
- lw dest, 0(addrTemp)
- */
- Label label(this);
- move(Imm32(address.offset), addrTempRegister);
- m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
- m_assembler.lw(dest, addrTempRegister, 0);
- m_fixedWidth = false;
- return label;
+ DataLabelCompact dataLabel(this);
+ load32WithAddressOffsetPatch(address, dest);
+ return dataLabel;
}
- Label loadPtrWithAddressOffsetPatch(Address address, RegisterID dest)
+ /* Need to use zero-extened load half-word for load16. */
+ void load16(ImplicitAddress address, RegisterID dest)
{
- return loadPtrWithPatchToLEA(address, dest);
+ if (address.offset >= -32768 && address.offset <= 32767
+ && !m_fixedWidth)
+ m_assembler.lhu(dest, address.base, address.offset);
+ else {
+ /*
+ lui addrTemp, (offset + 0x8000) >> 16
+ addu addrTemp, addrTemp, base
+ lhu dest, (offset & 0xffff)(addrTemp)
+ */
+ m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
+ m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
+ m_assembler.lhu(dest, addrTempRegister, address.offset);
+ }
}
/* Need to use zero-extened load half-word for load16. */
sw src, 0(addrTemp)
*/
DataLabel32 dataLabel(this);
- move(Imm32(address.offset), addrTempRegister);
+ move(TrustedImm32(address.offset), addrTempRegister);
m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
m_assembler.sw(src, addrTempRegister, 0);
m_fixedWidth = false;
}
}
- void store32(Imm32 imm, ImplicitAddress address)
+ void store32(TrustedImm32 imm, ImplicitAddress address)
{
if (address.offset >= -32768 && address.offset <= 32767
&& !m_fixedWidth) {
}
}
- void store32(RegisterID src, void* address)
+ void store32(RegisterID src, const void* address)
{
/*
li addrTemp, address
sw src, 0(addrTemp)
*/
- move(ImmPtr(address), addrTempRegister);
+ move(TrustedImmPtr(address), addrTempRegister);
m_assembler.sw(src, addrTempRegister, 0);
}
- void store32(Imm32 imm, void* address)
+ void store32(TrustedImm32 imm, const void* address)
{
/*
li immTemp, imm
sw src, 0(addrTemp)
*/
if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth) {
- move(ImmPtr(address), addrTempRegister);
+ move(TrustedImmPtr(address), addrTempRegister);
m_assembler.sw(MIPSRegisters::zero, addrTempRegister, 0);
} else {
move(imm, immTempRegister);
- move(ImmPtr(address), addrTempRegister);
+ move(TrustedImmPtr(address), addrTempRegister);
m_assembler.sw(immTempRegister, addrTempRegister, 0);
}
}
#endif
}
+ bool supportsFloatingPointSqrt() const
+ {
+#if WTF_MIPS_DOUBLE_FLOAT && WTF_MIPS_ISA_AT_LEAST(2)
+ return true;
+#else
+ return false;
+#endif
+ }
+
// Stack manipulation operations:
//
// The ABI is assumed to provide a stack abstraction to memory,
push(dataTempRegister);
}
- void push(Imm32 imm)
+ void push(TrustedImm32 imm)
{
move(imm, immTempRegister);
push(immTempRegister);
//
// Move values in registers.
- void move(Imm32 imm, RegisterID dest)
+ void move(TrustedImm32 imm, RegisterID dest)
{
if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth)
move(MIPSRegisters::zero, dest);
m_assembler.move(dest, src);
}
- void move(ImmPtr imm, RegisterID dest)
+ void move(TrustedImmPtr imm, RegisterID dest)
{
- move(Imm32(imm), dest);
+ move(TrustedImm32(imm), dest);
}
void swap(RegisterID reg1, RegisterID reg2)
// used (representing the names 'below' and 'above').
//
// Operands to the comparision are provided in the expected order, e.g.
- // jle32(reg1, Imm32(5)) will branch if the value held in reg1, when
+ // jle32(reg1, TrustedImm32(5)) will branch if the value held in reg1, when
// treated as a signed 32bit value, is less than or equal to 5.
//
// jz and jnz test whether the first operand is equal to zero, and take
// an optional second operand of a mask under which to perform the test.
- Jump branch8(Condition cond, Address left, Imm32 right)
+ Jump branch8(RelationalCondition cond, Address left, TrustedImm32 right)
{
// Make sure the immediate value is unsigned 8 bits.
ASSERT(!(right.m_value & 0xFFFFFF00));
return branch32(cond, dataTempRegister, immTempRegister);
}
- Jump branch32(Condition cond, RegisterID left, RegisterID right)
+ Jump branch32(RelationalCondition cond, RegisterID left, RegisterID right)
{
- if (cond == Equal || cond == Zero)
+ if (cond == Equal)
return branchEqual(left, right);
- if (cond == NotEqual || cond == NonZero)
+ if (cond == NotEqual)
return branchNotEqual(left, right);
if (cond == Above) {
m_assembler.sltu(cmpTempRegister, right, left);
m_assembler.slt(cmpTempRegister, right, left);
return branchEqual(cmpTempRegister, MIPSRegisters::zero);
}
- if (cond == Overflow) {
- /*
- xor cmpTemp, left, right
- bgez No_overflow, cmpTemp # same sign bit -> no overflow
- nop
- subu cmpTemp, left, right
- xor cmpTemp, cmpTemp, left
- bgez No_overflow, cmpTemp # same sign bit -> no overflow
- nop
- b Overflow
- nop
- nop
- nop
- nop
- nop
- No_overflow:
- */
- m_assembler.xorInsn(cmpTempRegister, left, right);
- m_assembler.bgez(cmpTempRegister, 11);
- m_assembler.nop();
- m_assembler.subu(cmpTempRegister, left, right);
- m_assembler.xorInsn(cmpTempRegister, cmpTempRegister, left);
- m_assembler.bgez(cmpTempRegister, 7);
- m_assembler.nop();
- return jump();
- }
- if (cond == Signed) {
- m_assembler.subu(cmpTempRegister, left, right);
- // Check if the result is negative.
- m_assembler.slt(cmpTempRegister, cmpTempRegister,
- MIPSRegisters::zero);
- return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
- }
ASSERT(0);
return Jump();
}
- Jump branch32(Condition cond, RegisterID left, Imm32 right)
+ Jump branch32(RelationalCondition cond, RegisterID left, TrustedImm32 right)
{
move(right, immTempRegister);
return branch32(cond, left, immTempRegister);
}
- Jump branch32(Condition cond, RegisterID left, Address right)
+ Jump branch32(RelationalCondition cond, RegisterID left, Address right)
{
load32(right, dataTempRegister);
return branch32(cond, left, dataTempRegister);
}
- Jump branch32(Condition cond, Address left, RegisterID right)
+ Jump branch32(RelationalCondition cond, Address left, RegisterID right)
{
load32(left, dataTempRegister);
return branch32(cond, dataTempRegister, right);
}
- Jump branch32(Condition cond, Address left, Imm32 right)
+ Jump branch32(RelationalCondition cond, Address left, TrustedImm32 right)
{
load32(left, dataTempRegister);
move(right, immTempRegister);
return branch32(cond, dataTempRegister, immTempRegister);
}
- Jump branch32(Condition cond, BaseIndex left, Imm32 right)
+ Jump branch32(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
{
load32(left, dataTempRegister);
// Be careful that the previous load32() uses immTempRegister.
return branch32(cond, dataTempRegister, immTempRegister);
}
- Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right)
+ Jump branch32WithUnalignedHalfWords(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
{
load32WithUnalignedHalfWords(left, dataTempRegister);
// Be careful that the previous load32WithUnalignedHalfWords()
return branch32(cond, dataTempRegister, immTempRegister);
}
- Jump branch32(Condition cond, AbsoluteAddress left, RegisterID right)
+ Jump branch32(RelationalCondition cond, AbsoluteAddress left, RegisterID right)
{
load32(left.m_ptr, dataTempRegister);
return branch32(cond, dataTempRegister, right);
}
- Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right)
+ Jump branch32(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right)
{
load32(left.m_ptr, dataTempRegister);
move(right, immTempRegister);
return branch32(cond, dataTempRegister, immTempRegister);
}
- Jump branch16(Condition cond, BaseIndex left, RegisterID right)
+ Jump branch16(RelationalCondition cond, BaseIndex left, RegisterID right)
{
load16(left, dataTempRegister);
return branch32(cond, dataTempRegister, right);
}
- Jump branch16(Condition cond, BaseIndex left, Imm32 right)
+ Jump branch16(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
{
ASSERT(!(right.m_value & 0xFFFF0000));
load16(left, dataTempRegister);
return branch32(cond, dataTempRegister, immTempRegister);
}
- Jump branchTest32(Condition cond, RegisterID reg, RegisterID mask)
+ Jump branchTest32(ResultCondition cond, RegisterID reg, RegisterID mask)
{
ASSERT((cond == Zero) || (cond == NonZero));
m_assembler.andInsn(cmpTempRegister, reg, mask);
return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
}
- Jump branchTest32(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1))
+ Jump branchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
{
ASSERT((cond == Zero) || (cond == NonZero));
if (mask.m_value == -1 && !m_fixedWidth) {
return branchTest32(cond, reg, immTempRegister);
}
- Jump branchTest32(Condition cond, Address address, Imm32 mask = Imm32(-1))
+ Jump branchTest32(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
{
load32(address, dataTempRegister);
return branchTest32(cond, dataTempRegister, mask);
}
- Jump branchTest32(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1))
+ Jump branchTest32(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
{
load32(address, dataTempRegister);
return branchTest32(cond, dataTempRegister, mask);
}
- Jump branchTest8(Condition cond, Address address, Imm32 mask = Imm32(-1))
+ Jump branchTest8(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
{
load8(address, dataTempRegister);
return branchTest32(cond, dataTempRegister, mask);
// * jo operations branch if the (signed) arithmetic
// operation caused an overflow to occur.
- Jump branchAdd32(Condition cond, RegisterID src, RegisterID dest)
+ Jump branchAdd32(ResultCondition cond, RegisterID src, RegisterID dest)
{
ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
if (cond == Overflow) {
return Jump();
}
- Jump branchAdd32(Condition cond, Imm32 imm, RegisterID dest)
+ Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
{
move(imm, immTempRegister);
return branchAdd32(cond, immTempRegister, dest);
}
- Jump branchMul32(Condition cond, RegisterID src, RegisterID dest)
+ Jump branchMul32(ResultCondition cond, RegisterID src, RegisterID dest)
{
ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
if (cond == Overflow) {
return Jump();
}
- Jump branchMul32(Condition cond, Imm32 imm, RegisterID src, RegisterID dest)
+ Jump branchMul32(ResultCondition cond, TrustedImm32 imm, RegisterID src, RegisterID dest)
{
move(imm, immTempRegister);
move(src, dest);
return branchMul32(cond, immTempRegister, dest);
}
- Jump branchSub32(Condition cond, RegisterID src, RegisterID dest)
+ Jump branchSub32(ResultCondition cond, RegisterID src, RegisterID dest)
{
ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
if (cond == Overflow) {
return Jump();
}
- Jump branchSub32(Condition cond, Imm32 imm, RegisterID dest)
+ Jump branchSub32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
{
move(imm, immTempRegister);
return branchSub32(cond, immTempRegister, dest);
}
+ Jump branchOr32(ResultCondition cond, RegisterID src, RegisterID dest)
+ {
+ ASSERT((cond == Signed) || (cond == Zero) || (cond == NonZero));
+ if (cond == Signed) {
+ or32(src, dest);
+ // Check if dest is negative.
+ m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
+ return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
+ }
+ if (cond == Zero) {
+ or32(src, dest);
+ return branchEqual(dest, MIPSRegisters::zero);
+ }
+ if (cond == NonZero) {
+ or32(src, dest);
+ return branchNotEqual(dest, MIPSRegisters::zero);
+ }
+ ASSERT(0);
+ return Jump();
+ }
+
// Miscellaneous operations:
void breakpoint()
m_assembler.nop();
m_assembler.jal();
m_assembler.nop();
- return Call(m_assembler.newJmpSrc(), Call::LinkableNear);
+ return Call(m_assembler.label(), Call::LinkableNear);
}
Call call()
m_assembler.ori(MIPSRegisters::t9, MIPSRegisters::t9, 0);
m_assembler.jalr(MIPSRegisters::t9);
m_assembler.nop();
- return Call(m_assembler.newJmpSrc(), Call::Linkable);
+ return Call(m_assembler.label(), Call::Linkable);
}
Call call(RegisterID target)
{
m_assembler.jalr(target);
m_assembler.nop();
- return Call(m_assembler.newJmpSrc(), Call::None);
+ return Call(m_assembler.label(), Call::None);
}
Call call(Address address)
m_assembler.jalr(MIPSRegisters::t9);
m_assembler.nop();
m_fixedWidth = false;
- return Call(m_assembler.newJmpSrc(), Call::None);
+ return Call(m_assembler.label(), Call::None);
}
void ret()
m_assembler.nop();
}
- void set32(Condition cond, RegisterID left, RegisterID right, RegisterID dest)
+ void compare32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID dest)
{
- if (cond == Equal || cond == Zero) {
+ if (cond == Equal) {
m_assembler.xorInsn(dest, left, right);
m_assembler.sltiu(dest, dest, 1);
- } else if (cond == NotEqual || cond == NonZero) {
+ } else if (cond == NotEqual) {
m_assembler.xorInsn(dest, left, right);
m_assembler.sltu(dest, MIPSRegisters::zero, dest);
} else if (cond == Above)
else if (cond == LessThanOrEqual) {
m_assembler.slt(dest, right, left);
m_assembler.xori(dest, dest, 1);
- } else if (cond == Overflow) {
- /*
- xor cmpTemp, left, right
- bgez Done, cmpTemp # same sign bit -> no overflow
- move dest, 0
- subu cmpTemp, left, right
- xor cmpTemp, cmpTemp, left # diff sign bit -> overflow
- slt dest, cmpTemp, 0
- Done:
- */
- m_assembler.xorInsn(cmpTempRegister, left, right);
- m_assembler.bgez(cmpTempRegister, 4);
- m_assembler.move(dest, MIPSRegisters::zero);
- m_assembler.subu(cmpTempRegister, left, right);
- m_assembler.xorInsn(cmpTempRegister, cmpTempRegister, left);
- m_assembler.slt(dest, cmpTempRegister, MIPSRegisters::zero);
- } else if (cond == Signed) {
- m_assembler.subu(dest, left, right);
- // Check if the result is negative.
- m_assembler.slt(dest, dest, MIPSRegisters::zero);
}
}
- void set32(Condition cond, RegisterID left, Imm32 right, RegisterID dest)
+ void compare32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
{
move(right, immTempRegister);
- set32(cond, left, immTempRegister, dest);
+ compare32(cond, left, immTempRegister, dest);
}
- void setTest8(Condition cond, Address address, Imm32 mask, RegisterID dest)
+ void test8(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
{
ASSERT((cond == Zero) || (cond == NonZero));
load8(address, dataTempRegister);
}
}
- void setTest32(Condition cond, Address address, Imm32 mask, RegisterID dest)
+ void test32(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
{
ASSERT((cond == Zero) || (cond == NonZero));
load32(address, dataTempRegister);
}
}
- DataLabel32 moveWithPatch(Imm32 imm, RegisterID dest)
+ DataLabel32 moveWithPatch(TrustedImm32 imm, RegisterID dest)
{
m_fixedWidth = true;
DataLabel32 label(this);
return label;
}
- DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest)
+ DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
{
m_fixedWidth = true;
DataLabelPtr label(this);
return label;
}
- Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0))
+ Jump branchPtrWithPatch(RelationalCondition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
{
m_fixedWidth = true;
dataLabel = moveWithPatch(initialRightValue, immTempRegister);
return temp;
}
- Jump branchPtrWithPatch(Condition cond, Address left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0))
+ Jump branchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
{
m_fixedWidth = true;
load32(left, dataTempRegister);
return temp;
}
- DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address)
+ DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
{
m_fixedWidth = true;
DataLabelPtr dataLabel = moveWithPatch(initialValue, dataTempRegister);
DataLabelPtr storePtrWithPatch(ImplicitAddress address)
{
- return storePtrWithPatch(ImmPtr(0), address);
+ return storePtrWithPatch(TrustedImmPtr(0), address);
}
Call tailRecursiveCall()
{
// Like a normal call, but don't update the returned address register
m_fixedWidth = true;
- move(Imm32(0), MIPSRegisters::t9);
+ move(TrustedImm32(0), MIPSRegisters::t9);
m_assembler.jr(MIPSRegisters::t9);
m_assembler.nop();
m_fixedWidth = false;
- return Call(m_assembler.newJmpSrc(), Call::Linkable);
+ return Call(m_assembler.label(), Call::Linkable);
}
Call makeTailRecursiveCall(Jump oldJump)
lwc1 dest, 0(addrTemp)
lwc1 dest+1, 4(addrTemp)
*/
- move(Imm32(address.offset), addrTempRegister);
+ move(TrustedImm32(address.offset), addrTempRegister);
m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
m_assembler.lwc1(dest, addrTempRegister, 0);
m_assembler.lwc1(FPRegisterID(dest + 1), addrTempRegister, 4);
#endif
}
+ void loadDouble(const void* address, FPRegisterID dest)
+ {
+#if WTF_MIPS_ISA(1)
+ /*
+ li addrTemp, address
+ lwc1 dest, 0(addrTemp)
+ lwc1 dest+1, 4(addrTemp)
+ */
+ move(TrustedImmPtr(address), addrTempRegister);
+ m_assembler.lwc1(dest, addrTempRegister, 0);
+ m_assembler.lwc1(FPRegisterID(dest + 1), addrTempRegister, 4);
+#else
+ /*
+ li addrTemp, address
+ ldc1 dest, 0(addrTemp)
+ */
+ move(TrustedImmPtr(address), addrTempRegister);
+ m_assembler.ldc1(dest, addrTempRegister, 0);
+#endif
+ }
+
+
void storeDouble(FPRegisterID src, ImplicitAddress address)
{
#if WTF_MIPS_ISA(1)
swc1 dest, 0(addrTemp)
swc1 dest+1, 4(addrTemp)
*/
- move(Imm32(address.offset), addrTempRegister);
+ move(TrustedImm32(address.offset), addrTempRegister);
m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
m_assembler.swc1(src, addrTempRegister, 0);
m_assembler.swc1(FPRegisterID(src + 1), addrTempRegister, 4);
m_assembler.muld(dest, dest, fpTempRegister);
}
+ void divDouble(FPRegisterID src, FPRegisterID dest)
+ {
+ m_assembler.divd(dest, dest, src);
+ }
+
void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
{
m_assembler.mtc1(src, fpTempRegister);
m_assembler.cvtdw(dest, fpTempRegister);
}
+ void convertInt32ToDouble(Address src, FPRegisterID dest)
+ {
+ load32(src, dataTempRegister);
+ m_assembler.mtc1(dataTempRegister, fpTempRegister);
+ m_assembler.cvtdw(dest, fpTempRegister);
+ }
+
+ void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest)
+ {
+ load32(src.m_ptr, dataTempRegister);
+ m_assembler.mtc1(dataTempRegister, fpTempRegister);
+ m_assembler.cvtdw(dest, fpTempRegister);
+ }
+
void insertRelaxationWords()
{
/* We need four words for relaxation. */
m_assembler.bc1t();
m_assembler.nop();
insertRelaxationWords();
- return Jump(m_assembler.newJmpSrc());
+ return Jump(m_assembler.label());
}
Jump branchFalse()
m_assembler.bc1f();
m_assembler.nop();
insertRelaxationWords();
- return Jump(m_assembler.newJmpSrc());
+ return Jump(m_assembler.label());
}
Jump branchEqual(RegisterID rs, RegisterID rt)
m_assembler.beq(rs, rt, 0);
m_assembler.nop();
insertRelaxationWords();
- return Jump(m_assembler.newJmpSrc());
+ return Jump(m_assembler.label());
}
Jump branchNotEqual(RegisterID rs, RegisterID rt)
m_assembler.bne(rs, rt, 0);
m_assembler.nop();
insertRelaxationWords();
- return Jump(m_assembler.newJmpSrc());
+ return Jump(m_assembler.label());
}
Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
return branchTrue();
}
if (cond == DoubleNotEqual) {
- m_assembler.ceqd(left, right);
+ m_assembler.cueqd(left, right);
return branchFalse(); // false
}
if (cond == DoubleGreaterThan) {
return branchFalse(); // false
}
if (cond == DoubleGreaterThanOrEqual) {
- m_assembler.cnged(right, left);
+ m_assembler.cnged(left, right);
return branchFalse(); // false
}
if (cond == DoubleLessThan) {
m_assembler.cueqd(left, right);
return branchTrue();
}
+ if (cond == DoubleNotEqualOrUnordered) {
+ m_assembler.ceqd(left, right);
+ return branchFalse(); // false
+ }
if (cond == DoubleGreaterThanOrUnordered) {
m_assembler.coled(left, right);
return branchFalse(); // false
{
m_assembler.truncwd(fpTempRegister, src);
m_assembler.mfc1(dest, fpTempRegister);
- return branch32(Equal, dest, Imm32(0x7fffffff));
+ return branch32(Equal, dest, TrustedImm32(0x7fffffff));
+ }
+
+ // Convert 'src' to an integer, and places the resulting 'dest'.
+ // If the result is not representable as a 32 bit value, branch.
+ // May also branch for some values that are representable in 32 bits
+ // (specifically, in this case, 0).
+ void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID fpTemp)
+ {
+ m_assembler.cvtwd(fpTempRegister, src);
+ m_assembler.mfc1(dest, fpTempRegister);
+
+ // If the result is zero, it might have been -0.0, and the double comparison won't catch this!
+ failureCases.append(branch32(Equal, dest, MIPSRegisters::zero));
+
+ // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump.
+ convertInt32ToDouble(dest, fpTemp);
+ failureCases.append(branchDouble(DoubleNotEqualOrUnordered, fpTemp, src));
+ }
+
+ Jump branchDoubleNonZero(FPRegisterID reg, FPRegisterID scratch)
+ {
+#if WTF_MIPS_ISA_REV(2) && WTF_MIPS_FP64
+ m_assembler.mtc1(MIPSRegisters::zero, scratch);
+ m_assembler.mthc1(MIPSRegisters::zero, scratch);
+#else
+ m_assembler.mtc1(MIPSRegisters::zero, scratch);
+ m_assembler.mtc1(MIPSRegisters::zero, FPRegisterID(scratch + 1));
+#endif
+ return branchDouble(DoubleNotEqual, reg, scratch);
+ }
+
+ Jump branchDoubleZeroOrNaN(FPRegisterID reg, FPRegisterID scratch)
+ {
+#if WTF_MIPS_ISA_REV(2) && WTF_MIPS_FP64
+ m_assembler.mtc1(MIPSRegisters::zero, scratch);
+ m_assembler.mthc1(MIPSRegisters::zero, scratch);
+#else
+ m_assembler.mtc1(MIPSRegisters::zero, scratch);
+ m_assembler.mtc1(MIPSRegisters::zero, FPRegisterID(scratch + 1));
+#endif
+ return branchDouble(DoubleEqualOrUnordered, reg, scratch);
+ }
+
+ void nop()
+ {
+ m_assembler.nop();
}
private:
--- /dev/null
+/*
+ * Copyright (C) 2011 STMicroelectronics. All rights reserved.
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "config.h"
+
+#if ENABLE(ASSEMBLER) && CPU(SH4)
+
+#include "MacroAssemblerSH4.h"
+
+namespace JSC {
+
+void MacroAssemblerSH4::linkCall(void* code, Call call, FunctionPtr function)
+{
+ SH4Assembler::linkCall(code, call.m_jmp, function.value());
+}
+
+void MacroAssemblerSH4::repatchCall(CodeLocationCall call, CodeLocationLabel destination)
+{
+ SH4Assembler::relinkCall(call.dataLocation(), destination.executableAddress());
+}
+
+void MacroAssemblerSH4::repatchCall(CodeLocationCall call, FunctionPtr destination)
+{
+ SH4Assembler::relinkCall(call.dataLocation(), destination.executableAddress());
+}
+
+} // namespace JSC
+
+#endif // ENABLE(ASSEMBLER)
--- /dev/null
+/*
+ * Copyright (C) 2009-2011 STMicroelectronics. All rights reserved.
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MacroAssemblerSH4_h
+#define MacroAssemblerSH4_h
+
+#if ENABLE(ASSEMBLER) && CPU(SH4)
+
+#include "AbstractMacroAssembler.h"
+#include "SH4Assembler.h"
+#include <wtf/Assertions.h>
+
+namespace JSC {
+
+class MacroAssemblerSH4 : public AbstractMacroAssembler<SH4Assembler> {
+public:
+ typedef SH4Assembler::FPRegisterID FPRegisterID;
+
+ static const Scale ScalePtr = TimesFour;
+ static const FPRegisterID fscratch = SH4Registers::fr10;
+ static const RegisterID stackPointerRegister = SH4Registers::sp;
+ static const RegisterID linkRegister = SH4Registers::pr;
+ static const RegisterID scratchReg3 = SH4Registers::r13;
+
+ static const int MaximumCompactPtrAlignedAddressOffset = 0x7FFFFFFF;
+
+ enum RelationalCondition {
+ Equal = SH4Assembler::EQ,
+ NotEqual = SH4Assembler::NE,
+ Above = SH4Assembler::HI,
+ AboveOrEqual = SH4Assembler::HS,
+ Below = SH4Assembler::LI,
+ BelowOrEqual = SH4Assembler::LS,
+ GreaterThan = SH4Assembler::GT,
+ GreaterThanOrEqual = SH4Assembler::GE,
+ LessThan = SH4Assembler::LT,
+ LessThanOrEqual = SH4Assembler::LE
+ };
+
+ enum ResultCondition {
+ Overflow = SH4Assembler::OF,
+ Signed = SH4Assembler::SI,
+ Zero = SH4Assembler::EQ,
+ NonZero = SH4Assembler::NE
+ };
+
+ enum DoubleCondition {
+ // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN.
+ DoubleEqual = SH4Assembler::EQ,
+ DoubleNotEqual = SH4Assembler::NE,
+ DoubleGreaterThan = SH4Assembler::GT,
+ DoubleGreaterThanOrEqual = SH4Assembler::GE,
+ DoubleLessThan = SH4Assembler::LT,
+ DoubleLessThanOrEqual = SH4Assembler::LE,
+ // If either operand is NaN, these conditions always evaluate to true.
+ DoubleEqualOrUnordered = SH4Assembler::EQU,
+ DoubleNotEqualOrUnordered = SH4Assembler::NEU,
+ DoubleGreaterThanOrUnordered = SH4Assembler::GTU,
+ DoubleGreaterThanOrEqualOrUnordered = SH4Assembler::GEU,
+ DoubleLessThanOrUnordered = SH4Assembler::LTU,
+ DoubleLessThanOrEqualOrUnordered = SH4Assembler::LEU,
+ };
+
+ RegisterID claimScratch()
+ {
+ return m_assembler.claimScratch();
+ }
+
+ void releaseScratch(RegisterID reg)
+ {
+ m_assembler.releaseScratch(reg);
+ }
+
+ // Integer arithmetic operations
+
+ void add32(RegisterID src, RegisterID dest)
+ {
+ m_assembler.addlRegReg(src, dest);
+ }
+
+ void add32(TrustedImm32 imm, RegisterID dest)
+ {
+ if (m_assembler.isImmediate(imm.m_value)) {
+ m_assembler.addlImm8r(imm.m_value, dest);
+ return;
+ }
+
+ RegisterID scr = claimScratch();
+ m_assembler.loadConstant(imm.m_value, scr);
+ m_assembler.addlRegReg(scr, dest);
+ releaseScratch(scr);
+ }
+
+ void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
+ {
+ if (src != dest)
+ m_assembler.movlRegReg(src, dest);
+ add32(imm, dest);
+ }
+
+ void add32(TrustedImm32 imm, Address address)
+ {
+ RegisterID scr = claimScratch();
+ load32(address, scr);
+ add32(imm, scr);
+ store32(scr, address);
+ releaseScratch(scr);
+ }
+
+ void add32(Address src, RegisterID dest)
+ {
+ RegisterID scr = claimScratch();
+ load32(src, scr);
+ m_assembler.addlRegReg(scr, dest);
+ releaseScratch(scr);
+ }
+
+ void and32(RegisterID src, RegisterID dest)
+ {
+ m_assembler.andlRegReg(src, dest);
+ }
+
+ void and32(TrustedImm32 imm, RegisterID dest)
+ {
+ if ((imm.m_value <= 255) && (imm.m_value >= 0) && (dest == SH4Registers::r0)) {
+ m_assembler.andlImm8r(imm.m_value, dest);
+ return;
+ }
+
+ RegisterID scr = claimScratch();
+ m_assembler.loadConstant((imm.m_value), scr);
+ m_assembler.andlRegReg(scr, dest);
+ releaseScratch(scr);
+ }
+
+ void lshift32(RegisterID shiftamount, RegisterID dest)
+ {
+ m_assembler.shllRegReg(dest, shiftamount);
+ }
+
+ void rshift32(int imm, RegisterID dest)
+ {
+ RegisterID scr = claimScratch();
+ m_assembler.loadConstant(-imm, scr);
+ m_assembler.shaRegReg(dest, scr);
+ releaseScratch(scr);
+ }
+
+ void lshift32(TrustedImm32 imm, RegisterID dest)
+ {
+ if ((imm.m_value == 1) || (imm.m_value == 2) || (imm.m_value == 8) || (imm.m_value == 16)) {
+ m_assembler.shllImm8r(imm.m_value, dest);
+ return;
+ }
+
+ RegisterID scr = claimScratch();
+ m_assembler.loadConstant(imm.m_value, scr);
+ m_assembler.shllRegReg(dest, scr);
+ releaseScratch(scr);
+ }
+
+ void mul32(RegisterID src, RegisterID dest)
+ {
+ m_assembler.imullRegReg(src, dest);
+ m_assembler.stsmacl(dest);
+ }
+
+ void mul32(TrustedImm32 imm, RegisterID src, RegisterID dest)
+ {
+ RegisterID scr = claimScratch();
+ move(imm, scr);
+ if (src != dest)
+ move(src, dest);
+ mul32(scr, dest);
+ releaseScratch(scr);
+ }
+
+ void not32(RegisterID src, RegisterID dest)
+ {
+ m_assembler.notlReg(src, dest);
+ }
+
+ void or32(RegisterID src, RegisterID dest)
+ {
+ m_assembler.orlRegReg(src, dest);
+ }
+
+ void or32(TrustedImm32 imm, RegisterID dest)
+ {
+ if ((imm.m_value <= 255) && (imm.m_value >= 0) && (dest == SH4Registers::r0)) {
+ m_assembler.orlImm8r(imm.m_value, dest);
+ return;
+ }
+
+ RegisterID scr = claimScratch();
+ m_assembler.loadConstant(imm.m_value, scr);
+ m_assembler.orlRegReg(scr, dest);
+ releaseScratch(scr);
+ }
+
+ void rshift32(RegisterID shiftamount, RegisterID dest)
+ {
+ compare32(32, shiftamount, Equal);
+ m_assembler.ensureSpace(m_assembler.maxInstructionSize + 4);
+ m_assembler.branch(BT_OPCODE, 1);
+ m_assembler.neg(shiftamount, shiftamount);
+ m_assembler.shaRegReg(dest, shiftamount);
+ }
+
+ void rshift32(TrustedImm32 imm, RegisterID dest)
+ {
+ if (imm.m_value & 0x1f)
+ rshift32(imm.m_value & 0x1f, dest);
+ }
+
+ void sub32(RegisterID src, RegisterID dest)
+ {
+ m_assembler.sublRegReg(src, dest);
+ }
+
+ void sub32(TrustedImm32 imm, AbsoluteAddress address, RegisterID scratchReg)
+ {
+ RegisterID result = claimScratch();
+
+ m_assembler.loadConstant(reinterpret_cast<uint32_t>(address.m_ptr), scratchReg);
+ m_assembler.movlMemReg(scratchReg, result);
+
+ if (m_assembler.isImmediate(-imm.m_value))
+ m_assembler.addlImm8r(-imm.m_value, result);
+ else {
+ m_assembler.loadConstant(imm.m_value, scratchReg3);
+ m_assembler.sublRegReg(scratchReg3, result);
+ }
+
+ store32(result, scratchReg);
+ releaseScratch(result);
+ }
+
+ void sub32(TrustedImm32 imm, AbsoluteAddress address)
+ {
+ RegisterID result = claimScratch();
+ RegisterID scratchReg = claimScratch();
+
+ m_assembler.loadConstant(reinterpret_cast<uint32_t>(address.m_ptr), scratchReg);
+ m_assembler.movlMemReg(scratchReg, result);
+
+ if (m_assembler.isImmediate(-imm.m_value))
+ m_assembler.addlImm8r(-imm.m_value, result);
+ else {
+ m_assembler.loadConstant(imm.m_value, scratchReg3);
+ m_assembler.sublRegReg(scratchReg3, result);
+ }
+
+ store32(result, scratchReg);
+ releaseScratch(result);
+ releaseScratch(scratchReg);
+ }
+
+ void add32(TrustedImm32 imm, AbsoluteAddress address, RegisterID scratchReg)
+ {
+ RegisterID result = claimScratch();
+
+ m_assembler.loadConstant(reinterpret_cast<uint32_t>(address.m_ptr), scratchReg);
+ m_assembler.movlMemReg(scratchReg, result);
+
+ if (m_assembler.isImmediate(imm.m_value))
+ m_assembler.addlImm8r(imm.m_value, result);
+ else {
+ m_assembler.loadConstant(imm.m_value, scratchReg3);
+ m_assembler.addlRegReg(scratchReg3, result);
+ }
+
+ store32(result, scratchReg);
+ releaseScratch(result);
+ }
+
+ void add32(TrustedImm32 imm, AbsoluteAddress address)
+ {
+ RegisterID result = claimScratch();
+ RegisterID scratchReg = claimScratch();
+
+ m_assembler.loadConstant(reinterpret_cast<uint32_t>(address.m_ptr), scratchReg);
+ m_assembler.movlMemReg(scratchReg, result);
+
+ if (m_assembler.isImmediate(imm.m_value))
+ m_assembler.addlImm8r(imm.m_value, result);
+ else {
+ m_assembler.loadConstant(imm.m_value, scratchReg3);
+ m_assembler.addlRegReg(scratchReg3, result);
+ }
+
+ store32(result, scratchReg);
+ releaseScratch(result);
+ releaseScratch(scratchReg);
+ }
+
+ void sub32(TrustedImm32 imm, RegisterID dest)
+ {
+ if (m_assembler.isImmediate(-imm.m_value)) {
+ m_assembler.addlImm8r(-imm.m_value, dest);
+ return;
+ }
+
+ RegisterID scr = claimScratch();
+ m_assembler.loadConstant(imm.m_value, scr);
+ m_assembler.sublRegReg(scr, dest);
+ releaseScratch(scr);
+ }
+
+ void sub32(Address src, RegisterID dest)
+ {
+ RegisterID scr = claimScratch();
+ load32(src, scr);
+ m_assembler.sublRegReg(scr, dest);
+ releaseScratch(scr);
+ }
+
+ void xor32(RegisterID src, RegisterID dest)
+ {
+ m_assembler.xorlRegReg(src, dest);
+ }
+
+ void xor32(TrustedImm32 imm, RegisterID srcDest)
+ {
+ if ((srcDest != SH4Registers::r0) || (imm.m_value > 255) || (imm.m_value < 0)) {
+ RegisterID scr = claimScratch();
+ m_assembler.loadConstant((imm.m_value), scr);
+ m_assembler.xorlRegReg(scr, srcDest);
+ releaseScratch(scr);
+ return;
+ }
+
+ m_assembler.xorlImm8r(imm.m_value, srcDest);
+ }
+
+ void compare32(int imm, RegisterID dst, RelationalCondition cond)
+ {
+ if (((cond == Equal) || (cond == NotEqual)) && (dst == SH4Registers::r0) && m_assembler.isImmediate(imm)) {
+ m_assembler.cmpEqImmR0(imm, dst);
+ return;
+ }
+
+ RegisterID scr = claimScratch();
+ m_assembler.loadConstant(imm, scr);
+ m_assembler.cmplRegReg(scr, dst, SH4Condition(cond));
+ releaseScratch(scr);
+ }
+
+ void compare32(int offset, RegisterID base, RegisterID left, RelationalCondition cond)
+ {
+ RegisterID scr = claimScratch();
+ if (!offset) {
+ m_assembler.movlMemReg(base, scr);
+ m_assembler.cmplRegReg(scr, left, SH4Condition(cond));
+ releaseScratch(scr);
+ return;
+ }
+
+ if ((offset < 0) || (offset >= 64)) {
+ m_assembler.loadConstant(offset, scr);
+ m_assembler.addlRegReg(base, scr);
+ m_assembler.movlMemReg(scr, scr);
+ m_assembler.cmplRegReg(scr, left, SH4Condition(cond));
+ releaseScratch(scr);
+ return;
+ }
+
+ m_assembler.movlMemReg(offset >> 2, base, scr);
+ m_assembler.cmplRegReg(scr, left, SH4Condition(cond));
+ releaseScratch(scr);
+ }
+
+ void testImm(int imm, int offset, RegisterID base)
+ {
+ RegisterID scr = claimScratch();
+ RegisterID scr1 = claimScratch();
+
+ if ((offset < 0) || (offset >= 64)) {
+ m_assembler.loadConstant(offset, scr);
+ m_assembler.addlRegReg(base, scr);
+ m_assembler.movlMemReg(scr, scr);
+ } else if (offset)
+ m_assembler.movlMemReg(offset >> 2, base, scr);
+ else
+ m_assembler.movlMemReg(base, scr);
+ if (m_assembler.isImmediate(imm))
+ m_assembler.movImm8(imm, scr1);
+ else
+ m_assembler.loadConstant(imm, scr1);
+
+ m_assembler.testlRegReg(scr, scr1);
+ releaseScratch(scr);
+ releaseScratch(scr1);
+ }
+
+ void testlImm(int imm, RegisterID dst)
+ {
+ if ((dst == SH4Registers::r0) && (imm <= 255) && (imm >= 0)) {
+ m_assembler.testlImm8r(imm, dst);
+ return;
+ }
+
+ RegisterID scr = claimScratch();
+ m_assembler.loadConstant(imm, scr);
+ m_assembler.testlRegReg(scr, dst);
+ releaseScratch(scr);
+ }
+
+ void compare32(RegisterID right, int offset, RegisterID base, RelationalCondition cond)
+ {
+ if (!offset) {
+ RegisterID scr = claimScratch();
+ m_assembler.movlMemReg(base, scr);
+ m_assembler.cmplRegReg(right, scr, SH4Condition(cond));
+ releaseScratch(scr);
+ return;
+ }
+
+ if ((offset < 0) || (offset >= 64)) {
+ RegisterID scr = claimScratch();
+ m_assembler.loadConstant(offset, scr);
+ m_assembler.addlRegReg(base, scr);
+ m_assembler.movlMemReg(scr, scr);
+ m_assembler.cmplRegReg(right, scr, SH4Condition(cond));
+ releaseScratch(scr);
+ return;
+ }
+
+ RegisterID scr = claimScratch();
+ m_assembler.movlMemReg(offset >> 2, base, scr);
+ m_assembler.cmplRegReg(right, scr, SH4Condition(cond));
+ releaseScratch(scr);
+ }
+
+ void compare32(int imm, int offset, RegisterID base, RelationalCondition cond)
+ {
+ if (!offset) {
+ RegisterID scr = claimScratch();
+ RegisterID scr1 = claimScratch();
+ m_assembler.movlMemReg(base, scr);
+ m_assembler.loadConstant(imm, scr1);
+ m_assembler.cmplRegReg(scr1, scr, SH4Condition(cond));
+ releaseScratch(scr1);
+ releaseScratch(scr);
+ return;
+ }
+
+ if ((offset < 0) || (offset >= 64)) {
+ RegisterID scr = claimScratch();
+ RegisterID scr1 = claimScratch();
+ m_assembler.loadConstant(offset, scr);
+ m_assembler.addlRegReg(base, scr);
+ m_assembler.movlMemReg(scr, scr);
+ m_assembler.loadConstant(imm, scr1);
+ m_assembler.cmplRegReg(scr1, scr, SH4Condition(cond));
+ releaseScratch(scr1);
+ releaseScratch(scr);
+ return;
+ }
+
+ RegisterID scr = claimScratch();
+ RegisterID scr1 = claimScratch();
+ m_assembler.movlMemReg(offset >> 2, base, scr);
+ m_assembler.loadConstant(imm, scr1);
+ m_assembler.cmplRegReg(scr1, scr, SH4Condition(cond));
+ releaseScratch(scr1);
+ releaseScratch(scr);
+ }
+
+ // Memory access operation
+
+ void load32(ImplicitAddress address, RegisterID dest)
+ {
+ load32(address.base, address.offset, dest);
+ }
+
+ void load8(ImplicitAddress address, RegisterID dest)
+ {
+ load8(address.base, address.offset, dest);
+ }
+
+ void load32(BaseIndex address, RegisterID dest)
+ {
+ RegisterID scr = claimScratch();
+ move(address.index, scr);
+ lshift32(TrustedImm32(address.scale), scr);
+ add32(address.base, scr);
+ load32(scr, address.offset, dest);
+ releaseScratch(scr);
+ }
+
+ void load32(void* address, RegisterID dest)
+ {
+ m_assembler.loadConstant(reinterpret_cast<uint32_t>(address), dest);
+ m_assembler.movlMemReg(dest, dest);
+ }
+
+ void load32(RegisterID base, int offset, RegisterID dest)
+ {
+ if (!offset) {
+ m_assembler.movlMemReg(base, dest);
+ return;
+ }
+
+ if ((offset >= 0) && (offset < 64)) {
+ m_assembler.movlMemReg(offset >> 2, base, dest);
+ return;
+ }
+
+ if ((dest == SH4Registers::r0) && (dest != base)) {
+ m_assembler.loadConstant((offset), dest);
+ m_assembler.movlR0mr(base, dest);
+ return;
+ }
+
+ RegisterID scr;
+ if (dest == base)
+ scr = claimScratch();
+ else
+ scr = dest;
+ m_assembler.loadConstant((offset), scr);
+ m_assembler.addlRegReg(base, scr);
+ m_assembler.movlMemReg(scr, dest);
+
+ if (dest == base)
+ releaseScratch(scr);
+ }
+
+ void load8(RegisterID base, int offset, RegisterID dest)
+ {
+ if (!offset) {
+ m_assembler.movbMemReg(base, dest);
+ return;
+ }
+
+ if ((offset > 0) && (offset < 64) && (dest == SH4Registers::r0)) {
+ m_assembler.movbMemReg(offset, base, dest);
+ return;
+ }
+
+ if (base != dest) {
+ m_assembler.loadConstant((offset), dest);
+ m_assembler.addlRegReg(base, dest);
+ m_assembler.movbMemReg(dest, dest);
+ return;
+ }
+
+ RegisterID scr = claimScratch();
+ m_assembler.loadConstant((offset), scr);
+ m_assembler.addlRegReg(base, scr);
+ m_assembler.movbMemReg(scr, dest);
+ releaseScratch(scr);
+ }
+
+ void load32(RegisterID r0, RegisterID src, RegisterID dst)
+ {
+ ASSERT(r0 == SH4Registers::r0);
+ m_assembler.movlR0mr(src, dst);
+ }
+
+ void load32(RegisterID src, RegisterID dst)
+ {
+ m_assembler.movlMemReg(src, dst);
+ }
+
+ void load16(ImplicitAddress address, RegisterID dest)
+ {
+ if (!address.offset) {
+ m_assembler.movwMemReg(address.base, dest);
+ return;
+ }
+
+ if ((address.offset > 0) && (address.offset < 64) && (dest == SH4Registers::r0)) {
+ m_assembler.movwMemReg(address.offset, address.base, dest);
+ return;
+ }
+
+ if (address.base != dest) {
+ m_assembler.loadConstant((address.offset), dest);
+ m_assembler.addlRegReg(address.base, dest);
+ m_assembler.movwMemReg(dest, dest);
+ return;
+ }
+
+ RegisterID scr = claimScratch();
+ m_assembler.loadConstant((address.offset), scr);
+ m_assembler.addlRegReg(address.base, scr);
+ m_assembler.movwMemReg(scr, dest);
+ releaseScratch(scr);
+ }
+
+ void load16(RegisterID src, RegisterID dest)
+ {
+ m_assembler.movwMemReg(src, dest);
+ }
+
+ void load16(RegisterID r0, RegisterID src, RegisterID dest)
+ {
+ ASSERT(r0 == SH4Registers::r0);
+ m_assembler.movwR0mr(src, dest);
+ }
+
+ void load16(BaseIndex address, RegisterID dest)
+ {
+ RegisterID scr = claimScratch();
+
+ move(address.index, scr);
+ lshift32(TrustedImm32(address.scale), scr);
+
+ if (address.offset)
+ add32(TrustedImm32(address.offset), scr);
+ if (scr == SH4Registers::r0)
+ m_assembler.movwR0mr(address.base, scr);
+ else {
+ add32(address.base, scr);
+ load16(scr, scr);
+ }
+
+ extuw(scr, dest);
+ releaseScratch(scr);
+ }
+
+ void store32(RegisterID src, ImplicitAddress address)
+ {
+ RegisterID scr = claimScratch();
+ store32(src, address.offset, address.base, scr);
+ releaseScratch(scr);
+ }
+
+ void store32(RegisterID src, int offset, RegisterID base, RegisterID scr)
+ {
+ if (!offset) {
+ m_assembler.movlRegMem(src, base);
+ return;
+ }
+
+ if ((offset >=0) && (offset < 64)) {
+ m_assembler.movlRegMem(src, offset >> 2, base);
+ return;
+ }
+
+ m_assembler.loadConstant((offset), scr);
+ if (scr == SH4Registers::r0) {
+ m_assembler.movlRegMemr0(src, base);
+ return;
+ }
+
+ m_assembler.addlRegReg(base, scr);
+ m_assembler.movlRegMem(src, scr);
+ }
+
+ void store32(RegisterID src, RegisterID offset, RegisterID base)
+ {
+ ASSERT(offset == SH4Registers::r0);
+ m_assembler.movlRegMemr0(src, base);
+ }
+
+ void store32(RegisterID src, RegisterID dst)
+ {
+ m_assembler.movlRegMem(src, dst);
+ }
+
+ void store32(TrustedImm32 imm, ImplicitAddress address)
+ {
+ RegisterID scr = claimScratch();
+ RegisterID scr1 = claimScratch();
+ m_assembler.loadConstant((imm.m_value), scr);
+ store32(scr, address.offset, address.base, scr1);
+ releaseScratch(scr);
+ releaseScratch(scr1);
+ }
+
+ void store32(RegisterID src, BaseIndex address)
+ {
+ RegisterID scr = claimScratch();
+
+ move(address.index, scr);
+ lshift32(TrustedImm32(address.scale), scr);
+ add32(address.base, scr);
+ store32(src, Address(scr, address.offset));
+
+ releaseScratch(scr);
+ }
+
+ void store32(TrustedImm32 imm, void* address)
+ {
+ RegisterID scr = claimScratch();
+ RegisterID scr1 = claimScratch();
+ m_assembler.loadConstant((imm.m_value), scr);
+ m_assembler.loadConstant(reinterpret_cast<uint32_t>(address), scr1);
+ m_assembler.movlMemReg(scr, scr1);
+ releaseScratch(scr);
+ releaseScratch(scr1);
+ }
+
+ void store32(RegisterID src, void* address)
+ {
+ RegisterID scr = claimScratch();
+ m_assembler.loadConstant(reinterpret_cast<uint32_t>(address), scr);
+ m_assembler.movlMemReg(src, scr);
+ releaseScratch(scr);
+ }
+
+ DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest)
+ {
+ RegisterID scr = claimScratch();
+ DataLabel32 label(this);
+ m_assembler.loadConstantUnReusable(address.offset, scr);
+ m_assembler.addlRegReg(address.base, scr);
+ m_assembler.movlMemReg(scr, dest);
+ releaseScratch(scr);
+ return label;
+ }
+
+ DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest)
+ {
+ RegisterID scr = claimScratch();
+ DataLabelCompact label(this);
+ m_assembler.loadConstantUnReusable(address.offset, scr);
+ m_assembler.addlRegReg(address.base, scr);
+ m_assembler.movlMemReg(scr, dest);
+ releaseScratch(scr);
+ return label;
+ }
+
+ DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
+ {
+ RegisterID scr = claimScratch();
+ DataLabel32 label(this);
+ m_assembler.loadConstantUnReusable(address.offset, scr);
+ m_assembler.addlRegReg(address.base, scr);
+ m_assembler.movlRegMem(src, scr);
+ releaseScratch(scr);
+ return label;
+ }
+
+ // Floating-point operations
+
+ bool supportsFloatingPoint() const { return true; }
+ bool supportsFloatingPointTruncate() const { return true; }
+ bool supportsFloatingPointSqrt() const { return true; }
+
+ void loadDouble(ImplicitAddress address, FPRegisterID dest)
+ {
+ RegisterID scr = claimScratch();
+
+ m_assembler.loadConstant(address.offset, scr);
+ if (address.base == SH4Registers::r0) {
+ m_assembler.fmovsReadr0r(scr, (FPRegisterID)(dest + 1));
+ m_assembler.addlImm8r(4, scr);
+ m_assembler.fmovsReadr0r(scr, dest);
+ releaseScratch(scr);
+ return;
+ }
+
+ m_assembler.addlRegReg(address.base, scr);
+ m_assembler.fmovsReadrminc(scr, (FPRegisterID)(dest + 1));
+ m_assembler.fmovsReadrm(scr, dest);
+ releaseScratch(scr);
+ }
+
+ void loadDouble(const void* address, FPRegisterID dest)
+ {
+ RegisterID scr = claimScratch();
+ m_assembler.loadConstant(reinterpret_cast<uint32_t>(address), scr);
+ m_assembler.fmovsReadrminc(scr, (FPRegisterID)(dest + 1));
+ m_assembler.fmovsReadrm(scr, dest);
+ releaseScratch(scr);
+ }
+
+ void storeDouble(FPRegisterID src, ImplicitAddress address)
+ {
+ RegisterID scr = claimScratch();
+ m_assembler.loadConstant(address.offset, scr);
+ m_assembler.addlRegReg(address.base, scr);
+ m_assembler.fmovsWriterm((FPRegisterID)(src + 1), scr);
+ m_assembler.addlImm8r(4, scr);
+ m_assembler.fmovsWriterm(src, scr);
+ releaseScratch(scr);
+ }
+
+ void addDouble(FPRegisterID src, FPRegisterID dest)
+ {
+ m_assembler.daddRegReg(src, dest);
+ }
+
+ void addDouble(Address address, FPRegisterID dest)
+ {
+ loadDouble(address, fscratch);
+ addDouble(fscratch, dest);
+ }
+
+ void subDouble(FPRegisterID src, FPRegisterID dest)
+ {
+ m_assembler.dsubRegReg(src, dest);
+ }
+
+ void subDouble(Address address, FPRegisterID dest)
+ {
+ loadDouble(address, fscratch);
+ subDouble(fscratch, dest);
+ }
+
+ void mulDouble(FPRegisterID src, FPRegisterID dest)
+ {
+ m_assembler.dmulRegReg(src, dest);
+ }
+
+ void mulDouble(Address address, FPRegisterID dest)
+ {
+ loadDouble(address, fscratch);
+ mulDouble(fscratch, dest);
+ }
+
+ void divDouble(FPRegisterID src, FPRegisterID dest)
+ {
+ m_assembler.ddivRegReg(src, dest);
+ }
+
+ void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
+ {
+ m_assembler.ldsrmfpul(src);
+ m_assembler.floatfpulDreg(dest);
+ }
+
+ void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest)
+ {
+ RegisterID scr = claimScratch();
+ m_assembler.loadConstant(reinterpret_cast<uint32_t>(src.m_ptr), scr);
+ convertInt32ToDouble(scr, dest);
+ releaseScratch(scr);
+ }
+
+ void convertInt32ToDouble(Address src, FPRegisterID dest)
+ {
+ RegisterID scr = claimScratch();
+ load32(src, scr);
+ convertInt32ToDouble(scr, dest);
+ releaseScratch(scr);
+ }
+
+ void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest)
+ {
+ RegisterID scr = claimScratch();
+
+ move(address.index, scr);
+ lshift32(TrustedImm32(address.scale), scr);
+ add32(address.base, scr);
+
+ if (address.offset)
+ add32(TrustedImm32(address.offset), scr);
+
+ RegisterID scr1 = claimScratch();
+ load16(scr, scr1);
+ add32(TrustedImm32(2), scr);
+ load16(scr, dest);
+ move(TrustedImm32(16), scr);
+ m_assembler.shllRegReg(dest, scr);
+ or32(scr1, dest);
+
+ releaseScratch(scr);
+ releaseScratch(scr1);
+ }
+
+ Jump branch32WithUnalignedHalfWords(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
+ {
+ RegisterID scr = scratchReg3;
+ load32WithUnalignedHalfWords(left, scr);
+ if (((cond == Equal) || (cond == NotEqual)) && !right.m_value)
+ m_assembler.testlRegReg(scr, scr);
+ else
+ compare32(right.m_value, scr, cond);
+
+ if (cond == NotEqual)
+ return branchFalse();
+ return branchTrue();
+ }
+
+ Jump branchDoubleNonZero(FPRegisterID reg, FPRegisterID scratch)
+ {
+ m_assembler.movImm8(0, scratchReg3);
+ convertInt32ToDouble(scratchReg3, scratch);
+ return branchDouble(DoubleNotEqual, reg, scratch);
+ }
+
+ Jump branchDoubleZeroOrNaN(FPRegisterID reg, FPRegisterID scratch)
+ {
+ m_assembler.movImm8(0, scratchReg3);
+ convertInt32ToDouble(scratchReg3, scratch);
+ return branchDouble(DoubleEqualOrUnordered, reg, scratch);
+ }
+
+ Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
+ {
+ if (cond == DoubleEqual) {
+ m_assembler.dcmppeq(right, left);
+ return branchTrue();
+ }
+
+ if (cond == DoubleNotEqual) {
+ RegisterID scr = claimScratch();
+ m_assembler.loadConstant(0x7fbfffff, scratchReg3);
+ m_assembler.dcnvds(right);
+ m_assembler.stsfpulReg(scr);
+ m_assembler.cmplRegReg(scratchReg3, scr, SH4Condition(Equal));
+ m_assembler.ensureSpace(m_assembler.maxInstructionSize + 22, sizeof(uint32_t));
+ m_assembler.branch(BT_OPCODE, 8);
+ m_assembler.dcnvds(left);
+ m_assembler.stsfpulReg(scr);
+ m_assembler.cmplRegReg(scratchReg3, scr, SH4Condition(Equal));
+ m_assembler.branch(BT_OPCODE, 4);
+ m_assembler.dcmppeq(right, left);
+ releaseScratch(scr);
+ return branchFalse();
+ }
+
+ if (cond == DoubleGreaterThan) {
+ m_assembler.dcmppgt(right, left);
+ return branchTrue();
+ }
+
+ if (cond == DoubleGreaterThanOrEqual) {
+ m_assembler.dcmppgt(left, right);
+ return branchFalse();
+ }
+
+ if (cond == DoubleLessThan) {
+ m_assembler.dcmppgt(left, right);
+ return branchTrue();
+ }
+
+ if (cond == DoubleLessThanOrEqual) {
+ m_assembler.dcmppgt(right, left);
+ return branchFalse();
+ }
+
+ if (cond == DoubleEqualOrUnordered) {
+ RegisterID scr = claimScratch();
+ m_assembler.loadConstant(0x7fbfffff, scratchReg3);
+ m_assembler.dcnvds(right);
+ m_assembler.stsfpulReg(scr);
+ m_assembler.cmplRegReg(scratchReg3, scr, SH4Condition(Equal));
+ m_assembler.ensureSpace(m_assembler.maxInstructionSize + 22, sizeof(uint32_t));
+ m_assembler.branch(BT_OPCODE, 5);
+ m_assembler.dcnvds(left);
+ m_assembler.stsfpulReg(scr);
+ m_assembler.cmplRegReg(scratchReg3, scr, SH4Condition(Equal));
+ m_assembler.branch(BT_OPCODE, 1);
+ m_assembler.dcmppeq(left, right);
+ releaseScratch(scr);
+ return branchTrue();
+ }
+
+ if (cond == DoubleGreaterThanOrUnordered) {
+ RegisterID scr = claimScratch();
+ m_assembler.loadConstant(0x7fbfffff, scratchReg3);
+ m_assembler.dcnvds(right);
+ m_assembler.stsfpulReg(scr);
+ m_assembler.cmplRegReg(scratchReg3, scr, SH4Condition(Equal));
+ m_assembler.ensureSpace(m_assembler.maxInstructionSize + 22, sizeof(uint32_t));
+ m_assembler.branch(BT_OPCODE, 5);
+ m_assembler.dcnvds(left);
+ m_assembler.stsfpulReg(scr);
+ m_assembler.cmplRegReg(scratchReg3, scr, SH4Condition(Equal));
+ m_assembler.branch(BT_OPCODE, 1);
+ m_assembler.dcmppgt(right, left);
+ releaseScratch(scr);
+ return branchTrue();
+ }
+
+ if (cond == DoubleGreaterThanOrEqualOrUnordered) {
+ RegisterID scr = claimScratch();
+ m_assembler.loadConstant(0x7fbfffff, scratchReg3);
+ m_assembler.dcnvds(right);
+ m_assembler.stsfpulReg(scr);
+ m_assembler.cmplRegReg(scratchReg3, scr, SH4Condition(Equal));
+ m_assembler.ensureSpace(m_assembler.maxInstructionSize + 22, sizeof(uint32_t));
+ m_assembler.branch(BT_OPCODE, 5);
+ m_assembler.dcnvds(left);
+ m_assembler.stsfpulReg(scr);
+ m_assembler.cmplRegReg(scratchReg3, scr, SH4Condition(Equal));
+ m_assembler.branch(BT_OPCODE, 1);
+ m_assembler.dcmppgt(left, right);
+ releaseScratch(scr);
+ return branchFalse();
+ }
+
+ if (cond == DoubleLessThanOrUnordered) {
+ RegisterID scr = claimScratch();
+ m_assembler.loadConstant(0x7fbfffff, scratchReg3);
+ m_assembler.dcnvds(right);
+ m_assembler.stsfpulReg(scr);
+ m_assembler.cmplRegReg(scratchReg3, scr, SH4Condition(Equal));
+ m_assembler.ensureSpace(m_assembler.maxInstructionSize + 22, sizeof(uint32_t));
+ m_assembler.branch(BT_OPCODE, 5);
+ m_assembler.dcnvds(left);
+ m_assembler.stsfpulReg(scr);
+ m_assembler.cmplRegReg(scratchReg3, scr, SH4Condition(Equal));
+ m_assembler.branch(BT_OPCODE, 1);
+ m_assembler.dcmppgt(left, right);
+ releaseScratch(scr);
+ return branchTrue();
+ }
+
+ if (cond == DoubleLessThanOrEqualOrUnordered) {
+ RegisterID scr = claimScratch();
+ m_assembler.loadConstant(0x7fbfffff, scratchReg3);
+ m_assembler.dcnvds(right);
+ m_assembler.stsfpulReg(scr);
+ m_assembler.cmplRegReg(scratchReg3, scr, SH4Condition(Equal));
+ m_assembler.ensureSpace(m_assembler.maxInstructionSize + 22, sizeof(uint32_t));
+ m_assembler.branch(BT_OPCODE, 5);
+ m_assembler.dcnvds(left);
+ m_assembler.stsfpulReg(scr);
+ m_assembler.cmplRegReg(scratchReg3, scr, SH4Condition(Equal));
+ m_assembler.branch(BT_OPCODE, 1);
+ m_assembler.dcmppgt(right, left);
+ releaseScratch(scr);
+ return branchFalse();
+ }
+
+ ASSERT(cond == DoubleNotEqualOrUnordered);
+ RegisterID scr = claimScratch();
+ m_assembler.loadConstant(0x7fbfffff, scratchReg3);
+ m_assembler.dcnvds(right);
+ m_assembler.stsfpulReg(scr);
+ m_assembler.cmplRegReg(scratchReg3, scr, SH4Condition(Equal));
+ m_assembler.ensureSpace(m_assembler.maxInstructionSize + 22, sizeof(uint32_t));
+ m_assembler.branch(BT_OPCODE, 5);
+ m_assembler.dcnvds(left);
+ m_assembler.stsfpulReg(scr);
+ m_assembler.cmplRegReg(scratchReg3, scr, SH4Condition(Equal));
+ m_assembler.branch(BT_OPCODE, 1);
+ m_assembler.dcmppeq(right, left);
+ releaseScratch(scr);
+ return branchFalse();
+ }
+
+ Jump branchTrue()
+ {
+ m_assembler.ensureSpace(m_assembler.maxInstructionSize + 6, sizeof(uint32_t));
+ Jump m_jump = Jump(m_assembler.je());
+ m_assembler.loadConstantUnReusable(0x0, scratchReg3);
+ m_assembler.nop();
+ m_assembler.nop();
+ return m_jump;
+ }
+
+ Jump branchFalse()
+ {
+ m_assembler.ensureSpace(m_assembler.maxInstructionSize + 6, sizeof(uint32_t));
+ Jump m_jump = Jump(m_assembler.jne());
+ m_assembler.loadConstantUnReusable(0x0, scratchReg3);
+ m_assembler.nop();
+ m_assembler.nop();
+ return m_jump;
+ }
+
+ Jump branch32(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
+ {
+ RegisterID scr = claimScratch();
+ move(left.index, scr);
+ lshift32(TrustedImm32(left.scale), scr);
+ add32(left.base, scr);
+ load32(scr, left.offset, scr);
+ compare32(right.m_value, scr, cond);
+ releaseScratch(scr);
+
+ if (cond == NotEqual)
+ return branchFalse();
+ return branchTrue();
+ }
+
+ void sqrtDouble(FPRegisterID src, FPRegisterID dest)
+ {
+ if (dest != src)
+ m_assembler.dmovRegReg(src, dest);
+ m_assembler.dsqrt(dest);
+ }
+
+ Jump branchTest8(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
+ {
+ RegisterID addressTempRegister = claimScratch();
+ load8(address, addressTempRegister);
+ Jump jmp = branchTest32(cond, addressTempRegister, mask);
+ releaseScratch(addressTempRegister);
+ return jmp;
+ }
+
+ void signExtend32ToPtr(RegisterID src, RegisterID dest)
+ {
+ if (src != dest)
+ move(src, dest);
+ }
+
+ Jump branch8(RelationalCondition cond, Address left, TrustedImm32 right)
+ {
+ RegisterID addressTempRegister = claimScratch();
+ load8(left, addressTempRegister);
+ Jump jmp = branch32(cond, addressTempRegister, right);
+ releaseScratch(addressTempRegister);
+ return jmp;
+ }
+
+ Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest)
+ {
+ m_assembler.ftrcdrmfpul(src);
+ m_assembler.stsfpulReg(dest);
+ m_assembler.loadConstant(0x7fffffff, scratchReg3);
+ m_assembler.cmplRegReg(dest, scratchReg3, SH4Condition(Equal));
+ m_assembler.ensureSpace(m_assembler.maxInstructionSize + 14, sizeof(uint32_t));
+ m_assembler.branch(BT_OPCODE, 2);
+ m_assembler.addlImm8r(1, scratchReg3);
+ m_assembler.cmplRegReg(dest, scratchReg3, SH4Condition(Equal));
+ return branchTrue();
+ }
+
+ // Stack manipulation operations
+
+ void pop(RegisterID dest)
+ {
+ m_assembler.popReg(dest);
+ }
+
+ void push(RegisterID src)
+ {
+ m_assembler.pushReg(src);
+ }
+
+ void push(Address address)
+ {
+ if (!address.offset) {
+ push(address.base);
+ return;
+ }
+
+ if ((address.offset < 0) || (address.offset >= 64)) {
+ RegisterID scr = claimScratch();
+ m_assembler.loadConstant(address.offset, scr);
+ m_assembler.addlRegReg(address.base, scr);
+ m_assembler.movlMemReg(scr, SH4Registers::sp);
+ m_assembler.addlImm8r(-4, SH4Registers::sp);
+ releaseScratch(scr);
+ return;
+ }
+
+ m_assembler.movlMemReg(address.offset >> 2, address.base, SH4Registers::sp);
+ m_assembler.addlImm8r(-4, SH4Registers::sp);
+ }
+
+ void push(TrustedImm32 imm)
+ {
+ RegisterID scr = claimScratch();
+ m_assembler.loadConstant(imm.m_value, scr);
+ push(scr);
+ releaseScratch(scr);
+ }
+
+ // Register move operations
+
+ void move(TrustedImm32 imm, RegisterID dest)
+ {
+ m_assembler.loadConstant(imm.m_value, dest);
+ }
+
+ DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
+ {
+ DataLabelPtr dataLabel(this);
+ m_assembler.loadConstantUnReusable(reinterpret_cast<uint32_t>(initialValue.m_value), dest, true);
+ return dataLabel;
+ }
+
+ void move(RegisterID src, RegisterID dest)
+ {
+ m_assembler.movlRegReg(src, dest);
+ }
+
+ void move(TrustedImmPtr imm, RegisterID dest)
+ {
+ m_assembler.loadConstant(imm.asIntptr(), dest);
+ }
+
+ void extuw(RegisterID src, RegisterID dst)
+ {
+ m_assembler.extuw(src, dst);
+ }
+
+ void compare32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID dest)
+ {
+ m_assembler.cmplRegReg(right, left, SH4Condition(cond));
+ if (cond != NotEqual) {
+ m_assembler.movt(dest);
+ return;
+ }
+
+ m_assembler.ensureSpace(m_assembler.maxInstructionSize + 4);
+ m_assembler.movImm8(0, dest);
+ m_assembler.branch(BT_OPCODE, 0);
+ m_assembler.movImm8(1, dest);
+ }
+
+ void compare32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
+ {
+ if (left != dest) {
+ move(right, dest);
+ compare32(cond, left, dest, dest);
+ return;
+ }
+
+ RegisterID scr = claimScratch();
+ move(right, scr);
+ compare32(cond, left, scr, dest);
+ releaseScratch(scr);
+ }
+
+ void test8(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
+ {
+ ASSERT((cond == Zero) || (cond == NonZero));
+
+ load8(address, dest);
+ if (mask.m_value == -1)
+ compare32(0, dest, static_cast<RelationalCondition>(cond));
+ else
+ testlImm(mask.m_value, dest);
+ if (cond != NonZero) {
+ m_assembler.movt(dest);
+ return;
+ }
+
+ m_assembler.ensureSpace(m_assembler.maxInstructionSize + 4);
+ m_assembler.movImm8(0, dest);
+ m_assembler.branch(BT_OPCODE, 0);
+ m_assembler.movImm8(1, dest);
+ }
+
+ void loadPtrLinkReg(ImplicitAddress address)
+ {
+ RegisterID scr = claimScratch();
+ load32(address, scr);
+ m_assembler.ldspr(scr);
+ releaseScratch(scr);
+ }
+
+ Jump branch32(RelationalCondition cond, RegisterID left, RegisterID right)
+ {
+ m_assembler.cmplRegReg(right, left, SH4Condition(cond));
+ /* BT label => BF off
+ nop LDR reg
+ nop braf @reg
+ nop nop
+ */
+ if (cond == NotEqual)
+ return branchFalse();
+ return branchTrue();
+ }
+
+ Jump branch32(RelationalCondition cond, RegisterID left, TrustedImm32 right)
+ {
+ if (((cond == Equal) || (cond == NotEqual)) && !right.m_value)
+ m_assembler.testlRegReg(left, left);
+ else
+ compare32(right.m_value, left, cond);
+
+ if (cond == NotEqual)
+ return branchFalse();
+ return branchTrue();
+ }
+
+ Jump branch32(RelationalCondition cond, RegisterID left, Address right)
+ {
+ compare32(right.offset, right.base, left, cond);
+ if (cond == NotEqual)
+ return branchFalse();
+ return branchTrue();
+ }
+
+ Jump branch32(RelationalCondition cond, Address left, RegisterID right)
+ {
+ compare32(right, left.offset, left.base, cond);
+ if (cond == NotEqual)
+ return branchFalse();
+ return branchTrue();
+ }
+
+ Jump branch32(RelationalCondition cond, Address left, TrustedImm32 right)
+ {
+ compare32(right.m_value, left.offset, left.base, cond);
+ if (cond == NotEqual)
+ return branchFalse();
+ return branchTrue();
+ }
+
+ Jump branch32(RelationalCondition cond, AbsoluteAddress left, RegisterID right)
+ {
+ RegisterID scr = claimScratch();
+
+ move(TrustedImm32(reinterpret_cast<uint32_t>(left.m_ptr)), scr);
+ m_assembler.cmplRegReg(right, scr, SH4Condition(cond));
+ releaseScratch(scr);
+
+ if (cond == NotEqual)
+ return branchFalse();
+ return branchTrue();
+ }
+
+ Jump branch32(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right)
+ {
+ RegisterID addressTempRegister = claimScratch();
+
+ m_assembler.loadConstant(reinterpret_cast<uint32_t>(left.m_ptr), addressTempRegister);
+ m_assembler.movlMemReg(addressTempRegister, addressTempRegister);
+ compare32(right.m_value, addressTempRegister, cond);
+ releaseScratch(addressTempRegister);
+
+ if (cond == NotEqual)
+ return branchFalse();
+ return branchTrue();
+ }
+
+ Jump branch16(RelationalCondition cond, BaseIndex left, RegisterID right)
+ {
+ RegisterID scr = claimScratch();
+
+ move(left.index, scr);
+ lshift32(TrustedImm32(left.scale), scr);
+
+ if (left.offset)
+ add32(TrustedImm32(left.offset), scr);
+ add32(left.base, scr);
+ load16(scr, scr);
+ extuw(scr, scr);
+ releaseScratch(scr);
+
+ return branch32(cond, scr, right);
+ }
+
+ Jump branch16(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
+ {
+ RegisterID scr = claimScratch();
+
+ move(left.index, scr);
+ lshift32(TrustedImm32(left.scale), scr);
+
+ if (left.offset)
+ add32(TrustedImm32(left.offset), scr);
+ add32(left.base, scr);
+ load16(scr, scr);
+ extuw(scr, scr);
+ RegisterID scr1 = claimScratch();
+ m_assembler.loadConstant(right.m_value, scr1);
+ releaseScratch(scr);
+ releaseScratch(scr1);
+
+ return branch32(cond, scr, scr1);
+ }
+
+ Jump branchTest32(ResultCondition cond, RegisterID reg, RegisterID mask)
+ {
+ ASSERT((cond == Zero) || (cond == NonZero));
+
+ m_assembler.testlRegReg(reg, mask);
+
+ if (cond == NotEqual)
+ return branchFalse();
+ return branchTrue();
+ }
+
+ Jump branchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
+ {
+ ASSERT((cond == Zero) || (cond == NonZero));
+
+ if (mask.m_value == -1)
+ m_assembler.testlRegReg(reg, reg);
+ else
+ testlImm(mask.m_value, reg);
+
+ if (cond == NotEqual)
+ return branchFalse();
+ return branchTrue();
+ }
+
+ Jump branchTest32(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
+ {
+ ASSERT((cond == Zero) || (cond == NonZero));
+
+ if (mask.m_value == -1)
+ compare32(0, address.offset, address.base, static_cast<RelationalCondition>(cond));
+ else
+ testImm(mask.m_value, address.offset, address.base);
+
+ if (cond == NotEqual)
+ return branchFalse();
+ return branchTrue();
+ }
+
+ Jump branchTest32(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
+ {
+ RegisterID scr = claimScratch();
+
+ move(address.index, scr);
+ lshift32(TrustedImm32(address.scale), scr);
+ add32(address.base, scr);
+ load32(scr, address.offset, scr);
+
+ if (mask.m_value == -1)
+ m_assembler.testlRegReg(scr, scr);
+ else
+ testlImm(mask.m_value, scr);
+
+ releaseScratch(scr);
+
+ if (cond == NotEqual)
+ return branchFalse();
+ return branchTrue();
+ }
+
+ Jump jump()
+ {
+ return Jump(m_assembler.jmp());
+ }
+
+ void jump(RegisterID target)
+ {
+ m_assembler.jmpReg(target);
+ }
+
+ void jump(Address address)
+ {
+ RegisterID scr = claimScratch();
+
+ if ((address.offset < 0) || (address.offset >= 64)) {
+ m_assembler.loadConstant(address.offset, scr);
+ m_assembler.addlRegReg(address.base, scr);
+ m_assembler.movlMemReg(scr, scr);
+ } else if (address.offset)
+ m_assembler.movlMemReg(address.offset >> 2, address.base, scr);
+ else
+ m_assembler.movlMemReg(address.base, scr);
+ m_assembler.jmpReg(scr);
+
+ releaseScratch(scr);
+ }
+
+ // Arithmetic control flow operations
+
+ Jump branchAdd32(ResultCondition cond, RegisterID src, RegisterID dest)
+ {
+ ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
+
+ if (cond == Overflow) {
+ m_assembler.addvlRegReg(src, dest);
+ return branchTrue();
+ }
+
+ if (cond == Signed) {
+ m_assembler.addlRegReg(src, dest);
+ // Check if dest is negative
+ m_assembler.cmppz(dest);
+ return branchFalse();
+ }
+
+ m_assembler.addlRegReg(src, dest);
+ compare32(0, dest, Equal);
+
+ if (cond == NotEqual)
+ return branchFalse();
+ return branchTrue();
+ }
+
+ Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
+ {
+ ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
+
+ move(imm, scratchReg3);
+ return branchAdd32(cond, scratchReg3, dest);
+ }
+
+ Jump branchMul32(ResultCondition cond, RegisterID src, RegisterID dest)
+ {
+ ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
+
+ if (cond == Overflow) {
+ RegisterID scr1 = claimScratch();
+ RegisterID scr = claimScratch();
+ m_assembler.dmullRegReg(src, dest);
+ m_assembler.stsmacl(dest);
+ m_assembler.movImm8(-31, scr);
+ m_assembler.movlRegReg(dest, scr1);
+ m_assembler.shaRegReg(scr1, scr);
+ m_assembler.stsmach(scr);
+ m_assembler.cmplRegReg(scr, scr1, SH4Condition(Equal));
+ releaseScratch(scr1);
+ releaseScratch(scr);
+ return branchFalse();
+ }
+
+ m_assembler.imullRegReg(src, dest);
+ m_assembler.stsmacl(dest);
+ if (cond == Signed) {
+ // Check if dest is negative
+ m_assembler.cmppz(dest);
+ return branchFalse();
+ }
+
+ compare32(0, dest, static_cast<RelationalCondition>(cond));
+
+ if (cond == NotEqual)
+ return branchFalse();
+ return branchTrue();
+ }
+
+ Jump branchMul32(ResultCondition cond, TrustedImm32 imm, RegisterID src, RegisterID dest)
+ {
+ ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
+
+ move(imm, scratchReg3);
+ if (src != dest)
+ move(src, dest);
+
+ return branchMul32(cond, scratchReg3, dest);
+ }
+
+ Jump branchSub32(ResultCondition cond, RegisterID src, RegisterID dest)
+ {
+ ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
+
+ if (cond == Overflow) {
+ m_assembler.subvlRegReg(src, dest);
+ return branchTrue();
+ }
+
+ if (cond == Signed) {
+ // Check if dest is negative
+ m_assembler.sublRegReg(src, dest);
+ compare32(0, dest, LessThan);
+ return branchTrue();
+ }
+
+ sub32(src, dest);
+ compare32(0, dest, static_cast<RelationalCondition>(cond));
+
+ if (cond == NotEqual)
+ return branchFalse();
+ return branchTrue();
+ }
+
+ Jump branchSub32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
+ {
+ ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
+
+ move(imm, scratchReg3);
+ return branchSub32(cond, scratchReg3, dest);
+ }
+
+ Jump branchOr32(ResultCondition cond, RegisterID src, RegisterID dest)
+ {
+ ASSERT((cond == Signed) || (cond == Zero) || (cond == NonZero));
+
+ if (cond == Signed) {
+ or32(src, dest);
+ compare32(0, dest, static_cast<RelationalCondition>(LessThan));
+ return branchTrue();
+ }
+
+ or32(src, dest);
+ compare32(0, dest, static_cast<RelationalCondition>(cond));
+
+ if (cond == NotEqual)
+ return branchFalse();
+ return branchTrue();
+ }
+
+ void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID fpTemp)
+ {
+ m_assembler.ftrcdrmfpul(src);
+ m_assembler.stsfpulReg(dest);
+ convertInt32ToDouble(dest, fscratch);
+ failureCases.append(branchDouble(DoubleNotEqualOrUnordered, fscratch, src));
+
+ if (dest == SH4Registers::r0)
+ m_assembler.cmpEqImmR0(0, dest);
+ else {
+ m_assembler.movImm8(0, scratchReg3);
+ m_assembler.cmplRegReg(scratchReg3, dest, SH4Condition(Equal));
+ }
+ failureCases.append(branchTrue());
+ }
+
+ void neg32(RegisterID dst)
+ {
+ m_assembler.neg(dst, dst);
+ }
+
+ void not32(RegisterID dst)
+ {
+ m_assembler.notlReg(dst, dst);
+ }
+
+ void urshift32(RegisterID shiftamount, RegisterID dest)
+ {
+ compare32(32, shiftamount, Equal);
+ m_assembler.ensureSpace(m_assembler.maxInstructionSize + 4);
+ m_assembler.branch(BT_OPCODE, 1);
+ m_assembler.neg(shiftamount, shiftamount);
+ m_assembler.shllRegReg(dest, shiftamount);
+ }
+
+ void urshift32(TrustedImm32 imm, RegisterID dest)
+ {
+ RegisterID scr = claimScratch();
+ m_assembler.loadConstant(-(imm.m_value), scr);
+ m_assembler.shaRegReg(dest, scr);
+ releaseScratch(scr);
+ }
+
+ Call call()
+ {
+ return Call(m_assembler.call(), Call::Linkable);
+ }
+
+ Call nearCall()
+ {
+ return Call(m_assembler.call(), Call::LinkableNear);
+ }
+
+ Call call(RegisterID target)
+ {
+ return Call(m_assembler.call(target), Call::None);
+ }
+
+ void call(Address address, RegisterID target)
+ {
+ load32(address.base, address.offset, target);
+ m_assembler.ensureSpace(m_assembler.maxInstructionSize + 2);
+ m_assembler.branch(JSR_OPCODE, target);
+ m_assembler.nop();
+ }
+
+ void breakpoint()
+ {
+ m_assembler.bkpt();
+ m_assembler.nop();
+ }
+
+ Jump branchPtrWithPatch(RelationalCondition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
+ {
+ RegisterID dataTempRegister = claimScratch();
+
+ dataLabel = moveWithPatch(initialRightValue, dataTempRegister);
+ m_assembler.cmplRegReg(dataTempRegister, left, SH4Condition(cond));
+ releaseScratch(dataTempRegister);
+
+ if (cond == NotEqual)
+ return branchFalse();
+ return branchTrue();
+ }
+
+ Jump branchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
+ {
+ RegisterID scr = claimScratch();
+
+ m_assembler.loadConstant(left.offset, scr);
+ m_assembler.addlRegReg(left.base, scr);
+ m_assembler.movlMemReg(scr, scr);
+ RegisterID scr1 = claimScratch();
+ dataLabel = moveWithPatch(initialRightValue, scr1);
+ m_assembler.cmplRegReg(scr1, scr, SH4Condition(cond));
+ releaseScratch(scr);
+ releaseScratch(scr1);
+
+ if (cond == NotEqual)
+ return branchFalse();
+ return branchTrue();
+ }
+
+ void ret()
+ {
+ m_assembler.ret();
+ m_assembler.nop();
+ }
+
+ DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
+ {
+ RegisterID scr = claimScratch();
+ DataLabelPtr label = moveWithPatch(initialValue, scr);
+ store32(scr, address);
+ releaseScratch(scr);
+ return label;
+ }
+
+ DataLabelPtr storePtrWithPatch(ImplicitAddress address) { return storePtrWithPatch(TrustedImmPtr(0), address); }
+
+ int sizeOfConstantPool()
+ {
+ return m_assembler.sizeOfConstantPool();
+ }
+
+ Call tailRecursiveCall()
+ {
+ RegisterID scr = claimScratch();
+
+ m_assembler.loadConstantUnReusable(0x0, scr, true);
+ Jump m_jump = Jump(m_assembler.jmp(scr));
+ releaseScratch(scr);
+
+ return Call::fromTailJump(m_jump);
+ }
+
+ Call makeTailRecursiveCall(Jump oldJump)
+ {
+ oldJump.link(this);
+ return tailRecursiveCall();
+ }
+
+ void nop()
+ {
+ m_assembler.nop();
+ }
+
+protected:
+ SH4Assembler::Condition SH4Condition(RelationalCondition cond)
+ {
+ return static_cast<SH4Assembler::Condition>(cond);
+ }
+
+ SH4Assembler::Condition SH4Condition(ResultCondition cond)
+ {
+ return static_cast<SH4Assembler::Condition>(cond);
+ }
+private:
+ friend class LinkBuffer;
+ friend class RepatchBuffer;
+
+ static void linkCall(void*, Call, FunctionPtr);
+ static void repatchCall(CodeLocationCall, CodeLocationLabel);
+ static void repatchCall(CodeLocationCall, FunctionPtr);
+};
+
+} // namespace JSC
+
+#endif // ENABLE(ASSEMBLER)
+
+#endif // MacroAssemblerSH4_h
using MacroAssemblerX86Common::loadDouble;
using MacroAssemblerX86Common::convertInt32ToDouble;
- void add32(Imm32 imm, RegisterID src, RegisterID dest)
+ void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
{
m_assembler.leal_mr(imm.m_value, src, dest);
}
- void add32(Imm32 imm, AbsoluteAddress address)
+ void add32(TrustedImm32 imm, AbsoluteAddress address)
{
m_assembler.addl_im(imm.m_value, address.m_ptr);
}
- void addWithCarry32(Imm32 imm, AbsoluteAddress address)
+ void addWithCarry32(TrustedImm32 imm, AbsoluteAddress address)
{
m_assembler.adcl_im(imm.m_value, address.m_ptr);
}
- void and32(Imm32 imm, AbsoluteAddress address)
+ void and32(TrustedImm32 imm, AbsoluteAddress address)
{
m_assembler.andl_im(imm.m_value, address.m_ptr);
}
- void or32(Imm32 imm, AbsoluteAddress address)
+ void or32(TrustedImm32 imm, AbsoluteAddress address)
{
m_assembler.orl_im(imm.m_value, address.m_ptr);
}
- void sub32(Imm32 imm, AbsoluteAddress address)
+ void sub32(TrustedImm32 imm, AbsoluteAddress address)
{
m_assembler.subl_im(imm.m_value, address.m_ptr);
}
m_assembler.cvtsi2sd_mr(src.m_ptr, dest);
}
- void store32(Imm32 imm, void* address)
+ void store32(TrustedImm32 imm, void* address)
{
m_assembler.movl_i32m(imm.m_value, address);
}
m_assembler.movl_rm(src, address);
}
- Jump branch32(Condition cond, AbsoluteAddress left, RegisterID right)
+ Jump branch32(RelationalCondition cond, AbsoluteAddress left, RegisterID right)
{
m_assembler.cmpl_rm(right, left.m_ptr);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right)
+ Jump branch32(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right)
{
m_assembler.cmpl_im(right.m_value, left.m_ptr);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest)
+ DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
{
m_assembler.movl_i32r(initialValue.asIntptr(), dest);
return DataLabelPtr(this);
}
- Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0))
+ Jump branchPtrWithPatch(RelationalCondition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
{
m_assembler.cmpl_ir_force32(initialRightValue.asIntptr(), left);
dataLabel = DataLabelPtr(this);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- Jump branchPtrWithPatch(Condition cond, Address left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0))
+ Jump branchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
{
m_assembler.cmpl_im_force32(initialRightValue.asIntptr(), left.offset, left.base);
dataLabel = DataLabelPtr(this);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address)
+ DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
{
m_assembler.movl_i32m(initialValue.asIntptr(), address.offset, address.base);
return DataLabelPtr(this);
}
- Label loadPtrWithPatchToLEA(Address address, RegisterID dest)
- {
- Label label(this);
- load32(address, dest);
- return label;
- }
-
bool supportsFloatingPoint() const { return m_isSSE2Present; }
// See comment on MacroAssemblerARMv7::supportsFloatingPointTruncate()
bool supportsFloatingPointTruncate() const { return m_isSSE2Present; }
public:
typedef X86Assembler::FPRegisterID FPRegisterID;
+
+ static const int MaximumCompactPtrAlignedAddressOffset = 127;
- enum Condition {
+ enum RelationalCondition {
Equal = X86Assembler::ConditionE,
NotEqual = X86Assembler::ConditionNE,
Above = X86Assembler::ConditionA,
GreaterThan = X86Assembler::ConditionG,
GreaterThanOrEqual = X86Assembler::ConditionGE,
LessThan = X86Assembler::ConditionL,
- LessThanOrEqual = X86Assembler::ConditionLE,
+ LessThanOrEqual = X86Assembler::ConditionLE
+ };
+
+ enum ResultCondition {
Overflow = X86Assembler::ConditionO,
Signed = X86Assembler::ConditionS,
Zero = X86Assembler::ConditionE,
// Integer arithmetic operations:
//
// Operations are typically two operand - operation(source, srcDst)
- // For many operations the source may be an Imm32, the srcDst operand
+ // For many operations the source may be an TrustedImm32, the srcDst operand
// may often be a memory location (explictly described using an Address
// object).
m_assembler.addl_rr(src, dest);
}
- void add32(Imm32 imm, Address address)
+ void add32(TrustedImm32 imm, Address address)
{
m_assembler.addl_im(imm.m_value, address.offset, address.base);
}
- void add32(Imm32 imm, RegisterID dest)
+ void add32(TrustedImm32 imm, RegisterID dest)
{
m_assembler.addl_ir(imm.m_value, dest);
}
m_assembler.andl_rr(src, dest);
}
- void and32(Imm32 imm, RegisterID dest)
+ void and32(TrustedImm32 imm, RegisterID dest)
{
m_assembler.andl_ir(imm.m_value, dest);
}
m_assembler.andl_mr(src.offset, src.base, dest);
}
- void and32(Imm32 imm, Address address)
+ void and32(TrustedImm32 imm, Address address)
{
m_assembler.andl_im(imm.m_value, address.offset, address.base);
}
- void lshift32(Imm32 imm, RegisterID dest)
+ void and32(RegisterID op1, RegisterID op2, RegisterID dest)
{
- m_assembler.shll_i8r(imm.m_value, dest);
+ if (op1 == op2)
+ zeroExtend32ToPtr(op1, dest);
+ else if (op1 == dest)
+ and32(op2, dest);
+ else {
+ move(op2, dest);
+ and32(op1, dest);
+ }
}
-
+
+ void and32(TrustedImm32 imm, RegisterID src, RegisterID dest)
+ {
+ move(src, dest);
+ and32(imm, dest);
+ }
+
void lshift32(RegisterID shift_amount, RegisterID dest)
{
- // On x86 we can only shift by ecx; if asked to shift by another register we'll
- // need rejig the shift amount into ecx first, and restore the registers afterwards.
- if (shift_amount != X86Registers::ecx) {
- swap(shift_amount, X86Registers::ecx);
+ ASSERT(shift_amount != dest);
- // E.g. transform "shll %eax, %eax" -> "xchgl %eax, %ecx; shll %ecx, %ecx; xchgl %eax, %ecx"
- if (dest == shift_amount)
- m_assembler.shll_CLr(X86Registers::ecx);
- // E.g. transform "shll %eax, %ecx" -> "xchgl %eax, %ecx; shll %ecx, %eax; xchgl %eax, %ecx"
- else if (dest == X86Registers::ecx)
- m_assembler.shll_CLr(shift_amount);
- // E.g. transform "shll %eax, %ebx" -> "xchgl %eax, %ecx; shll %ecx, %ebx; xchgl %eax, %ecx"
- else
- m_assembler.shll_CLr(dest);
-
- swap(shift_amount, X86Registers::ecx);
- } else
+ if (shift_amount == X86Registers::ecx)
m_assembler.shll_CLr(dest);
+ else {
+ // On x86 we can only shift by ecx; if asked to shift by another register we'll
+ // need rejig the shift amount into ecx first, and restore the registers afterwards.
+ // If we dest is ecx, then shift the swapped register!
+ swap(shift_amount, X86Registers::ecx);
+ m_assembler.shll_CLr(dest == X86Registers::ecx ? shift_amount : dest);
+ swap(shift_amount, X86Registers::ecx);
+ }
+ }
+
+ void lshift32(RegisterID src, RegisterID shift_amount, RegisterID dest)
+ {
+ ASSERT(shift_amount != dest);
+
+ if (src != dest)
+ move(src, dest);
+ lshift32(shift_amount, dest);
+ }
+
+ void lshift32(TrustedImm32 imm, RegisterID dest)
+ {
+ m_assembler.shll_i8r(imm.m_value, dest);
+ }
+
+ void lshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
+ {
+ if (src != dest)
+ move(src, dest);
+ lshift32(imm, dest);
}
void mul32(RegisterID src, RegisterID dest)
m_assembler.imull_mr(src.offset, src.base, dest);
}
- void mul32(Imm32 imm, RegisterID src, RegisterID dest)
+ void mul32(TrustedImm32 imm, RegisterID src, RegisterID dest)
{
m_assembler.imull_i32r(src, imm.m_value, dest);
}
m_assembler.orl_rr(src, dest);
}
- void or32(Imm32 imm, RegisterID dest)
+ void or32(TrustedImm32 imm, RegisterID dest)
{
m_assembler.orl_ir(imm.m_value, dest);
}
m_assembler.orl_mr(src.offset, src.base, dest);
}
- void or32(Imm32 imm, Address address)
+ void or32(TrustedImm32 imm, Address address)
{
m_assembler.orl_im(imm.m_value, address.offset, address.base);
}
+ void or32(RegisterID op1, RegisterID op2, RegisterID dest)
+ {
+ if (op1 == op2)
+ zeroExtend32ToPtr(op1, dest);
+ else if (op1 == dest)
+ or32(op2, dest);
+ else {
+ move(op2, dest);
+ or32(op1, dest);
+ }
+ }
+
+ void or32(TrustedImm32 imm, RegisterID src, RegisterID dest)
+ {
+ move(src, dest);
+ or32(imm, dest);
+ }
+
void rshift32(RegisterID shift_amount, RegisterID dest)
{
- // On x86 we can only shift by ecx; if asked to shift by another register we'll
- // need rejig the shift amount into ecx first, and restore the registers afterwards.
- if (shift_amount != X86Registers::ecx) {
- swap(shift_amount, X86Registers::ecx);
+ ASSERT(shift_amount != dest);
- // E.g. transform "shll %eax, %eax" -> "xchgl %eax, %ecx; shll %ecx, %ecx; xchgl %eax, %ecx"
- if (dest == shift_amount)
- m_assembler.sarl_CLr(X86Registers::ecx);
- // E.g. transform "shll %eax, %ecx" -> "xchgl %eax, %ecx; shll %ecx, %eax; xchgl %eax, %ecx"
- else if (dest == X86Registers::ecx)
- m_assembler.sarl_CLr(shift_amount);
- // E.g. transform "shll %eax, %ebx" -> "xchgl %eax, %ecx; shll %ecx, %ebx; xchgl %eax, %ecx"
- else
- m_assembler.sarl_CLr(dest);
-
- swap(shift_amount, X86Registers::ecx);
- } else
+ if (shift_amount == X86Registers::ecx)
m_assembler.sarl_CLr(dest);
+ else {
+ // On x86 we can only shift by ecx; if asked to shift by another register we'll
+ // need rejig the shift amount into ecx first, and restore the registers afterwards.
+ // If we dest is ecx, then shift the swapped register!
+ swap(shift_amount, X86Registers::ecx);
+ m_assembler.sarl_CLr(dest == X86Registers::ecx ? shift_amount : dest);
+ swap(shift_amount, X86Registers::ecx);
+ }
}
- void rshift32(Imm32 imm, RegisterID dest)
+ void rshift32(RegisterID src, RegisterID shift_amount, RegisterID dest)
+ {
+ ASSERT(shift_amount != dest);
+
+ if (src != dest)
+ move(src, dest);
+ rshift32(shift_amount, dest);
+ }
+
+ void rshift32(TrustedImm32 imm, RegisterID dest)
{
m_assembler.sarl_i8r(imm.m_value, dest);
}
+ void rshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
+ {
+ if (src != dest)
+ move(src, dest);
+ rshift32(imm, dest);
+ }
+
void urshift32(RegisterID shift_amount, RegisterID dest)
{
- // On x86 we can only shift by ecx; if asked to shift by another register we'll
- // need rejig the shift amount into ecx first, and restore the registers afterwards.
- if (shift_amount != X86Registers::ecx) {
+ ASSERT(shift_amount != dest);
+
+ if (shift_amount == X86Registers::ecx)
+ m_assembler.shrl_CLr(dest);
+ else {
+ // On x86 we can only shift by ecx; if asked to shift by another register we'll
+ // need rejig the shift amount into ecx first, and restore the registers afterwards.
+ // If we dest is ecx, then shift the swapped register!
swap(shift_amount, X86Registers::ecx);
-
- // E.g. transform "shrl %eax, %eax" -> "xchgl %eax, %ecx; shrl %ecx, %ecx; xchgl %eax, %ecx"
- if (dest == shift_amount)
- m_assembler.shrl_CLr(X86Registers::ecx);
- // E.g. transform "shrl %eax, %ecx" -> "xchgl %eax, %ecx; shrl %ecx, %eax; xchgl %eax, %ecx"
- else if (dest == X86Registers::ecx)
- m_assembler.shrl_CLr(shift_amount);
- // E.g. transform "shrl %eax, %ebx" -> "xchgl %eax, %ecx; shrl %ecx, %ebx; xchgl %eax, %ecx"
- else
- m_assembler.shrl_CLr(dest);
-
+ m_assembler.shrl_CLr(dest == X86Registers::ecx ? shift_amount : dest);
swap(shift_amount, X86Registers::ecx);
- } else
- m_assembler.shrl_CLr(dest);
+ }
}
-
- void urshift32(Imm32 imm, RegisterID dest)
+
+ void urshift32(RegisterID src, RegisterID shift_amount, RegisterID dest)
{
- m_assembler.shrl_i8r(imm.m_value, dest);
+ ASSERT(shift_amount != dest);
+
+ if (src != dest)
+ move(src, dest);
+ urshift32(shift_amount, dest);
}
+ void urshift32(TrustedImm32 imm, RegisterID dest)
+ {
+ m_assembler.shrl_i8r(imm.m_value, dest);
+ }
+
+ void urshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
+ {
+ if (src != dest)
+ move(src, dest);
+ urshift32(imm, dest);
+ }
+
void sub32(RegisterID src, RegisterID dest)
{
m_assembler.subl_rr(src, dest);
}
- void sub32(Imm32 imm, RegisterID dest)
+ void sub32(TrustedImm32 imm, RegisterID dest)
{
m_assembler.subl_ir(imm.m_value, dest);
}
- void sub32(Imm32 imm, Address address)
+ void sub32(TrustedImm32 imm, Address address)
{
m_assembler.subl_im(imm.m_value, address.offset, address.base);
}
m_assembler.xorl_rr(src, dest);
}
- void xor32(Imm32 imm, Address dest)
+ void xor32(TrustedImm32 imm, Address dest)
{
m_assembler.xorl_im(imm.m_value, dest.offset, dest.base);
}
- void xor32(Imm32 imm, RegisterID dest)
+ void xor32(TrustedImm32 imm, RegisterID dest)
{
m_assembler.xorl_ir(imm.m_value, dest);
}
m_assembler.xorl_mr(src.offset, src.base, dest);
}
+ void xor32(RegisterID op1, RegisterID op2, RegisterID dest)
+ {
+ if (op1 == op2)
+ move(TrustedImm32(0), dest);
+ else if (op1 == dest)
+ xor32(op2, dest);
+ else {
+ move(op2, dest);
+ xor32(op1, dest);
+ }
+ }
+
+ void xor32(TrustedImm32 imm, RegisterID src, RegisterID dest)
+ {
+ move(src, dest);
+ xor32(imm, dest);
+ }
+
void sqrtDouble(FPRegisterID src, FPRegisterID dst)
{
m_assembler.sqrtsd_rr(src, dst);
// Memory access operations:
//
// Loads are of the form load(address, destination) and stores of the form
- // store(source, address). The source for a store may be an Imm32. Address
+ // store(source, address). The source for a store may be an TrustedImm32. Address
// operand objects to loads and store will be implicitly constructed if a
// register is passed.
m_assembler.movl_mr_disp32(address.offset, address.base, dest);
return DataLabel32(this);
}
+
+ DataLabelCompact load32WithCompactAddressOffsetPatch(Address address, RegisterID dest)
+ {
+ m_assembler.movl_mr_disp8(address.offset, address.base, dest);
+ return DataLabelCompact(this);
+ }
+
+ static void repatchCompact(CodeLocationDataLabelCompact dataLabelCompact, int32_t value)
+ {
+ ASSERT(value >= 0);
+ ASSERT(value < MaximumCompactPtrAlignedAddressOffset);
+ AssemblerType_T::repatchCompact(dataLabelCompact.dataLocation(), value);
+ }
+
+ DataLabelCompact loadCompactWithAddressOffsetPatch(Address address, RegisterID dest)
+ {
+ m_assembler.movl_mr_disp8(address.offset, address.base, dest);
+ return DataLabelCompact(this);
+ }
void load16(BaseIndex address, RegisterID dest)
{
m_assembler.movl_rm(src, address.offset, address.base, address.index, address.scale);
}
- void store32(Imm32 imm, ImplicitAddress address)
+ void store32(TrustedImm32 imm, ImplicitAddress address)
{
m_assembler.movl_i32m(imm.m_value, address.offset, address.base);
}
//
// Presently only supports SSE, not x87 floating point.
+ void moveDouble(FPRegisterID src, FPRegisterID dest)
+ {
+ ASSERT(isSSE2Present());
+ if (src != dest)
+ m_assembler.movsd_rr(src, dest);
+ }
+
void loadDouble(ImplicitAddress address, FPRegisterID dest)
{
ASSERT(isSSE2Present());
m_assembler.addsd_rr(src, dest);
}
+ void addDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
+ {
+ ASSERT(isSSE2Present());
+ if (op1 == dest)
+ addDouble(op2, dest);
+ else {
+ moveDouble(op2, dest);
+ addDouble(op1, dest);
+ }
+ }
+
void addDouble(Address src, FPRegisterID dest)
{
ASSERT(isSSE2Present());
m_assembler.divsd_rr(src, dest);
}
+ void divDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
+ {
+ // B := A / B is invalid.
+ ASSERT(op1 == dest || op2 != dest);
+
+ moveDouble(op1, dest);
+ divDouble(op2, dest);
+ }
+
void divDouble(Address src, FPRegisterID dest)
{
ASSERT(isSSE2Present());
m_assembler.subsd_rr(src, dest);
}
+ void subDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
+ {
+ // B := A - B is invalid.
+ ASSERT(op1 == dest || op2 != dest);
+
+ moveDouble(op1, dest);
+ subDouble(op2, dest);
+ }
+
void subDouble(Address src, FPRegisterID dest)
{
ASSERT(isSSE2Present());
m_assembler.mulsd_rr(src, dest);
}
+ void mulDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
+ {
+ ASSERT(isSSE2Present());
+ if (op1 == dest)
+ mulDouble(op2, dest);
+ else {
+ moveDouble(op2, dest);
+ mulDouble(op1, dest);
+ }
+ }
+
void mulDouble(Address src, FPRegisterID dest)
{
ASSERT(isSSE2Present());
// If the result is not representable as a 32 bit value, branch.
// May also branch for some values that are representable in 32 bits
// (specifically, in this case, INT_MIN).
- Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest)
+ enum BranchTruncateType { BranchIfTruncateFailed, BranchIfTruncateSuccessful };
+ Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
{
ASSERT(isSSE2Present());
m_assembler.cvttsd2si_rr(src, dest);
- return branch32(Equal, dest, Imm32(0x80000000));
+ return branch32(branchType ? NotEqual : Equal, dest, TrustedImm32(0x80000000));
}
// Convert 'src' to an integer, and places the resulting 'dest'.
m_assembler.push_m(address.offset, address.base);
}
- void push(Imm32 imm)
+ void push(TrustedImm32 imm)
{
m_assembler.push_i32(imm.m_value);
}
//
// Move values in registers.
- void move(Imm32 imm, RegisterID dest)
+ void move(TrustedImm32 imm, RegisterID dest)
{
- // Note: on 64-bit the Imm32 value is zero extended into the register, it
+ // Note: on 64-bit the TrustedImm32 value is zero extended into the register, it
// may be useful to have a separate version that sign extends the value?
if (!imm.m_value)
m_assembler.xorl_rr(dest, dest);
m_assembler.movq_rr(src, dest);
}
- void move(ImmPtr imm, RegisterID dest)
+ void move(TrustedImmPtr imm, RegisterID dest)
{
m_assembler.movq_i64r(imm.asIntptr(), dest);
}
m_assembler.movl_rr(src, dest);
}
- void move(ImmPtr imm, RegisterID dest)
+ void move(TrustedImmPtr imm, RegisterID dest)
{
m_assembler.movl_i32r(imm.asIntptr(), dest);
}
// used (representing the names 'below' and 'above').
//
// Operands to the comparision are provided in the expected order, e.g.
- // jle32(reg1, Imm32(5)) will branch if the value held in reg1, when
+ // jle32(reg1, TrustedImm32(5)) will branch if the value held in reg1, when
// treated as a signed 32bit value, is less than or equal to 5.
//
// jz and jnz test whether the first operand is equal to zero, and take
// an optional second operand of a mask under which to perform the test.
public:
- Jump branch8(Condition cond, Address left, Imm32 right)
+ Jump branch8(RelationalCondition cond, Address left, TrustedImm32 right)
{
m_assembler.cmpb_im(right.m_value, left.offset, left.base);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- Jump branch32(Condition cond, RegisterID left, RegisterID right)
+ Jump branch32(RelationalCondition cond, RegisterID left, RegisterID right)
{
m_assembler.cmpl_rr(right, left);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- Jump branch32(Condition cond, RegisterID left, Imm32 right)
+ Jump branch32(RelationalCondition cond, RegisterID left, TrustedImm32 right)
{
if (((cond == Equal) || (cond == NotEqual)) && !right.m_value)
m_assembler.testl_rr(left, left);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- Jump branch32(Condition cond, RegisterID left, Address right)
+ Jump branch32(RelationalCondition cond, TrustedImm32 left, RegisterID right)
+ {
+ if (((cond == Equal) || (cond == NotEqual)) && !left.m_value)
+ m_assembler.testl_rr(right, right);
+ else
+ m_assembler.cmpl_ir(left.m_value, right);
+ return Jump(m_assembler.jCC(x86Condition(commute(cond))));
+ }
+
+ Jump branch32(RelationalCondition cond, RegisterID left, Address right)
{
m_assembler.cmpl_mr(right.offset, right.base, left);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- Jump branch32(Condition cond, Address left, RegisterID right)
+ Jump branch32(RelationalCondition cond, Address left, RegisterID right)
{
m_assembler.cmpl_rm(right, left.offset, left.base);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- Jump branch32(Condition cond, Address left, Imm32 right)
+ Jump branch32(RelationalCondition cond, Address left, TrustedImm32 right)
{
m_assembler.cmpl_im(right.m_value, left.offset, left.base);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- Jump branch32(Condition cond, BaseIndex left, Imm32 right)
+ Jump branch32(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
{
m_assembler.cmpl_im(right.m_value, left.offset, left.base, left.index, left.scale);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right)
+ Jump branch32WithUnalignedHalfWords(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
{
return branch32(cond, left, right);
}
- Jump branch16(Condition cond, BaseIndex left, RegisterID right)
+ Jump branch16(RelationalCondition cond, BaseIndex left, RegisterID right)
{
m_assembler.cmpw_rm(right, left.offset, left.base, left.index, left.scale);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- Jump branch16(Condition cond, BaseIndex left, Imm32 right)
+ Jump branch16(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
{
ASSERT(!(right.m_value & 0xFFFF0000));
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- Jump branchTest32(Condition cond, RegisterID reg, RegisterID mask)
+ Jump branchTest32(ResultCondition cond, RegisterID reg, RegisterID mask)
{
- ASSERT((cond == Zero) || (cond == NonZero));
m_assembler.testl_rr(reg, mask);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- Jump branchTest32(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1))
+ Jump branchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
{
- ASSERT((cond == Zero) || (cond == NonZero));
// if we are only interested in the low seven bits, this can be tested with a testb
if (mask.m_value == -1)
m_assembler.testl_rr(reg, reg);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- Jump branchTest32(Condition cond, Address address, Imm32 mask = Imm32(-1))
+ Jump branchTest32(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
{
- ASSERT((cond == Zero) || (cond == NonZero));
if (mask.m_value == -1)
m_assembler.cmpl_im(0, address.offset, address.base);
else
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- Jump branchTest32(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1))
+ Jump branchTest32(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
{
- ASSERT((cond == Zero) || (cond == NonZero));
if (mask.m_value == -1)
m_assembler.cmpl_im(0, address.offset, address.base, address.index, address.scale);
else
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- Jump branchTest8(Condition cond, Address address, Imm32 mask = Imm32(-1))
+ Jump branchTest8(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
{
- ASSERT((cond == Zero) || (cond == NonZero));
+ // Byte in TrustedImm32 is not well defined, so be a little permisive here, but don't accept nonsense values.
+ ASSERT(mask.m_value >= -128 && mask.m_value <= 255);
+ if (mask.m_value == -1)
+ m_assembler.testb_rr(reg, reg);
+ else
+ m_assembler.testb_i8r(mask.m_value, reg);
+ return Jump(m_assembler.jCC(x86Condition(cond)));
+ }
+
+ Jump branchTest8(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
+ {
+ // Byte in TrustedImm32 is not well defined, so be a little permisive here, but don't accept nonsense values.
+ ASSERT(mask.m_value >= -128 && mask.m_value <= 255);
if (mask.m_value == -1)
m_assembler.cmpb_im(0, address.offset, address.base);
else
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- Jump branchTest8(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1))
+ Jump branchTest8(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
{
- ASSERT((cond == Zero) || (cond == NonZero));
+ // Byte in TrustedImm32 is not well defined, so be a little permisive here, but don't accept nonsense values.
+ ASSERT(mask.m_value >= -128 && mask.m_value <= 255);
if (mask.m_value == -1)
m_assembler.cmpb_im(0, address.offset, address.base, address.index, address.scale);
else
// * jo operations branch if the (signed) arithmetic
// operation caused an overflow to occur.
- Jump branchAdd32(Condition cond, RegisterID src, RegisterID dest)
+ Jump branchAdd32(ResultCondition cond, RegisterID src, RegisterID dest)
{
- ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
add32(src, dest);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- Jump branchAdd32(Condition cond, Imm32 imm, RegisterID dest)
+ Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
{
- ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
add32(imm, dest);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- Jump branchAdd32(Condition cond, Imm32 src, Address dest)
+ Jump branchAdd32(ResultCondition cond, TrustedImm32 src, Address dest)
{
- ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero));
add32(src, dest);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- Jump branchAdd32(Condition cond, RegisterID src, Address dest)
+ Jump branchAdd32(ResultCondition cond, RegisterID src, Address dest)
{
- ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero));
add32(src, dest);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- Jump branchAdd32(Condition cond, Address src, RegisterID dest)
+ Jump branchAdd32(ResultCondition cond, Address src, RegisterID dest)
{
- ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero));
add32(src, dest);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- Jump branchMul32(Condition cond, RegisterID src, RegisterID dest)
+ Jump branchAdd32(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest)
+ {
+ if (src1 == dest)
+ return branchAdd32(cond, src2, dest);
+ move(src2, dest);
+ return branchAdd32(cond, src1, dest);
+ }
+
+ Jump branchAdd32(ResultCondition cond, RegisterID src, TrustedImm32 imm, RegisterID dest)
+ {
+ move(src, dest);
+ return branchAdd32(cond, imm, dest);
+ }
+
+ Jump branchMul32(ResultCondition cond, RegisterID src, RegisterID dest)
{
- ASSERT(cond == Overflow);
mul32(src, dest);
+ if (cond != Overflow)
+ m_assembler.testl_rr(dest, dest);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- Jump branchMul32(Condition cond, Address src, RegisterID dest)
+ Jump branchMul32(ResultCondition cond, Address src, RegisterID dest)
{
- ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero));
mul32(src, dest);
+ if (cond != Overflow)
+ m_assembler.testl_rr(dest, dest);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- Jump branchMul32(Condition cond, Imm32 imm, RegisterID src, RegisterID dest)
+ Jump branchMul32(ResultCondition cond, TrustedImm32 imm, RegisterID src, RegisterID dest)
{
- ASSERT(cond == Overflow);
mul32(imm, src, dest);
+ if (cond != Overflow)
+ m_assembler.testl_rr(dest, dest);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- Jump branchSub32(Condition cond, RegisterID src, RegisterID dest)
+ Jump branchMul32(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest)
+ {
+ if (src1 == dest)
+ return branchMul32(cond, src2, dest);
+ move(src2, dest);
+ return branchMul32(cond, src1, dest);
+ }
+
+ Jump branchSub32(ResultCondition cond, RegisterID src, RegisterID dest)
{
- ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
sub32(src, dest);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- Jump branchSub32(Condition cond, Imm32 imm, RegisterID dest)
+ Jump branchSub32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
{
- ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
sub32(imm, dest);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- Jump branchSub32(Condition cond, Imm32 imm, Address dest)
+ Jump branchSub32(ResultCondition cond, TrustedImm32 imm, Address dest)
{
- ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero));
sub32(imm, dest);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- Jump branchSub32(Condition cond, RegisterID src, Address dest)
+ Jump branchSub32(ResultCondition cond, RegisterID src, Address dest)
{
- ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero));
sub32(src, dest);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- Jump branchSub32(Condition cond, Address src, RegisterID dest)
+ Jump branchSub32(ResultCondition cond, Address src, RegisterID dest)
{
- ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero));
sub32(src, dest);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- Jump branchNeg32(Condition cond, RegisterID srcDest)
+ Jump branchSub32(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest)
+ {
+ // B := A - B is invalid.
+ ASSERT(src1 == dest || src2 != dest);
+
+ move(src1, dest);
+ return branchSub32(cond, src2, dest);
+ }
+
+ Jump branchSub32(ResultCondition cond, RegisterID src1, TrustedImm32 src2, RegisterID dest)
+ {
+ move(src1, dest);
+ return branchSub32(cond, src2, dest);
+ }
+
+ Jump branchNeg32(ResultCondition cond, RegisterID srcDest)
{
- ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero));
neg32(srcDest);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- Jump branchOr32(Condition cond, RegisterID src, RegisterID dest)
+ Jump branchOr32(ResultCondition cond, RegisterID src, RegisterID dest)
{
- ASSERT((cond == Signed) || (cond == Zero) || (cond == NonZero));
or32(src, dest);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
m_assembler.ret();
}
- void set8(Condition cond, RegisterID left, RegisterID right, RegisterID dest)
- {
- m_assembler.cmpl_rr(right, left);
- m_assembler.setCC_r(x86Condition(cond), dest);
- }
-
- void set8(Condition cond, Address left, RegisterID right, RegisterID dest)
- {
- m_assembler.cmpl_mr(left.offset, left.base, right);
- m_assembler.setCC_r(x86Condition(cond), dest);
- }
-
- void set8(Condition cond, RegisterID left, Imm32 right, RegisterID dest)
- {
- if (((cond == Equal) || (cond == NotEqual)) && !right.m_value)
- m_assembler.testl_rr(left, left);
- else
- m_assembler.cmpl_ir(right.m_value, left);
- m_assembler.setCC_r(x86Condition(cond), dest);
- }
-
- void set32(Condition cond, RegisterID left, RegisterID right, RegisterID dest)
+ void compare32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID dest)
{
m_assembler.cmpl_rr(right, left);
m_assembler.setCC_r(x86Condition(cond), dest);
m_assembler.movzbl_rr(dest, dest);
}
- void set32(Condition cond, RegisterID left, Imm32 right, RegisterID dest)
+ void compare32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
{
if (((cond == Equal) || (cond == NotEqual)) && !right.m_value)
m_assembler.testl_rr(left, left);
// dest-src, operations always have a dest? ... possibly not true, considering
// asm ops like test, or pseudo ops like pop().
- void setTest8(Condition cond, Address address, Imm32 mask, RegisterID dest)
+ void test8(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
{
if (mask.m_value == -1)
m_assembler.cmpb_im(0, address.offset, address.base);
m_assembler.movzbl_rr(dest, dest);
}
- void setTest32(Condition cond, Address address, Imm32 mask, RegisterID dest)
+ void test32(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
{
if (mask.m_value == -1)
m_assembler.cmpl_im(0, address.offset, address.base);
m_assembler.movzbl_rr(dest, dest);
}
+ // Invert a relational condition, e.g. == becomes !=, < becomes >=, etc.
+ static RelationalCondition invert(RelationalCondition cond)
+ {
+ return static_cast<RelationalCondition>(cond ^ 1);
+ }
+
+ // Commute a relational condition, returns a new condition that will produce
+ // the same results given the same inputs but with their positions exchanged.
+ static RelationalCondition commute(RelationalCondition cond)
+ {
+ // Equality is commutative!
+ if (cond == Equal || cond == NotEqual)
+ return cond;
+
+ // Based on the values of x86 condition codes, remap > with < and >= with <=
+ if (cond >= LessThan) {
+ ASSERT(cond == LessThan || cond == LessThanOrEqual || cond == GreaterThan || cond == GreaterThanOrEqual);
+ return static_cast<RelationalCondition>(X86Assembler::ConditionL + X86Assembler::ConditionG - cond);
+ }
+
+ // As above, for unsigned conditions.
+ ASSERT(cond == Below || cond == BelowOrEqual || cond == Above || cond == AboveOrEqual);
+ return static_cast<RelationalCondition>(X86Assembler::ConditionB + X86Assembler::ConditionA - cond);
+ }
+
+ void nop()
+ {
+ m_assembler.nop();
+ }
+
protected:
- X86Assembler::Condition x86Condition(Condition cond)
+ X86Assembler::Condition x86Condition(RelationalCondition cond)
+ {
+ return static_cast<X86Assembler::Condition>(cond);
+ }
+
+ X86Assembler::Condition x86Condition(ResultCondition cond)
{
return static_cast<X86Assembler::Condition>(cond);
}
using MacroAssemblerX86Common::load32;
using MacroAssemblerX86Common::store32;
using MacroAssemblerX86Common::call;
+ using MacroAssemblerX86Common::addDouble;
using MacroAssemblerX86Common::loadDouble;
using MacroAssemblerX86Common::convertInt32ToDouble;
- void add32(Imm32 imm, AbsoluteAddress address)
+ void add32(TrustedImm32 imm, AbsoluteAddress address)
{
- move(ImmPtr(address.m_ptr), scratchRegister);
+ move(TrustedImmPtr(address.m_ptr), scratchRegister);
add32(imm, Address(scratchRegister));
}
- void and32(Imm32 imm, AbsoluteAddress address)
+ void and32(TrustedImm32 imm, AbsoluteAddress address)
{
- move(ImmPtr(address.m_ptr), scratchRegister);
+ move(TrustedImmPtr(address.m_ptr), scratchRegister);
and32(imm, Address(scratchRegister));
}
- void or32(Imm32 imm, AbsoluteAddress address)
+ void or32(TrustedImm32 imm, AbsoluteAddress address)
{
- move(ImmPtr(address.m_ptr), scratchRegister);
+ move(TrustedImmPtr(address.m_ptr), scratchRegister);
or32(imm, Address(scratchRegister));
}
- void sub32(Imm32 imm, AbsoluteAddress address)
+ void sub32(TrustedImm32 imm, AbsoluteAddress address)
{
- move(ImmPtr(address.m_ptr), scratchRegister);
+ move(TrustedImmPtr(address.m_ptr), scratchRegister);
sub32(imm, Address(scratchRegister));
}
void loadDouble(const void* address, FPRegisterID dest)
{
- move(ImmPtr(address), scratchRegister);
+ move(TrustedImmPtr(address), scratchRegister);
loadDouble(scratchRegister, dest);
}
- void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest)
+ void addDouble(AbsoluteAddress address, FPRegisterID dest)
{
- move(Imm32(*static_cast<int32_t*>(src.m_ptr)), scratchRegister);
+ move(TrustedImmPtr(address.m_ptr), scratchRegister);
+ m_assembler.addsd_mr(0, scratchRegister, dest);
+ }
+
+ void convertInt32ToDouble(TrustedImm32 imm, FPRegisterID dest)
+ {
+ move(imm, scratchRegister);
m_assembler.cvtsi2sd_rr(scratchRegister, dest);
}
- void store32(Imm32 imm, void* address)
+ void store32(TrustedImm32 imm, void* address)
{
move(X86Registers::eax, scratchRegister);
move(imm, X86Registers::eax);
Call call()
{
- DataLabelPtr label = moveWithPatch(ImmPtr(0), scratchRegister);
+ DataLabelPtr label = moveWithPatch(TrustedImmPtr(0), scratchRegister);
Call result = Call(m_assembler.call(scratchRegister), Call::Linkable);
- ASSERT(differenceBetween(label, result) == REPTACH_OFFSET_CALL_R11);
+ ASSERT_UNUSED(label, differenceBetween(label, result) == REPTACH_OFFSET_CALL_R11);
return result;
}
Call tailRecursiveCall()
{
- DataLabelPtr label = moveWithPatch(ImmPtr(0), scratchRegister);
+ DataLabelPtr label = moveWithPatch(TrustedImmPtr(0), scratchRegister);
Jump newJump = Jump(m_assembler.jmp_r(scratchRegister));
- ASSERT(differenceBetween(label, newJump) == REPTACH_OFFSET_CALL_R11);
+ ASSERT_UNUSED(label, differenceBetween(label, newJump) == REPTACH_OFFSET_CALL_R11);
return Call::fromTailJump(newJump);
}
Call makeTailRecursiveCall(Jump oldJump)
{
oldJump.link(this);
- DataLabelPtr label = moveWithPatch(ImmPtr(0), scratchRegister);
+ DataLabelPtr label = moveWithPatch(TrustedImmPtr(0), scratchRegister);
Jump newJump = Jump(m_assembler.jmp_r(scratchRegister));
- ASSERT(differenceBetween(label, newJump) == REPTACH_OFFSET_CALL_R11);
+ ASSERT_UNUSED(label, differenceBetween(label, newJump) == REPTACH_OFFSET_CALL_R11);
return Call::fromTailJump(newJump);
}
m_assembler.addq_rr(src, dest);
}
- void addPtr(Imm32 imm, RegisterID srcDest)
+ void addPtr(TrustedImm32 imm, RegisterID srcDest)
{
m_assembler.addq_ir(imm.m_value, srcDest);
}
- void addPtr(ImmPtr imm, RegisterID dest)
+ void addPtr(TrustedImmPtr imm, RegisterID dest)
{
move(imm, scratchRegister);
m_assembler.addq_rr(scratchRegister, dest);
}
- void addPtr(Imm32 imm, RegisterID src, RegisterID dest)
+ void addPtr(TrustedImm32 imm, RegisterID src, RegisterID dest)
{
m_assembler.leaq_mr(imm.m_value, src, dest);
}
- void addPtr(Imm32 imm, Address address)
+ void addPtr(TrustedImm32 imm, Address address)
{
m_assembler.addq_im(imm.m_value, address.offset, address.base);
}
- void addPtr(Imm32 imm, AbsoluteAddress address)
+ void addPtr(TrustedImm32 imm, AbsoluteAddress address)
{
- move(ImmPtr(address.m_ptr), scratchRegister);
+ move(TrustedImmPtr(address.m_ptr), scratchRegister);
addPtr(imm, Address(scratchRegister));
}
m_assembler.andq_rr(src, dest);
}
- void andPtr(Imm32 imm, RegisterID srcDest)
+ void andPtr(TrustedImm32 imm, RegisterID srcDest)
{
m_assembler.andq_ir(imm.m_value, srcDest);
}
m_assembler.orq_rr(src, dest);
}
- void orPtr(ImmPtr imm, RegisterID dest)
+ void orPtr(TrustedImmPtr imm, RegisterID dest)
{
move(imm, scratchRegister);
m_assembler.orq_rr(scratchRegister, dest);
}
- void orPtr(Imm32 imm, RegisterID dest)
+ void orPtr(TrustedImm32 imm, RegisterID dest)
{
m_assembler.orq_ir(imm.m_value, dest);
}
+ void orPtr(RegisterID op1, RegisterID op2, RegisterID dest)
+ {
+ if (op1 == op2)
+ move(op1, dest);
+ else if (op1 == dest)
+ orPtr(op2, dest);
+ else {
+ move(op2, dest);
+ orPtr(op1, dest);
+ }
+ }
+
+ void orPtr(TrustedImm32 imm, RegisterID src, RegisterID dest)
+ {
+ move(src, dest);
+ orPtr(imm, dest);
+ }
+
void subPtr(RegisterID src, RegisterID dest)
{
m_assembler.subq_rr(src, dest);
}
- void subPtr(Imm32 imm, RegisterID dest)
+ void subPtr(TrustedImm32 imm, RegisterID dest)
{
m_assembler.subq_ir(imm.m_value, dest);
}
- void subPtr(ImmPtr imm, RegisterID dest)
+ void subPtr(TrustedImmPtr imm, RegisterID dest)
{
move(imm, scratchRegister);
m_assembler.subq_rr(scratchRegister, dest);
m_assembler.xorq_rr(src, dest);
}
- void xorPtr(Imm32 imm, RegisterID srcDest)
+ void xorPtr(TrustedImm32 imm, RegisterID srcDest)
{
m_assembler.xorq_ir(imm.m_value, srcDest);
}
m_assembler.movq_mr(address.offset, address.base, address.index, address.scale, dest);
}
- void loadPtr(void* address, RegisterID dest)
+ void loadPtr(const void* address, RegisterID dest)
{
if (dest == X86Registers::eax)
m_assembler.movq_mEAX(address);
m_assembler.movq_mr_disp32(address.offset, address.base, dest);
return DataLabel32(this);
}
+
+ DataLabelCompact loadPtrWithCompactAddressOffsetPatch(Address address, RegisterID dest)
+ {
+ m_assembler.movq_mr_disp8(address.offset, address.base, dest);
+ return DataLabelCompact(this);
+ }
void storePtr(RegisterID src, ImplicitAddress address)
{
}
}
- void storePtr(ImmPtr imm, ImplicitAddress address)
+ void storePtr(TrustedImmPtr imm, ImplicitAddress address)
{
move(imm, scratchRegister);
storePtr(scratchRegister, address);
m_assembler.movq_rr(src, dest);
}
- void setPtr(Condition cond, RegisterID left, Imm32 right, RegisterID dest)
+ void comparePtr(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
{
if (((cond == Equal) || (cond == NotEqual)) && !right.m_value)
m_assembler.testq_rr(left, left);
m_assembler.movzbl_rr(dest, dest);
}
- Jump branchPtr(Condition cond, RegisterID left, RegisterID right)
+ Jump branchPtr(RelationalCondition cond, RegisterID left, RegisterID right)
{
m_assembler.cmpq_rr(right, left);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- Jump branchPtr(Condition cond, RegisterID left, ImmPtr right)
+ Jump branchPtr(RelationalCondition cond, RegisterID left, TrustedImmPtr right)
{
move(right, scratchRegister);
return branchPtr(cond, left, scratchRegister);
}
- Jump branchPtr(Condition cond, RegisterID left, Address right)
+ Jump branchPtr(RelationalCondition cond, RegisterID left, Address right)
{
m_assembler.cmpq_mr(right.offset, right.base, left);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- Jump branchPtr(Condition cond, AbsoluteAddress left, RegisterID right)
+ Jump branchPtr(RelationalCondition cond, AbsoluteAddress left, RegisterID right)
{
- move(ImmPtr(left.m_ptr), scratchRegister);
+ move(TrustedImmPtr(left.m_ptr), scratchRegister);
return branchPtr(cond, Address(scratchRegister), right);
}
- Jump branchPtr(Condition cond, Address left, RegisterID right)
+ Jump branchPtr(RelationalCondition cond, Address left, RegisterID right)
{
m_assembler.cmpq_rm(right, left.offset, left.base);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- Jump branchPtr(Condition cond, Address left, ImmPtr right)
+ Jump branchPtr(RelationalCondition cond, Address left, TrustedImmPtr right)
{
move(right, scratchRegister);
return branchPtr(cond, left, scratchRegister);
}
- Jump branchTestPtr(Condition cond, RegisterID reg, RegisterID mask)
+ Jump branchTestPtr(ResultCondition cond, RegisterID reg, RegisterID mask)
{
m_assembler.testq_rr(reg, mask);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- Jump branchTestPtr(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1))
+ Jump branchTestPtr(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
{
// if we are only interested in the low seven bits, this can be tested with a testb
if (mask.m_value == -1)
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- Jump branchTestPtr(Condition cond, Address address, Imm32 mask = Imm32(-1))
+ Jump branchTestPtr(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1))
+ {
+ loadPtr(address.m_ptr, scratchRegister);
+ return branchTestPtr(cond, scratchRegister, mask);
+ }
+
+ Jump branchTestPtr(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
{
if (mask.m_value == -1)
m_assembler.cmpq_im(0, address.offset, address.base);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- Jump branchTestPtr(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1))
+ Jump branchTestPtr(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
{
if (mask.m_value == -1)
m_assembler.cmpq_im(0, address.offset, address.base, address.index, address.scale);
}
- Jump branchAddPtr(Condition cond, RegisterID src, RegisterID dest)
+ Jump branchAddPtr(ResultCondition cond, RegisterID src, RegisterID dest)
{
- ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero));
addPtr(src, dest);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- Jump branchSubPtr(Condition cond, Imm32 imm, RegisterID dest)
+ Jump branchSubPtr(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
{
- ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero));
subPtr(imm, dest);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest)
+ DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
{
m_assembler.movq_i64r(initialValue.asIntptr(), dest);
return DataLabelPtr(this);
}
- Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0))
+ Jump branchPtrWithPatch(RelationalCondition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
{
dataLabel = moveWithPatch(initialRightValue, scratchRegister);
return branchPtr(cond, left, scratchRegister);
}
- Jump branchPtrWithPatch(Condition cond, Address left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0))
+ Jump branchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
{
dataLabel = moveWithPatch(initialRightValue, scratchRegister);
return branchPtr(cond, left, scratchRegister);
}
- DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address)
+ DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
{
DataLabelPtr label = moveWithPatch(initialValue, scratchRegister);
storePtr(scratchRegister, address);
}
using MacroAssemblerX86Common::branchTest8;
- Jump branchTest8(Condition cond, ExtendedAddress address, Imm32 mask = Imm32(-1))
+ Jump branchTest8(ResultCondition cond, ExtendedAddress address, TrustedImm32 mask = TrustedImm32(-1))
{
- ImmPtr addr(reinterpret_cast<void*>(address.offset));
+ TrustedImmPtr addr(reinterpret_cast<void*>(address.offset));
MacroAssemblerX86Common::move(addr, scratchRegister);
return MacroAssemblerX86Common::branchTest8(cond, BaseIndex(scratchRegister, address.base, TimesOne), mask);
}
- Label loadPtrWithPatchToLEA(Address address, RegisterID dest)
- {
- Label label(this);
- loadPtr(address, dest);
- return label;
- }
-
bool supportsFloatingPoint() const { return true; }
// See comment on MacroAssemblerARMv7::supportsFloatingPointTruncate()
bool supportsFloatingPointTruncate() const { return true; }
static void linkCall(void* code, Call call, FunctionPtr function)
{
if (!call.isFlagSet(Call::Near))
- X86Assembler::linkPointer(code, X86Assembler::labelFor(call.m_jmp, -REPTACH_OFFSET_CALL_R11), function.value());
+ X86Assembler::linkPointer(code, call.m_jmp.labelAtOffset(-REPTACH_OFFSET_CALL_R11), function.value());
else
X86Assembler::linkCall(code, call.m_jmp, function.value());
}
MacroAssembler::repatchInt32(dataLabel32, value);
}
- void repatch(CodeLocationDataLabelPtr dataLabelPtr, void* value)
+ void repatch(CodeLocationDataLabelCompact dataLabelCompact, int32_t value)
{
- MacroAssembler::repatchPointer(dataLabelPtr, value);
+ MacroAssembler::repatchCompact(dataLabelCompact, value);
}
- void repatchLoadPtrToLEA(CodeLocationInstruction instruction)
+ void repatch(CodeLocationDataLabelPtr dataLabelPtr, void* value)
{
- MacroAssembler::repatchLoadPtrToLEA(instruction);
+ MacroAssembler::repatchPointer(dataLabelPtr, value);
}
void relinkCallerToTrampoline(ReturnAddressPtr returnAddress, CodeLocationLabel label)
--- /dev/null
+/*
+ * Copyright (C) 2009-2011 STMicroelectronics. All rights reserved.
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SH4Assembler_h
+#define SH4Assembler_h
+
+#if ENABLE(ASSEMBLER) && CPU(SH4)
+
+#include "AssemblerBuffer.h"
+#include "AssemblerBufferWithConstantPool.h"
+#include <stdarg.h>
+#include <stdint.h>
+#include <wtf/Assertions.h>
+#include <wtf/Vector.h>
+
+#ifndef NDEBUG
+#define SH4_ASSEMBLER_TRACING
+#endif
+
+namespace JSC {
+typedef uint16_t SH4Word;
+
+enum {
+ INVALID_OPCODE = 0xffff,
+ ADD_OPCODE = 0x300c,
+ ADDIMM_OPCODE = 0x7000,
+ ADDC_OPCODE = 0x300e,
+ ADDV_OPCODE = 0x300f,
+ AND_OPCODE = 0x2009,
+ ANDIMM_OPCODE = 0xc900,
+ DIV0_OPCODE = 0x2007,
+ DIV1_OPCODE = 0x3004,
+ BF_OPCODE = 0x8b00,
+ BFS_OPCODE = 0x8f00,
+ BRA_OPCODE = 0xa000,
+ BRAF_OPCODE = 0x0023,
+ NOP_OPCODE = 0x0009,
+ BSR_OPCODE = 0xb000,
+ RTS_OPCODE = 0x000b,
+ BT_OPCODE = 0x8900,
+ BTS_OPCODE = 0x8d00,
+ BSRF_OPCODE = 0x0003,
+ BRK_OPCODE = 0x003b,
+ FTRC_OPCODE = 0xf03d,
+ CMPEQ_OPCODE = 0x3000,
+ CMPEQIMM_OPCODE = 0x8800,
+ CMPGE_OPCODE = 0x3003,
+ CMPGT_OPCODE = 0x3007,
+ CMPHI_OPCODE = 0x3006,
+ CMPHS_OPCODE = 0x3002,
+ CMPPL_OPCODE = 0x4015,
+ CMPPZ_OPCODE = 0x4011,
+ CMPSTR_OPCODE = 0x200c,
+ DT_OPCODE = 0x4010,
+ FCMPEQ_OPCODE = 0xf004,
+ FCMPGT_OPCODE = 0xf005,
+ FMOV_OPCODE = 0xf00c,
+ FADD_OPCODE = 0xf000,
+ FMUL_OPCODE = 0xf002,
+ FSUB_OPCODE = 0xf001,
+ FDIV_OPCODE = 0xf003,
+ FNEG_OPCODE = 0xf04d,
+ JMP_OPCODE = 0x402b,
+ JSR_OPCODE = 0x400b,
+ LDSPR_OPCODE = 0x402a,
+ LDSLPR_OPCODE = 0x4026,
+ MOV_OPCODE = 0x6003,
+ MOVIMM_OPCODE = 0xe000,
+ MOVB_WRITE_RN_OPCODE = 0x2000,
+ MOVB_WRITE_RNDEC_OPCODE = 0x2004,
+ MOVB_WRITE_R0RN_OPCODE = 0x0004,
+ MOVB_WRITE_OFFGBR_OPCODE = 0xc000,
+ MOVB_WRITE_OFFRN_OPCODE = 0x8000,
+ MOVB_READ_RM_OPCODE = 0x6000,
+ MOVB_READ_RMINC_OPCODE = 0x6004,
+ MOVB_READ_R0RM_OPCODE = 0x000c,
+ MOVB_READ_OFFGBR_OPCODE = 0xc400,
+ MOVB_READ_OFFRM_OPCODE = 0x8400,
+ MOVL_WRITE_RN_OPCODE = 0x2002,
+ MOVL_WRITE_RNDEC_OPCODE = 0x2006,
+ MOVL_WRITE_R0RN_OPCODE = 0x0006,
+ MOVL_WRITE_OFFGBR_OPCODE = 0xc200,
+ MOVL_WRITE_OFFRN_OPCODE = 0x1000,
+ MOVL_READ_RM_OPCODE = 0x6002,
+ MOVL_READ_RMINC_OPCODE = 0x6006,
+ MOVL_READ_R0RM_OPCODE = 0x000e,
+ MOVL_READ_OFFGBR_OPCODE = 0xc600,
+ MOVL_READ_OFFPC_OPCODE = 0xd000,
+ MOVL_READ_OFFRM_OPCODE = 0x5000,
+ MOVW_WRITE_RN_OPCODE = 0x2001,
+ MOVW_READ_RM_OPCODE = 0x6001,
+ MOVW_READ_R0RM_OPCODE = 0x000d,
+ MOVW_READ_OFFRM_OPCODE = 0x8500,
+ MOVW_READ_OFFPC_OPCODE = 0x9000,
+ MOVA_READ_OFFPC_OPCODE = 0xc700,
+ MOVT_OPCODE = 0x0029,
+ MULL_OPCODE = 0x0007,
+ DMULL_L_OPCODE = 0x3005,
+ STSMACL_OPCODE = 0x001a,
+ STSMACH_OPCODE = 0x000a,
+ DMULSL_OPCODE = 0x300d,
+ NEG_OPCODE = 0x600b,
+ NEGC_OPCODE = 0x600a,
+ NOT_OPCODE = 0x6007,
+ OR_OPCODE = 0x200b,
+ ORIMM_OPCODE = 0xcb00,
+ ORBIMM_OPCODE = 0xcf00,
+ SETS_OPCODE = 0x0058,
+ SETT_OPCODE = 0x0018,
+ SHAD_OPCODE = 0x400c,
+ SHAL_OPCODE = 0x4020,
+ SHAR_OPCODE = 0x4021,
+ SHLD_OPCODE = 0x400d,
+ SHLL_OPCODE = 0x4000,
+ SHLL2_OPCODE = 0x4008,
+ SHLL8_OPCODE = 0x4018,
+ SHLL16_OPCODE = 0x4028,
+ SHLR_OPCODE = 0x4001,
+ SHLR2_OPCODE = 0x4009,
+ SHLR8_OPCODE = 0x4019,
+ SHLR16_OPCODE = 0x4029,
+ STSPR_OPCODE = 0x002a,
+ STSLPR_OPCODE = 0x4022,
+ FLOAT_OPCODE = 0xf02d,
+ SUB_OPCODE = 0x3008,
+ SUBC_OPCODE = 0x300a,
+ SUBV_OPCODE = 0x300b,
+ TST_OPCODE = 0x2008,
+ TSTIMM_OPCODE = 0xc800,
+ TSTB_OPCODE = 0xcc00,
+ EXTUW_OPCODE = 0x600d,
+ XOR_OPCODE = 0x200a,
+ XORIMM_OPCODE = 0xca00,
+ XORB_OPCODE = 0xce00,
+ FMOVS_READ_RM_INC_OPCODE = 0xf009,
+ FMOVS_READ_RM_OPCODE = 0xf008,
+ FMOVS_READ_R0RM_OPCODE = 0xf006,
+ FMOVS_WRITE_RN_OPCODE = 0xf00a,
+ FMOVS_WRITE_RN_DEC_OPCODE = 0xf00b,
+ FMOVS_WRITE_R0RN_OPCODE = 0xf007,
+ FCNVDS_DRM_FPUL_OPCODE = 0xf0bd,
+ LDS_RM_FPUL_OPCODE = 0x405a,
+ FLDS_FRM_FPUL_OPCODE = 0xf01d,
+ STS_FPUL_RN_OPCODE = 0x005a,
+ FSTS_FPUL_FRN_OPCODE = 0xF00d,
+ LDSFPSCR_OPCODE = 0x406a,
+ STSFPSCR_OPCODE = 0x006a,
+ LDSRMFPUL_OPCODE = 0x405a,
+ FSTSFPULFRN_OPCODE = 0xf00d,
+ FSQRT_OPCODE = 0xf06d,
+ FSCHG_OPCODE = 0xf3fd,
+ CLRT_OPCODE = 8,
+};
+
+namespace SH4Registers {
+typedef enum {
+ r0,
+ r1,
+ r2,
+ r3,
+ r4,
+ r5,
+ r6,
+ r7,
+ r8,
+ r9,
+ r10,
+ r11,
+ r12,
+ r13,
+ r14, fp = r14,
+ r15, sp = r15,
+ pc,
+ pr,
+} RegisterID;
+
+typedef enum {
+ fr0, dr0 = fr0,
+ fr1,
+ fr2, dr2 = fr2,
+ fr3,
+ fr4, dr4 = fr4,
+ fr5,
+ fr6, dr6 = fr6,
+ fr7,
+ fr8, dr8 = fr8,
+ fr9,
+ fr10, dr10 = fr10,
+ fr11,
+ fr12, dr12 = fr12,
+ fr13,
+ fr14, dr14 = fr14,
+ fr15,
+} FPRegisterID;
+}
+
+inline uint16_t getOpcodeGroup1(uint16_t opc, int rm, int rn)
+{
+ return (opc | ((rm & 0xf) << 8) | ((rn & 0xf) << 4));
+}
+
+inline uint16_t getOpcodeGroup2(uint16_t opc, int rm)
+{
+ return (opc | ((rm & 0xf) << 8));
+}
+
+inline uint16_t getOpcodeGroup3(uint16_t opc, int rm, int rn)
+{
+ return (opc | ((rm & 0xf) << 8) | (rn & 0xff));
+}
+
+inline uint16_t getOpcodeGroup4(uint16_t opc, int rm, int rn, int offset)
+{
+ return (opc | ((rm & 0xf) << 8) | ((rn & 0xf) << 4) | (offset & 0xf));
+}
+
+inline uint16_t getOpcodeGroup5(uint16_t opc, int rm)
+{
+ return (opc | (rm & 0xff));
+}
+
+inline uint16_t getOpcodeGroup6(uint16_t opc, int rm)
+{
+ return (opc | (rm & 0xfff));
+}
+
+inline uint16_t getOpcodeGroup7(uint16_t opc, int rm)
+{
+ return (opc | ((rm & 0x7) << 9));
+}
+
+inline uint16_t getOpcodeGroup8(uint16_t opc, int rm, int rn)
+{
+ return (opc | ((rm & 0x7) << 9) | ((rn & 0x7) << 5));
+}
+
+inline uint16_t getOpcodeGroup9(uint16_t opc, int rm, int rn)
+{
+ return (opc | ((rm & 0xf) << 8) | ((rn & 0x7) << 5));
+}
+
+inline uint16_t getOpcodeGroup10(uint16_t opc, int rm, int rn)
+{
+ return (opc | ((rm & 0x7) << 9) | ((rn & 0xf) << 4));
+}
+
+inline uint16_t getOpcodeGroup11(uint16_t opc, int rm, int rn)
+{
+ return (opc | ((rm & 0xf) << 4) | (rn & 0xf));
+}
+
+inline uint16_t getRn(uint16_t x)
+{
+ return ((x & 0xf00) >> 8);
+}
+
+inline uint16_t getRm(uint16_t x)
+{
+ return ((x & 0xf0) >> 4);
+}
+
+inline uint16_t getDisp(uint16_t x)
+{
+ return (x & 0xf);
+}
+
+inline uint16_t getImm8(uint16_t x)
+{
+ return (x & 0xff);
+}
+
+inline uint16_t getImm12(uint16_t x)
+{
+ return (x & 0xfff);
+}
+
+inline uint16_t getDRn(uint16_t x)
+{
+ return ((x & 0xe00) >> 9);
+}
+
+inline uint16_t getDRm(uint16_t x)
+{
+ return ((x & 0xe0) >> 5);
+}
+
+class SH4Assembler {
+public:
+ typedef SH4Registers::RegisterID RegisterID;
+ typedef SH4Registers::FPRegisterID FPRegisterID;
+ typedef AssemblerBufferWithConstantPool<512, 4, 2, SH4Assembler> SH4Buffer;
+ static const RegisterID scratchReg1 = SH4Registers::r3;
+ static const RegisterID scratchReg2 = SH4Registers::r11;
+ static const uint32_t maxInstructionSize = 16;
+
+ enum {
+ padForAlign8 = 0x00,
+ padForAlign16 = 0x0009,
+ padForAlign32 = 0x00090009,
+ };
+
+ SH4Assembler()
+ {
+ m_claimscratchReg = 0x0;
+ }
+
+ // SH4 condition codes
+ typedef enum {
+ EQ = 0x0, // Equal
+ NE = 0x1, // Not Equal
+ HS = 0x2, // Unsigend Greater Than equal
+ HI = 0x3, // Unsigend Greater Than
+ LS = 0x4, // Unsigend Lower or Same
+ LI = 0x5, // Unsigend Lower
+ GE = 0x6, // Greater or Equal
+ LT = 0x7, // Less Than
+ GT = 0x8, // Greater Than
+ LE = 0x9, // Less or Equal
+ OF = 0xa, // OverFlow
+ SI = 0xb, // Signed
+ EQU= 0xc, // Equal or unordered(NaN)
+ NEU= 0xd,
+ GTU= 0xe,
+ GEU= 0xf,
+ LTU= 0x10,
+ LEU= 0x11,
+ } Condition;
+
+ // Opaque label types
+public:
+ bool isImmediate(int constant)
+ {
+ return ((constant <= 127) && (constant >= -128));
+ }
+
+ RegisterID claimScratch()
+ {
+ ASSERT((m_claimscratchReg != 0x3));
+
+ if (!(m_claimscratchReg & 0x1)) {
+ m_claimscratchReg = (m_claimscratchReg | 0x1);
+ return scratchReg1;
+ }
+
+ m_claimscratchReg = (m_claimscratchReg | 0x2);
+ return scratchReg2;
+ }
+
+ void releaseScratch(RegisterID scratchR)
+ {
+ if (scratchR == scratchReg1)
+ m_claimscratchReg = (m_claimscratchReg & 0x2);
+ else
+ m_claimscratchReg = (m_claimscratchReg & 0x1);
+ }
+
+ // Stack operations
+
+ void pushReg(RegisterID reg)
+ {
+ if (reg == SH4Registers::pr) {
+ oneShortOp(getOpcodeGroup2(STSLPR_OPCODE, SH4Registers::sp));
+ return;
+ }
+
+ oneShortOp(getOpcodeGroup1(MOVL_WRITE_RNDEC_OPCODE, SH4Registers::sp, reg));
+ }
+
+ void popReg(RegisterID reg)
+ {
+ if (reg == SH4Registers::pr) {
+ oneShortOp(getOpcodeGroup2(LDSLPR_OPCODE, SH4Registers::sp));
+ return;
+ }
+
+ oneShortOp(getOpcodeGroup1(MOVL_READ_RMINC_OPCODE, reg, SH4Registers::sp));
+ }
+
+ void movt(RegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup2(MOVT_OPCODE, dst);
+ oneShortOp(opc);
+ }
+
+ // Arithmetic operations
+
+ void addlRegReg(RegisterID src, RegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup1(ADD_OPCODE, dst, src);
+ oneShortOp(opc);
+ }
+
+ void addclRegReg(RegisterID src, RegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup1(ADDC_OPCODE, dst, src);
+ oneShortOp(opc);
+ }
+
+ void addvlRegReg(RegisterID src, RegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup1(ADDV_OPCODE, dst, src);
+ oneShortOp(opc);
+ }
+
+ void addlImm8r(int imm8, RegisterID dst)
+ {
+ ASSERT((imm8 <= 127) && (imm8 >= -128));
+
+ uint16_t opc = getOpcodeGroup3(ADDIMM_OPCODE, dst, imm8);
+ oneShortOp(opc);
+ }
+
+ void andlRegReg(RegisterID src, RegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup1(AND_OPCODE, dst, src);
+ oneShortOp(opc);
+ }
+
+ void andlImm8r(int imm8, RegisterID dst)
+ {
+ ASSERT((imm8 <= 255) && (imm8 >= 0));
+ ASSERT(dst == SH4Registers::r0);
+
+ uint16_t opc = getOpcodeGroup5(ANDIMM_OPCODE, imm8);
+ oneShortOp(opc);
+ }
+
+ void div1lRegReg(RegisterID src, RegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup1(DIV1_OPCODE, dst, src);
+ oneShortOp(opc);
+ }
+
+ void div0lRegReg(RegisterID src, RegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup1(DIV0_OPCODE, dst, src);
+ oneShortOp(opc);
+ }
+
+ void notlReg(RegisterID src, RegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup1(NOT_OPCODE, dst, src);
+ oneShortOp(opc);
+ }
+
+ void orlRegReg(RegisterID src, RegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup1(OR_OPCODE, dst, src);
+ oneShortOp(opc);
+ }
+
+ void orlImm8r(int imm8, RegisterID dst)
+ {
+ ASSERT((imm8 <= 255) && (imm8 >= 0));
+ ASSERT(dst == SH4Registers::r0);
+
+ uint16_t opc = getOpcodeGroup5(ORIMM_OPCODE, imm8);
+ oneShortOp(opc);
+ }
+
+ void sublRegReg(RegisterID src, RegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup1(SUB_OPCODE, dst, src);
+ oneShortOp(opc);
+ }
+
+ void subvlRegReg(RegisterID src, RegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup1(SUBV_OPCODE, dst, src);
+ oneShortOp(opc);
+ }
+
+ void xorlRegReg(RegisterID src, RegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup1(XOR_OPCODE, dst, src);
+ oneShortOp(opc);
+ }
+
+ void xorlImm8r(int imm8, RegisterID dst)
+ {
+ ASSERT((imm8 <= 255) && (imm8 >= 0));
+ ASSERT(dst == SH4Registers::r0);
+
+ uint16_t opc = getOpcodeGroup5(XORIMM_OPCODE, imm8);
+ oneShortOp(opc);
+ }
+
+ void shllImm8r(int imm, RegisterID dst)
+ {
+ switch (imm) {
+ case 1:
+ oneShortOp(getOpcodeGroup2(SHLL_OPCODE, dst));
+ break;
+ case 2:
+ oneShortOp(getOpcodeGroup2(SHLL2_OPCODE, dst));
+ break;
+ case 8:
+ oneShortOp(getOpcodeGroup2(SHLL8_OPCODE, dst));
+ break;
+ case 16:
+ oneShortOp(getOpcodeGroup2(SHLL16_OPCODE, dst));
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ }
+
+ void neg(RegisterID dst, RegisterID src)
+ {
+ uint16_t opc = getOpcodeGroup1(NEG_OPCODE, dst, src);
+ oneShortOp(opc);
+ }
+
+ void shllRegReg(RegisterID dst, RegisterID rShift)
+ {
+ uint16_t opc = getOpcodeGroup1(SHLD_OPCODE, dst, rShift);
+ oneShortOp(opc);
+ }
+
+ void shlrRegReg(RegisterID dst, RegisterID rShift)
+ {
+ neg(rShift, rShift);
+ shllRegReg(dst, rShift);
+ }
+
+ void sharRegReg(RegisterID dst, RegisterID rShift)
+ {
+ neg(rShift, rShift);
+ shaRegReg(dst, rShift);
+ }
+
+ void shaRegReg(RegisterID dst, RegisterID rShift)
+ {
+ uint16_t opc = getOpcodeGroup1(SHAD_OPCODE, dst, rShift);
+ oneShortOp(opc);
+ }
+
+ void shlrImm8r(int imm, RegisterID dst)
+ {
+ switch (imm) {
+ case 1:
+ oneShortOp(getOpcodeGroup2(SHLR_OPCODE, dst));
+ break;
+ case 2:
+ oneShortOp(getOpcodeGroup2(SHLR2_OPCODE, dst));
+ break;
+ case 8:
+ oneShortOp(getOpcodeGroup2(SHLR8_OPCODE, dst));
+ break;
+ case 16:
+ oneShortOp(getOpcodeGroup2(SHLR16_OPCODE, dst));
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ }
+
+ void imullRegReg(RegisterID src, RegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup1(MULL_OPCODE, dst, src);
+ oneShortOp(opc);
+ }
+
+ void dmullRegReg(RegisterID src, RegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup1(DMULL_L_OPCODE, dst, src);
+ oneShortOp(opc);
+ }
+
+ void dmulslRegReg(RegisterID src, RegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup1(DMULSL_OPCODE, dst, src);
+ oneShortOp(opc);
+ }
+
+ void stsmacl(RegisterID reg)
+ {
+ uint16_t opc = getOpcodeGroup2(STSMACL_OPCODE, reg);
+ oneShortOp(opc);
+ }
+
+ void stsmach(RegisterID reg)
+ {
+ uint16_t opc = getOpcodeGroup2(STSMACH_OPCODE, reg);
+ oneShortOp(opc);
+ }
+
+ // Comparisons
+
+ void cmplRegReg(RegisterID left, RegisterID right, Condition cond)
+ {
+ switch (cond) {
+ case NE:
+ oneShortOp(getOpcodeGroup1(CMPEQ_OPCODE, right, left));
+ break;
+ case GT:
+ oneShortOp(getOpcodeGroup1(CMPGT_OPCODE, right, left));
+ break;
+ case EQ:
+ oneShortOp(getOpcodeGroup1(CMPEQ_OPCODE, right, left));
+ break;
+ case GE:
+ oneShortOp(getOpcodeGroup1(CMPGE_OPCODE, right, left));
+ break;
+ case HS:
+ oneShortOp(getOpcodeGroup1(CMPHS_OPCODE, right, left));
+ break;
+ case HI:
+ oneShortOp(getOpcodeGroup1(CMPHI_OPCODE, right, left));
+ break;
+ case LI:
+ oneShortOp(getOpcodeGroup1(CMPHI_OPCODE, left, right));
+ break;
+ case LS:
+ oneShortOp(getOpcodeGroup1(CMPHS_OPCODE, left, right));
+ break;
+ case LE:
+ oneShortOp(getOpcodeGroup1(CMPGE_OPCODE, left, right));
+ break;
+ case LT:
+ oneShortOp(getOpcodeGroup1(CMPGT_OPCODE, left, right));
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ }
+
+ void cmppl(RegisterID reg)
+ {
+ uint16_t opc = getOpcodeGroup2(CMPPL_OPCODE, reg);
+ oneShortOp(opc);
+ }
+
+ void cmppz(RegisterID reg)
+ {
+ uint16_t opc = getOpcodeGroup2(CMPPZ_OPCODE, reg);
+ oneShortOp(opc);
+ }
+
+ void cmpEqImmR0(int imm, RegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup5(CMPEQIMM_OPCODE, imm);
+ oneShortOp(opc);
+ }
+
+ void testlRegReg(RegisterID src, RegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup1(TST_OPCODE, dst, src);
+ oneShortOp(opc);
+ }
+
+ void testlImm8r(int imm, RegisterID dst)
+ {
+ ASSERT((dst == SH4Registers::r0) && (imm <= 255) && (imm >= 0));
+
+ uint16_t opc = getOpcodeGroup5(TSTIMM_OPCODE, imm);
+ oneShortOp(opc);
+ }
+
+ void nop()
+ {
+ oneShortOp(NOP_OPCODE, false);
+ }
+
+ void sett()
+ {
+ oneShortOp(SETT_OPCODE);
+ }
+
+ void clrt()
+ {
+ oneShortOp(CLRT_OPCODE);
+ }
+
+ void fschg()
+ {
+ oneShortOp(FSCHG_OPCODE);
+ }
+
+ void bkpt()
+ {
+ oneShortOp(BRK_OPCODE, false);
+ }
+
+ void branch(uint16_t opc, int label)
+ {
+ switch (opc) {
+ case BT_OPCODE:
+ ASSERT((label <= 127) && (label >= -128));
+ oneShortOp(getOpcodeGroup5(BT_OPCODE, label));
+ break;
+ case BRA_OPCODE:
+ ASSERT((label <= 2047) && (label >= -2048));
+ oneShortOp(getOpcodeGroup6(BRA_OPCODE, label));
+ break;
+ case BF_OPCODE:
+ ASSERT((label <= 127) && (label >= -128));
+ oneShortOp(getOpcodeGroup5(BF_OPCODE, label));
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ }
+
+ void branch(uint16_t opc, RegisterID reg)
+ {
+ switch (opc) {
+ case BRAF_OPCODE:
+ oneShortOp(getOpcodeGroup2(BRAF_OPCODE, reg));
+ break;
+ case JMP_OPCODE:
+ oneShortOp(getOpcodeGroup2(JMP_OPCODE, reg));
+ break;
+ case JSR_OPCODE:
+ oneShortOp(getOpcodeGroup2(JSR_OPCODE, reg));
+ break;
+ case BSRF_OPCODE:
+ oneShortOp(getOpcodeGroup2(BSRF_OPCODE, reg));
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ }
+
+ void ldspr(RegisterID reg)
+ {
+ uint16_t opc = getOpcodeGroup2(LDSPR_OPCODE, reg);
+ oneShortOp(opc);
+ }
+
+ void stspr(RegisterID reg)
+ {
+ uint16_t opc = getOpcodeGroup2(STSPR_OPCODE, reg);
+ oneShortOp(opc);
+ }
+
+ void extuw(RegisterID src, RegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup1(EXTUW_OPCODE, dst, src);
+ oneShortOp(opc);
+ }
+
+ // float operations
+
+ void ldsrmfpul(RegisterID src)
+ {
+ uint16_t opc = getOpcodeGroup2(LDS_RM_FPUL_OPCODE, src);
+ oneShortOp(opc);
+ }
+
+ void fneg(FPRegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup2(FNEG_OPCODE, dst);
+ oneShortOp(opc, true, false);
+ }
+
+ void fsqrt(FPRegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup2(FSQRT_OPCODE, dst);
+ oneShortOp(opc, true, false);
+ }
+
+ void stsfpulReg(RegisterID src)
+ {
+ uint16_t opc = getOpcodeGroup2(STS_FPUL_RN_OPCODE, src);
+ oneShortOp(opc);
+ }
+
+ void floatfpulfrn(RegisterID src)
+ {
+ uint16_t opc = getOpcodeGroup2(FLOAT_OPCODE, src);
+ oneShortOp(opc, true, false);
+ }
+
+ void fmull(FPRegisterID src, FPRegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup1(FMUL_OPCODE, dst, src);
+ oneShortOp(opc, true, false);
+ }
+
+ void fmovsReadrm(RegisterID src, FPRegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup1(FMOVS_READ_RM_OPCODE, dst, src);
+ oneShortOp(opc, true, false);
+ }
+
+ void fmovsWriterm(FPRegisterID src, RegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup1(FMOVS_WRITE_RN_OPCODE, dst, src);
+ oneShortOp(opc, true, false);
+ }
+
+ void fmovsWriter0r(FPRegisterID src, RegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup1(FMOVS_WRITE_R0RN_OPCODE, dst, src);
+ oneShortOp(opc, true, false);
+ }
+
+ void fmovsReadr0r(RegisterID src, FPRegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup1(FMOVS_READ_R0RM_OPCODE, dst, src);
+ oneShortOp(opc, true, false);
+ }
+
+ void fmovsReadrminc(RegisterID src, FPRegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup1(FMOVS_READ_RM_INC_OPCODE, dst, src);
+ oneShortOp(opc, true, false);
+ }
+
+ void fmovsWriterndec(FPRegisterID src, RegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup1(FMOVS_WRITE_RN_DEC_OPCODE, dst, src);
+ oneShortOp(opc, true, false);
+ }
+
+ void ftrcRegfpul(FPRegisterID src)
+ {
+ uint16_t opc = getOpcodeGroup2(FTRC_OPCODE, src);
+ oneShortOp(opc, true, false);
+ }
+
+ void fldsfpul(RegisterID src)
+ {
+ uint16_t opc = getOpcodeGroup2(FLDS_FRM_FPUL_OPCODE, src);
+ oneShortOp(opc);
+ }
+
+ void fstsfpul(RegisterID src)
+ {
+ uint16_t opc = getOpcodeGroup2(FSTS_FPUL_FRN_OPCODE, src);
+ oneShortOp(opc);
+ }
+
+ void ldsfpscr(RegisterID reg)
+ {
+ uint16_t opc = getOpcodeGroup2(LDSFPSCR_OPCODE, reg);
+ oneShortOp(opc);
+ }
+
+ void stsfpscr(RegisterID reg)
+ {
+ uint16_t opc = getOpcodeGroup2(STSFPSCR_OPCODE, reg);
+ oneShortOp(opc);
+ }
+
+ // double operations
+
+ void dcnvds(FPRegisterID src)
+ {
+ uint16_t opc = getOpcodeGroup7(FCNVDS_DRM_FPUL_OPCODE, src >> 1);
+ oneShortOp(opc);
+ }
+
+ void dcmppeq(FPRegisterID src, FPRegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup8(FCMPEQ_OPCODE, dst >> 1, src >> 1);
+ oneShortOp(opc);
+ }
+
+ void dcmppgt(FPRegisterID src, FPRegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup8(FCMPGT_OPCODE, dst >> 1, src >> 1);
+ oneShortOp(opc);
+ }
+
+ void dmulRegReg(FPRegisterID src, FPRegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup8(FMUL_OPCODE, dst >> 1, src >> 1);
+ oneShortOp(opc);
+ }
+
+ void dsubRegReg(FPRegisterID src, FPRegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup8(FSUB_OPCODE, dst >> 1, src >> 1);
+ oneShortOp(opc);
+ }
+
+ void daddRegReg(FPRegisterID src, FPRegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup8(FADD_OPCODE, dst >> 1, src >> 1);
+ oneShortOp(opc);
+ }
+
+ void dmovRegReg(FPRegisterID src, FPRegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup8(FMOV_OPCODE, dst >> 1, src >> 1);
+ oneShortOp(opc);
+ }
+
+ void ddivRegReg(FPRegisterID src, FPRegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup8(FDIV_OPCODE, dst >> 1, src >> 1);
+ oneShortOp(opc);
+ }
+
+ void dsqrt(FPRegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup7(FSQRT_OPCODE, dst >> 1);
+ oneShortOp(opc);
+ }
+
+ void dneg(FPRegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup7(FNEG_OPCODE, dst >> 1);
+ oneShortOp(opc);
+ }
+
+ void fmovReadrm(RegisterID src, FPRegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup10(FMOVS_READ_RM_OPCODE, dst >> 1, src);
+ oneShortOp(opc);
+ }
+
+ void fmovWriterm(FPRegisterID src, RegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup9(FMOVS_WRITE_RN_OPCODE, dst, src >> 1);
+ oneShortOp(opc);
+ }
+
+ void fmovWriter0r(FPRegisterID src, RegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup9(FMOVS_WRITE_R0RN_OPCODE, dst, src >> 1);
+ oneShortOp(opc);
+ }
+
+ void fmovReadr0r(RegisterID src, FPRegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup10(FMOVS_READ_R0RM_OPCODE, dst >> 1, src);
+ oneShortOp(opc);
+ }
+
+ void fmovReadrminc(RegisterID src, FPRegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup10(FMOVS_READ_RM_INC_OPCODE, dst >> 1, src);
+ oneShortOp(opc);
+ }
+
+ void fmovWriterndec(FPRegisterID src, RegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup9(FMOVS_WRITE_RN_DEC_OPCODE, dst, src >> 1);
+ oneShortOp(opc);
+ }
+
+ void floatfpulDreg(FPRegisterID src)
+ {
+ uint16_t opc = getOpcodeGroup7(FLOAT_OPCODE, src >> 1);
+ oneShortOp(opc);
+ }
+
+ void ftrcdrmfpul(FPRegisterID src)
+ {
+ uint16_t opc = getOpcodeGroup7(FTRC_OPCODE, src >> 1);
+ oneShortOp(opc);
+ }
+
+ // Various move ops
+
+ void movImm8(int imm8, RegisterID dst)
+ {
+ ASSERT((imm8 <= 127) && (imm8 >= -128));
+
+ uint16_t opc = getOpcodeGroup3(MOVIMM_OPCODE, dst, imm8);
+ oneShortOp(opc);
+ }
+
+ void movlRegReg(RegisterID src, RegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup1(MOV_OPCODE, dst, src);
+ oneShortOp(opc);
+ }
+
+ void movwRegMem(RegisterID src, RegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup1(MOVW_WRITE_RN_OPCODE, dst, src);
+ oneShortOp(opc);
+ }
+
+ void movwMemReg(RegisterID src, RegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup1(MOVW_READ_RM_OPCODE, dst, src);
+ oneShortOp(opc);
+ }
+
+ void movwPCReg(int offset, RegisterID base, RegisterID dst)
+ {
+ ASSERT(base == SH4Registers::pc);
+ ASSERT((offset <= 255) && (offset >= 0));
+
+ uint16_t opc = getOpcodeGroup3(MOVW_READ_OFFPC_OPCODE, dst, offset);
+ oneShortOp(opc);
+ }
+
+ void movwMemReg(int offset, RegisterID base, RegisterID dst)
+ {
+ ASSERT(dst == SH4Registers::r0);
+
+ uint16_t opc = getOpcodeGroup11(MOVW_READ_OFFRM_OPCODE, base, offset);
+ oneShortOp(opc);
+ }
+
+ void movwR0mr(RegisterID src, RegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup1(MOVW_READ_R0RM_OPCODE, dst, src);
+ oneShortOp(opc);
+ }
+
+ void movlRegMem(RegisterID src, int offset, RegisterID base)
+ {
+ ASSERT((offset <= 15) && (offset >= 0));
+
+ if (!offset) {
+ oneShortOp(getOpcodeGroup1(MOVL_WRITE_RN_OPCODE, base, src));
+ return;
+ }
+
+ oneShortOp(getOpcodeGroup4(MOVL_WRITE_OFFRN_OPCODE, base, src, offset));
+ }
+
+ void movlRegMem(RegisterID src, RegisterID base)
+ {
+ uint16_t opc = getOpcodeGroup1(MOVL_WRITE_RN_OPCODE, base, src);
+ oneShortOp(opc);
+ }
+
+ void movlMemReg(int offset, RegisterID base, RegisterID dst)
+ {
+ if (base == SH4Registers::pc) {
+ ASSERT((offset <= 255) && (offset >= 0));
+ oneShortOp(getOpcodeGroup3(MOVL_READ_OFFPC_OPCODE, dst, offset));
+ return;
+ }
+
+ ASSERT((offset <= 15) && (offset >= 0));
+ if (!offset) {
+ oneShortOp(getOpcodeGroup1(MOVL_READ_RM_OPCODE, dst, base));
+ return;
+ }
+
+ oneShortOp(getOpcodeGroup4(MOVL_READ_OFFRM_OPCODE, dst, base, offset));
+ }
+
+ void movbMemReg(int offset, RegisterID base, RegisterID dst)
+ {
+ ASSERT(dst == SH4Registers::r0);
+
+ uint16_t opc = getOpcodeGroup11(MOVB_READ_OFFRM_OPCODE, base, offset);
+ oneShortOp(opc);
+ }
+
+ void movbR0mr(RegisterID src, RegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup1(MOVB_READ_R0RM_OPCODE, dst, src);
+ oneShortOp(opc);
+ }
+
+ void movbMemReg(RegisterID src, RegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup1(MOVB_READ_RM_OPCODE, dst, src);
+ oneShortOp(opc);
+ }
+
+ void movlMemReg(RegisterID base, RegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup1(MOVL_READ_RM_OPCODE, dst, base);
+ oneShortOp(opc);
+ }
+
+ void movlMemRegIn(RegisterID base, RegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup1(MOVL_READ_RMINC_OPCODE, dst, base);
+ oneShortOp(opc);
+ }
+
+ void movlR0mr(RegisterID src, RegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup1(MOVL_READ_R0RM_OPCODE, dst, src);
+ oneShortOp(opc);
+ }
+
+ void movlRegMemr0(RegisterID src, RegisterID dst)
+ {
+ uint16_t opc = getOpcodeGroup1(MOVL_WRITE_R0RN_OPCODE, dst, src);
+ oneShortOp(opc);
+ }
+
+ void movlImm8r(int imm8, RegisterID dst)
+ {
+ ASSERT((imm8 <= 127) && (imm8 >= -128));
+
+ uint16_t opc = getOpcodeGroup3(MOVIMM_OPCODE, dst, imm8);
+ oneShortOp(opc);
+ }
+
+ void loadConstant(uint32_t constant, RegisterID dst)
+ {
+ if (((int)constant <= 0x7f) && ((int)constant >= -0x80)) {
+ movImm8(constant, dst);
+ return;
+ }
+
+ uint16_t opc = getOpcodeGroup3(MOVIMM_OPCODE, dst, 0);
+
+ m_buffer.ensureSpace(maxInstructionSize, sizeof(uint32_t));
+ printInstr(getOpcodeGroup3(MOVIMM_OPCODE, dst, constant), m_buffer.codeSize());
+ m_buffer.putShortWithConstantInt(opc, constant, true);
+ }
+
+ void loadConstantUnReusable(uint32_t constant, RegisterID dst, bool ensureSpace = false)
+ {
+ uint16_t opc = getOpcodeGroup3(MOVIMM_OPCODE, dst, 0);
+
+ if (ensureSpace)
+ m_buffer.ensureSpace(maxInstructionSize, sizeof(uint32_t));
+
+ printInstr(getOpcodeGroup3(MOVIMM_OPCODE, dst, constant), m_buffer.codeSize());
+ m_buffer.putShortWithConstantInt(opc, constant);
+ }
+
+ // Flow control
+
+ AssemblerLabel call()
+ {
+ RegisterID scr = claimScratch();
+ m_buffer.ensureSpace(maxInstructionSize + 4, sizeof(uint32_t));
+ loadConstantUnReusable(0x0, scr);
+ branch(JSR_OPCODE, scr);
+ nop();
+ releaseScratch(scr);
+ return m_buffer.label();
+ }
+
+ AssemblerLabel call(RegisterID dst)
+ {
+ m_buffer.ensureSpace(maxInstructionSize + 2);
+ branch(JSR_OPCODE, dst);
+ nop();
+ return m_buffer.label();
+ }
+
+ AssemblerLabel jmp()
+ {
+ RegisterID scr = claimScratch();
+ m_buffer.ensureSpace(maxInstructionSize + 4, sizeof(uint32_t));
+ AssemblerLabel label = m_buffer.label();
+ loadConstantUnReusable(0x0, scr);
+ branch(BRAF_OPCODE, scr);
+ nop();
+ releaseScratch(scr);
+ return label;
+ }
+
+ AssemblerLabel jmp(RegisterID dst)
+ {
+ jmpReg(dst);
+ return m_buffer.label();
+ }
+
+ void jmpReg(RegisterID dst)
+ {
+ m_buffer.ensureSpace(maxInstructionSize + 2);
+ branch(JMP_OPCODE, dst);
+ nop();
+ }
+
+ AssemblerLabel jne()
+ {
+ AssemblerLabel label = m_buffer.label();
+ branch(BF_OPCODE, 0);
+ return label;
+ }
+
+ AssemblerLabel je()
+ {
+ AssemblerLabel label = m_buffer.label();
+ branch(BT_OPCODE, 0);
+ return label;
+ }
+
+ void ret()
+ {
+ m_buffer.ensureSpace(maxInstructionSize + 2);
+ oneShortOp(RTS_OPCODE, false);
+ }
+
+ AssemblerLabel label()
+ {
+ m_buffer.ensureSpaceForAnyOneInstruction();
+ return m_buffer.label();
+ }
+
+ int sizeOfConstantPool()
+ {
+ return m_buffer.sizeOfConstantPool();
+ }
+
+ AssemblerLabel align(int alignment)
+ {
+ m_buffer.ensureSpace(maxInstructionSize + 2);
+ while (!m_buffer.isAligned(alignment)) {
+ nop();
+ m_buffer.ensureSpace(maxInstructionSize + 2);
+ }
+ return label();
+ }
+
+ static void changePCrelativeAddress(int offset, uint16_t* instructionPtr, uint32_t newAddress)
+ {
+ uint32_t address = (offset << 2) + ((reinterpret_cast<uint32_t>(instructionPtr) + 4) &(~0x3));
+ *reinterpret_cast<uint32_t*>(address) = newAddress;
+ }
+
+ static uint32_t readPCrelativeAddress(int offset, uint16_t* instructionPtr)
+ {
+ uint32_t address = (offset << 2) + ((reinterpret_cast<uint32_t>(instructionPtr) + 4) &(~0x3));
+ return *reinterpret_cast<uint32_t*>(address);
+ }
+
+ static uint16_t* getInstructionPtr(void* code, int offset)
+ {
+ return reinterpret_cast<uint16_t*> (reinterpret_cast<uint32_t>(code) + offset);
+ }
+
+ static void linkJump(void* code, AssemblerLabel from, void* to)
+ {
+ ASSERT(from.isSet());
+
+ uint16_t* instructionPtr = getInstructionPtr(code, from.m_offset);
+ uint16_t instruction = *instructionPtr;
+ int offsetBits = (reinterpret_cast<uint32_t>(to) - reinterpret_cast<uint32_t>(code)) - from.m_offset;
+
+ if (((instruction & 0xff00) == BT_OPCODE) || ((instruction & 0xff00) == BF_OPCODE)) {
+ /* BT label ==> BF 2
+ nop LDR reg
+ nop braf @reg
+ nop nop
+ */
+ offsetBits -= 8;
+ instruction ^= 0x0202;
+ *instructionPtr++ = instruction;
+ changePCrelativeAddress((*instructionPtr & 0xff), instructionPtr, offsetBits);
+ instruction = (BRAF_OPCODE | (*instructionPtr++ & 0xf00));
+ *instructionPtr = instruction;
+ printBlockInstr(instructionPtr - 2, from.m_offset, 3);
+ return;
+ }
+
+ /* MOV #imm, reg => LDR reg
+ braf @reg braf @reg
+ nop nop
+ */
+ ASSERT((*(instructionPtr + 1) & BRAF_OPCODE) == BRAF_OPCODE);
+
+ offsetBits -= 4;
+ if (offsetBits >= -4096 && offsetBits <= 4094) {
+ *instructionPtr = getOpcodeGroup6(BRA_OPCODE, offsetBits >> 1);
+ *(++instructionPtr) = NOP_OPCODE;
+ printBlockInstr(instructionPtr - 1, from.m_offset, 2);
+ return;
+ }
+
+ changePCrelativeAddress((*instructionPtr & 0xff), instructionPtr, offsetBits - 2);
+ printInstr(*instructionPtr, from.m_offset + 2);
+ }
+
+ static void linkCall(void* code, AssemblerLabel from, void* to)
+ {
+ uint16_t* instructionPtr = getInstructionPtr(code, from.m_offset);
+ instructionPtr -= 3;
+ changePCrelativeAddress((*instructionPtr & 0xff), instructionPtr, reinterpret_cast<uint32_t>(to));
+ }
+
+ static void linkPointer(void* code, AssemblerLabel where, void* value)
+ {
+ uint16_t* instructionPtr = getInstructionPtr(code, where.m_offset);
+ changePCrelativeAddress((*instructionPtr & 0xff), instructionPtr, reinterpret_cast<uint32_t>(value));
+ }
+
+ static unsigned getCallReturnOffset(AssemblerLabel call)
+ {
+ ASSERT(call.isSet());
+ return call.m_offset;
+ }
+
+ static uint32_t* getLdrImmAddressOnPool(SH4Word* insn, uint32_t* constPool)
+ {
+ return (constPool + (*insn & 0xff));
+ }
+
+ static SH4Word patchConstantPoolLoad(SH4Word load, int value)
+ {
+ return ((load & ~0xff) | value);
+ }
+
+ static SH4Buffer::TwoShorts placeConstantPoolBarrier(int offset)
+ {
+ ASSERT(((offset >> 1) <=2047) && ((offset >> 1) >= -2048));
+
+ SH4Buffer::TwoShorts m_barrier;
+ m_barrier.high = (BRA_OPCODE | (offset >> 1));
+ m_barrier.low = NOP_OPCODE;
+ printInstr(((BRA_OPCODE | (offset >> 1))), 0);
+ printInstr(NOP_OPCODE, 0);
+ return m_barrier;
+ }
+
+ static void patchConstantPoolLoad(void* loadAddr, void* constPoolAddr)
+ {
+ SH4Word* instructionPtr = reinterpret_cast<SH4Word*>(loadAddr);
+ SH4Word instruction = *instructionPtr;
+ SH4Word index = instruction & 0xff;
+
+ if ((instruction & 0xf000) != MOVIMM_OPCODE)
+ return;
+
+ ASSERT((((reinterpret_cast<uint32_t>(constPoolAddr) - reinterpret_cast<uint32_t>(loadAddr)) + index * 4)) < 1024);
+
+ int offset = reinterpret_cast<uint32_t>(constPoolAddr) + (index * 4) - ((reinterpret_cast<uint32_t>(instructionPtr) & ~0x03) + 4);
+ instruction &=0xf00;
+ instruction |= 0xd000;
+ offset &= 0x03ff;
+ instruction |= (offset >> 2);
+ *instructionPtr = instruction;
+ printInstr(instruction, reinterpret_cast<uint32_t>(loadAddr));
+ }
+
+ static void repatchPointer(void* where, void* value)
+ {
+ patchPointer(where, value);
+ }
+
+ static void* readPointer(void* code)
+ {
+ return static_cast<void*>(readInt32(code));
+ }
+
+ static void repatchInt32(void* where, int32_t value)
+ {
+ uint16_t* instructionPtr = reinterpret_cast<uint16_t*>(where);
+ changePCrelativeAddress((*instructionPtr & 0xff), instructionPtr, value);
+ }
+
+ static void repatchCompact(void* where, int32_t value)
+ {
+ repatchInt32(where, value);
+ }
+
+ static void relinkCall(void* from, void* to)
+ {
+ uint16_t* instructionPtr = reinterpret_cast<uint16_t*>(from);
+ instructionPtr -= 3;
+ changePCrelativeAddress((*instructionPtr & 0xff), instructionPtr, reinterpret_cast<uint32_t>(to));
+ }
+
+ static void relinkJump(void* from, void* to)
+ {
+ uint16_t* instructionPtr = reinterpret_cast<uint16_t*> (from);
+ uint16_t instruction = *instructionPtr;
+ int32_t offsetBits = (reinterpret_cast<uint32_t>(to) - reinterpret_cast<uint32_t>(from));
+
+ if (((*instructionPtr & 0xff00) == BT_OPCODE) || ((*instructionPtr & 0xff00) == BF_OPCODE)) {
+ offsetBits -= 8;
+ instructionPtr++;
+ changePCrelativeAddress((*instructionPtr & 0xff), instructionPtr, offsetBits);
+ instruction = (BRAF_OPCODE | (*instructionPtr++ & 0xf00));
+ *instructionPtr = instruction;
+ printBlockInstr(instructionPtr, reinterpret_cast<uint32_t>(from) + 1, 3);
+ return;
+ }
+
+ ASSERT((*(instructionPtr + 1) & BRAF_OPCODE) == BRAF_OPCODE);
+ offsetBits -= 4;
+ if (offsetBits >= -4096 && offsetBits <= 4094) {
+ *instructionPtr = getOpcodeGroup6(BRA_OPCODE, offsetBits >> 1);
+ *(++instructionPtr) = NOP_OPCODE;
+ printBlockInstr(instructionPtr - 2, reinterpret_cast<uint32_t>(from), 2);
+ return;
+ }
+
+ changePCrelativeAddress((*instructionPtr & 0xff), instructionPtr, offsetBits - 2);
+ printInstr(*instructionPtr, reinterpret_cast<uint32_t>(from));
+ }
+
+ // Linking & patching
+
+ void linkJump(AssemblerLabel from, AssemblerLabel to)
+ {
+ ASSERT(to.isSet());
+ ASSERT(from.isSet());
+
+ uint16_t* instructionPtr = getInstructionPtr(data(), from.m_offset);
+ uint16_t instruction = *instructionPtr;
+ int offsetBits;
+
+ if (((instruction & 0xff00) == BT_OPCODE) || ((instruction & 0xff00) == BF_OPCODE)) {
+ /* BT label => BF 2
+ nop LDR reg
+ nop braf @reg
+ nop nop
+ */
+ offsetBits = (to.m_offset - from.m_offset) - 8;
+ instruction ^= 0x0202;
+ *instructionPtr++ = instruction;
+ if ((*instructionPtr & 0xf000) == 0xe000) {
+ uint32_t* addr = getLdrImmAddressOnPool(instructionPtr, m_buffer.poolAddress());
+ *addr = offsetBits;
+ } else
+ changePCrelativeAddress((*instructionPtr & 0xff), instructionPtr, offsetBits);
+ instruction = (BRAF_OPCODE | (*instructionPtr++ & 0xf00));
+ *instructionPtr = instruction;
+ printBlockInstr(instructionPtr - 2, from.m_offset, 3);
+ return;
+ }
+
+ /* MOV # imm, reg => LDR reg
+ braf @reg braf @reg
+ nop nop
+ */
+ ASSERT((*(instructionPtr + 1) & BRAF_OPCODE) == BRAF_OPCODE);
+ offsetBits = (to.m_offset - from.m_offset) - 4;
+ if (offsetBits >= -4096 && offsetBits <= 4094) {
+ *instructionPtr = getOpcodeGroup6(BRA_OPCODE, offsetBits >> 1);
+ *(++instructionPtr) = NOP_OPCODE;
+ printBlockInstr(instructionPtr - 1, from.m_offset, 2);
+ return;
+ }
+
+ instruction = *instructionPtr;
+ if ((instruction & 0xf000) == 0xe000) {
+ uint32_t* addr = getLdrImmAddressOnPool(instructionPtr, m_buffer.poolAddress());
+ *addr = offsetBits - 2;
+ printInstr(*instructionPtr, from.m_offset + 2);
+ return;
+ }
+
+ changePCrelativeAddress((*instructionPtr & 0xff), instructionPtr, offsetBits - 2);
+ printInstr(*instructionPtr, from.m_offset + 2);
+ }
+
+ static void* getRelocatedAddress(void* code, AssemblerLabel label)
+ {
+ return reinterpret_cast<void*>(reinterpret_cast<char*>(code) + label.m_offset);
+ }
+
+ static int getDifferenceBetweenLabels(AssemblerLabel a, AssemblerLabel b)
+ {
+ return b.m_offset - a.m_offset;
+ }
+
+ static void patchPointer(void* code, AssemblerLabel where, void* value)
+ {
+ patchPointer(reinterpret_cast<uint32_t*>(code) + where.m_offset, value);
+ }
+
+ static void patchPointer(void* code, void* value)
+ {
+ patchInt32(code, reinterpret_cast<uint32_t>(value));
+ }
+
+ static void patchInt32(void* code, uint32_t value)
+ {
+ changePCrelativeAddress((*(reinterpret_cast<uint16_t*>(code)) & 0xff), reinterpret_cast<uint16_t*>(code), value);
+ }
+
+ static uint32_t readInt32(void* code)
+ {
+ return readPCrelativeAddress((*(reinterpret_cast<uint16_t*>(code)) & 0xff), reinterpret_cast<uint16_t*>(code));
+ }
+
+ void* executableCopy(JSGlobalData& globalData, ExecutablePool* allocator)
+ {
+ return m_buffer.executableCopy(globalData, allocator);
+ }
+
+ void prefix(uint16_t pre)
+ {
+ m_buffer.putByte(pre);
+ }
+
+ void oneShortOp(uint16_t opcode, bool checksize = true, bool isDouble = true)
+ {
+ printInstr(opcode, m_buffer.codeSize(), isDouble);
+ if (checksize)
+ m_buffer.ensureSpace(maxInstructionSize);
+ m_buffer.putShortUnchecked(opcode);
+ }
+
+ void ensureSpace(int space)
+ {
+ m_buffer.ensureSpace(space);
+ }
+
+ void ensureSpace(int insnSpace, int constSpace)
+ {
+ m_buffer.ensureSpace(insnSpace, constSpace);
+ }
+
+ // Administrative methods
+
+ void* data() const { return m_buffer.data(); }
+ size_t codeSize() const { return m_buffer.codeSize(); }
+
+#ifdef SH4_ASSEMBLER_TRACING
+ static void printInstr(uint16_t opc, unsigned int size, bool isdoubleInst = true)
+ {
+ if (!getenv("JavaScriptCoreDumpJIT"))
+ return;
+
+ const char *format = 0;
+ printfStdoutInstr("offset: 0x%8.8x\t", size);
+ switch (opc) {
+ case BRK_OPCODE:
+ format = " BRK\n";
+ break;
+ case NOP_OPCODE:
+ format = " NOP\n";
+ break;
+ case RTS_OPCODE:
+ format =" *RTS\n";
+ break;
+ case SETS_OPCODE:
+ format = " SETS\n";
+ break;
+ case SETT_OPCODE:
+ format = " SETT\n";
+ break;
+ case CLRT_OPCODE:
+ format = " CLRT\n";
+ break;
+ case FSCHG_OPCODE:
+ format = " FSCHG\n";
+ break;
+ }
+ if (format) {
+ printfStdoutInstr(format);
+ return;
+ }
+ switch (opc & 0xf0ff) {
+ case BRAF_OPCODE:
+ format = " *BRAF R%d\n";
+ break;
+ case DT_OPCODE:
+ format = " DT R%d\n";
+ break;
+ case CMPPL_OPCODE:
+ format = " CMP/PL R%d\n";
+ break;
+ case CMPPZ_OPCODE:
+ format = " CMP/PZ R%d\n";
+ break;
+ case JMP_OPCODE:
+ format = " *JMP @R%d\n";
+ break;
+ case JSR_OPCODE:
+ format = " *JSR @R%d\n";
+ break;
+ case LDSPR_OPCODE:
+ format = " LDS R%d, PR\n";
+ break;
+ case LDSLPR_OPCODE:
+ format = " LDS.L @R%d+, PR\n";
+ break;
+ case MOVT_OPCODE:
+ format = " MOVT R%d\n";
+ break;
+ case SHAL_OPCODE:
+ format = " SHAL R%d\n";
+ break;
+ case SHAR_OPCODE:
+ format = " SHAR R%d\n";
+ break;
+ case SHLL_OPCODE:
+ format = " SHLL R%d\n";
+ break;
+ case SHLL2_OPCODE:
+ format = " SHLL2 R%d\n";
+ break;
+ case SHLL8_OPCODE:
+ format = " SHLL8 R%d\n";
+ break;
+ case SHLL16_OPCODE:
+ format = " SHLL16 R%d\n";
+ break;
+ case SHLR_OPCODE:
+ format = " SHLR R%d\n";
+ break;
+ case SHLR2_OPCODE:
+ format = " SHLR2 R%d\n";
+ break;
+ case SHLR8_OPCODE:
+ format = " SHLR8 R%d\n";
+ break;
+ case SHLR16_OPCODE:
+ format = " SHLR16 R%d\n";
+ break;
+ case STSPR_OPCODE:
+ format = " STS PR, R%d\n";
+ break;
+ case STSLPR_OPCODE:
+ format = " STS.L PR, @-R%d\n";
+ break;
+ case LDS_RM_FPUL_OPCODE:
+ format = " LDS R%d, FPUL\n";
+ break;
+ case STS_FPUL_RN_OPCODE:
+ format = " STS FPUL, R%d \n";
+ break;
+ case FLDS_FRM_FPUL_OPCODE:
+ format = " FLDS FR%d, FPUL\n";
+ break;
+ case FSTS_FPUL_FRN_OPCODE:
+ format = " FSTS FPUL, R%d \n";
+ break;
+ case LDSFPSCR_OPCODE:
+ format = " LDS R%d, FPSCR \n";
+ break;
+ case STSFPSCR_OPCODE:
+ format = " STS FPSCR, R%d \n";
+ break;
+ case STSMACL_OPCODE:
+ format = " STS MACL, R%d \n";
+ break;
+ case STSMACH_OPCODE:
+ format = " STS MACH, R%d \n";
+ break;
+ case BSRF_OPCODE:
+ format = " *BSRF R%d";
+ break;
+ case FTRC_OPCODE:
+ format = " FTRC FR%d, FPUL\n";
+ break;
+ }
+ if (format) {
+ printfStdoutInstr(format, getRn(opc));
+ return;
+ }
+ switch (opc & 0xf0ff) {
+ case FNEG_OPCODE:
+ format = " FNEG DR%d\n";
+ break;
+ case FLOAT_OPCODE:
+ format = " FLOAT DR%d\n";
+ break;
+ case FTRC_OPCODE:
+ format = " FTRC FR%d, FPUL\n";
+ break;
+ case FSQRT_OPCODE:
+ format = " FSQRT FR%d\n";
+ break;
+ case FCNVDS_DRM_FPUL_OPCODE:
+ format = " FCNVDS FR%d, FPUL\n";
+ break;
+ }
+ if (format) {
+ if (isdoubleInst)
+ printfStdoutInstr(format, getDRn(opc) << 1);
+ else
+ printfStdoutInstr(format, getRn(opc));
+ return;
+ }
+ switch (opc & 0xf00f) {
+ case ADD_OPCODE:
+ format = " ADD R%d, R%d\n";
+ break;
+ case ADDC_OPCODE:
+ format = " ADDC R%d, R%d\n";
+ break;
+ case ADDV_OPCODE:
+ format = " ADDV R%d, R%d\n";
+ break;
+ case AND_OPCODE:
+ format = " AND R%d, R%d\n";
+ break;
+ case DIV1_OPCODE:
+ format = " DIV1 R%d, R%d\n";
+ break;
+ case CMPEQ_OPCODE:
+ format = " CMP/EQ R%d, R%d\n";
+ break;
+ case CMPGE_OPCODE:
+ format = " CMP/GE R%d, R%d\n";
+ break;
+ case CMPGT_OPCODE:
+ format = " CMP/GT R%d, R%d\n";
+ break;
+ case CMPHI_OPCODE:
+ format = " CMP/HI R%d, R%d\n";
+ break;
+ case CMPHS_OPCODE:
+ format = " CMP/HS R%d, R%d\n";
+ break;
+ case MOV_OPCODE:
+ format = " MOV R%d, R%d\n";
+ break;
+ case MOVB_WRITE_RN_OPCODE:
+ format = " MOV.B R%d, @R%d\n";
+ break;
+ case MOVB_WRITE_RNDEC_OPCODE:
+ format = " MOV.B R%d, @-R%d\n";
+ break;
+ case MOVB_WRITE_R0RN_OPCODE:
+ format = " MOV.B R%d, @(R0, R%d)\n";
+ break;
+ case MOVB_READ_RM_OPCODE:
+ format = " MOV.B @R%d, R%d\n";
+ break;
+ case MOVB_READ_RMINC_OPCODE:
+ format = " MOV.B @R%d+, R%d\n";
+ break;
+ case MOVB_READ_R0RM_OPCODE:
+ format = " MOV.B @(R0, R%d), R%d\n";
+ break;
+ case MOVL_WRITE_RN_OPCODE:
+ format = " MOV.L R%d, @R%d\n";
+ break;
+ case MOVL_WRITE_RNDEC_OPCODE:
+ format = " MOV.L R%d, @-R%d\n";
+ break;
+ case MOVL_WRITE_R0RN_OPCODE:
+ format = " MOV.L R%d, @(R0, R%d)\n";
+ break;
+ case MOVL_READ_RM_OPCODE:
+ format = " MOV.L @R%d, R%d\n";
+ break;
+ case MOVL_READ_RMINC_OPCODE:
+ format = " MOV.L @R%d+, R%d\n";
+ break;
+ case MOVL_READ_R0RM_OPCODE:
+ format = " MOV.L @(R0, R%d), R%d\n";
+ break;
+ case MULL_OPCODE:
+ format = " MUL.L R%d, R%d\n";
+ break;
+ case DMULL_L_OPCODE:
+ format = " DMULU.L R%d, R%d\n";
+ break;
+ case DMULSL_OPCODE:
+ format = " DMULS.L R%d, R%d\n";
+ break;
+ case NEG_OPCODE:
+ format = " NEG R%d, R%d\n";
+ break;
+ case NEGC_OPCODE:
+ format = " NEGC R%d, R%d\n";
+ break;
+ case NOT_OPCODE:
+ format = " NOT R%d, R%d\n";
+ break;
+ case OR_OPCODE:
+ format = " OR R%d, R%d\n";
+ break;
+ case SHAD_OPCODE:
+ format = " SHAD R%d, R%d\n";
+ break;
+ case SHLD_OPCODE:
+ format = " SHLD R%d, R%d\n";
+ break;
+ case SUB_OPCODE:
+ format = " SUB R%d, R%d\n";
+ break;
+ case SUBC_OPCODE:
+ format = " SUBC R%d, R%d\n";
+ break;
+ case SUBV_OPCODE:
+ format = " SUBV R%d, R%d\n";
+ break;
+ case TST_OPCODE:
+ format = " TST R%d, R%d\n";
+ break;
+ case XOR_OPCODE:
+ format = " XOR R%d, R%d\n";break;
+ case MOVW_WRITE_RN_OPCODE:
+ format = " MOV.W R%d, @R%d\n";
+ break;
+ case MOVW_READ_RM_OPCODE:
+ format = " MOV.W @R%d, R%d\n";
+ break;
+ case MOVW_READ_R0RM_OPCODE:
+ format = " MOV.W @(R0, R%d), R%d\n";
+ break;
+ case EXTUW_OPCODE:
+ format = " EXTU.W R%d, R%d\n";
+ break;
+ }
+ if (format) {
+ printfStdoutInstr(format, getRm(opc), getRn(opc));
+ return;
+ }
+ switch (opc & 0xf00f) {
+ case FSUB_OPCODE:
+ format = " FSUB FR%d, FR%d\n";
+ break;
+ case FADD_OPCODE:
+ format = " FADD FR%d, FR%d\n";
+ break;
+ case FDIV_OPCODE:
+ format = " FDIV FR%d, FR%d\n";
+ break;
+ case FMUL_OPCODE:
+ format = " DMULL FR%d, FR%d\n";
+ break;
+ case FMOV_OPCODE:
+ format = " FMOV FR%d, FR%d\n";
+ break;
+ case FCMPEQ_OPCODE:
+ format = " FCMP/EQ FR%d, FR%d\n";
+ break;
+ case FCMPGT_OPCODE:
+ format = " FCMP/GT FR%d, FR%d\n";
+ break;
+ }
+ if (format) {
+ if (isdoubleInst)
+ printfStdoutInstr(format, getDRm(opc) << 1, getDRn(opc) << 1);
+ else
+ printfStdoutInstr(format, getRm(opc), getRn(opc));
+ return;
+ }
+ switch (opc & 0xf00f) {
+ case FMOVS_WRITE_RN_DEC_OPCODE:
+ format = " %s FR%d, @-R%d\n";
+ break;
+ case FMOVS_WRITE_RN_OPCODE:
+ format = " %s FR%d, @R%d\n";
+ break;
+ case FMOVS_WRITE_R0RN_OPCODE:
+ format = " %s FR%d, @(R0, R%d)\n";
+ break;
+ }
+ if (format) {
+ if (isdoubleInst)
+ printfStdoutInstr(format, "FMOV", getDRm(opc) << 1, getDRn(opc));
+ else
+ printfStdoutInstr(format, "FMOV.S", getRm(opc), getRn(opc));
+ return;
+ }
+ switch (opc & 0xf00f) {
+ case FMOVS_READ_RM_OPCODE:
+ format = " %s @R%d, FR%d\n";
+ break;
+ case FMOVS_READ_RM_INC_OPCODE:
+ format = " %s @R%d+, FR%d\n";
+ break;
+ case FMOVS_READ_R0RM_OPCODE:
+ format = " %s @(R0, R%d), FR%d\n";
+ break;
+ }
+ if (format) {
+ if (isdoubleInst)
+ printfStdoutInstr(format, "FMOV", getDRm(opc), getDRn(opc) << 1);
+ else
+ printfStdoutInstr(format, "FMOV.S", getRm(opc), getRn(opc));
+ return;
+ }
+ switch (opc & 0xff00) {
+ case BF_OPCODE:
+ format = " BF %d\n";
+ break;
+ case BFS_OPCODE:
+ format = " *BF/S %d\n";
+ break;
+ case ANDIMM_OPCODE:
+ format = " AND #%d, R0\n";
+ break;
+ case BT_OPCODE:
+ format = " BT %d\n";
+ break;
+ case BTS_OPCODE:
+ format = " *BT/S %d\n";
+ break;
+ case CMPEQIMM_OPCODE:
+ format = " CMP/EQ #%d, R0\n";
+ break;
+ case MOVB_WRITE_OFFGBR_OPCODE:
+ format = " MOV.B R0, @(%d, GBR)\n";
+ break;
+ case MOVB_READ_OFFGBR_OPCODE:
+ format = " MOV.B @(%d, GBR), R0\n";
+ break;
+ case MOVL_WRITE_OFFGBR_OPCODE:
+ format = " MOV.L R0, @(%d, GBR)\n";
+ break;
+ case MOVL_READ_OFFGBR_OPCODE:
+ format = " MOV.L @(%d, GBR), R0\n";
+ break;
+ case MOVA_READ_OFFPC_OPCODE:
+ format = " MOVA @(%d, PC), R0\n";
+ break;
+ case ORIMM_OPCODE:
+ format = " OR #%d, R0\n";
+ break;
+ case ORBIMM_OPCODE:
+ format = " OR.B #%d, @(R0, GBR)\n";
+ break;
+ case TSTIMM_OPCODE:
+ format = " TST #%d, R0\n";
+ break;
+ case TSTB_OPCODE:
+ format = " TST.B %d, @(R0, GBR)\n";
+ break;
+ case XORIMM_OPCODE:
+ format = " XOR #%d, R0\n";
+ break;
+ case XORB_OPCODE:
+ format = " XOR.B %d, @(R0, GBR)\n";
+ break;
+ }
+ if (format) {
+ printfStdoutInstr(format, getImm8(opc));
+ return;
+ }
+ switch (opc & 0xff00) {
+ case MOVB_WRITE_OFFRN_OPCODE:
+ format = " MOV.B R0, @(%d, R%d)\n";
+ break;
+ case MOVB_READ_OFFRM_OPCODE:
+ format = " MOV.B @(%d, R%d), R0\n";
+ break;
+ }
+ if (format) {
+ printfStdoutInstr(format, getDisp(opc), getRm(opc));
+ return;
+ }
+ switch (opc & 0xf000) {
+ case BRA_OPCODE:
+ format = " *BRA %d\n";
+ break;
+ case BSR_OPCODE:
+ format = " *BSR %d\n";
+ break;
+ }
+ if (format) {
+ printfStdoutInstr(format, getImm12(opc));
+ return;
+ }
+ switch (opc & 0xf000) {
+ case MOVL_READ_OFFPC_OPCODE:
+ format = " MOV.L @(%d, PC), R%d\n";
+ break;
+ case ADDIMM_OPCODE:
+ format = " ADD #%d, R%d\n";
+ break;
+ case MOVIMM_OPCODE:
+ format = " MOV #%d, R%d\n";
+ break;
+ case MOVW_READ_OFFPC_OPCODE:
+ format = " MOV.W @(%d, PC), R%d\n";
+ break;
+ }
+ if (format) {
+ printfStdoutInstr(format, getImm8(opc), getRn(opc));
+ return;
+ }
+ switch (opc & 0xf000) {
+ case MOVL_WRITE_OFFRN_OPCODE:
+ format = " MOV.L R%d, @(%d, R%d)\n";
+ printfStdoutInstr(format, getRm(opc), getDisp(opc), getRn(opc));
+ break;
+ case MOVL_READ_OFFRM_OPCODE:
+ format = " MOV.L @(%d, R%d), R%d\n";
+ printfStdoutInstr(format, getDisp(opc), getRm(opc), getRn(opc));
+ break;
+ }
+ }
+
+ static void printfStdoutInstr(const char* format, ...)
+ {
+ if (getenv("JavaScriptCoreDumpJIT")) {
+ va_list args;
+ va_start(args, format);
+ vprintfStdoutInstr(format, args);
+ va_end(args);
+ }
+ }
+
+ static void vprintfStdoutInstr(const char* format, va_list args)
+ {
+ if (getenv("JavaScriptCoreDumpJIT"))
+ vfprintf(stdout, format, args);
+ }
+
+ static void printBlockInstr(uint16_t* first, unsigned int offset, int nbInstr)
+ {
+ printfStdoutInstr(">> repatch instructions after link\n");
+ for (int i = 0; i <= nbInstr; i++)
+ printInstr(*(first + i), offset + i);
+ printfStdoutInstr(">> end repatch\n");
+ }
+#else
+ static void printInstr(uint16_t opc, unsigned int size, bool isdoubleInst = true) {};
+ static void printBlockInstr(uint16_t* first, unsigned int offset, int nbInstr) {};
+#endif
+
+private:
+ SH4Buffer m_buffer;
+ int m_claimscratchReg;
+};
+
+} // namespace JSC
+
+#endif // ENABLE(ASSEMBLER) && CPU(SH4)
+
+#endif // SH4Assembler_h
OP_GROUP1_EbIb = 0x80,
OP_GROUP1_EvIz = 0x81,
OP_GROUP1_EvIb = 0x83,
+ OP_TEST_EbGb = 0x84,
OP_TEST_EvGv = 0x85,
OP_XCHG_EvGv = 0x87,
OP_MOV_EvGv = 0x89,
OP_MOV_GvEv = 0x8B,
OP_LEA = 0x8D,
OP_GROUP1A_Ev = 0x8F,
+ OP_NOP = 0x90,
OP_CDQ = 0x99,
OP_MOV_EAXOv = 0xA1,
OP_MOV_OvEAX = 0xA3,
class X86InstructionFormatter;
public:
- class JmpSrc {
- friend class X86Assembler;
- friend class X86InstructionFormatter;
- public:
- JmpSrc()
- : m_offset(-1)
- {
- }
-
- private:
- JmpSrc(int offset)
- : m_offset(offset)
- {
- }
-
- int m_offset;
- };
-
- class JmpDst {
- friend class X86Assembler;
- friend class X86InstructionFormatter;
- public:
- JmpDst()
- : m_offset(-1)
- , m_used(false)
- {
- }
-
- bool isUsed() const { return m_used; }
- void used() { m_used = true; }
- private:
- JmpDst(int offset)
- : m_offset(offset)
- , m_used(false)
- {
- ASSERT(m_offset == offset);
- }
-
- int m_offset : 31;
- bool m_used : 1;
- };
-
X86Assembler()
{
}
- size_t size() const { return m_formatter.size(); }
-
// Stack operations:
void push_r(RegisterID reg)
// Arithmetic operations:
#if !CPU(X86_64)
- void adcl_im(int imm, void* addr)
+ void adcl_im(int imm, const void* addr)
{
if (CAN_SIGN_EXTEND_8_32(imm)) {
m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_ADC, addr);
}
}
#else
- void addl_im(int imm, void* addr)
+ void addl_im(int imm, const void* addr)
{
if (CAN_SIGN_EXTEND_8_32(imm)) {
m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_ADD, addr);
}
}
#else
- void andl_im(int imm, void* addr)
+ void andl_im(int imm, const void* addr)
{
if (CAN_SIGN_EXTEND_8_32(imm)) {
m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_AND, addr);
}
}
#else
- void orl_im(int imm, void* addr)
+ void orl_im(int imm, const void* addr)
{
if (CAN_SIGN_EXTEND_8_32(imm)) {
m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_OR, addr);
}
}
#else
- void subl_im(int imm, void* addr)
+ void subl_im(int imm, const void* addr)
{
if (CAN_SIGN_EXTEND_8_32(imm)) {
m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_SUB, addr);
}
}
#else
- void cmpl_rm(RegisterID reg, void* addr)
+ void cmpl_rm(RegisterID reg, const void* addr)
{
m_formatter.oneByteOp(OP_CMP_EvGv, reg, addr);
}
- void cmpl_im(int imm, void* addr)
+ void cmpl_im(int imm, const void* addr)
{
if (CAN_SIGN_EXTEND_8_32(imm)) {
m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_CMP, addr);
m_formatter.oneByteOp(OP_GROUP3_EvIz, GROUP3_OP_TEST, base, offset);
m_formatter.immediate32(imm);
}
-
+
+ void testb_rr(RegisterID src, RegisterID dst)
+ {
+ m_formatter.oneByteOp(OP_TEST_EbGb, src, dst);
+ }
+
void testb_im(int imm, int offset, RegisterID base)
{
m_formatter.oneByteOp(OP_GROUP3_EbIb, GROUP3_OP_TEST, base, offset);
m_formatter.oneByteOp(OP_MOV_EvGv, src, base, index, scale, offset);
}
- void movl_mEAX(void* addr)
+ void movl_mEAX(const void* addr)
{
m_formatter.oneByteOp(OP_MOV_EAXOv);
#if CPU(X86_64)
{
m_formatter.oneByteOp_disp32(OP_MOV_GvEv, dst, base, offset);
}
+
+ void movl_mr_disp8(int offset, RegisterID base, RegisterID dst)
+ {
+ m_formatter.oneByteOp_disp8(OP_MOV_GvEv, dst, base, offset);
+ }
void movl_mr(int offset, RegisterID base, RegisterID index, int scale, RegisterID dst)
{
m_formatter.immediate32(imm);
}
- void movl_EAXm(void* addr)
+ void movl_EAXm(const void* addr)
{
m_formatter.oneByteOp(OP_MOV_OvEAX);
#if CPU(X86_64)
m_formatter.oneByteOp64(OP_MOV_EvGv, src, base, index, scale, offset);
}
- void movq_mEAX(void* addr)
+ void movq_mEAX(const void* addr)
{
m_formatter.oneByteOp64(OP_MOV_EAXOv);
m_formatter.immediate64(reinterpret_cast<int64_t>(addr));
}
- void movq_EAXm(void* addr)
+ void movq_EAXm(const void* addr)
{
m_formatter.oneByteOp64(OP_MOV_OvEAX);
m_formatter.immediate64(reinterpret_cast<int64_t>(addr));
m_formatter.oneByteOp64_disp32(OP_MOV_GvEv, dst, base, offset);
}
+ void movq_mr_disp8(int offset, RegisterID base, RegisterID dst)
+ {
+ m_formatter.oneByteOp64_disp8(OP_MOV_GvEv, dst, base, offset);
+ }
+
void movq_mr(int offset, RegisterID base, RegisterID index, int scale, RegisterID dst)
{
m_formatter.oneByteOp64(OP_MOV_GvEv, dst, base, index, scale, offset);
#else
- void movl_rm(RegisterID src, void* addr)
+ void movl_rm(RegisterID src, const void* addr)
{
if (src == X86Registers::eax)
movl_EAXm(addr);
m_formatter.oneByteOp(OP_MOV_EvGv, src, addr);
}
- void movl_mr(void* addr, RegisterID dst)
+ void movl_mr(const void* addr, RegisterID dst)
{
if (dst == X86Registers::eax)
movl_mEAX(addr);
m_formatter.oneByteOp(OP_MOV_GvEv, dst, addr);
}
- void movl_i32m(int imm, void* addr)
+ void movl_i32m(int imm, const void* addr)
{
m_formatter.oneByteOp(OP_GROUP11_EvIz, GROUP11_MOV, addr);
m_formatter.immediate32(imm);
// Flow control:
- JmpSrc call()
+ AssemblerLabel call()
{
m_formatter.oneByteOp(OP_CALL_rel32);
return m_formatter.immediateRel32();
}
- JmpSrc call(RegisterID dst)
+ AssemblerLabel call(RegisterID dst)
{
m_formatter.oneByteOp(OP_GROUP5_Ev, GROUP5_OP_CALLN, dst);
- return JmpSrc(m_formatter.size());
+ return m_formatter.label();
}
void call_m(int offset, RegisterID base)
m_formatter.oneByteOp(OP_GROUP5_Ev, GROUP5_OP_CALLN, base, offset);
}
- JmpSrc jmp()
+ AssemblerLabel jmp()
{
m_formatter.oneByteOp(OP_JMP_rel32);
return m_formatter.immediateRel32();
}
- // Return a JmpSrc so we have a label to the jump, so we can use this
+ // Return a AssemblerLabel so we have a label to the jump, so we can use this
// To make a tail recursive call on x86-64. The MacroAssembler
// really shouldn't wrap this as a Jump, since it can't be linked. :-/
- JmpSrc jmp_r(RegisterID dst)
+ AssemblerLabel jmp_r(RegisterID dst)
{
m_formatter.oneByteOp(OP_GROUP5_Ev, GROUP5_OP_JMPN, dst);
- return JmpSrc(m_formatter.size());
+ return m_formatter.label();
}
void jmp_m(int offset, RegisterID base)
m_formatter.oneByteOp(OP_GROUP5_Ev, GROUP5_OP_JMPN, base, offset);
}
- JmpSrc jne()
+ AssemblerLabel jne()
{
m_formatter.twoByteOp(jccRel32(ConditionNE));
return m_formatter.immediateRel32();
}
- JmpSrc jnz()
+ AssemblerLabel jnz()
{
return jne();
}
- JmpSrc je()
+ AssemblerLabel je()
{
m_formatter.twoByteOp(jccRel32(ConditionE));
return m_formatter.immediateRel32();
}
- JmpSrc jz()
+ AssemblerLabel jz()
{
return je();
}
- JmpSrc jl()
+ AssemblerLabel jl()
{
m_formatter.twoByteOp(jccRel32(ConditionL));
return m_formatter.immediateRel32();
}
- JmpSrc jb()
+ AssemblerLabel jb()
{
m_formatter.twoByteOp(jccRel32(ConditionB));
return m_formatter.immediateRel32();
}
- JmpSrc jle()
+ AssemblerLabel jle()
{
m_formatter.twoByteOp(jccRel32(ConditionLE));
return m_formatter.immediateRel32();
}
- JmpSrc jbe()
+ AssemblerLabel jbe()
{
m_formatter.twoByteOp(jccRel32(ConditionBE));
return m_formatter.immediateRel32();
}
- JmpSrc jge()
+ AssemblerLabel jge()
{
m_formatter.twoByteOp(jccRel32(ConditionGE));
return m_formatter.immediateRel32();
}
- JmpSrc jg()
+ AssemblerLabel jg()
{
m_formatter.twoByteOp(jccRel32(ConditionG));
return m_formatter.immediateRel32();
}
- JmpSrc ja()
+ AssemblerLabel ja()
{
m_formatter.twoByteOp(jccRel32(ConditionA));
return m_formatter.immediateRel32();
}
- JmpSrc jae()
+ AssemblerLabel jae()
{
m_formatter.twoByteOp(jccRel32(ConditionAE));
return m_formatter.immediateRel32();
}
- JmpSrc jo()
+ AssemblerLabel jo()
{
m_formatter.twoByteOp(jccRel32(ConditionO));
return m_formatter.immediateRel32();
}
- JmpSrc jp()
+ AssemblerLabel jp()
{
m_formatter.twoByteOp(jccRel32(ConditionP));
return m_formatter.immediateRel32();
}
- JmpSrc js()
+ AssemblerLabel js()
{
m_formatter.twoByteOp(jccRel32(ConditionS));
return m_formatter.immediateRel32();
}
- JmpSrc jCC(Condition cond)
+ AssemblerLabel jCC(Condition cond)
{
m_formatter.twoByteOp(jccRel32(cond));
return m_formatter.immediateRel32();
}
#if !CPU(X86_64)
- void cvtsi2sd_mr(void* address, XMMRegisterID dst)
+ void cvtsi2sd_mr(const void* address, XMMRegisterID dst)
{
m_formatter.prefix(PRE_SSE_F2);
m_formatter.twoByteOp(OP2_CVTSI2SD_VsdEd, (RegisterID)dst, address);
}
#endif
+ void movsd_rr(XMMRegisterID src, XMMRegisterID dst)
+ {
+ m_formatter.prefix(PRE_SSE_F2);
+ m_formatter.twoByteOp(OP2_MOVSD_VsdWsd, (RegisterID)dst, (RegisterID)src);
+ }
+
void movsd_rm(XMMRegisterID src, int offset, RegisterID base)
{
m_formatter.prefix(PRE_SSE_F2);
// Assembler admin methods:
- JmpDst label()
+ size_t codeSize() const
{
- return JmpDst(m_formatter.size());
+ return m_formatter.codeSize();
}
-
- static JmpDst labelFor(JmpSrc jump, intptr_t offset = 0)
+
+ AssemblerLabel label()
{
- return JmpDst(jump.m_offset + offset);
+ return m_formatter.label();
}
-
- JmpDst align(int alignment)
+
+ AssemblerLabel align(int alignment)
{
while (!m_formatter.isAligned(alignment))
m_formatter.oneByteOp(OP_HLT);
// writable region of memory; to modify the code in an execute-only execuable
// pool the 'repatch' and 'relink' methods should be used.
- void linkJump(JmpSrc from, JmpDst to)
+ void linkJump(AssemblerLabel from, AssemblerLabel to)
{
- ASSERT(from.m_offset != -1);
- ASSERT(to.m_offset != -1);
+ ASSERT(from.isSet());
+ ASSERT(to.isSet());
char* code = reinterpret_cast<char*>(m_formatter.data());
+ ASSERT(!reinterpret_cast<int32_t*>(code + from.m_offset)[-1]);
setRel32(code + from.m_offset, code + to.m_offset);
}
- static void linkJump(void* code, JmpSrc from, void* to)
+ static void linkJump(void* code, AssemblerLabel from, void* to)
{
- ASSERT(from.m_offset != -1);
+ ASSERT(from.isSet());
setRel32(reinterpret_cast<char*>(code) + from.m_offset, to);
}
- static void linkCall(void* code, JmpSrc from, void* to)
+ static void linkCall(void* code, AssemblerLabel from, void* to)
{
- ASSERT(from.m_offset != -1);
+ ASSERT(from.isSet());
setRel32(reinterpret_cast<char*>(code) + from.m_offset, to);
}
- static void linkPointer(void* code, JmpDst where, void* value)
+ static void linkPointer(void* code, AssemblerLabel where, void* value)
{
- ASSERT(where.m_offset != -1);
+ ASSERT(where.isSet());
setPointer(reinterpret_cast<char*>(code) + where.m_offset, value);
}
{
setRel32(from, to);
}
+
+ static void repatchCompact(void* where, int32_t value)
+ {
+ ASSERT(value >= 0);
+ ASSERT(value <= std::numeric_limits<int8_t>::max());
+ setInt8(where, value);
+ }
static void repatchInt32(void* where, int32_t value)
{
{
setPointer(where, value);
}
-
- static void repatchLoadPtrToLEA(void* where)
- {
-#if CPU(X86_64)
- // On x86-64 pointer memory accesses require a 64-bit operand, and as such a REX prefix.
- // Skip over the prefix byte.
- where = reinterpret_cast<char*>(where) + 1;
-#endif
- *reinterpret_cast<unsigned char*>(where) = static_cast<unsigned char>(OP_LEA);
- }
- static unsigned getCallReturnOffset(JmpSrc call)
+ static void* readPointer(void* where)
{
- ASSERT(call.m_offset >= 0);
- return call.m_offset;
+ return reinterpret_cast<void**>(where)[-1];
}
- static void* getRelocatedAddress(void* code, JmpSrc jump)
+ static unsigned getCallReturnOffset(AssemblerLabel call)
{
- ASSERT(jump.m_offset != -1);
-
- return reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(code) + jump.m_offset);
+ ASSERT(call.isSet());
+ return call.m_offset;
}
-
- static void* getRelocatedAddress(void* code, JmpDst destination)
- {
- ASSERT(destination.m_offset != -1);
- return reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(code) + destination.m_offset);
- }
-
- static int getDifferenceBetweenLabels(JmpDst src, JmpDst dst)
+ static void* getRelocatedAddress(void* code, AssemblerLabel label)
{
- return dst.m_offset - src.m_offset;
+ ASSERT(label.isSet());
+ return reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(code) + label.m_offset);
}
- static int getDifferenceBetweenLabels(JmpDst src, JmpSrc dst)
+ static int getDifferenceBetweenLabels(AssemblerLabel a, AssemblerLabel b)
{
- return dst.m_offset - src.m_offset;
+ return b.m_offset - a.m_offset;
}
- static int getDifferenceBetweenLabels(JmpSrc src, JmpDst dst)
+ void* executableCopy(JSGlobalData& globalData, ExecutablePool* allocator)
{
- return dst.m_offset - src.m_offset;
+ return m_formatter.executableCopy(globalData, allocator);
}
-
- void* executableCopy(ExecutablePool* allocator)
+
+ void rewindToLabel(AssemblerLabel rewindTo) { m_formatter.rewindToLabel(rewindTo); }
+
+#ifndef NDEBUG
+ unsigned debugOffset() { return m_formatter.debugOffset(); }
+#endif
+
+ void nop()
{
- void* copy = m_formatter.executableCopy(allocator);
- ASSERT(copy);
- return copy;
+ m_formatter.oneByteOp(OP_NOP);
}
private:
{
reinterpret_cast<int32_t*>(where)[-1] = value;
}
+
+ static void setInt8(void* where, int8_t value)
+ {
+ reinterpret_cast<int8_t*>(where)[-1] = value;
+ }
static void setRel32(void* from, void* to)
{
m_buffer.putByteUnchecked(opcode);
memoryModRM_disp32(reg, base, offset);
}
+
+ void oneByteOp_disp8(OneByteOpcodeID opcode, int reg, RegisterID base, int offset)
+ {
+ m_buffer.ensureSpace(maxInstructionSize);
+ emitRexIfNeeded(reg, 0, base);
+ m_buffer.putByteUnchecked(opcode);
+ memoryModRM_disp8(reg, base, offset);
+ }
void oneByteOp(OneByteOpcodeID opcode, int reg, RegisterID base, RegisterID index, int scale, int offset)
{
}
#if !CPU(X86_64)
- void oneByteOp(OneByteOpcodeID opcode, int reg, void* address)
+ void oneByteOp(OneByteOpcodeID opcode, int reg, const void* address)
{
m_buffer.ensureSpace(maxInstructionSize);
m_buffer.putByteUnchecked(opcode);
m_buffer.putByteUnchecked(opcode);
memoryModRM_disp32(reg, base, offset);
}
+
+ void oneByteOp64_disp8(OneByteOpcodeID opcode, int reg, RegisterID base, int offset)
+ {
+ m_buffer.ensureSpace(maxInstructionSize);
+ emitRexW(reg, 0, base);
+ m_buffer.putByteUnchecked(opcode);
+ memoryModRM_disp8(reg, base, offset);
+ }
void oneByteOp64(OneByteOpcodeID opcode, int reg, RegisterID base, RegisterID index, int scale, int offset)
{
m_buffer.putInt64Unchecked(imm);
}
- JmpSrc immediateRel32()
+ AssemblerLabel immediateRel32()
{
m_buffer.putIntUnchecked(0);
- return JmpSrc(m_buffer.size());
+ return label();
}
// Administrative methods:
- size_t size() const { return m_buffer.size(); }
+ size_t codeSize() const { return m_buffer.codeSize(); }
+ AssemblerLabel label() const { return m_buffer.label(); }
bool isAligned(int alignment) const { return m_buffer.isAligned(alignment); }
void* data() const { return m_buffer.data(); }
- void* executableCopy(ExecutablePool* allocator) { return m_buffer.executableCopy(allocator); }
+
+ void* executableCopy(JSGlobalData& globalData, ExecutablePool* allocator)
+ {
+ return m_buffer.executableCopy(globalData, allocator);
+ }
+
+ void rewindToLabel(AssemblerLabel rewindTo) { m_buffer.rewindToLabel(rewindTo); }
+
+#ifndef NDEBUG
+ unsigned debugOffset() { return m_buffer.debugOffset(); }
+#endif
private:
}
}
}
-
+
+ void memoryModRM_disp8(int reg, RegisterID base, int offset)
+ {
+ // A base of esp or r12 would be interpreted as a sib, so force a sib with no index & put the base in there.
+ ASSERT(CAN_SIGN_EXTEND_8_32(offset));
+#if CPU(X86_64)
+ if ((base == hasSib) || (base == hasSib2)) {
+#else
+ if (base == hasSib) {
+#endif
+ putModRmSib(ModRmMemoryDisp8, reg, base, noIndex, 0);
+ m_buffer.putByteUnchecked(offset);
+ } else {
+ putModRm(ModRmMemoryDisp8, reg, base);
+ m_buffer.putByteUnchecked(offset);
+ }
+ }
+
void memoryModRM_disp32(int reg, RegisterID base, int offset)
{
// A base of esp or r12 would be interpreted as a sib, so force a sib with no index & put the base in there.
/*
- * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2009, 2010 Apple Inc. All rights reserved.
* Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
*
* Redistribution and use in source and binary forms, with or without
#include "config.h"
#include "CodeBlock.h"
-#include "JIT.h"
-#include "JSValue.h"
+#include "BytecodeGenerator.h"
+#include "Debugger.h"
#include "Interpreter.h"
+#include "JIT.h"
+#include "JSActivation.h"
#include "JSFunction.h"
#include "JSStaticScopeObject.h"
-#include "Debugger.h"
-#include "BytecodeGenerator.h"
+#include "JSValue.h"
+#include "RepatchBuffer.h"
+#include "UStringConcatenate.h"
#include <stdio.h>
#include <wtf/StringExtras.h>
static UString escapeQuotes(const UString& str)
{
UString result = str;
- unsigned pos = 0;
- while ((pos = result.find('\"', pos)) != UString::NotFound) {
- result = makeString(result.substr(0, pos), "\"\\\"\"", result.substr(pos + 1));
+ size_t pos = 0;
+ while ((pos = result.find('\"', pos)) != notFound) {
+ result = makeUString(result.substringSharingImpl(0, pos), "\"\\\"\"", result.substringSharingImpl(pos + 1));
pos += 4;
}
return result;
return "0";
if (val.isString())
- return makeString("\"", escapeQuotes(val.toString(exec)), "\"");
+ return makeUString("\"", escapeQuotes(val.toString(exec)), "\"");
return val.toString(exec);
}
static CString constantName(ExecState* exec, int k, JSValue value)
{
- return makeString(valueToSourceString(exec, value), "(@k", UString::from(k - FirstConstantRegisterIndex), ")").UTF8String();
+ return makeUString(valueToSourceString(exec, value), "(@k", UString::number(k - FirstConstantRegisterIndex), ")").utf8();
}
static CString idName(int id0, const Identifier& ident)
{
- return makeString(ident.ustring(), "(@id", UString::from(id0), ")").UTF8String();
+ return makeUString(ident.ustring(), "(@id", UString::number(id0), ")").utf8();
}
CString CodeBlock::registerName(ExecState* exec, int r) const
if (isConstantRegisterIndex(r))
return constantName(exec, r, getConstant(r));
- return makeString("r", UString::from(r)).UTF8String();
+ return makeUString("r", UString::number(r)).utf8();
}
static UString regexpToSourceString(RegExp* regExp)
if (regExp->multiline())
postfix[index] = 'm';
- return makeString("/", regExp->pattern(), postfix);
+ return makeUString("/", regExp->pattern(), postfix);
}
static CString regexpName(int re, RegExp* regexp)
{
- return makeString(regexpToSourceString(regexp), "(@re", UString::from(re), ")").UTF8String();
+ return makeUString(regexpToSourceString(regexp), "(@re", UString::number(re), ")").utf8();
}
static UString pointerToSourceString(void* p)
int id0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
printf("[%4d] %s\t %s, %s, %s\n", location, op, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), registerName(exec, r1).data());
- it += 4;
+ it += 5;
}
#if ENABLE(JIT)
static void printGlobalResolveInfo(const GlobalResolveInfo& resolveInfo, unsigned instructionOffset)
{
- printf(" [%4d] %s: %s\n", instructionOffset, "resolve_global", pointerToSourceString(resolveInfo.structure).UTF8String().data());
+ printf(" [%4d] %s: %s\n", instructionOffset, "resolve_global", pointerToSourceString(resolveInfo.structure).utf8().data());
}
static void printStructureStubInfo(const StructureStubInfo& stubInfo, unsigned instructionOffset)
{
switch (stubInfo.accessType) {
case access_get_by_id_self:
- printf(" [%4d] %s: %s\n", instructionOffset, "get_by_id_self", pointerToSourceString(stubInfo.u.getByIdSelf.baseObjectStructure).UTF8String().data());
+ printf(" [%4d] %s: %s\n", instructionOffset, "get_by_id_self", pointerToSourceString(stubInfo.u.getByIdSelf.baseObjectStructure).utf8().data());
return;
case access_get_by_id_proto:
- printf(" [%4d] %s: %s, %s\n", instructionOffset, "get_by_id_proto", pointerToSourceString(stubInfo.u.getByIdProto.baseObjectStructure).UTF8String().data(), pointerToSourceString(stubInfo.u.getByIdProto.prototypeStructure).UTF8String().data());
+ printf(" [%4d] %s: %s, %s\n", instructionOffset, "get_by_id_proto", pointerToSourceString(stubInfo.u.getByIdProto.baseObjectStructure).utf8().data(), pointerToSourceString(stubInfo.u.getByIdProto.prototypeStructure).utf8().data());
return;
case access_get_by_id_chain:
- printf(" [%4d] %s: %s, %s\n", instructionOffset, "get_by_id_chain", pointerToSourceString(stubInfo.u.getByIdChain.baseObjectStructure).UTF8String().data(), pointerToSourceString(stubInfo.u.getByIdChain.chain).UTF8String().data());
+ printf(" [%4d] %s: %s, %s\n", instructionOffset, "get_by_id_chain", pointerToSourceString(stubInfo.u.getByIdChain.baseObjectStructure).utf8().data(), pointerToSourceString(stubInfo.u.getByIdChain.chain).utf8().data());
return;
case access_get_by_id_self_list:
- printf(" [%4d] %s: %s (%d)\n", instructionOffset, "op_get_by_id_self_list", pointerToSourceString(stubInfo.u.getByIdSelfList.structureList).UTF8String().data(), stubInfo.u.getByIdSelfList.listSize);
+ printf(" [%4d] %s: %s (%d)\n", instructionOffset, "op_get_by_id_self_list", pointerToSourceString(stubInfo.u.getByIdSelfList.structureList).utf8().data(), stubInfo.u.getByIdSelfList.listSize);
return;
case access_get_by_id_proto_list:
- printf(" [%4d] %s: %s (%d)\n", instructionOffset, "op_get_by_id_proto_list", pointerToSourceString(stubInfo.u.getByIdProtoList.structureList).UTF8String().data(), stubInfo.u.getByIdProtoList.listSize);
+ printf(" [%4d] %s: %s (%d)\n", instructionOffset, "op_get_by_id_proto_list", pointerToSourceString(stubInfo.u.getByIdProtoList.structureList).utf8().data(), stubInfo.u.getByIdProtoList.listSize);
return;
case access_put_by_id_transition:
- printf(" [%4d] %s: %s, %s, %s\n", instructionOffset, "put_by_id_transition", pointerToSourceString(stubInfo.u.putByIdTransition.previousStructure).UTF8String().data(), pointerToSourceString(stubInfo.u.putByIdTransition.structure).UTF8String().data(), pointerToSourceString(stubInfo.u.putByIdTransition.chain).UTF8String().data());
+ printf(" [%4d] %s: %s, %s, %s\n", instructionOffset, "put_by_id_transition", pointerToSourceString(stubInfo.u.putByIdTransition.previousStructure).utf8().data(), pointerToSourceString(stubInfo.u.putByIdTransition.structure).utf8().data(), pointerToSourceString(stubInfo.u.putByIdTransition.chain).utf8().data());
return;
case access_put_by_id_replace:
- printf(" [%4d] %s: %s\n", instructionOffset, "put_by_id_replace", pointerToSourceString(stubInfo.u.putByIdReplace.baseObjectStructure).UTF8String().data());
+ printf(" [%4d] %s: %s\n", instructionOffset, "put_by_id_replace", pointerToSourceString(stubInfo.u.putByIdReplace.baseObjectStructure).utf8().data());
return;
case access_get_by_id:
printf(" [%4d] %s\n", instructionOffset, "get_by_id");
void CodeBlock::printStructure(const char* name, const Instruction* vPC, int operand) const
{
unsigned instructionOffset = vPC - m_instructions.begin();
- printf(" [%4d] %s: %s\n", instructionOffset, name, pointerToSourceString(vPC[operand].u.structure).UTF8String().data());
+ printf(" [%4d] %s: %s\n", instructionOffset, name, pointerToSourceString(vPC[operand].u.structure).utf8().data());
}
void CodeBlock::printStructures(const Instruction* vPC) const
return;
}
if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto)) {
- printf(" [%4d] %s: %s, %s\n", instructionOffset, "get_by_id_proto", pointerToSourceString(vPC[4].u.structure).UTF8String().data(), pointerToSourceString(vPC[5].u.structure).UTF8String().data());
+ printf(" [%4d] %s: %s, %s\n", instructionOffset, "get_by_id_proto", pointerToSourceString(vPC[4].u.structure).utf8().data(), pointerToSourceString(vPC[5].u.structure).utf8().data());
return;
}
if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_transition)) {
- printf(" [%4d] %s: %s, %s, %s\n", instructionOffset, "put_by_id_transition", pointerToSourceString(vPC[4].u.structure).UTF8String().data(), pointerToSourceString(vPC[5].u.structure).UTF8String().data(), pointerToSourceString(vPC[6].u.structureChain).UTF8String().data());
+ printf(" [%4d] %s: %s, %s, %s\n", instructionOffset, "put_by_id_transition", pointerToSourceString(vPC[4].u.structure).utf8().data(), pointerToSourceString(vPC[5].u.structure).utf8().data(), pointerToSourceString(vPC[6].u.structureChain).utf8().data());
return;
}
if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_chain)) {
- printf(" [%4d] %s: %s, %s\n", instructionOffset, "get_by_id_chain", pointerToSourceString(vPC[4].u.structure).UTF8String().data(), pointerToSourceString(vPC[5].u.structureChain).UTF8String().data());
+ printf(" [%4d] %s: %s, %s\n", instructionOffset, "get_by_id_chain", pointerToSourceString(vPC[4].u.structure).utf8().data(), pointerToSourceString(vPC[5].u.structureChain).utf8().data());
return;
}
if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id)) {
printf("\nIdentifiers:\n");
size_t i = 0;
do {
- printf(" id%u = %s\n", static_cast<unsigned>(i), m_identifiers[i].ascii());
+ printf(" id%u = %s\n", static_cast<unsigned>(i), m_identifiers[i].ustring().utf8().data());
++i;
} while (i != m_identifiers.size());
}
unsigned registerIndex = m_numVars;
size_t i = 0;
do {
- printf(" k%u = %s\n", registerIndex, valueToSourceString(exec, m_constantRegisters[i].jsValue()).ascii());
+ printf(" k%u = %s\n", registerIndex, valueToSourceString(exec, m_constantRegisters[i].get()).utf8().data());
++i;
++registerIndex;
} while (i < m_constantRegisters.size());
printf("\nm_regexps:\n");
size_t i = 0;
do {
- printf(" re%u = %s\n", static_cast<unsigned>(i), regexpToSourceString(m_rareData->m_regexps[i].get()).ascii());
+ printf(" re%u = %s\n", static_cast<unsigned>(i), regexpToSourceString(m_rareData->m_regexps[i].get()).utf8().data());
++i;
} while (i < m_rareData->m_regexps.size());
}
++i;
} while (i < m_structureStubInfos.size());
}
-#else
+#endif
+#if ENABLE(INTERPRETER)
if (!m_globalResolveInstructions.isEmpty() || !m_propertyAccessInstructions.isEmpty())
printf("\nStructures:\n");
continue;
ASSERT(!((i + m_rareData->m_characterSwitchJumpTables[i].min) & ~0xFFFF));
UChar ch = static_cast<UChar>(entry + m_rareData->m_characterSwitchJumpTables[i].min);
- printf("\t\t\"%s\" => %04d\n", UString(&ch, 1).ascii(), *iter);
+ printf("\t\t\"%s\" => %04d\n", UString(&ch, 1).utf8().data(), *iter);
}
printf(" }\n");
++i;
printf(" %1d = {\n", i);
StringJumpTable::StringOffsetTable::const_iterator end = m_rareData->m_stringSwitchJumpTables[i].offsetTable.end();
for (StringJumpTable::StringOffsetTable::const_iterator iter = m_rareData->m_stringSwitchJumpTables[i].offsetTable.begin(); iter != end; ++iter)
- printf("\t\t\"%s\" => %04d\n", UString(iter->first).ascii(), iter->second.branchOffset);
+ printf("\t\t\"%s\" => %04d\n", UString(iter->first).utf8().data(), iter->second.branchOffset);
printf(" }\n");
++i;
} while (i < m_rareData->m_stringSwitchJumpTables.size());
printf("[%4d] enter\n", location);
break;
}
- case op_enter_with_activation: {
+ case op_create_activation: {
int r0 = (++it)->u.operand;
- printf("[%4d] enter_with_activation %s\n", location, registerName(exec, r0).data());
+ printf("[%4d] create_activation %s\n", location, registerName(exec, r0).data());
break;
}
case op_create_arguments: {
- printf("[%4d] create_arguments\n", location);
+ int r0 = (++it)->u.operand;
+ printf("[%4d] create_arguments\t %s\n", location, registerName(exec, r0).data());
break;
}
- case op_init_arguments: {
- printf("[%4d] init_arguments\n", location);
+ case op_init_lazy_reg: {
+ int r0 = (++it)->u.operand;
+ printf("[%4d] init_lazy_reg\t %s\n", location, registerName(exec, r0).data());
+ break;
+ }
+ case op_get_callee: {
+ int r0 = (++it)->u.operand;
+ printf("[%4d] op_get_callee %s\n", location, registerName(exec, r0).data());
+ break;
+ }
+ case op_create_this: {
+ int r0 = (++it)->u.operand;
+ int r1 = (++it)->u.operand;
+ printf("[%4d] create_this %s %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data());
break;
}
case op_convert_this: {
printf("[%4d] convert_this %s\n", location, registerName(exec, r0).data());
break;
}
+ case op_convert_this_strict: {
+ int r0 = (++it)->u.operand;
+ printf("[%4d] convert_this_strict %s\n", location, registerName(exec, r0).data());
+ break;
+ }
case op_new_object: {
int r0 = (++it)->u.operand;
printf("[%4d] new_object\t %s\n", location, registerName(exec, r0).data());
printf("[%4d] new_array\t %s, %s, %d\n", location, registerName(exec, dst).data(), registerName(exec, argv).data(), argc);
break;
}
+ case op_new_array_buffer: {
+ int dst = (++it)->u.operand;
+ int argv = (++it)->u.operand;
+ int argc = (++it)->u.operand;
+ printf("[%4d] new_array_buffer %s, %d, %d\n", location, registerName(exec, dst).data(), argv, argc);
+ break;
+ }
case op_new_regexp: {
int r0 = (++it)->u.operand;
int re0 = (++it)->u.operand;
printUnaryOp(exec, location, it, "bitnot");
break;
}
+ case op_check_has_instance: {
+ int base = (++it)->u.operand;
+ printf("[%4d] check_has_instance\t\t %s\n", location, registerName(exec, base).data());
+ break;
+ }
case op_instanceof: {
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
}
case op_resolve_global: {
int r0 = (++it)->u.operand;
- JSValue scope = JSValue((++it)->u.jsCell);
int id0 = (++it)->u.operand;
- printf("[%4d] resolve_global\t %s, %s, %s\n", location, registerName(exec, r0).data(), valueToSourceString(exec, scope).ascii(), idName(id0, m_identifiers[id0]).data());
+ printf("[%4d] resolve_global\t %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data());
it += 2;
break;
}
case op_resolve_global_dynamic: {
int r0 = (++it)->u.operand;
- JSValue scope = JSValue((++it)->u.jsCell);
int id0 = (++it)->u.operand;
- int depth = it[2].u.operand;
- printf("[%4d] resolve_global_dynamic\t %s, %s, %s, %d\n", location, registerName(exec, r0).data(), valueToSourceString(exec, scope).ascii(), idName(id0, m_identifiers[id0]).data(), depth);
- it += 3;
+ JSValue scope = JSValue((++it)->u.jsCell.get());
+ ++it;
+ int depth = (++it)->u.operand;
+ printf("[%4d] resolve_global_dynamic\t %s, %s, %s, %d\n", location, registerName(exec, r0).data(), valueToSourceString(exec, scope).utf8().data(), idName(id0, m_identifiers[id0]).data(), depth);
break;
}
case op_get_scoped_var: {
}
case op_get_global_var: {
int r0 = (++it)->u.operand;
- JSValue scope = JSValue((++it)->u.jsCell);
int index = (++it)->u.operand;
- printf("[%4d] get_global_var\t %s, %s, %d\n", location, registerName(exec, r0).data(), valueToSourceString(exec, scope).ascii(), index);
+ printf("[%4d] get_global_var\t %s, %d\n", location, registerName(exec, r0).data(), index);
break;
}
case op_put_global_var: {
- JSValue scope = JSValue((++it)->u.jsCell);
int index = (++it)->u.operand;
int r0 = (++it)->u.operand;
- printf("[%4d] put_global_var\t %s, %d, %s\n", location, valueToSourceString(exec, scope).ascii(), index, registerName(exec, r0).data());
+ printf("[%4d] put_global_var\t %d, %s\n", location, index, registerName(exec, r0).data());
break;
}
case op_resolve_base: {
int r0 = (++it)->u.operand;
int id0 = (++it)->u.operand;
- printf("[%4d] resolve_base\t %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data());
+ int isStrict = (++it)->u.operand;
+ printf("[%4d] resolve_base%s\t %s, %s\n", location, isStrict ? "_strict" : "", registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data());
+ break;
+ }
+ case op_ensure_property_exists: {
+ int r0 = (++it)->u.operand;
+ int id0 = (++it)->u.operand;
+ printf("[%4d] ensure_property_exists\t %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data());
break;
}
case op_resolve_with_base: {
printGetByIdOp(exec, location, it, "get_string_length");
break;
}
+ case op_get_arguments_length: {
+ printUnaryOp(exec, location, it, "get_arguments_length");
+ it++;
+ break;
+ }
case op_put_by_id: {
printPutByIdOp(exec, location, it, "put_by_id");
break;
printf("[%4d] get_by_val\t %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
break;
}
+ case op_get_argument_by_val: {
+ int r0 = (++it)->u.operand;
+ int r1 = (++it)->u.operand;
+ int r2 = (++it)->u.operand;
+ printf("[%4d] get_argument_by_val\t %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
+ break;
+ }
case op_get_by_pname: {
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
case op_new_func: {
int r0 = (++it)->u.operand;
int f0 = (++it)->u.operand;
- printf("[%4d] new_func\t\t %s, f%d\n", location, registerName(exec, r0).data(), f0);
+ int shouldCheck = (++it)->u.operand;
+ printf("[%4d] new_func\t\t %s, f%d, %s\n", location, registerName(exec, r0).data(), f0, shouldCheck ? "<Checked>" : "<Unchecked>");
break;
}
case op_new_func_exp: {
break;
}
case op_call: {
- int dst = (++it)->u.operand;
int func = (++it)->u.operand;
int argCount = (++it)->u.operand;
int registerOffset = (++it)->u.operand;
- printf("[%4d] call\t\t %s, %s, %d, %d\n", location, registerName(exec, dst).data(), registerName(exec, func).data(), argCount, registerOffset);
+ printf("[%4d] call\t\t %s, %d, %d\n", location, registerName(exec, func).data(), argCount, registerOffset);
break;
}
case op_call_eval: {
- int dst = (++it)->u.operand;
int func = (++it)->u.operand;
int argCount = (++it)->u.operand;
int registerOffset = (++it)->u.operand;
- printf("[%4d] call_eval\t %s, %s, %d, %d\n", location, registerName(exec, dst).data(), registerName(exec, func).data(), argCount, registerOffset);
+ printf("[%4d] call_eval\t %s, %d, %d\n", location, registerName(exec, func).data(), argCount, registerOffset);
break;
}
case op_call_varargs: {
- int dst = (++it)->u.operand;
int func = (++it)->u.operand;
int argCount = (++it)->u.operand;
int registerOffset = (++it)->u.operand;
- printf("[%4d] call_varargs\t %s, %s, %s, %d\n", location, registerName(exec, dst).data(), registerName(exec, func).data(), registerName(exec, argCount).data(), registerOffset);
+ printf("[%4d] call_varargs\t %s, %s, %d\n", location, registerName(exec, func).data(), registerName(exec, argCount).data(), registerOffset);
break;
}
case op_load_varargs: {
}
case op_tear_off_activation: {
int r0 = (++it)->u.operand;
- printf("[%4d] tear_off_activation\t %s\n", location, registerName(exec, r0).data());
+ int r1 = (++it)->u.operand;
+ printf("[%4d] tear_off_activation\t %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data());
break;
}
case op_tear_off_arguments: {
- printf("[%4d] tear_off_arguments\n", location);
+ int r0 = (++it)->u.operand;
+ printf("[%4d] tear_off_arguments\t %s\n", location, registerName(exec, r0).data());
break;
}
case op_ret: {
printf("[%4d] ret\t\t %s\n", location, registerName(exec, r0).data());
break;
}
- case op_construct: {
- int dst = (++it)->u.operand;
- int func = (++it)->u.operand;
- int argCount = (++it)->u.operand;
- int registerOffset = (++it)->u.operand;
- int proto = (++it)->u.operand;
- int thisRegister = (++it)->u.operand;
- printf("[%4d] construct\t %s, %s, %d, %d, %s, %s\n", location, registerName(exec, dst).data(), registerName(exec, func).data(), argCount, registerOffset, registerName(exec, proto).data(), registerName(exec, thisRegister).data());
+ case op_call_put_result: {
+ int r0 = (++it)->u.operand;
+ printf("[%4d] op_call_put_result\t\t %s\n", location, registerName(exec, r0).data());
break;
}
- case op_construct_verify: {
+ case op_ret_object_or_this: {
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
- printf("[%4d] construct_verify\t %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data());
+ printf("[%4d] constructor_ret\t\t %s %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data());
+ break;
+ }
+ case op_construct: {
+ int func = (++it)->u.operand;
+ int argCount = (++it)->u.operand;
+ int registerOffset = (++it)->u.operand;
+ printf("[%4d] construct\t %s, %d, %d\n", location, registerName(exec, func).data(), argCount, registerOffset);
break;
}
case op_strcat: {
}
case op_next_pname: {
int dest = it[1].u.operand;
- int iter = it[4].u.operand;
- int offset = it[5].u.operand;
- printf("[%4d] next_pname\t %s, %s, %d(->%d)\n", location, registerName(exec, dest).data(), registerName(exec, iter).data(), offset, location + offset);
+ int base = it[2].u.operand;
+ int i = it[3].u.operand;
+ int size = it[4].u.operand;
+ int iter = it[5].u.operand;
+ int offset = it[6].u.operand;
+ printf("[%4d] next_pname\t %s, %s, %s, %s, %s, %d(->%d)\n", location, registerName(exec, dest).data(), registerName(exec, base).data(), registerName(exec, i).data(), registerName(exec, size).data(), registerName(exec, iter).data(), offset, location + offset);
it += OPCODE_LENGTH(op_next_pname) - 1;
break;
}
printf("[%4d] throw\t\t %s\n", location, registerName(exec, r0).data());
break;
}
- case op_new_error: {
- int r0 = (++it)->u.operand;
- int errorType = (++it)->u.operand;
+ case op_throw_reference_error: {
int k0 = (++it)->u.operand;
- printf("[%4d] new_error\t %s, %d, %s\n", location, registerName(exec, r0).data(), errorType, constantName(exec, k0, getConstant(k0)).data());
+ printf("[%4d] throw_reference_error\t %s\n", location, constantName(exec, k0, getConstant(k0)).data());
break;
}
case op_jsr: {
macro(immediateSwitchJumpTables) \
macro(characterSwitchJumpTables) \
macro(stringSwitchJumpTables) \
- macro(functionRegisterInfos)
-
-#define FOR_EACH_MEMBER_VECTOR_EXCEPTION_INFO(macro) \
+ macro(evalCodeCache) \
macro(expressionInfo) \
macro(lineInfo) \
- macro(getByIdExceptionInfo) \
- macro(pcVector)
+ macro(callReturnIndexVector)
template<typename T>
static size_t sizeInBytes(const Vector<T>& vector)
#define DEFINE_VARS(name) size_t name##IsNotEmpty = 0; size_t name##TotalSize = 0;
FOR_EACH_MEMBER_VECTOR(DEFINE_VARS)
FOR_EACH_MEMBER_VECTOR_RARE_DATA(DEFINE_VARS)
- FOR_EACH_MEMBER_VECTOR_EXCEPTION_INFO(DEFINE_VARS)
#undef DEFINE_VARS
// Non-vector data members
size_t symbolTableIsNotEmpty = 0;
size_t symbolTableTotalSize = 0;
- size_t hasExceptionInfo = 0;
size_t hasRareData = 0;
size_t isFunctionCode = 0;
symbolTableTotalSize += (codeBlock->m_symbolTable.capacity() * (sizeof(SymbolTable::KeyType) + sizeof(SymbolTable::MappedType)));
}
- if (codeBlock->m_exceptionInfo) {
- hasExceptionInfo++;
- #define GET_STATS(name) if (!codeBlock->m_exceptionInfo->m_##name.isEmpty()) { name##IsNotEmpty++; name##TotalSize += sizeInBytes(codeBlock->m_exceptionInfo->m_##name); }
- FOR_EACH_MEMBER_VECTOR_EXCEPTION_INFO(GET_STATS)
- #undef GET_STATS
- }
-
if (codeBlock->m_rareData) {
hasRareData++;
#define GET_STATS(name) if (!codeBlock->m_rareData->m_##name.isEmpty()) { name##IsNotEmpty++; name##TotalSize += sizeInBytes(codeBlock->m_rareData->m_##name); }
#define GET_TOTAL_SIZE(name) totalSize += name##TotalSize;
FOR_EACH_MEMBER_VECTOR(GET_TOTAL_SIZE)
FOR_EACH_MEMBER_VECTOR_RARE_DATA(GET_TOTAL_SIZE)
- FOR_EACH_MEMBER_VECTOR_EXCEPTION_INFO(GET_TOTAL_SIZE)
#undef GET_TOTAL_SIZE
totalSize += symbolTableTotalSize;
printf("Number of GlobalCode CodeBlocks: %zu (%.3f%%)\n", isGlobalCode, static_cast<double>(isGlobalCode) * 100.0 / liveCodeBlockSet.size());
printf("Number of EvalCode CodeBlocks: %zu (%.3f%%)\n", isEvalCode, static_cast<double>(isEvalCode) * 100.0 / liveCodeBlockSet.size());
- printf("Number of CodeBlocks with exception info: %zu (%.3f%%)\n", hasExceptionInfo, static_cast<double>(hasExceptionInfo) * 100.0 / liveCodeBlockSet.size());
printf("Number of CodeBlocks with rare data: %zu (%.3f%%)\n", hasRareData, static_cast<double>(hasRareData) * 100.0 / liveCodeBlockSet.size());
#define PRINT_STATS(name) printf("Number of CodeBlocks with " #name ": %zu\n", name##IsNotEmpty); printf("Size of all " #name ": %zu\n", name##TotalSize);
FOR_EACH_MEMBER_VECTOR(PRINT_STATS)
FOR_EACH_MEMBER_VECTOR_RARE_DATA(PRINT_STATS)
- FOR_EACH_MEMBER_VECTOR_EXCEPTION_INFO(PRINT_STATS)
#undef PRINT_STATS
printf("Number of CodeBlocks with evalCodeCache: %zu\n", evalCodeCacheIsNotEmpty);
#endif
}
-CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, CodeType codeType, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset, SymbolTable* symTab)
- : m_numCalleeRegisters(0)
+CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, CodeType codeType, JSGlobalObject *globalObject, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset, SymbolTable* symTab, bool isConstructor)
+ : m_globalObject(globalObject->globalData(), ownerExecutable, globalObject)
+ , m_heap(&m_globalObject->globalData().heap)
+ , m_numCalleeRegisters(0)
, m_numVars(0)
, m_numParameters(0)
- , m_ownerExecutable(ownerExecutable)
+ , m_isConstructor(isConstructor)
+ , m_ownerExecutable(globalObject->globalData(), ownerExecutable, ownerExecutable)
, m_globalData(0)
#ifndef NDEBUG
, m_instructionCount(0)
#endif
+ , m_argumentsRegister(-1)
, m_needsFullScopeChain(ownerExecutable->needsActivation())
, m_usesEval(ownerExecutable->usesEval())
- , m_usesArguments(false)
, m_isNumericCompareFunction(false)
+ , m_isStrictMode(ownerExecutable->isStrictMode())
, m_codeType(codeType)
, m_source(sourceProvider)
, m_sourceOffset(sourceOffset)
, m_symbolTable(symTab)
- , m_exceptionInfo(new ExceptionInfo)
{
ASSERT(m_source);
CodeBlock::~CodeBlock()
{
-#if ENABLE(INTERPRETER)
- for (size_t size = m_globalResolveInstructions.size(), i = 0; i < size; ++i)
- derefStructures(&m_instructions[m_globalResolveInstructions[i]]);
-
- for (size_t size = m_propertyAccessInstructions.size(), i = 0; i < size; ++i)
- derefStructures(&m_instructions[m_propertyAccessInstructions[i]]);
-#endif
#if ENABLE(JIT)
- for (size_t size = m_globalResolveInfos.size(), i = 0; i < size; ++i) {
- if (m_globalResolveInfos[i].structure)
- m_globalResolveInfos[i].structure->deref();
- }
-
for (size_t size = m_structureStubInfos.size(), i = 0; i < size; ++i)
m_structureStubInfos[i].deref();
-
- for (size_t size = m_callLinkInfos.size(), i = 0; i < size; ++i) {
- CallLinkInfo* callLinkInfo = &m_callLinkInfos[i];
- if (callLinkInfo->isLinked())
- callLinkInfo->callee->removeCaller(callLinkInfo);
- }
-
- for (size_t size = m_methodCallLinkInfos.size(), i = 0; i < size; ++i) {
- if (Structure* structure = m_methodCallLinkInfos[i].cachedStructure) {
- structure->deref();
- // Both members must be filled at the same time
- ASSERT(!!m_methodCallLinkInfos[i].cachedPrototypeStructure);
- m_methodCallLinkInfos[i].cachedPrototypeStructure->deref();
- }
- }
-
-#if ENABLE(JIT_OPTIMIZE_CALL)
- unlinkCallers();
-#endif
-
#endif // ENABLE(JIT)
#if DUMP_CODE_BLOCK_STATISTICS
#endif
}
-#if ENABLE(JIT_OPTIMIZE_CALL)
-void CodeBlock::unlinkCallers()
-{
- size_t size = m_linkedCallerList.size();
- for (size_t i = 0; i < size; ++i) {
- CallLinkInfo* currentCaller = m_linkedCallerList[i];
- JIT::unlinkCall(currentCaller);
- currentCaller->setUnlinked();
- }
- m_linkedCallerList.clear();
-}
-#endif
-
-void CodeBlock::derefStructures(Instruction* vPC) const
+void CodeBlock::visitStructures(SlotVisitor& visitor, Instruction* vPC) const
{
Interpreter* interpreter = m_globalData->interpreter;
+ if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id) && vPC[4].u.structure) {
+ visitor.append(&vPC[4].u.structure);
+ return;
+ }
+
if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_self) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_custom_self)) {
- vPC[4].u.structure->deref();
+ visitor.append(&vPC[4].u.structure);
return;
}
if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_proto) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_custom_proto)) {
- vPC[4].u.structure->deref();
- vPC[5].u.structure->deref();
+ visitor.append(&vPC[4].u.structure);
+ visitor.append(&vPC[5].u.structure);
return;
}
if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_chain) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_chain) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_custom_chain)) {
- vPC[4].u.structure->deref();
- vPC[5].u.structureChain->deref();
+ visitor.append(&vPC[4].u.structure);
+ visitor.append(&vPC[5].u.structureChain);
return;
}
if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_transition)) {
- vPC[4].u.structure->deref();
- vPC[5].u.structure->deref();
- vPC[6].u.structureChain->deref();
+ visitor.append(&vPC[4].u.structure);
+ visitor.append(&vPC[5].u.structure);
+ visitor.append(&vPC[6].u.structureChain);
+ return;
+ }
+ if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id) && vPC[4].u.structure) {
+ visitor.append(&vPC[4].u.structure);
return;
}
if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_replace)) {
- vPC[4].u.structure->deref();
+ visitor.append(&vPC[4].u.structure);
return;
}
if (vPC[0].u.opcode == interpreter->getOpcode(op_resolve_global) || vPC[0].u.opcode == interpreter->getOpcode(op_resolve_global_dynamic)) {
- if(vPC[4].u.structure)
- vPC[4].u.structure->deref();
+ if (vPC[3].u.structure)
+ visitor.append(&vPC[3].u.structure);
return;
}
if ((vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto_list))
|| (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_custom_proto_list))
|| (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_custom_self_list))) {
PolymorphicAccessStructureList* polymorphicStructures = vPC[4].u.polymorphicStructures;
- polymorphicStructures->derefStructures(vPC[5].u.operand);
+ polymorphicStructures->visitAggregate(visitor, vPC[5].u.operand);
delete polymorphicStructures;
return;
}
ASSERT(vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id) || vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_generic) || vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_generic) || vPC[0].u.opcode == interpreter->getOpcode(op_get_array_length) || vPC[0].u.opcode == interpreter->getOpcode(op_get_string_length));
}
-void CodeBlock::refStructures(Instruction* vPC) const
+void EvalCodeCache::visitAggregate(SlotVisitor& visitor)
{
- Interpreter* interpreter = m_globalData->interpreter;
-
- if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_self) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_custom_self)) {
- vPC[4].u.structure->ref();
- return;
- }
- if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_proto) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_custom_proto)) {
- vPC[4].u.structure->ref();
- vPC[5].u.structure->ref();
- return;
- }
- if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_chain) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_chain) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_custom_chain)) {
- vPC[4].u.structure->ref();
- vPC[5].u.structureChain->ref();
- return;
- }
- if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_transition)) {
- vPC[4].u.structure->ref();
- vPC[5].u.structure->ref();
- vPC[6].u.structureChain->ref();
- return;
- }
- if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_replace)) {
- vPC[4].u.structure->ref();
- return;
- }
-
- // These instructions don't ref their Structures.
- ASSERT(vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id) || vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_generic) || vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_generic));
+ EvalCacheMap::iterator end = m_cacheMap.end();
+ for (EvalCacheMap::iterator ptr = m_cacheMap.begin(); ptr != end; ++ptr)
+ visitor.append(&ptr->second);
}
-void CodeBlock::markAggregate(MarkStack& markStack)
+void CodeBlock::visitAggregate(SlotVisitor& visitor)
{
- for (size_t i = 0; i < m_constantRegisters.size(); ++i)
- markStack.append(m_constantRegisters[i].jsValue());
+ visitor.append(&m_globalObject);
+ visitor.append(&m_ownerExecutable);
+ if (m_rareData) {
+ m_rareData->m_evalCodeCache.visitAggregate(visitor);
+ size_t regExpCount = m_rareData->m_regexps.size();
+ WriteBarrier<RegExp>* regexps = m_rareData->m_regexps.data();
+ for (size_t i = 0; i < regExpCount; i++)
+ visitor.append(regexps + i);
+ }
+ visitor.appendValues(m_constantRegisters.data(), m_constantRegisters.size());
for (size_t i = 0; i < m_functionExprs.size(); ++i)
- m_functionExprs[i]->markAggregate(markStack);
+ visitor.append(&m_functionExprs[i]);
for (size_t i = 0; i < m_functionDecls.size(); ++i)
- m_functionDecls[i]->markAggregate(markStack);
-}
+ visitor.append(&m_functionDecls[i]);
+#if ENABLE(JIT_OPTIMIZE_CALL)
+ if (visitor.shouldUnlinkCalls())
+ unlinkCalls();
+ for (unsigned i = 0; i < numberOfCallLinkInfos(); ++i)
+ if (callLinkInfo(i).isLinked())
+ visitor.append(&callLinkInfo(i).callee);
+#endif
+#if ENABLE(INTERPRETER)
+ for (size_t size = m_propertyAccessInstructions.size(), i = 0; i < size; ++i)
+ visitStructures(visitor, &m_instructions[m_propertyAccessInstructions[i]]);
+ for (size_t size = m_globalResolveInstructions.size(), i = 0; i < size; ++i)
+ visitStructures(visitor, &m_instructions[m_globalResolveInstructions[i]]);
+#endif
+#if ENABLE(JIT)
+ for (size_t size = m_globalResolveInfos.size(), i = 0; i < size; ++i) {
+ if (m_globalResolveInfos[i].structure)
+ visitor.append(&m_globalResolveInfos[i].structure);
+ }
-void CodeBlock::reparseForExceptionInfoIfNecessary(CallFrame* callFrame)
-{
- if (m_exceptionInfo)
- return;
+ for (size_t size = m_structureStubInfos.size(), i = 0; i < size; ++i)
+ m_structureStubInfos[i].visitAggregate(visitor);
- ScopeChainNode* scopeChain = callFrame->scopeChain();
- if (m_needsFullScopeChain) {
- ScopeChain sc(scopeChain);
- int scopeDelta = sc.localDepth();
- if (m_codeType == EvalCode)
- scopeDelta -= static_cast<EvalCodeBlock*>(this)->baseScopeDepth();
- else if (m_codeType == FunctionCode)
- scopeDelta++; // Compilation of function code assumes activation is not on the scope chain yet.
- ASSERT(scopeDelta >= 0);
- while (scopeDelta--)
- scopeChain = scopeChain->next;
+ for (size_t size = m_methodCallLinkInfos.size(), i = 0; i < size; ++i) {
+ if (m_methodCallLinkInfos[i].cachedStructure) {
+ // Both members must be filled at the same time
+ visitor.append(&m_methodCallLinkInfos[i].cachedStructure);
+ ASSERT(!!m_methodCallLinkInfos[i].cachedPrototypeStructure);
+ visitor.append(&m_methodCallLinkInfos[i].cachedPrototypeStructure);
+ visitor.append(&m_methodCallLinkInfos[i].cachedFunction);
+ visitor.append(&m_methodCallLinkInfos[i].cachedPrototype);
+ }
}
-
- m_exceptionInfo.set(m_ownerExecutable->reparseExceptionInfo(m_globalData, scopeChain, this));
+#endif
}
HandlerInfo* CodeBlock::handlerForBytecodeOffset(unsigned bytecodeOffset)
return 0;
}
-int CodeBlock::lineNumberForBytecodeOffset(CallFrame* callFrame, unsigned bytecodeOffset)
+int CodeBlock::lineNumberForBytecodeOffset(unsigned bytecodeOffset)
{
ASSERT(bytecodeOffset < m_instructionCount);
- reparseForExceptionInfoIfNecessary(callFrame);
- ASSERT(m_exceptionInfo);
+ if (!m_rareData)
+ return m_ownerExecutable->source().firstLine();
- if (!m_exceptionInfo->m_lineInfo.size())
- return m_ownerExecutable->source().firstLine(); // Empty function
+ Vector<LineInfo>& lineInfo = m_rareData->m_lineInfo;
int low = 0;
- int high = m_exceptionInfo->m_lineInfo.size();
+ int high = lineInfo.size();
while (low < high) {
int mid = low + (high - low) / 2;
- if (m_exceptionInfo->m_lineInfo[mid].instructionOffset <= bytecodeOffset)
+ if (lineInfo[mid].instructionOffset <= bytecodeOffset)
low = mid + 1;
else
high = mid;
}
-
+
if (!low)
return m_ownerExecutable->source().firstLine();
- return m_exceptionInfo->m_lineInfo[low - 1].lineNumber;
+ return lineInfo[low - 1].lineNumber;
}
-int CodeBlock::expressionRangeForBytecodeOffset(CallFrame* callFrame, unsigned bytecodeOffset, int& divot, int& startOffset, int& endOffset)
+void CodeBlock::expressionRangeForBytecodeOffset(unsigned bytecodeOffset, int& divot, int& startOffset, int& endOffset)
{
ASSERT(bytecodeOffset < m_instructionCount);
- reparseForExceptionInfoIfNecessary(callFrame);
- ASSERT(m_exceptionInfo);
-
- if (!m_exceptionInfo->m_expressionInfo.size()) {
- // We didn't think anything could throw. Apparently we were wrong.
+ if (!m_rareData) {
startOffset = 0;
endOffset = 0;
divot = 0;
- return lineNumberForBytecodeOffset(callFrame, bytecodeOffset);
+ return;
}
+ Vector<ExpressionRangeInfo>& expressionInfo = m_rareData->m_expressionInfo;
+
int low = 0;
- int high = m_exceptionInfo->m_expressionInfo.size();
+ int high = expressionInfo.size();
while (low < high) {
int mid = low + (high - low) / 2;
- if (m_exceptionInfo->m_expressionInfo[mid].instructionOffset <= bytecodeOffset)
+ if (expressionInfo[mid].instructionOffset <= bytecodeOffset)
low = mid + 1;
else
high = mid;
}
-
+
ASSERT(low);
if (!low) {
startOffset = 0;
endOffset = 0;
divot = 0;
- return lineNumberForBytecodeOffset(callFrame, bytecodeOffset);
- }
-
- startOffset = m_exceptionInfo->m_expressionInfo[low - 1].startOffset;
- endOffset = m_exceptionInfo->m_expressionInfo[low - 1].endOffset;
- divot = m_exceptionInfo->m_expressionInfo[low - 1].divotPoint + m_sourceOffset;
- return lineNumberForBytecodeOffset(callFrame, bytecodeOffset);
-}
-
-bool CodeBlock::getByIdExceptionInfoForBytecodeOffset(CallFrame* callFrame, unsigned bytecodeOffset, OpcodeID& opcodeID)
-{
- ASSERT(bytecodeOffset < m_instructionCount);
-
- reparseForExceptionInfoIfNecessary(callFrame);
- ASSERT(m_exceptionInfo);
-
- if (!m_exceptionInfo->m_getByIdExceptionInfo.size())
- return false;
-
- int low = 0;
- int high = m_exceptionInfo->m_getByIdExceptionInfo.size();
- while (low < high) {
- int mid = low + (high - low) / 2;
- if (m_exceptionInfo->m_getByIdExceptionInfo[mid].bytecodeOffset <= bytecodeOffset)
- low = mid + 1;
- else
- high = mid;
- }
-
- if (!low || m_exceptionInfo->m_getByIdExceptionInfo[low - 1].bytecodeOffset != bytecodeOffset)
- return false;
-
- opcodeID = m_exceptionInfo->m_getByIdExceptionInfo[low - 1].isOpConstruct ? op_construct : op_instanceof;
- return true;
-}
-
-#if ENABLE(JIT)
-bool CodeBlock::functionRegisterForBytecodeOffset(unsigned bytecodeOffset, int& functionRegisterIndex)
-{
- ASSERT(bytecodeOffset < m_instructionCount);
-
- if (!m_rareData || !m_rareData->m_functionRegisterInfos.size())
- return false;
-
- int low = 0;
- int high = m_rareData->m_functionRegisterInfos.size();
- while (low < high) {
- int mid = low + (high - low) / 2;
- if (m_rareData->m_functionRegisterInfos[mid].bytecodeOffset <= bytecodeOffset)
- low = mid + 1;
- else
- high = mid;
+ return;
}
- if (!low || m_rareData->m_functionRegisterInfos[low - 1].bytecodeOffset != bytecodeOffset)
- return false;
-
- functionRegisterIndex = m_rareData->m_functionRegisterInfos[low - 1].functionRegisterIndex;
- return true;
+ startOffset = expressionInfo[low - 1].startOffset;
+ endOffset = expressionInfo[low - 1].endOffset;
+ divot = expressionInfo[low - 1].divotPoint + m_sourceOffset;
+ return;
}
-#endif
#if ENABLE(INTERPRETER)
bool CodeBlock::hasGlobalResolveInstructionAtBytecodeOffset(unsigned bytecodeOffset)
m_structureStubInfos.shrinkToFit();
m_globalResolveInfos.shrinkToFit();
m_callLinkInfos.shrinkToFit();
- m_linkedCallerList.shrinkToFit();
#endif
m_identifiers.shrinkToFit();
m_functionExprs.shrinkToFit();
m_constantRegisters.shrinkToFit();
- if (m_exceptionInfo) {
- m_exceptionInfo->m_expressionInfo.shrinkToFit();
- m_exceptionInfo->m_lineInfo.shrinkToFit();
- m_exceptionInfo->m_getByIdExceptionInfo.shrinkToFit();
- }
-
if (m_rareData) {
m_rareData->m_exceptionHandlers.shrinkToFit();
m_rareData->m_regexps.shrinkToFit();
m_rareData->m_immediateSwitchJumpTables.shrinkToFit();
m_rareData->m_characterSwitchJumpTables.shrinkToFit();
m_rareData->m_stringSwitchJumpTables.shrinkToFit();
+ m_rareData->m_expressionInfo.shrinkToFit();
+ m_rareData->m_lineInfo.shrinkToFit();
+ }
+}
+
+void CodeBlock::createActivation(CallFrame* callFrame)
+{
+ ASSERT(codeType() == FunctionCode);
+ ASSERT(needsFullScopeChain());
+ ASSERT(!callFrame->uncheckedR(activationRegister()).jsValue());
+ JSActivation* activation = new (callFrame) JSActivation(callFrame, static_cast<FunctionExecutable*>(ownerExecutable()));
+ callFrame->uncheckedR(activationRegister()) = JSValue(activation);
+ callFrame->setScopeChain(callFrame->scopeChain()->push(activation));
+}
+
#if ENABLE(JIT)
- m_rareData->m_functionRegisterInfos.shrinkToFit();
-#endif
+void CodeBlock::unlinkCalls()
+{
+ if (!(m_callLinkInfos.size() || m_methodCallLinkInfos.size()))
+ return;
+ if (!m_globalData->canUseJIT())
+ return;
+ RepatchBuffer repatchBuffer(this);
+ for (size_t i = 0; i < m_callLinkInfos.size(); i++) {
+ if (!m_callLinkInfos[i].isLinked())
+ continue;
+ repatchBuffer.relink(m_callLinkInfos[i].callReturnLocation, m_callLinkInfos[i].isCall ? m_globalData->jitStubs->ctiVirtualCallLink() : m_globalData->jitStubs->ctiVirtualConstructLink());
+ m_callLinkInfos[i].unlink();
}
}
+#endif
+
+void CodeBlock::clearEvalCache()
+{
+ if (!m_rareData)
+ return;
+ m_rareData->m_evalCodeCache.clear();
+}
} // namespace JSC
/*
- * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2009, 2010 Apple Inc. All rights reserved.
* Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
*
* Redistribution and use in source and binary forms, with or without
#include "EvalCodeCache.h"
#include "Instruction.h"
#include "JITCode.h"
+#include "JITWriteBarrier.h"
#include "JSGlobalObject.h"
#include "JumpTable.h"
#include "Nodes.h"
-#include "RegExp.h"
+#include "RegExpObject.h"
#include "UString.h"
#include <wtf/FastAllocBase.h>
+#include <wtf/PassOwnPtr.h>
#include <wtf/RefPtr.h>
#include <wtf/Vector.h>
#include "StructureStubInfo.h"
#endif
-// Register numbers used in bytecode operations have different meaning accoring to their ranges:
-// 0x80000000-0xFFFFFFFF Negative indicies from the CallFrame pointer are entries in the call frame, see RegisterFile.h.
+// Register numbers used in bytecode operations have different meaning according to their ranges:
+// 0x80000000-0xFFFFFFFF Negative indices from the CallFrame pointer are entries in the call frame, see RegisterFile.h.
// 0x00000000-0x3FFFFFFF Forwards indices from the CallFrame pointer are local vars and temporaries with the function's callframe.
// 0x40000000-0x7FFFFFFF Positive indices from 0x40000000 specify entries in the constant pool on the CodeBlock.
static const int FirstConstantRegisterIndex = 0x40000000;
enum CodeType { GlobalCode, EvalCode, FunctionCode };
+ inline int unmodifiedArgumentsRegister(int argumentsRegister) { return argumentsRegister - 1; }
+
static ALWAYS_INLINE int missingThisObjectMarker() { return std::numeric_limits<int>::max(); }
struct HandlerInfo {
int32_t lineNumber;
};
- // Both op_construct and op_instanceof require a use of op_get_by_id to get
- // the prototype property from an object. The exception messages for exceptions
- // thrown by these instances op_get_by_id need to reflect this.
- struct GetByIdExceptionInfo {
- unsigned bytecodeOffset : 31;
- bool isOpConstruct : 1;
- };
-
#if ENABLE(JIT)
struct CallLinkInfo {
CallLinkInfo()
- : callee(0)
- , position(0)
- , hasSeenShouldRepatch(0)
+ : hasSeenShouldRepatch(false)
+ , isCall(false)
{
}
- unsigned bytecodeIndex;
CodeLocationNearCall callReturnLocation;
CodeLocationDataLabelPtr hotPathBegin;
CodeLocationNearCall hotPathOther;
- CodeBlock* ownerCodeBlock;
- CodeBlock* callee;
- unsigned position : 31;
- unsigned hasSeenShouldRepatch : 1;
-
- void setUnlinked() { callee = 0; }
+ JITWriteBarrier<JSFunction> callee;
+ bool hasSeenShouldRepatch : 1;
+ bool isCall : 1;
+
bool isLinked() { return callee; }
+ void unlink()
+ {
+ hasSeenShouldRepatch = false;
+ callee.clear();
+ }
bool seenOnce()
{
struct MethodCallLinkInfo {
MethodCallLinkInfo()
- : cachedStructure(0)
- , cachedPrototypeStructure(0)
{
}
bool seenOnce()
{
ASSERT(!cachedStructure);
- return cachedPrototypeStructure;
+ return cachedPrototypeStructure.isFlagged();
}
void setSeen()
// - Once this transition has been taken once, cachedStructure is
// null and cachedPrototypeStructure is set to a nun-null value.
// - Once the call is linked both structures are set to non-null values.
- cachedPrototypeStructure = (Structure*)1;
+ cachedPrototypeStructure.setFlagOnBarrier();
}
CodeLocationCall callReturnLocation;
- CodeLocationDataLabelPtr structureLabel;
- Structure* cachedStructure;
- Structure* cachedPrototypeStructure;
- };
-
- struct FunctionRegisterInfo {
- FunctionRegisterInfo(unsigned bytecodeOffset, int functionRegisterIndex)
- : bytecodeOffset(bytecodeOffset)
- , functionRegisterIndex(functionRegisterIndex)
- {
- }
-
- unsigned bytecodeOffset;
- int functionRegisterIndex;
+ JITWriteBarrier<Structure> cachedStructure;
+ JITWriteBarrier<Structure> cachedPrototypeStructure;
+ // We'd like this to actually be JSFunction, but InternalFunction and JSFunction
+ // don't have a common parent class and we allow specialisation on both
+ JITWriteBarrier<JSObjectWithGlobalObject> cachedFunction;
+ JITWriteBarrier<JSObject> cachedPrototype;
};
struct GlobalResolveInfo {
GlobalResolveInfo(unsigned bytecodeOffset)
- : structure(0)
- , offset(0)
+ : offset(0)
, bytecodeOffset(bytecodeOffset)
{
}
- Structure* structure;
+ WriteBarrier<Structure> structure;
unsigned offset;
unsigned bytecodeOffset;
};
// (given as an offset in bytes into the JIT code) back to
// the bytecode index of the corresponding bytecode operation.
// This is then used to look up the corresponding handler.
- struct CallReturnOffsetToBytecodeIndex {
- CallReturnOffsetToBytecodeIndex(unsigned callReturnOffset, unsigned bytecodeIndex)
+ struct CallReturnOffsetToBytecodeOffset {
+ CallReturnOffsetToBytecodeOffset(unsigned callReturnOffset, unsigned bytecodeOffset)
: callReturnOffset(callReturnOffset)
- , bytecodeIndex(bytecodeIndex)
+ , bytecodeOffset(bytecodeOffset)
{
}
unsigned callReturnOffset;
- unsigned bytecodeIndex;
+ unsigned bytecodeOffset;
};
- // valueAtPosition helpers for the binaryChop algorithm below.
+ // valueAtPosition helpers for the binarySearch algorithm.
inline void* getStructureStubInfoReturnLocation(StructureStubInfo* structureStubInfo)
{
return methodCallLinkInfo->callReturnLocation.executableAddress();
}
- inline unsigned getCallReturnOffset(CallReturnOffsetToBytecodeIndex* pc)
+ inline unsigned getCallReturnOffset(CallReturnOffsetToBytecodeOffset* pc)
{
return pc->callReturnOffset;
}
-
- // Binary chop algorithm, calls valueAtPosition on pre-sorted elements in array,
- // compares result with key (KeyTypes should be comparable with '--', '<', '>').
- // Optimized for cases where the array contains the key, checked by assertions.
- template<typename ArrayType, typename KeyType, KeyType(*valueAtPosition)(ArrayType*)>
- inline ArrayType* binaryChop(ArrayType* array, size_t size, KeyType key)
- {
- // The array must contain at least one element (pre-condition, array does conatin key).
- // If the array only contains one element, no need to do the comparison.
- while (size > 1) {
- // Pick an element to check, half way through the array, and read the value.
- int pos = (size - 1) >> 1;
- KeyType val = valueAtPosition(&array[pos]);
-
- // If the key matches, success!
- if (val == key)
- return &array[pos];
- // The item we are looking for is smaller than the item being check; reduce the value of 'size',
- // chopping off the right hand half of the array.
- else if (key < val)
- size = pos;
- // Discard all values in the left hand half of the array, up to and including the item at pos.
- else {
- size -= (pos + 1);
- array += (pos + 1);
- }
-
- // 'size' should never reach zero.
- ASSERT(size);
- }
-
- // If we reach this point we've chopped down to one element, no need to check it matches
- ASSERT(size == 1);
- ASSERT(key == valueAtPosition(&array[0]));
- return &array[0];
- }
-#endif
-
- struct ExceptionInfo : FastAllocBase {
- Vector<ExpressionRangeInfo> m_expressionInfo;
- Vector<LineInfo> m_lineInfo;
- Vector<GetByIdExceptionInfo> m_getByIdExceptionInfo;
-
-#if ENABLE(JIT)
- Vector<CallReturnOffsetToBytecodeIndex> m_callReturnIndexVector;
#endif
- };
- class CodeBlock : public FastAllocBase {
+ class CodeBlock {
+ WTF_MAKE_FAST_ALLOCATED;
friend class JIT;
protected:
- CodeBlock(ScriptExecutable* ownerExecutable, CodeType, PassRefPtr<SourceProvider>, unsigned sourceOffset, SymbolTable* symbolTable);
+ CodeBlock(ScriptExecutable* ownerExecutable, CodeType, JSGlobalObject*, PassRefPtr<SourceProvider>, unsigned sourceOffset, SymbolTable* symbolTable, bool isConstructor);
+
+ WriteBarrier<JSGlobalObject> m_globalObject;
+ Heap* m_heap;
+
public:
virtual ~CodeBlock();
- void markAggregate(MarkStack&);
- void refStructures(Instruction* vPC) const;
- void derefStructures(Instruction* vPC) const;
-#if ENABLE(JIT_OPTIMIZE_CALL)
- void unlinkCallers();
-#endif
+ void visitAggregate(SlotVisitor&);
static void dumpStatistics();
void printStructure(const char* name, const Instruction*, int operand) const;
#endif
+ bool isStrictMode() const { return m_isStrictMode; }
+
inline bool isKnownNotImmediate(int index)
{
- if (index == m_thisRegister)
+ if (index == m_thisRegister && !m_isStrictMode)
return true;
if (isConstantRegisterIndex(index))
}
HandlerInfo* handlerForBytecodeOffset(unsigned bytecodeOffset);
- int lineNumberForBytecodeOffset(CallFrame*, unsigned bytecodeOffset);
- int expressionRangeForBytecodeOffset(CallFrame*, unsigned bytecodeOffset, int& divot, int& startOffset, int& endOffset);
- bool getByIdExceptionInfoForBytecodeOffset(CallFrame*, unsigned bytecodeOffset, OpcodeID&);
+ int lineNumberForBytecodeOffset(unsigned bytecodeOffset);
+ void expressionRangeForBytecodeOffset(unsigned bytecodeOffset, int& divot, int& startOffset, int& endOffset);
#if ENABLE(JIT)
- void addCaller(CallLinkInfo* caller)
- {
- caller->callee = this;
- caller->position = m_linkedCallerList.size();
- m_linkedCallerList.append(caller);
- }
-
- void removeCaller(CallLinkInfo* caller)
- {
- unsigned pos = caller->position;
- unsigned lastPos = m_linkedCallerList.size() - 1;
-
- if (pos != lastPos) {
- m_linkedCallerList[pos] = m_linkedCallerList[lastPos];
- m_linkedCallerList[pos]->position = pos;
- }
- m_linkedCallerList.shrink(lastPos);
- }
StructureStubInfo& getStubInfo(ReturnAddressPtr returnAddress)
{
- return *(binaryChop<StructureStubInfo, void*, getStructureStubInfoReturnLocation>(m_structureStubInfos.begin(), m_structureStubInfos.size(), returnAddress.value()));
+ return *(binarySearch<StructureStubInfo, void*, getStructureStubInfoReturnLocation>(m_structureStubInfos.begin(), m_structureStubInfos.size(), returnAddress.value()));
}
CallLinkInfo& getCallLinkInfo(ReturnAddressPtr returnAddress)
{
- return *(binaryChop<CallLinkInfo, void*, getCallLinkInfoReturnLocation>(m_callLinkInfos.begin(), m_callLinkInfos.size(), returnAddress.value()));
+ return *(binarySearch<CallLinkInfo, void*, getCallLinkInfoReturnLocation>(m_callLinkInfos.begin(), m_callLinkInfos.size(), returnAddress.value()));
}
MethodCallLinkInfo& getMethodCallLinkInfo(ReturnAddressPtr returnAddress)
{
- return *(binaryChop<MethodCallLinkInfo, void*, getMethodCallLinkInfoReturnLocation>(m_methodCallLinkInfos.begin(), m_methodCallLinkInfos.size(), returnAddress.value()));
+ return *(binarySearch<MethodCallLinkInfo, void*, getMethodCallLinkInfoReturnLocation>(m_methodCallLinkInfos.begin(), m_methodCallLinkInfos.size(), returnAddress.value()));
}
- unsigned getBytecodeIndex(CallFrame* callFrame, ReturnAddressPtr returnAddress)
+ unsigned bytecodeOffset(ReturnAddressPtr returnAddress)
{
- reparseForExceptionInfoIfNecessary(callFrame);
- return binaryChop<CallReturnOffsetToBytecodeIndex, unsigned, getCallReturnOffset>(callReturnIndexVector().begin(), callReturnIndexVector().size(), ownerExecutable()->generatedJITCode().offsetOf(returnAddress.value()))->bytecodeIndex;
+ if (!m_rareData)
+ return 1;
+ Vector<CallReturnOffsetToBytecodeOffset>& callIndices = m_rareData->m_callReturnIndexVector;
+ if (!callIndices.size())
+ return 1;
+ return binarySearch<CallReturnOffsetToBytecodeOffset, unsigned, getCallReturnOffset>(callIndices.begin(), callIndices.size(), getJITCode().offsetOf(returnAddress.value()))->bytecodeOffset;
}
-
- bool functionRegisterForBytecodeOffset(unsigned bytecodeOffset, int& functionRegisterIndex);
+
+ void unlinkCalls();
#endif
+
#if ENABLE(INTERPRETER)
- unsigned bytecodeOffset(CallFrame*, Instruction* returnAddress)
+ unsigned bytecodeOffset(Instruction* returnAddress)
{
return static_cast<Instruction*>(returnAddress) - instructions().begin();
}
#endif
#if ENABLE(JIT)
- JITCode& getJITCode() { return ownerExecutable()->generatedJITCode(); }
- ExecutablePool* executablePool() { return ownerExecutable()->getExecutablePool(); }
+ JITCode& getJITCode() { return m_isConstructor ? ownerExecutable()->generatedJITCodeForConstruct() : ownerExecutable()->generatedJITCodeForCall(); }
+ ExecutablePool* executablePool() { return getJITCode().getExecutablePool(); }
#endif
- ScriptExecutable* ownerExecutable() const { return m_ownerExecutable; }
+ ScriptExecutable* ownerExecutable() const { return m_ownerExecutable.get(); }
void setGlobalData(JSGlobalData* globalData) { m_globalData = globalData; }
bool needsFullScopeChain() const { return m_needsFullScopeChain; }
void setUsesEval(bool usesEval) { m_usesEval = usesEval; }
bool usesEval() const { return m_usesEval; }
- void setUsesArguments(bool usesArguments) { m_usesArguments = usesArguments; }
- bool usesArguments() const { return m_usesArguments; }
+
+ void setArgumentsRegister(int argumentsRegister)
+ {
+ ASSERT(argumentsRegister != -1);
+ m_argumentsRegister = argumentsRegister;
+ ASSERT(usesArguments());
+ }
+ int argumentsRegister()
+ {
+ ASSERT(usesArguments());
+ return m_argumentsRegister;
+ }
+ void setActivationRegister(int activationRegister)
+ {
+ m_activationRegister = activationRegister;
+ }
+ int activationRegister()
+ {
+ ASSERT(needsFullScopeChain());
+ return m_activationRegister;
+ }
+ bool usesArguments() const { return m_argumentsRegister != -1; }
CodeType codeType() const { return m_codeType; }
unsigned jumpTarget(int index) const { return m_jumpTargets[index]; }
unsigned lastJumpTarget() const { return m_jumpTargets.last(); }
+ void createActivation(CallFrame*);
+
+ void clearEvalCache();
+
#if ENABLE(INTERPRETER)
- void addPropertyAccessInstruction(unsigned propertyAccessInstruction) { m_propertyAccessInstructions.append(propertyAccessInstruction); }
- void addGlobalResolveInstruction(unsigned globalResolveInstruction) { m_globalResolveInstructions.append(globalResolveInstruction); }
+ void addPropertyAccessInstruction(unsigned propertyAccessInstruction)
+ {
+ if (!m_globalData->canUseJIT())
+ m_propertyAccessInstructions.append(propertyAccessInstruction);
+ }
+ void addGlobalResolveInstruction(unsigned globalResolveInstruction)
+ {
+ if (!m_globalData->canUseJIT())
+ m_globalResolveInstructions.append(globalResolveInstruction);
+ }
bool hasGlobalResolveInstructionAtBytecodeOffset(unsigned bytecodeOffset);
#endif
#if ENABLE(JIT)
size_t numberOfStructureStubInfos() const { return m_structureStubInfos.size(); }
- void addStructureStubInfo(const StructureStubInfo& stubInfo) { m_structureStubInfos.append(stubInfo); }
+ void addStructureStubInfo(const StructureStubInfo& stubInfo)
+ {
+ if (m_globalData->canUseJIT())
+ m_structureStubInfos.append(stubInfo);
+ }
StructureStubInfo& structureStubInfo(int index) { return m_structureStubInfos[index]; }
- void addGlobalResolveInfo(unsigned globalResolveInstruction) { m_globalResolveInfos.append(GlobalResolveInfo(globalResolveInstruction)); }
+ void addGlobalResolveInfo(unsigned globalResolveInstruction)
+ {
+ if (m_globalData->canUseJIT())
+ m_globalResolveInfos.append(GlobalResolveInfo(globalResolveInstruction));
+ }
GlobalResolveInfo& globalResolveInfo(int index) { return m_globalResolveInfos[index]; }
bool hasGlobalResolveInfoAtBytecodeOffset(unsigned bytecodeOffset);
void addCallLinkInfo() { m_callLinkInfos.append(CallLinkInfo()); }
CallLinkInfo& callLinkInfo(int index) { return m_callLinkInfos[index]; }
- void addMethodCallLinkInfos(unsigned n) { m_methodCallLinkInfos.grow(n); }
+ void addMethodCallLinkInfos(unsigned n) { ASSERT(m_globalData->canUseJIT()); m_methodCallLinkInfos.grow(n); }
MethodCallLinkInfo& methodCallLinkInfo(int index) { return m_methodCallLinkInfos[index]; }
-
- void addFunctionRegisterInfo(unsigned bytecodeOffset, int functionIndex) { createRareDataIfNecessary(); m_rareData->m_functionRegisterInfos.append(FunctionRegisterInfo(bytecodeOffset, functionIndex)); }
#endif
+ unsigned globalResolveInfoCount() const
+ {
+#if ENABLE(JIT)
+ if (m_globalData->canUseJIT())
+ return m_globalResolveInfos.size();
+#endif
+ return 0;
+ }
// Exception handling support
void addExceptionHandler(const HandlerInfo& hanler) { createRareDataIfNecessary(); return m_rareData->m_exceptionHandlers.append(hanler); }
HandlerInfo& exceptionHandler(int index) { ASSERT(m_rareData); return m_rareData->m_exceptionHandlers[index]; }
- bool hasExceptionInfo() const { return m_exceptionInfo; }
- void clearExceptionInfo() { m_exceptionInfo.clear(); }
- ExceptionInfo* extractExceptionInfo() { ASSERT(m_exceptionInfo); return m_exceptionInfo.release(); }
+ void addExpressionInfo(const ExpressionRangeInfo& expressionInfo)
+ {
+ createRareDataIfNecessary();
+ m_rareData->m_expressionInfo.append(expressionInfo);
+ }
- void addExpressionInfo(const ExpressionRangeInfo& expressionInfo) { ASSERT(m_exceptionInfo); m_exceptionInfo->m_expressionInfo.append(expressionInfo); }
- void addGetByIdExceptionInfo(const GetByIdExceptionInfo& info) { ASSERT(m_exceptionInfo); m_exceptionInfo->m_getByIdExceptionInfo.append(info); }
+ void addLineInfo(unsigned bytecodeOffset, int lineNo)
+ {
+ createRareDataIfNecessary();
+ Vector<LineInfo>& lineInfo = m_rareData->m_lineInfo;
+ if (!lineInfo.size() || lineInfo.last().lineNumber != lineNo) {
+ LineInfo info = { bytecodeOffset, lineNo };
+ lineInfo.append(info);
+ }
+ }
- size_t numberOfLineInfos() const { ASSERT(m_exceptionInfo); return m_exceptionInfo->m_lineInfo.size(); }
- void addLineInfo(const LineInfo& lineInfo) { ASSERT(m_exceptionInfo); m_exceptionInfo->m_lineInfo.append(lineInfo); }
- LineInfo& lastLineInfo() { ASSERT(m_exceptionInfo); return m_exceptionInfo->m_lineInfo.last(); }
+ bool hasExpressionInfo() { return m_rareData && m_rareData->m_expressionInfo.size(); }
+ bool hasLineInfo() { return m_rareData && m_rareData->m_lineInfo.size(); }
+ // We only generate exception handling info if the user is debugging
+ // (and may want line number info), or if the function contains exception handler.
+ bool needsCallReturnIndices()
+ {
+ return m_rareData &&
+ (m_rareData->m_expressionInfo.size() || m_rareData->m_lineInfo.size() || m_rareData->m_exceptionHandlers.size());
+ }
#if ENABLE(JIT)
- Vector<CallReturnOffsetToBytecodeIndex>& callReturnIndexVector() { ASSERT(m_exceptionInfo); return m_exceptionInfo->m_callReturnIndexVector; }
+ Vector<CallReturnOffsetToBytecodeOffset>& callReturnIndexVector()
+ {
+ createRareDataIfNecessary();
+ return m_rareData->m_callReturnIndexVector;
+ }
#endif
// Constant Pool
Identifier& identifier(int index) { return m_identifiers[index]; }
size_t numberOfConstantRegisters() const { return m_constantRegisters.size(); }
- void addConstantRegister(const Register& r) { return m_constantRegisters.append(r); }
- Register& constantRegister(int index) { return m_constantRegisters[index - FirstConstantRegisterIndex]; }
+ void addConstant(JSValue v)
+ {
+ m_constantRegisters.append(WriteBarrier<Unknown>());
+ m_constantRegisters.last().set(m_globalObject->globalData(), m_ownerExecutable.get(), v);
+ }
+ WriteBarrier<Unknown>& constantRegister(int index) { return m_constantRegisters[index - FirstConstantRegisterIndex]; }
ALWAYS_INLINE bool isConstantRegisterIndex(int index) const { return index >= FirstConstantRegisterIndex; }
- ALWAYS_INLINE JSValue getConstant(int index) const { return m_constantRegisters[index - FirstConstantRegisterIndex].jsValue(); }
+ ALWAYS_INLINE JSValue getConstant(int index) const { return m_constantRegisters[index - FirstConstantRegisterIndex].get(); }
- unsigned addFunctionDecl(NonNullPassRefPtr<FunctionExecutable> n) { unsigned size = m_functionDecls.size(); m_functionDecls.append(n); return size; }
+ unsigned addFunctionDecl(FunctionExecutable* n)
+ {
+ unsigned size = m_functionDecls.size();
+ m_functionDecls.append(WriteBarrier<FunctionExecutable>());
+ m_functionDecls.last().set(m_globalObject->globalData(), m_ownerExecutable.get(), n);
+ return size;
+ }
FunctionExecutable* functionDecl(int index) { return m_functionDecls[index].get(); }
int numberOfFunctionDecls() { return m_functionDecls.size(); }
- unsigned addFunctionExpr(NonNullPassRefPtr<FunctionExecutable> n) { unsigned size = m_functionExprs.size(); m_functionExprs.append(n); return size; }
+ unsigned addFunctionExpr(FunctionExecutable* n)
+ {
+ unsigned size = m_functionExprs.size();
+ m_functionExprs.append(WriteBarrier<FunctionExecutable>());
+ m_functionExprs.last().set(m_globalObject->globalData(), m_ownerExecutable.get(), n);
+ return size;
+ }
FunctionExecutable* functionExpr(int index) { return m_functionExprs[index].get(); }
- unsigned addRegExp(RegExp* r) { createRareDataIfNecessary(); unsigned size = m_rareData->m_regexps.size(); m_rareData->m_regexps.append(r); return size; }
+ unsigned addRegExp(RegExp* r)
+ {
+ createRareDataIfNecessary();
+ unsigned size = m_rareData->m_regexps.size();
+ m_rareData->m_regexps.append(WriteBarrier<RegExp>(*m_globalData, ownerExecutable(), r));
+ return size;
+ }
RegExp* regexp(int index) const { ASSERT(m_rareData); return m_rareData->m_regexps[index].get(); }
+ unsigned addConstantBuffer(unsigned length)
+ {
+ createRareDataIfNecessary();
+ unsigned size = m_rareData->m_constantBuffers.size();
+ m_rareData->m_constantBuffers.append(Vector<JSValue>(length));
+ return size;
+ }
+
+ JSValue* constantBuffer(unsigned index)
+ {
+ ASSERT(m_rareData);
+ return m_rareData->m_constantBuffers[index].data();
+ }
+
+ JSGlobalObject* globalObject() { return m_globalObject.get(); }
// Jump Tables
int m_numCalleeRegisters;
int m_numVars;
+ int m_numCapturedVars;
int m_numParameters;
+ bool m_isConstructor;
private:
#if !defined(NDEBUG) || ENABLE(OPCODE_SAMPLING)
void printGetByIdOp(ExecState*, int location, Vector<Instruction>::const_iterator&, const char* op) const;
void printPutByIdOp(ExecState*, int location, Vector<Instruction>::const_iterator&, const char* op) const;
#endif
-
- void reparseForExceptionInfoIfNecessary(CallFrame*);
+ void visitStructures(SlotVisitor&, Instruction* vPC) const;
void createRareDataIfNecessary()
{
if (!m_rareData)
- m_rareData.set(new RareData);
+ m_rareData = adoptPtr(new RareData);
}
- ScriptExecutable* m_ownerExecutable;
+ WriteBarrier<ScriptExecutable> m_ownerExecutable;
JSGlobalData* m_globalData;
Vector<Instruction> m_instructions;
#endif
int m_thisRegister;
+ int m_argumentsRegister;
+ int m_activationRegister;
bool m_needsFullScopeChain;
bool m_usesEval;
- bool m_usesArguments;
bool m_isNumericCompareFunction;
+ bool m_isStrictMode;
CodeType m_codeType;
Vector<GlobalResolveInfo> m_globalResolveInfos;
Vector<CallLinkInfo> m_callLinkInfos;
Vector<MethodCallLinkInfo> m_methodCallLinkInfos;
- Vector<CallLinkInfo*> m_linkedCallerList;
#endif
Vector<unsigned> m_jumpTargets;
// Constant Pool
Vector<Identifier> m_identifiers;
- Vector<Register> m_constantRegisters;
- Vector<RefPtr<FunctionExecutable> > m_functionDecls;
- Vector<RefPtr<FunctionExecutable> > m_functionExprs;
+ COMPILE_ASSERT(sizeof(Register) == sizeof(WriteBarrier<Unknown>), Register_must_be_same_size_as_WriteBarrier_Unknown);
+ Vector<WriteBarrier<Unknown> > m_constantRegisters;
+ Vector<WriteBarrier<FunctionExecutable> > m_functionDecls;
+ Vector<WriteBarrier<FunctionExecutable> > m_functionExprs;
SymbolTable* m_symbolTable;
- OwnPtr<ExceptionInfo> m_exceptionInfo;
-
- struct RareData : FastAllocBase {
+ struct RareData {
+ WTF_MAKE_FAST_ALLOCATED;
+ public:
Vector<HandlerInfo> m_exceptionHandlers;
// Rare Constants
- Vector<RefPtr<RegExp> > m_regexps;
+ Vector<WriteBarrier<RegExp> > m_regexps;
+ // Buffers used for large array literals
+ Vector<Vector<JSValue> > m_constantBuffers;
+
// Jump Tables
Vector<SimpleJumpTable> m_immediateSwitchJumpTables;
Vector<SimpleJumpTable> m_characterSwitchJumpTables;
EvalCodeCache m_evalCodeCache;
+ // Expression info - present if debugging.
+ Vector<ExpressionRangeInfo> m_expressionInfo;
+ // Line info - present if profiling or debugging.
+ Vector<LineInfo> m_lineInfo;
#if ENABLE(JIT)
- Vector<FunctionRegisterInfo> m_functionRegisterInfos;
+ Vector<CallReturnOffsetToBytecodeOffset> m_callReturnIndexVector;
#endif
};
+#if COMPILER(MSVC)
+ friend void WTF::deleteOwnedPtr<RareData>(RareData*);
+#endif
OwnPtr<RareData> m_rareData;
};
class GlobalCodeBlock : public CodeBlock {
public:
- GlobalCodeBlock(ScriptExecutable* ownerExecutable, CodeType codeType, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset, JSGlobalObject* globalObject)
- : CodeBlock(ownerExecutable, codeType, sourceProvider, sourceOffset, &m_unsharedSymbolTable)
- , m_globalObject(globalObject)
- {
- m_globalObject->codeBlocks().add(this);
- }
-
- ~GlobalCodeBlock()
+ GlobalCodeBlock(ScriptExecutable* ownerExecutable, CodeType codeType, JSGlobalObject* globalObject, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset)
+ : CodeBlock(ownerExecutable, codeType, globalObject, sourceProvider, sourceOffset, &m_unsharedSymbolTable, false)
{
- if (m_globalObject)
- m_globalObject->codeBlocks().remove(this);
}
- void clearGlobalObject() { m_globalObject = 0; }
-
private:
- JSGlobalObject* m_globalObject; // For program and eval nodes, the global object that marks the constant pool.
SymbolTable m_unsharedSymbolTable;
};
class ProgramCodeBlock : public GlobalCodeBlock {
public:
ProgramCodeBlock(ProgramExecutable* ownerExecutable, CodeType codeType, JSGlobalObject* globalObject, PassRefPtr<SourceProvider> sourceProvider)
- : GlobalCodeBlock(ownerExecutable, codeType, sourceProvider, 0, globalObject)
+ : GlobalCodeBlock(ownerExecutable, codeType, globalObject, sourceProvider, 0)
{
}
};
class EvalCodeBlock : public GlobalCodeBlock {
public:
EvalCodeBlock(EvalExecutable* ownerExecutable, JSGlobalObject* globalObject, PassRefPtr<SourceProvider> sourceProvider, int baseScopeDepth)
- : GlobalCodeBlock(ownerExecutable, EvalCode, sourceProvider, 0, globalObject)
+ : GlobalCodeBlock(ownerExecutable, EvalCode, globalObject, sourceProvider, 0)
, m_baseScopeDepth(baseScopeDepth)
{
}
// as we need to initialise the CodeBlock before we could initialise any RefPtr to hold the shared
// symbol table, so we just pass as a raw pointer with a ref count of 1. We then manually deref
// in the destructor.
- FunctionCodeBlock(FunctionExecutable* ownerExecutable, CodeType codeType, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset)
- : CodeBlock(ownerExecutable, codeType, sourceProvider, sourceOffset, new SharedSymbolTable)
+ FunctionCodeBlock(FunctionExecutable* ownerExecutable, CodeType codeType, JSGlobalObject* globalObject, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset, bool isConstructor)
+ : CodeBlock(ownerExecutable, codeType, globalObject, sourceProvider, sourceOffset, SharedSymbolTable::create().leakRef(), isConstructor)
{
}
~FunctionCodeBlock()
{
CodeBlock* codeBlock = this->codeBlock();
if (codeBlock->isConstantRegisterIndex(index))
- return codeBlock->constantRegister(index);
+ return *reinterpret_cast<Register*>(&codeBlock->constantRegister(index));
return this[index];
}
+ inline Register& ExecState::uncheckedR(int index)
+ {
+ ASSERT(index < FirstConstantRegisterIndex);
+ return this[index];
+ }
+
} // namespace JSC
#endif // CodeBlock_h
namespace JSC {
+ class MarkStack;
+ typedef MarkStack SlotVisitor;
+
class EvalCodeCache {
public:
- PassRefPtr<EvalExecutable> get(ExecState* exec, const UString& evalSource, ScopeChainNode* scopeChain, JSValue& exceptionValue)
+ EvalExecutable* get(ExecState* exec, ScriptExecutable* owner, bool inStrictContext, const UString& evalSource, ScopeChainNode* scopeChain, JSValue& exceptionValue)
{
- RefPtr<EvalExecutable> evalExecutable;
+ EvalExecutable* evalExecutable = 0;
- if (evalSource.size() < maxCacheableSourceLength && (*scopeChain->begin())->isVariableObject())
- evalExecutable = m_cacheMap.get(evalSource.rep());
+ if (!inStrictContext && evalSource.length() < maxCacheableSourceLength && (*scopeChain->begin())->isVariableObject())
+ evalExecutable = m_cacheMap.get(evalSource.impl()).get();
if (!evalExecutable) {
- evalExecutable = EvalExecutable::create(exec, makeSource(evalSource));
+ evalExecutable = EvalExecutable::create(exec, makeSource(evalSource), inStrictContext);
exceptionValue = evalExecutable->compile(exec, scopeChain);
if (exceptionValue)
return 0;
- if (evalSource.size() < maxCacheableSourceLength && (*scopeChain->begin())->isVariableObject() && m_cacheMap.size() < maxCacheEntries)
- m_cacheMap.set(evalSource.rep(), evalExecutable);
+ if (!inStrictContext && evalSource.length() < maxCacheableSourceLength && (*scopeChain->begin())->isVariableObject() && m_cacheMap.size() < maxCacheEntries)
+ m_cacheMap.set(evalSource.impl(), WriteBarrier<EvalExecutable>(exec->globalData(), owner, evalExecutable));
}
- return evalExecutable.release();
+ return evalExecutable;
}
bool isEmpty() const { return m_cacheMap.isEmpty(); }
+ void visitAggregate(SlotVisitor&);
+
+ void clear()
+ {
+ m_cacheMap.clear();
+ }
+
private:
static const unsigned maxCacheableSourceLength = 256;
static const int maxCacheEntries = 64;
- typedef HashMap<RefPtr<UString::Rep>, RefPtr<EvalExecutable> > EvalCacheMap;
+ typedef HashMap<RefPtr<StringImpl>, WriteBarrier<EvalExecutable> > EvalCacheMap;
EvalCacheMap m_cacheMap;
};
#include "Opcode.h"
#include "PropertySlot.h"
#include "Structure.h"
+#include "StructureChain.h"
#include <wtf/VectorTraits.h>
#define POLYMORPHIC_LIST_CACHE_SIZE 8
class StructureChain;
// Structure used by op_get_by_id_self_list and op_get_by_id_proto_list instruction to hold data off the main opcode stream.
- struct PolymorphicAccessStructureList : FastAllocBase {
+ struct PolymorphicAccessStructureList {
+ WTF_MAKE_FAST_ALLOCATED;
+ public:
struct PolymorphicStubInfo {
bool isChain;
PolymorphicAccessStructureListStubRoutineType stubRoutine;
- Structure* base;
+ WriteBarrier<Structure> base;
union {
- Structure* proto;
- StructureChain* chain;
+ WriteBarrierBase<Structure> proto;
+ WriteBarrierBase<StructureChain> chain;
} u;
- void set(PolymorphicAccessStructureListStubRoutineType _stubRoutine, Structure* _base)
+ PolymorphicStubInfo()
+ {
+ u.proto.clear();
+ }
+
+ void set(JSGlobalData& globalData, JSCell* owner, PolymorphicAccessStructureListStubRoutineType _stubRoutine, Structure* _base)
{
stubRoutine = _stubRoutine;
- base = _base;
- u.proto = 0;
+ base.set(globalData, owner, _base);
+ u.proto.clear();
isChain = false;
}
- void set(PolymorphicAccessStructureListStubRoutineType _stubRoutine, Structure* _base, Structure* _proto)
+ void set(JSGlobalData& globalData, JSCell* owner, PolymorphicAccessStructureListStubRoutineType _stubRoutine, Structure* _base, Structure* _proto)
{
stubRoutine = _stubRoutine;
- base = _base;
- u.proto = _proto;
+ base.set(globalData, owner, _base);
+ u.proto.set(globalData, owner, _proto);
isChain = false;
}
- void set(PolymorphicAccessStructureListStubRoutineType _stubRoutine, Structure* _base, StructureChain* _chain)
+ void set(JSGlobalData& globalData, JSCell* owner, PolymorphicAccessStructureListStubRoutineType _stubRoutine, Structure* _base, StructureChain* _chain)
{
stubRoutine = _stubRoutine;
- base = _base;
- u.chain = _chain;
+ base.set(globalData, owner, _base);
+ u.chain.set(globalData, owner, _chain);
isChain = true;
}
} list[POLYMORPHIC_LIST_CACHE_SIZE];
- PolymorphicAccessStructureList(PolymorphicAccessStructureListStubRoutineType stubRoutine, Structure* firstBase)
+ PolymorphicAccessStructureList(JSGlobalData& globalData, JSCell* owner, PolymorphicAccessStructureListStubRoutineType stubRoutine, Structure* firstBase)
{
- list[0].set(stubRoutine, firstBase);
+ list[0].set(globalData, owner, stubRoutine, firstBase);
}
- PolymorphicAccessStructureList(PolymorphicAccessStructureListStubRoutineType stubRoutine, Structure* firstBase, Structure* firstProto)
+ PolymorphicAccessStructureList(JSGlobalData& globalData, JSCell* owner, PolymorphicAccessStructureListStubRoutineType stubRoutine, Structure* firstBase, Structure* firstProto)
{
- list[0].set(stubRoutine, firstBase, firstProto);
+ list[0].set(globalData, owner, stubRoutine, firstBase, firstProto);
}
- PolymorphicAccessStructureList(PolymorphicAccessStructureListStubRoutineType stubRoutine, Structure* firstBase, StructureChain* firstChain)
+ PolymorphicAccessStructureList(JSGlobalData& globalData, JSCell* owner, PolymorphicAccessStructureListStubRoutineType stubRoutine, Structure* firstBase, StructureChain* firstChain)
{
- list[0].set(stubRoutine, firstBase, firstChain);
+ list[0].set(globalData, owner, stubRoutine, firstBase, firstChain);
}
- void derefStructures(int count)
+ void visitAggregate(SlotVisitor& visitor, int count)
{
for (int i = 0; i < count; ++i) {
PolymorphicStubInfo& info = list[i];
-
- ASSERT(info.base);
- info.base->deref();
-
- if (info.u.proto) {
- if (info.isChain)
- info.u.chain->deref();
- else
- info.u.proto->deref();
+ if (!info.base) {
+ // We're being marked during initialisation of an entry
+ ASSERT(!info.u.proto);
+ continue;
}
+
+ visitor.append(&info.base);
+ if (info.u.proto && !info.isChain)
+ visitor.append(&info.u.proto);
+ if (info.u.chain && info.isChain)
+ visitor.append(&info.u.chain);
}
}
};
#if !ENABLE(COMPUTED_GOTO_INTERPRETER)
// We have to initialize one of the pointer members to ensure that
// the entire struct is initialized, when opcode is not a pointer.
- u.jsCell = 0;
+ u.jsCell.clear();
#endif
u.opcode = opcode;
}
{
// We have to initialize one of the pointer members to ensure that
// the entire struct is initialized in 64-bit.
- u.jsCell = 0;
+ u.jsCell.clear();
u.operand = operand;
}
- Instruction(Structure* structure) { u.structure = structure; }
- Instruction(StructureChain* structureChain) { u.structureChain = structureChain; }
- Instruction(JSCell* jsCell) { u.jsCell = jsCell; }
+ Instruction(JSGlobalData& globalData, JSCell* owner, Structure* structure)
+ {
+ u.structure.clear();
+ u.structure.set(globalData, owner, structure);
+ }
+ Instruction(JSGlobalData& globalData, JSCell* owner, StructureChain* structureChain)
+ {
+ u.structureChain.clear();
+ u.structureChain.set(globalData, owner, structureChain);
+ }
+ Instruction(JSGlobalData& globalData, JSCell* owner, JSCell* jsCell)
+ {
+ u.jsCell.clear();
+ u.jsCell.set(globalData, owner, jsCell);
+ }
Instruction(PolymorphicAccessStructureList* polymorphicStructures) { u.polymorphicStructures = polymorphicStructures; }
Instruction(PropertySlot::GetValueFunc getterFunc) { u.getterFunc = getterFunc; }
union {
Opcode opcode;
int operand;
- Structure* structure;
- StructureChain* structureChain;
- JSCell* jsCell;
+ WriteBarrierBase<Structure> structure;
+ WriteBarrierBase<StructureChain> structureChain;
+ WriteBarrierBase<JSCell> jsCell;
PolymorphicAccessStructureList* polymorphicStructures;
PropertySlot::GetValueFunc getterFunc;
} u;
+
+ private:
+ Instruction(StructureChain*);
+ Instruction(Structure*);
};
} // namespace JSC
};
struct StringJumpTable {
- typedef HashMap<RefPtr<UString::Rep>, OffsetLocation> StringOffsetTable;
+ typedef HashMap<RefPtr<StringImpl>, OffsetLocation> StringOffsetTable;
StringOffsetTable offsetTable;
#if ENABLE(JIT)
CodeLocationLabel ctiDefault; // FIXME: it should not be necessary to store this.
#endif
- inline int32_t offsetForValue(UString::Rep* value, int32_t defaultOffset)
+ inline int32_t offsetForValue(StringImpl* value, int32_t defaultOffset)
{
StringOffsetTable::const_iterator end = offsetTable.end();
StringOffsetTable::const_iterator loc = offsetTable.find(value);
}
#if ENABLE(JIT)
- inline CodeLocationLabel ctiForValue(UString::Rep* value)
+ inline CodeLocationLabel ctiForValue(StringImpl* value)
{
StringOffsetTable::const_iterator end = offsetTable.end();
StringOffsetTable::const_iterator loc = offsetTable.find(value);
#include "config.h"
#include "Opcode.h"
+#if ENABLE(OPCODE_STATS)
+#include <stdio.h>
+#include <wtf/FixedArray.h>
+#endif
+
using namespace std;
namespace JSC {
for (int j = 0; j < numOpcodeIDs; ++j)
totalInstructionPairs += opcodePairCounts[i][j];
- int sortedIndices[numOpcodeIDs];
+ FixedArray<int, numOpcodeIDs> sortedIndices;
for (int i = 0; i < numOpcodeIDs; ++i)
sortedIndices[i] = i;
- qsort(sortedIndices, numOpcodeIDs, sizeof(int), compareOpcodeIndices);
+ qsort(sortedIndices.data(), numOpcodeIDs, sizeof(int), compareOpcodeIndices);
pair<int, int> sortedPairIndices[numOpcodeIDs * numOpcodeIDs];
pair<int, int>* currentPairIndex = sortedPairIndices;
#define FOR_EACH_OPCODE_ID(macro) \
macro(op_enter, 1) \
- macro(op_enter_with_activation, 2) \
- macro(op_init_arguments, 1) \
- macro(op_create_arguments, 1) \
+ macro(op_create_activation, 2) \
+ macro(op_init_lazy_reg, 2) \
+ macro(op_create_arguments, 2) \
+ macro(op_create_this, 3) \
+ macro(op_get_callee, 2) \
macro(op_convert_this, 2) \
+ macro(op_convert_this_strict, 2) \
\
macro(op_new_object, 2) \
macro(op_new_array, 4) \
+ macro(op_new_array_buffer, 4) \
macro(op_new_regexp, 3) \
macro(op_mov, 3) \
\
macro(op_bitor, 5) \
macro(op_bitnot, 3) \
\
+ macro(op_check_has_instance, 2) \
macro(op_instanceof, 5) \
macro(op_typeof, 3) \
macro(op_is_undefined, 3) \
\
macro(op_resolve, 3) \
macro(op_resolve_skip, 4) \
- macro(op_resolve_global, 6) \
- macro(op_resolve_global_dynamic, 7) \
+ macro(op_resolve_global, 5) \
+ macro(op_resolve_global_dynamic, 6) \
macro(op_get_scoped_var, 4) \
macro(op_put_scoped_var, 4) \
- macro(op_get_global_var, 4) \
- macro(op_put_global_var, 4) \
- macro(op_resolve_base, 3) \
+ macro(op_get_global_var, 3) \
+ macro(op_put_global_var, 3) \
+ macro(op_resolve_base, 4) \
+ macro(op_ensure_property_exists, 3) \
macro(op_resolve_with_base, 4) \
macro(op_get_by_id, 8) \
macro(op_get_by_id_self, 8) \
macro(op_get_by_id_generic, 8) \
macro(op_get_array_length, 8) \
macro(op_get_string_length, 8) \
+ macro(op_get_arguments_length, 4) \
macro(op_put_by_id, 9) \
macro(op_put_by_id_transition, 9) \
macro(op_put_by_id_replace, 9) \
macro(op_put_by_id_generic, 9) \
macro(op_del_by_id, 4) \
macro(op_get_by_val, 4) \
+ macro(op_get_argument_by_val, 4) \
macro(op_get_by_pname, 7) \
macro(op_put_by_val, 4) \
macro(op_del_by_val, 4) \
macro(op_switch_char, 4) \
macro(op_switch_string, 4) \
\
- macro(op_new_func, 3) \
+ macro(op_new_func, 4) \
macro(op_new_func_exp, 3) \
- macro(op_call, 5) \
- macro(op_call_eval, 5) \
- macro(op_call_varargs, 5) \
- macro(op_load_varargs, 3) \
- macro(op_tear_off_activation, 2) \
- macro(op_tear_off_arguments, 1) \
+ macro(op_call, 4) \
+ macro(op_call_eval, 4) \
+ macro(op_call_varargs, 4) \
+ macro(op_load_varargs, 4) \
+ macro(op_tear_off_activation, 3) \
+ macro(op_tear_off_arguments, 2) \
macro(op_ret, 2) \
+ macro(op_call_put_result, 2) \
+ macro(op_ret_object_or_this, 3) \
macro(op_method_check, 1) \
\
- macro(op_construct, 7) \
- macro(op_construct_verify, 3) \
+ macro(op_construct, 4) \
macro(op_strcat, 4) \
macro(op_to_primitive, 3) \
\
\
macro(op_catch, 2) \
macro(op_throw, 2) \
- macro(op_new_error, 4) \
+ macro(op_throw_reference_error, 2) \
\
macro(op_jsr, 3) \
macro(op_sret, 2) \
#undef VERIFY_OPCODE_ID
#if ENABLE(COMPUTED_GOTO_INTERPRETER)
-#if COMPILER(RVCT)
+#if COMPILER(RVCT) || COMPILER(INTEL)
typedef void* Opcode;
#else
typedef const void* Opcode;
#endif
+ inline size_t opcodeLength(OpcodeID opcode)
+ {
+ switch (opcode) {
+#define OPCODE_ID_LENGTHS(id, length) case id: return OPCODE_LENGTH(id);
+ FOR_EACH_OPCODE_ID(OPCODE_ID_LENGTHS)
+#undef OPCODE_ID_LENGTHS
+ }
+ ASSERT_NOT_REACHED();
+ return 0;
+ }
+
} // namespace JSC
#endif // Opcode_h
if (blockPercent >= 1) {
//Instruction* code = codeBlock->instructions().begin();
- printf("#%d: %s:%d: %d / %lld (%.3f%%)\n", i + 1, record->m_executable->sourceURL().ascii(), codeBlock->lineNumberForBytecodeOffset(exec, 0), record->m_sampleCount, m_sampleCount, blockPercent);
+ printf("#%d: %s:%d: %d / %lld (%.3f%%)\n", i + 1, record->m_executable->sourceURL().utf8().data(), codeBlock->lineNumberForBytecodeOffset(0), record->m_sampleCount, m_sampleCount, blockPercent);
if (i < 10) {
HashMap<unsigned,unsigned> lineCounts;
codeBlock->dump(exec);
int count = record->m_samples[op];
if (count) {
printf(" [% 4d] has sample count: % 4d\n", op, count);
- unsigned line = codeBlock->lineNumberForBytecodeOffset(exec, op);
+ unsigned line = codeBlock->lineNumberForBytecodeOffset(op);
lineCounts.set(line, (lineCounts.contains(line) ? lineCounts.get(line) : 0) + count);
}
}
#ifndef SamplingTool_h
#define SamplingTool_h
+#include "Strong.h"
+#include "Nodes.h"
+#include "Opcode.h"
#include <wtf/Assertions.h>
#include <wtf/HashMap.h>
#include <wtf/Threading.h>
-#include "Nodes.h"
-#include "Opcode.h"
-
namespace JSC {
class ScriptExecutable;
class SamplingFlags {
- friend class JIT;
public:
static void start();
static void stop();
int m_flag;
};
+ static const void* addressOfFlags()
+ {
+ return &s_flags;
+ }
+
#endif
private:
static uint32_t s_flags;
struct Instruction;
struct ScriptSampleRecord {
- ScriptSampleRecord(ScriptExecutable* executable)
- : m_executable(executable)
+ ScriptSampleRecord(JSGlobalData& globalData, ScriptExecutable* executable)
+ : m_executable(globalData, executable)
, m_codeBlock(0)
, m_sampleCount(0)
, m_opcodeSampleCount(0)
void sample(CodeBlock*, Instruction*);
- RefPtr<ScriptExecutable> m_executable;
+ Strong<ScriptExecutable> m_executable;
CodeBlock* m_codeBlock;
int m_sampleCount;
int m_opcodeSampleCount;
friend class HostCallRecord;
#if ENABLE(OPCODE_SAMPLING)
- class CallRecord : public Noncopyable {
+ class CallRecord {
+ WTF_MAKE_NONCOPYABLE(CallRecord);
public:
CallRecord(SamplingTool* samplingTool)
: m_samplingTool(samplingTool)
}
};
#else
- class CallRecord : public Noncopyable {
+ class CallRecord {
+ WTF_MAKE_NONCOPYABLE(CallRecord);
public:
CallRecord(SamplingTool*)
{
// Implements a named set of counters, printed on exit if ENABLE(SAMPLING_COUNTERS).
// See subclasses below, SamplingCounter, GlobalSamplingCounter and DeletableSamplingCounter.
class AbstractSamplingCounter {
- friend class JIT;
friend class DeletableSamplingCounter;
public:
void count(uint32_t count = 1)
static void dump();
+ int64_t* addressOfCounter() { return &m_counter; }
+
protected:
// Effectively the contructor, however called lazily in the case of GlobalSamplingCounter.
void init(const char* name)
#include "config.h"
#include "StructureStubInfo.h"
+#include "JSObject.h"
+#include "ScopeChain.h"
+
namespace JSC {
#if ENABLE(JIT)
void StructureStubInfo::deref()
+{
+ switch (accessType) {
+ case access_get_by_id_self_list: {
+ PolymorphicAccessStructureList* polymorphicStructures = u.getByIdSelfList.structureList;
+ delete polymorphicStructures;
+ return;
+ }
+ case access_get_by_id_proto_list: {
+ PolymorphicAccessStructureList* polymorphicStructures = u.getByIdProtoList.structureList;
+ delete polymorphicStructures;
+ return;
+ }
+ case access_get_by_id_self:
+ case access_get_by_id_proto:
+ case access_get_by_id_chain:
+ case access_put_by_id_transition:
+ case access_put_by_id_replace:
+ case access_get_by_id:
+ case access_put_by_id:
+ case access_get_by_id_generic:
+ case access_put_by_id_generic:
+ case access_get_array_length:
+ case access_get_string_length:
+ // These instructions don't have to release any allocated memory
+ return;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+}
+
+void StructureStubInfo::visitAggregate(SlotVisitor& visitor)
{
switch (accessType) {
case access_get_by_id_self:
- u.getByIdSelf.baseObjectStructure->deref();
+ visitor.append(&u.getByIdSelf.baseObjectStructure);
return;
case access_get_by_id_proto:
- u.getByIdProto.baseObjectStructure->deref();
- u.getByIdProto.prototypeStructure->deref();
+ visitor.append(&u.getByIdProto.baseObjectStructure);
+ visitor.append(&u.getByIdProto.prototypeStructure);
return;
case access_get_by_id_chain:
- u.getByIdChain.baseObjectStructure->deref();
- u.getByIdChain.chain->deref();
+ visitor.append(&u.getByIdChain.baseObjectStructure);
+ visitor.append(&u.getByIdChain.chain);
return;
case access_get_by_id_self_list: {
PolymorphicAccessStructureList* polymorphicStructures = u.getByIdSelfList.structureList;
- polymorphicStructures->derefStructures(u.getByIdSelfList.listSize);
- delete polymorphicStructures;
+ polymorphicStructures->visitAggregate(visitor, u.getByIdSelfList.listSize);
return;
}
case access_get_by_id_proto_list: {
PolymorphicAccessStructureList* polymorphicStructures = u.getByIdProtoList.structureList;
- polymorphicStructures->derefStructures(u.getByIdProtoList.listSize);
- delete polymorphicStructures;
+ polymorphicStructures->visitAggregate(visitor, u.getByIdProtoList.listSize);
return;
}
case access_put_by_id_transition:
- u.putByIdTransition.previousStructure->deref();
- u.putByIdTransition.structure->deref();
- u.putByIdTransition.chain->deref();
+ visitor.append(&u.putByIdTransition.previousStructure);
+ visitor.append(&u.putByIdTransition.structure);
+ visitor.append(&u.putByIdTransition.chain);
return;
case access_put_by_id_replace:
- u.putByIdReplace.baseObjectStructure->deref();
+ visitor.append(&u.putByIdReplace.baseObjectStructure);
return;
case access_get_by_id:
case access_put_by_id:
case access_put_by_id_generic:
case access_get_array_length:
case access_get_string_length:
- // These instructions don't ref their Structures.
+ // These instructions don't need to mark anything
return;
default:
ASSERT_NOT_REACHED();
{
}
- void initGetByIdSelf(Structure* baseObjectStructure)
+ void initGetByIdSelf(JSGlobalData& globalData, JSCell* owner, Structure* baseObjectStructure)
{
accessType = access_get_by_id_self;
- u.getByIdSelf.baseObjectStructure = baseObjectStructure;
- baseObjectStructure->ref();
+ u.getByIdSelf.baseObjectStructure.set(globalData, owner, baseObjectStructure);
}
- void initGetByIdProto(Structure* baseObjectStructure, Structure* prototypeStructure)
+ void initGetByIdProto(JSGlobalData& globalData, JSCell* owner, Structure* baseObjectStructure, Structure* prototypeStructure)
{
accessType = access_get_by_id_proto;
- u.getByIdProto.baseObjectStructure = baseObjectStructure;
- baseObjectStructure->ref();
-
- u.getByIdProto.prototypeStructure = prototypeStructure;
- prototypeStructure->ref();
+ u.getByIdProto.baseObjectStructure.set(globalData, owner, baseObjectStructure);
+ u.getByIdProto.prototypeStructure.set(globalData, owner, prototypeStructure);
}
- void initGetByIdChain(Structure* baseObjectStructure, StructureChain* chain)
+ void initGetByIdChain(JSGlobalData& globalData, JSCell* owner, Structure* baseObjectStructure, StructureChain* chain)
{
accessType = access_get_by_id_chain;
- u.getByIdChain.baseObjectStructure = baseObjectStructure;
- baseObjectStructure->ref();
-
- u.getByIdChain.chain = chain;
- chain->ref();
+ u.getByIdChain.baseObjectStructure.set(globalData, owner, baseObjectStructure);
+ u.getByIdChain.chain.set(globalData, owner, chain);
}
void initGetByIdSelfList(PolymorphicAccessStructureList* structureList, int listSize)
// PutById*
- void initPutByIdTransition(Structure* previousStructure, Structure* structure, StructureChain* chain)
+ void initPutByIdTransition(JSGlobalData& globalData, JSCell* owner, Structure* previousStructure, Structure* structure, StructureChain* chain)
{
accessType = access_put_by_id_transition;
- u.putByIdTransition.previousStructure = previousStructure;
- previousStructure->ref();
-
- u.putByIdTransition.structure = structure;
- structure->ref();
-
- u.putByIdTransition.chain = chain;
- chain->ref();
+ u.putByIdTransition.previousStructure.set(globalData, owner, previousStructure);
+ u.putByIdTransition.structure.set(globalData, owner, structure);
+ u.putByIdTransition.chain.set(globalData, owner, chain);
}
- void initPutByIdReplace(Structure* baseObjectStructure)
+ void initPutByIdReplace(JSGlobalData& globalData, JSCell* owner, Structure* baseObjectStructure)
{
accessType = access_put_by_id_replace;
- u.putByIdReplace.baseObjectStructure = baseObjectStructure;
- baseObjectStructure->ref();
+ u.putByIdReplace.baseObjectStructure.set(globalData, owner, baseObjectStructure);
}
void deref();
+ void visitAggregate(SlotVisitor&);
bool seenOnce()
{
union {
struct {
- Structure* baseObjectStructure;
+ WriteBarrierBase<Structure> baseObjectStructure;
} getByIdSelf;
struct {
- Structure* baseObjectStructure;
- Structure* prototypeStructure;
+ WriteBarrierBase<Structure> baseObjectStructure;
+ WriteBarrierBase<Structure> prototypeStructure;
} getByIdProto;
struct {
- Structure* baseObjectStructure;
- StructureChain* chain;
+ WriteBarrierBase<Structure> baseObjectStructure;
+ WriteBarrierBase<StructureChain> chain;
} getByIdChain;
struct {
PolymorphicAccessStructureList* structureList;
int listSize;
} getByIdProtoList;
struct {
- Structure* previousStructure;
- Structure* structure;
- StructureChain* chain;
+ WriteBarrierBase<Structure> previousStructure;
+ WriteBarrierBase<Structure> structure;
+ WriteBarrierBase<StructureChain> chain;
} putByIdTransition;
struct {
- Structure* baseObjectStructure;
+ WriteBarrierBase<Structure> baseObjectStructure;
} putByIdReplace;
} u;
#include "BytecodeGenerator.h"
#include "BatchedTransitionOptimizer.h"
-#include "PrototypeFunction.h"
#include "JSFunction.h"
#include "Interpreter.h"
+#include "ScopeChain.h"
#include "UString.h"
using namespace std;
#endif
}
-void BytecodeGenerator::generate()
+JSObject* BytecodeGenerator::generate()
{
m_codeBlock->setThisRegister(m_thisRegister.index());
m_codeBlock->setInstructionCount(m_codeBlock->instructions().size());
if (s_dumpsGeneratedCode)
- m_codeBlock->dump(m_scopeChain->globalObject()->globalExec());
+ m_codeBlock->dump(m_scopeChain->globalObject->globalExec());
#endif
if ((m_codeType == FunctionCode && !m_codeBlock->needsFullScopeChain() && !m_codeBlock->usesArguments()) || m_codeType == EvalCode)
symbolTable().clear();
-
- m_codeBlock->setIsNumericCompareFunction(instructions() == m_globalData->numericCompareFunction(m_scopeChain->globalObject()->globalExec()));
-
-#if !ENABLE(OPCODE_SAMPLING)
- if (!m_regeneratingForExceptionInfo && (m_codeType == FunctionCode || m_codeType == EvalCode))
- m_codeBlock->clearExceptionInfo();
-#endif
m_codeBlock->shrinkToFit();
+
+ if (m_expressionTooDeep)
+ return createOutOfMemoryError(m_scopeChain->globalObject.get());
+ return 0;
}
bool BytecodeGenerator::addVar(const Identifier& ident, bool isConstant, RegisterID*& r0)
{
int index = m_calleeRegisters.size();
SymbolTableEntry newEntry(index, isConstant ? ReadOnly : 0);
- pair<SymbolTable::iterator, bool> result = symbolTable().add(ident.ustring().rep(), newEntry);
+ pair<SymbolTable::iterator, bool> result = symbolTable().add(ident.impl(), newEntry);
if (!result.second) {
r0 = ®isterFor(result.first->second.getIndex());
return false;
}
- ++m_codeBlock->m_numVars;
- r0 = newRegister();
+ r0 = addVar();
return true;
}
{
int index = m_nextGlobalIndex;
SymbolTableEntry newEntry(index, isConstant ? ReadOnly : 0);
- pair<SymbolTable::iterator, bool> result = symbolTable().add(ident.ustring().rep(), newEntry);
+ pair<SymbolTable::iterator, bool> result = symbolTable().add(ident.impl(), newEntry);
if (!result.second)
index = result.first->second.getIndex();
m_lastVar = &m_calleeRegisters.last();
}
-BytecodeGenerator::BytecodeGenerator(ProgramNode* programNode, const Debugger* debugger, const ScopeChain& scopeChain, SymbolTable* symbolTable, ProgramCodeBlock* codeBlock)
- : m_shouldEmitDebugHooks(!!debugger)
- , m_shouldEmitProfileHooks(scopeChain.globalObject()->supportsProfiling())
- , m_scopeChain(&scopeChain)
+BytecodeGenerator::BytecodeGenerator(ProgramNode* programNode, ScopeChainNode* scopeChain, SymbolTable* symbolTable, ProgramCodeBlock* codeBlock)
+ : m_shouldEmitDebugHooks(scopeChain->globalObject->debugger())
+ , m_shouldEmitProfileHooks(scopeChain->globalObject->supportsProfiling())
+ , m_shouldEmitRichSourceInfo(scopeChain->globalObject->supportsRichSourceInfo())
+ , m_scopeChain(*scopeChain->globalData, scopeChain)
, m_symbolTable(symbolTable)
, m_scopeNode(programNode)
, m_codeBlock(codeBlock)
, m_nextGlobalIndex(-1)
, m_nextConstantOffset(0)
, m_globalConstantIndex(0)
- , m_globalData(&scopeChain.globalObject()->globalExec()->globalData())
+ , m_hasCreatedActivation(true)
+ , m_firstLazyFunction(0)
+ , m_lastLazyFunction(0)
+ , m_globalData(scopeChain->globalData)
, m_lastOpcodeID(op_end)
- , m_emitNodeDepth(0)
- , m_regeneratingForExceptionInfo(false)
- , m_codeBlockBeingRegeneratedFrom(0)
+#ifndef NDEBUG
+ , m_lastOpcodePosition(0)
+#endif
+ , m_stack(m_globalData->stack())
+ , m_usesExceptions(false)
+ , m_expressionTooDeep(false)
{
if (m_shouldEmitDebugHooks)
m_codeBlock->setNeedsFullScopeChain(true);
m_codeBlock->m_numParameters = 1; // Allocate space for "this"
- JSGlobalObject* globalObject = scopeChain.globalObject();
+ JSGlobalObject* globalObject = scopeChain->globalObject.get();
ExecState* exec = globalObject->globalExec();
RegisterFile* registerFile = &exec->globalData().interpreter->registerFile();
SymbolTable::iterator end = symbolTable->end();
for (SymbolTable::iterator it = symbolTable->begin(); it != end; ++it)
registerFor(it->second.getIndex()).setIndex(it->second.getIndex() + m_globalVarStorageOffset);
-
- BatchedTransitionOptimizer optimizer(globalObject);
+
+ BatchedTransitionOptimizer optimizer(*m_globalData, globalObject);
const VarStack& varStack = programNode->varStack();
const FunctionStack& functionStack = programNode->functionStack();
// Shift new symbols so they get stored prior to existing symbols.
m_nextGlobalIndex -= symbolTable->size();
+ HashSet<StringImpl*, IdentifierRepHash> newGlobals;
+ Vector<std::pair<int, bool>, 16> functionInfo(functionStack.size());
+ for (size_t i = 0; i < functionStack.size(); ++i) {
+ FunctionBodyNode* function = functionStack[i];
+ globalObject->removeDirect(*m_globalData, function->ident()); // Make sure our new function is not shadowed by an old property.
+ SymbolTableEntry entry = symbolTable->inlineGet(function->ident().impl());
+
+ if (entry.isNull())
+ newGlobals.add(function->ident().impl());
+ functionInfo[i] = make_pair(entry.getIndex(), entry.isReadOnly());
+ }
+
+ Vector<bool, 16> shouldCreateVar(varStack.size());
+ for (size_t i = 0; i < varStack.size(); ++i) {
+ if (newGlobals.contains(varStack[i].first->impl()) || globalObject->hasProperty(exec, *varStack[i].first)) {
+ shouldCreateVar[i] = false;
+ continue;
+ }
+ shouldCreateVar[i] = true;
+ newGlobals.add(varStack[i].first->impl());
+ }
+
+ int expectedSize = symbolTable->size() + newGlobals.size();
+ globalObject->resizeRegisters(symbolTable->size(), expectedSize);
+
for (size_t i = 0; i < functionStack.size(); ++i) {
FunctionBodyNode* function = functionStack[i];
- globalObject->removeDirect(function->ident()); // Make sure our new function is not shadowed by an old property.
- emitNewFunction(addGlobalVar(function->ident(), false), function);
+ if (functionInfo[i].second)
+ continue;
+ RegisterID* dst = addGlobalVar(function->ident(), false);
+ JSValue value = new (exec) JSFunction(exec, makeFunction(exec, function), scopeChain);
+ globalObject->registerAt(dst->index() - m_globalVarStorageOffset).set(*m_globalData, globalObject, value);
}
- Vector<RegisterID*, 32> newVars;
- for (size_t i = 0; i < varStack.size(); ++i)
- if (!globalObject->hasProperty(exec, *varStack[i].first))
- newVars.append(addGlobalVar(*varStack[i].first, varStack[i].second & DeclarationStacks::IsConstant));
+ for (size_t i = 0; i < varStack.size(); ++i) {
+ if (!shouldCreateVar[i])
+ continue;
+ addGlobalVar(*varStack[i].first, varStack[i].second & DeclarationStacks::IsConstant);
+ }
+ if (symbolTable->size() != expectedSize)
+ CRASH();
preserveLastVar();
-
- for (size_t i = 0; i < newVars.size(); ++i)
- emitLoad(newVars[i], jsUndefined());
} else {
for (size_t i = 0; i < functionStack.size(); ++i) {
FunctionBodyNode* function = functionStack[i];
- globalObject->putWithAttributes(exec, function->ident(), new (exec) JSFunction(exec, makeFunction(exec, function), scopeChain.node()), DontDelete);
+ globalObject->putWithAttributes(exec, function->ident(), new (exec) JSFunction(exec, makeFunction(exec, function), scopeChain), DontDelete);
}
for (size_t i = 0; i < varStack.size(); ++i) {
- if (globalObject->hasProperty(exec, *varStack[i].first))
+ if (globalObject->symbolTableHasProperty(*varStack[i].first) || globalObject->hasProperty(exec, *varStack[i].first))
continue;
int attributes = DontDelete;
if (varStack[i].second & DeclarationStacks::IsConstant)
preserveLastVar();
}
+ codeBlock->m_numCapturedVars = codeBlock->m_numVars;
}
-BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, const Debugger* debugger, const ScopeChain& scopeChain, SymbolTable* symbolTable, CodeBlock* codeBlock)
- : m_shouldEmitDebugHooks(!!debugger)
- , m_shouldEmitProfileHooks(scopeChain.globalObject()->supportsProfiling())
- , m_scopeChain(&scopeChain)
+BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, ScopeChainNode* scopeChain, SymbolTable* symbolTable, CodeBlock* codeBlock)
+ : m_shouldEmitDebugHooks(scopeChain->globalObject->debugger())
+ , m_shouldEmitProfileHooks(scopeChain->globalObject->supportsProfiling())
+ , m_shouldEmitRichSourceInfo(scopeChain->globalObject->supportsRichSourceInfo())
+ , m_scopeChain(*scopeChain->globalData, scopeChain)
, m_symbolTable(symbolTable)
, m_scopeNode(functionBody)
, m_codeBlock(codeBlock)
+ , m_activationRegister(0)
, m_finallyDepth(0)
, m_dynamicScopeDepth(0)
, m_baseScopeDepth(0)
, m_codeType(FunctionCode)
, m_nextConstantOffset(0)
, m_globalConstantIndex(0)
- , m_globalData(&scopeChain.globalObject()->globalExec()->globalData())
+ , m_hasCreatedActivation(false)
+ , m_firstLazyFunction(0)
+ , m_lastLazyFunction(0)
+ , m_globalData(scopeChain->globalData)
, m_lastOpcodeID(op_end)
- , m_emitNodeDepth(0)
- , m_regeneratingForExceptionInfo(false)
- , m_codeBlockBeingRegeneratedFrom(0)
+#ifndef NDEBUG
+ , m_lastOpcodePosition(0)
+#endif
+ , m_stack(m_globalData->stack())
+ , m_usesExceptions(false)
+ , m_expressionTooDeep(false)
{
if (m_shouldEmitDebugHooks)
m_codeBlock->setNeedsFullScopeChain(true);
codeBlock->setGlobalData(m_globalData);
-
- bool usesArguments = functionBody->usesArguments();
- codeBlock->setUsesArguments(usesArguments);
- if (usesArguments) {
- m_argumentsRegister.setIndex(RegisterFile::OptionalCalleeArguments);
- addVar(propertyNames().arguments, false);
+
+ emitOpcode(op_enter);
+ if (m_codeBlock->needsFullScopeChain()) {
+ m_activationRegister = addVar();
+ emitInitLazyRegister(m_activationRegister);
+ m_codeBlock->setActivationRegister(m_activationRegister->index());
}
- if (m_codeBlock->needsFullScopeChain()) {
- ++m_codeBlock->m_numVars;
- m_activationRegisterIndex = newRegister()->index();
- emitOpcode(op_enter_with_activation);
- instructions().append(m_activationRegisterIndex);
- } else
- emitOpcode(op_enter);
+ // Both op_tear_off_activation and op_tear_off_arguments tear off the 'arguments'
+ // object, if created.
+ if (m_codeBlock->needsFullScopeChain() || functionBody->usesArguments()) {
+ RegisterID* unmodifiedArgumentsRegister = addVar(); // Anonymous, so it can't be modified by user code.
+ RegisterID* argumentsRegister = addVar(propertyNames().arguments, false); // Can be changed by assigning to 'arguments'.
+
+ // We can save a little space by hard-coding the knowledge that the two
+ // 'arguments' values are stored in consecutive registers, and storing
+ // only the index of the assignable one.
+ codeBlock->setArgumentsRegister(argumentsRegister->index());
+ ASSERT_UNUSED(unmodifiedArgumentsRegister, unmodifiedArgumentsRegister->index() == JSC::unmodifiedArgumentsRegister(codeBlock->argumentsRegister()));
- if (usesArguments) {
- emitOpcode(op_init_arguments);
+ emitInitLazyRegister(argumentsRegister);
+ emitInitLazyRegister(unmodifiedArgumentsRegister);
+
+ if (m_codeBlock->isStrictMode()) {
+ emitOpcode(op_create_arguments);
+ instructions().append(argumentsRegister->index());
+ }
// The debugger currently retrieves the arguments object from an activation rather than pulling
// it from a call frame. In the long-term it should stop doing that (<rdar://problem/6911886>),
// but for now we force eager creation of the arguments object when debugging.
- if (m_shouldEmitDebugHooks)
+ if (m_shouldEmitDebugHooks) {
emitOpcode(op_create_arguments);
+ instructions().append(argumentsRegister->index());
+ }
}
const DeclarationStacks::FunctionStack& functionStack = functionBody->functionStack();
+ const DeclarationStacks::VarStack& varStack = functionBody->varStack();
+
+ // Captured variables and functions go first so that activations don't have
+ // to step over the non-captured locals to mark them.
+ m_hasCreatedActivation = false;
+ if (functionBody->hasCapturedVariables()) {
+ for (size_t i = 0; i < functionStack.size(); ++i) {
+ FunctionBodyNode* function = functionStack[i];
+ const Identifier& ident = function->ident();
+ if (functionBody->captures(ident)) {
+ if (!m_hasCreatedActivation) {
+ m_hasCreatedActivation = true;
+ emitOpcode(op_create_activation);
+ instructions().append(m_activationRegister->index());
+ }
+ m_functions.add(ident.impl());
+ emitNewFunction(addVar(ident, false), function);
+ }
+ }
+ for (size_t i = 0; i < varStack.size(); ++i) {
+ const Identifier& ident = *varStack[i].first;
+ if (functionBody->captures(ident))
+ addVar(ident, varStack[i].second & DeclarationStacks::IsConstant);
+ }
+ }
+ bool canLazilyCreateFunctions = !functionBody->needsActivationForMoreThanVariables() && !m_shouldEmitDebugHooks;
+ if (!canLazilyCreateFunctions && !m_hasCreatedActivation) {
+ m_hasCreatedActivation = true;
+ emitOpcode(op_create_activation);
+ instructions().append(m_activationRegister->index());
+ }
+
+ codeBlock->m_numCapturedVars = codeBlock->m_numVars;
+ m_firstLazyFunction = codeBlock->m_numVars;
for (size_t i = 0; i < functionStack.size(); ++i) {
FunctionBodyNode* function = functionStack[i];
const Identifier& ident = function->ident();
- m_functions.add(ident.ustring().rep());
- emitNewFunction(addVar(ident, false), function);
+ if (!functionBody->captures(ident)) {
+ m_functions.add(ident.impl());
+ RefPtr<RegisterID> reg = addVar(ident, false);
+ // Don't lazily create functions that override the name 'arguments'
+ // as this would complicate lazy instantiation of actual arguments.
+ if (!canLazilyCreateFunctions || ident == propertyNames().arguments)
+ emitNewFunction(reg.get(), function);
+ else {
+ emitInitLazyRegister(reg.get());
+ m_lazyFunctions.set(reg->index(), function);
+ }
+ }
}
-
- const DeclarationStacks::VarStack& varStack = functionBody->varStack();
- for (size_t i = 0; i < varStack.size(); ++i)
- addVar(*varStack[i].first, varStack[i].second & DeclarationStacks::IsConstant);
+ m_lastLazyFunction = canLazilyCreateFunctions ? codeBlock->m_numVars : m_firstLazyFunction;
+ for (size_t i = 0; i < varStack.size(); ++i) {
+ const Identifier& ident = *varStack[i].first;
+ if (!functionBody->captures(ident))
+ addVar(ident, varStack[i].second & DeclarationStacks::IsConstant);
+ }
+
+ if (m_shouldEmitDebugHooks)
+ codeBlock->m_numCapturedVars = codeBlock->m_numVars;
FunctionParameters& parameters = *functionBody->parameters();
size_t parameterCount = parameters.size();
- m_nextParameterIndex = -RegisterFile::CallFrameHeaderSize - parameterCount - 1;
+ int nextParameterIndex = -RegisterFile::CallFrameHeaderSize - parameterCount - 1;
m_parameters.grow(1 + parameterCount); // reserve space for "this"
// Add "this" as a parameter
- m_thisRegister.setIndex(m_nextParameterIndex);
- ++m_nextParameterIndex;
+ m_thisRegister.setIndex(nextParameterIndex);
++m_codeBlock->m_numParameters;
-
- if (functionBody->usesThis() || m_shouldEmitDebugHooks) {
- emitOpcode(op_convert_this);
- instructions().append(m_thisRegister.index());
- }
for (size_t i = 0; i < parameterCount; ++i)
- addParameter(parameters[i]);
+ addParameter(parameters[i], ++nextParameterIndex);
preserveLastVar();
+
+ if (isConstructor()) {
+ RefPtr<RegisterID> func = newTemporary();
+ RefPtr<RegisterID> funcProto = newTemporary();
+
+ emitOpcode(op_get_callee);
+ instructions().append(func->index());
+ // Load prototype.
+ emitGetById(funcProto.get(), func.get(), globalData()->propertyNames->prototype);
+
+ emitOpcode(op_create_this);
+ instructions().append(m_thisRegister.index());
+ instructions().append(funcProto->index());
+ } else if (functionBody->usesThis() || m_shouldEmitDebugHooks) {
+ if (codeBlock->isStrictMode())
+ emitOpcode(op_convert_this_strict);
+ else
+ emitOpcode(op_convert_this);
+ instructions().append(m_thisRegister.index());
+ }
}
-BytecodeGenerator::BytecodeGenerator(EvalNode* evalNode, const Debugger* debugger, const ScopeChain& scopeChain, SymbolTable* symbolTable, EvalCodeBlock* codeBlock)
- : m_shouldEmitDebugHooks(!!debugger)
- , m_shouldEmitProfileHooks(scopeChain.globalObject()->supportsProfiling())
- , m_scopeChain(&scopeChain)
+BytecodeGenerator::BytecodeGenerator(EvalNode* evalNode, ScopeChainNode* scopeChain, SymbolTable* symbolTable, EvalCodeBlock* codeBlock)
+ : m_shouldEmitDebugHooks(scopeChain->globalObject->debugger())
+ , m_shouldEmitProfileHooks(scopeChain->globalObject->supportsProfiling())
+ , m_shouldEmitRichSourceInfo(scopeChain->globalObject->supportsRichSourceInfo())
+ , m_scopeChain(*scopeChain->globalData, scopeChain)
, m_symbolTable(symbolTable)
, m_scopeNode(evalNode)
, m_codeBlock(codeBlock)
, m_codeType(EvalCode)
, m_nextConstantOffset(0)
, m_globalConstantIndex(0)
- , m_globalData(&scopeChain.globalObject()->globalExec()->globalData())
+ , m_hasCreatedActivation(true)
+ , m_firstLazyFunction(0)
+ , m_lastLazyFunction(0)
+ , m_globalData(scopeChain->globalData)
, m_lastOpcodeID(op_end)
- , m_emitNodeDepth(0)
- , m_regeneratingForExceptionInfo(false)
- , m_codeBlockBeingRegeneratedFrom(0)
+#ifndef NDEBUG
+ , m_lastOpcodePosition(0)
+#endif
+ , m_stack(m_globalData->stack())
+ , m_usesExceptions(false)
+ , m_expressionTooDeep(false)
{
if (m_shouldEmitDebugHooks || m_baseScopeDepth)
m_codeBlock->setNeedsFullScopeChain(true);
for (size_t i = 0; i < numVariables; ++i)
variables.append(*varStack[i].first);
codeBlock->adoptVariables(variables);
-
+ codeBlock->m_numCapturedVars = codeBlock->m_numVars;
preserveLastVar();
}
-RegisterID* BytecodeGenerator::addParameter(const Identifier& ident)
+RegisterID* BytecodeGenerator::emitInitLazyRegister(RegisterID* reg)
+{
+ emitOpcode(op_init_lazy_reg);
+ instructions().append(reg->index());
+ return reg;
+}
+
+void BytecodeGenerator::addParameter(const Identifier& ident, int parameterIndex)
{
// Parameters overwrite var declarations, but not function declarations.
- RegisterID* result = 0;
- UString::Rep* rep = ident.ustring().rep();
+ StringImpl* rep = ident.impl();
if (!m_functions.contains(rep)) {
- symbolTable().set(rep, m_nextParameterIndex);
- RegisterID& parameter = registerFor(m_nextParameterIndex);
- parameter.setIndex(m_nextParameterIndex);
- result = ¶meter;
+ symbolTable().set(rep, parameterIndex);
+ RegisterID& parameter = registerFor(parameterIndex);
+ parameter.setIndex(parameterIndex);
}
// To maintain the calling convention, we have to allocate unique space for
// each parameter, even if the parameter doesn't make it into the symbol table.
- ++m_nextParameterIndex;
++m_codeBlock->m_numParameters;
- return result;
}
RegisterID* BytecodeGenerator::registerFor(const Identifier& ident)
if (!shouldOptimizeLocals())
return 0;
- SymbolTableEntry entry = symbolTable().get(ident.ustring().rep());
+ SymbolTableEntry entry = symbolTable().get(ident.impl());
if (entry.isNull())
return 0;
if (ident == propertyNames().arguments)
createArgumentsIfNecessary();
- return ®isterFor(entry.getIndex());
+ return createLazyRegisterIfNecessary(®isterFor(entry.getIndex()));
}
bool BytecodeGenerator::willResolveToArguments(const Identifier& ident)
if (!shouldOptimizeLocals())
return false;
- SymbolTableEntry entry = symbolTable().get(ident.ustring().rep());
+ SymbolTableEntry entry = symbolTable().get(ident.impl());
if (entry.isNull())
return false;
{
ASSERT(willResolveToArguments(propertyNames().arguments));
- SymbolTableEntry entry = symbolTable().get(propertyNames().arguments.ustring().rep());
+ SymbolTableEntry entry = symbolTable().get(propertyNames().arguments.impl());
ASSERT(!entry.isNull());
return ®isterFor(entry.getIndex());
}
+RegisterID* BytecodeGenerator::createLazyRegisterIfNecessary(RegisterID* reg)
+{
+ if (m_lastLazyFunction <= reg->index() || reg->index() < m_firstLazyFunction)
+ return reg;
+ emitLazyNewFunction(reg, m_lazyFunctions.get(reg->index()));
+ return reg;
+}
+
RegisterID* BytecodeGenerator::constRegisterFor(const Identifier& ident)
{
if (m_codeType == EvalCode)
return 0;
- SymbolTableEntry entry = symbolTable().get(ident.ustring().rep());
+ SymbolTableEntry entry = symbolTable().get(ident.impl());
if (entry.isNull())
return 0;
- return ®isterFor(entry.getIndex());
+ return createLazyRegisterIfNecessary(®isterFor(entry.getIndex()));
}
bool BytecodeGenerator::isLocal(const Identifier& ident)
if (ident == propertyNames().thisIdentifier)
return true;
- return shouldOptimizeLocals() && symbolTable().contains(ident.ustring().rep());
+ return shouldOptimizeLocals() && symbolTable().contains(ident.impl());
}
bool BytecodeGenerator::isLocalConstant(const Identifier& ident)
{
- return symbolTable().get(ident.ustring().rep()).isReadOnly();
+ return symbolTable().get(ident.impl()).isReadOnly();
}
RegisterID* BytecodeGenerator::newRegister()
void BytecodeGenerator::emitOpcode(OpcodeID opcodeID)
{
+#ifndef NDEBUG
+ size_t opcodePosition = instructions().size();
+ ASSERT(opcodePosition - m_lastOpcodePosition == opcodeLength(m_lastOpcodeID) || m_lastOpcodeID == op_end);
+ m_lastOpcodePosition = opcodePosition;
+#endif
instructions().append(globalData()->interpreter->getOpcode(opcodeID));
m_lastOpcodeID = opcodeID;
}
{
ASSERT(instructions().size() >= 4);
instructions().shrink(instructions().size() - 4);
+ m_lastOpcodeID = op_end;
}
void ALWAYS_INLINE BytecodeGenerator::rewindUnaryOp()
{
ASSERT(instructions().size() >= 3);
instructions().shrink(instructions().size() - 3);
+ m_lastOpcodeID = op_end;
}
PassRefPtr<Label> BytecodeGenerator::emitJump(Label* target)
emitOpcode(op_jneq_ptr);
instructions().append(cond->index());
- instructions().append(m_scopeChain->globalObject()->d()->callFunction);
+ instructions().append(Instruction(*m_globalData, m_codeBlock->ownerExecutable(), m_scopeChain->globalObject->callFunction()));
instructions().append(target->bind(begin, instructions().size()));
return target;
}
emitOpcode(op_jneq_ptr);
instructions().append(cond->index());
- instructions().append(m_scopeChain->globalObject()->d()->applyFunction);
+ instructions().append(Instruction(*m_globalData, m_codeBlock->ownerExecutable(), m_scopeChain->globalObject->applyFunction()));
instructions().append(target->bind(begin, instructions().size()));
return target;
}
unsigned BytecodeGenerator::addConstant(const Identifier& ident)
{
- UString::Rep* rep = ident.ustring().rep();
+ StringImpl* rep = ident.impl();
pair<IdentifierMap::iterator, bool> result = m_identifierMap.add(rep, m_codeBlock->numberOfIdentifiers());
if (result.second) // new entry
m_codeBlock->addIdentifier(Identifier(m_globalData, rep));
if (result.second) {
m_constantPoolRegisters.append(FirstConstantRegisterIndex + m_nextConstantOffset);
++m_nextConstantOffset;
- m_codeBlock->addConstantRegister(JSValue(v));
+ m_codeBlock->addConstant(JSValue(v));
} else
index = result.first->second;
if (src1->index() == dstIndex
&& src1->isTemporary()
&& m_codeBlock->isConstantRegisterIndex(src2->index())
- && m_codeBlock->constantRegister(src2->index()).jsValue().isString()) {
- const UString& value = asString(m_codeBlock->constantRegister(src2->index()).jsValue())->tryGetValue();
+ && m_codeBlock->constantRegister(src2->index()).get().isString()) {
+ const UString& value = asString(m_codeBlock->constantRegister(src2->index()).get())->tryGetValue();
if (value == "undefined") {
rewindUnaryOp();
emitOpcode(op_is_undefined);
RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, double number)
{
- // FIXME: Our hash tables won't hold infinity, so we make a new JSNumberCell each time.
- // Later we can do the extra work to handle that like the other cases.
- if (number == HashTraits<double>::emptyValue() || HashTraits<double>::isDeletedValue(number))
- return emitLoad(dst, jsNumber(globalData(), number));
+ // FIXME: Our hash tables won't hold infinity, so we make a new JSValue each time.
+ // Later we can do the extra work to handle that like the other cases. They also don't
+ // work correctly with NaN as a key.
+ if (isnan(number) || number == HashTraits<double>::emptyValue() || HashTraits<double>::isDeletedValue(number))
+ return emitLoad(dst, jsNumber(number));
JSValue& valueInMap = m_numberMap.add(number, JSValue()).first->second;
if (!valueInMap)
- valueInMap = jsNumber(globalData(), number);
+ valueInMap = jsNumber(number);
return emitLoad(dst, valueInMap);
}
RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, const Identifier& identifier)
{
- JSString*& stringInMap = m_stringMap.add(identifier.ustring().rep(), 0).first->second;
+ JSString*& stringInMap = m_stringMap.add(identifier.impl(), 0).first->second;
if (!stringInMap)
stringInMap = jsOwnedString(globalData(), identifier.ustring());
return emitLoad(dst, JSValue(stringInMap));
if (shouldOptimizeLocals() && m_codeType == GlobalCode) {
ScopeChainIterator iter = m_scopeChain->begin();
- globalObject = *iter;
+ globalObject = iter->get();
ASSERT((++iter) == m_scopeChain->end());
}
return false;
ScopeChainIterator iter = m_scopeChain->begin();
ScopeChainIterator end = m_scopeChain->end();
for (; iter != end; ++iter, ++depth) {
- JSObject* currentScope = *iter;
+ JSObject* currentScope = iter->get();
if (!currentScope->isVariableObject())
break;
JSVariableObject* currentVariableObject = static_cast<JSVariableObject*>(currentScope);
- SymbolTableEntry entry = currentVariableObject->symbolTable().get(property.ustring().rep());
+ SymbolTableEntry entry = currentVariableObject->symbolTable().get(property.impl());
// Found the property
if (!entry.isNull()) {
globalObject = currentVariableObject;
return false;
}
- stackDepth = depth;
+ stackDepth = depth + m_codeBlock->needsFullScopeChain();
index = entry.getIndex();
if (++iter == end)
globalObject = currentVariableObject;
requiresDynamicChecks |= scopeRequiresDynamicChecks;
}
// Can't locate the property but we're able to avoid a few lookups.
- stackDepth = depth;
+ stackDepth = depth + m_codeBlock->needsFullScopeChain();
index = missingSymbolMarker();
- JSObject* scope = *iter;
+ JSObject* scope = iter->get();
if (++iter == end)
globalObject = scope;
return true;
}
+void BytecodeGenerator::emitCheckHasInstance(RegisterID* base)
+{
+ emitOpcode(op_check_has_instance);
+ instructions().append(base->index());
+}
+
RegisterID* BytecodeGenerator::emitInstanceOf(RegisterID* dst, RegisterID* value, RegisterID* base, RegisterID* basePrototype)
{
emitOpcode(op_instanceof);
return dst;
}
+static const unsigned maxGlobalResolves = 128;
+
+bool BytecodeGenerator::shouldAvoidResolveGlobal()
+{
+ return m_codeBlock->globalResolveInfoCount() > maxGlobalResolves && !m_labelScopes.size();
+}
+
RegisterID* BytecodeGenerator::emitResolve(RegisterID* dst, const Identifier& property)
{
size_t depth = 0;
instructions().append(addConstant(property));
return dst;
}
-
+ if (shouldAvoidResolveGlobal()) {
+ globalObject = 0;
+ requiresDynamicChecks = true;
+ }
+
if (globalObject) {
bool forceGlobalResolve = false;
- if (m_regeneratingForExceptionInfo) {
-#if ENABLE(JIT)
- forceGlobalResolve = m_codeBlockBeingRegeneratedFrom->hasGlobalResolveInfoAtBytecodeOffset(instructions().size());
-#else
- forceGlobalResolve = m_codeBlockBeingRegeneratedFrom->hasGlobalResolveInstructionAtBytecodeOffset(instructions().size());
-#endif
- }
if (index != missingSymbolMarker() && !forceGlobalResolve && !requiresDynamicChecks) {
// Directly index the property lookup across multiple scopes.
#if ENABLE(JIT)
m_codeBlock->addGlobalResolveInfo(instructions().size());
-#else
+#endif
+#if ENABLE(INTERPRETER)
m_codeBlock->addGlobalResolveInstruction(instructions().size());
#endif
emitOpcode(requiresDynamicChecks ? op_resolve_global_dynamic : op_resolve_global);
instructions().append(dst->index());
- instructions().append(globalObject);
instructions().append(addConstant(property));
instructions().append(0);
instructions().append(0);
if (globalObject) {
emitOpcode(op_get_global_var);
instructions().append(dst->index());
- instructions().append(asCell(globalObject));
instructions().append(index);
return dst;
}
{
if (globalObject) {
emitOpcode(op_put_global_var);
- instructions().append(asCell(globalObject));
instructions().append(index);
instructions().append(value->index());
return value;
emitOpcode(op_resolve_base);
instructions().append(dst->index());
instructions().append(addConstant(property));
+ instructions().append(false);
return dst;
}
return emitLoad(dst, JSValue(globalObject));
}
+RegisterID* BytecodeGenerator::emitResolveBaseForPut(RegisterID* dst, const Identifier& property)
+{
+ if (!m_codeBlock->isStrictMode())
+ return emitResolveBase(dst, property);
+ size_t depth = 0;
+ int index = 0;
+ JSObject* globalObject = 0;
+ bool requiresDynamicChecks = false;
+ findScopedProperty(property, index, depth, false, requiresDynamicChecks, globalObject);
+ if (!globalObject || requiresDynamicChecks) {
+ // We can't optimise at all :-(
+ emitOpcode(op_resolve_base);
+ instructions().append(dst->index());
+ instructions().append(addConstant(property));
+ instructions().append(true);
+ return dst;
+ }
+
+ // Global object is the base
+ RefPtr<RegisterID> result = emitLoad(dst, JSValue(globalObject));
+ emitOpcode(op_ensure_property_exists);
+ instructions().append(dst->index());
+ instructions().append(addConstant(property));
+ return result.get();
+}
+
RegisterID* BytecodeGenerator::emitResolveWithBase(RegisterID* baseDst, RegisterID* propDst, const Identifier& property)
{
size_t depth = 0;
}
bool forceGlobalResolve = false;
- if (m_regeneratingForExceptionInfo) {
-#if ENABLE(JIT)
- forceGlobalResolve = m_codeBlockBeingRegeneratedFrom->hasGlobalResolveInfoAtBytecodeOffset(instructions().size());
-#else
- forceGlobalResolve = m_codeBlockBeingRegeneratedFrom->hasGlobalResolveInstructionAtBytecodeOffset(instructions().size());
-#endif
- }
// Global object is the base
emitLoad(baseDst, JSValue(globalObject));
emitGetScopedVar(propDst, depth, index, globalObject);
return baseDst;
}
-
+ if (shouldAvoidResolveGlobal()) {
+ emitOpcode(op_resolve);
+ instructions().append(propDst->index());
+ instructions().append(addConstant(property));
+ return baseDst;
+ }
#if ENABLE(JIT)
m_codeBlock->addGlobalResolveInfo(instructions().size());
-#else
+#endif
+#if ENABLE(INTERPRETER)
m_codeBlock->addGlobalResolveInstruction(instructions().size());
#endif
emitOpcode(requiresDynamicChecks ? op_resolve_global_dynamic : op_resolve_global);
instructions().append(propDst->index());
- instructions().append(globalObject);
instructions().append(addConstant(property));
instructions().append(0);
instructions().append(0);
{
#if ENABLE(JIT)
m_codeBlock->addStructureStubInfo(StructureStubInfo(access_get_by_id));
-#else
+#endif
+
+#if ENABLE(INTERPRETER)
m_codeBlock->addPropertyAccessInstruction(instructions().size());
#endif
return dst;
}
+RegisterID* BytecodeGenerator::emitGetArgumentsLength(RegisterID* dst, RegisterID* base)
+{
+ emitOpcode(op_get_arguments_length);
+ instructions().append(dst->index());
+ ASSERT(base->index() == m_codeBlock->argumentsRegister());
+ instructions().append(base->index());
+ instructions().append(addConstant(propertyNames().length));
+ return dst;
+}
+
RegisterID* BytecodeGenerator::emitPutById(RegisterID* base, const Identifier& property, RegisterID* value)
{
#if ENABLE(JIT)
m_codeBlock->addStructureStubInfo(StructureStubInfo(access_put_by_id));
-#else
+#endif
+#if ENABLE(INTERPRETER)
m_codeBlock->addPropertyAccessInstruction(instructions().size());
#endif
{
#if ENABLE(JIT)
m_codeBlock->addStructureStubInfo(StructureStubInfo(access_put_by_id));
-#else
+#endif
+#if ENABLE(INTERPRETER)
m_codeBlock->addPropertyAccessInstruction(instructions().size());
#endif
return dst;
}
+RegisterID* BytecodeGenerator::emitGetArgumentByVal(RegisterID* dst, RegisterID* base, RegisterID* property)
+{
+ emitOpcode(op_get_argument_by_val);
+ instructions().append(dst->index());
+ ASSERT(base->index() == m_codeBlock->argumentsRegister());
+ instructions().append(base->index());
+ instructions().append(property->index());
+ return dst;
+}
+
RegisterID* BytecodeGenerator::emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property)
{
for (size_t i = m_forInContextStack.size(); i > 0; i--) {
return dst;
}
-RegisterID* BytecodeGenerator::emitNewArray(RegisterID* dst, ElementNode* elements)
+unsigned BytecodeGenerator::addConstantBuffer(unsigned length)
+{
+ return m_codeBlock->addConstantBuffer(length);
+}
+
+JSString* BytecodeGenerator::addStringConstant(const Identifier& identifier)
+{
+ JSString*& stringInMap = m_stringMap.add(identifier.impl(), 0).first->second;
+ if (!stringInMap) {
+ stringInMap = jsString(globalData(), identifier.ustring());
+ addConstantValue(stringInMap);
+ }
+ return stringInMap;
+}
+
+RegisterID* BytecodeGenerator::emitNewArray(RegisterID* dst, ElementNode* elements, unsigned length)
{
+#if !ASSERT_DISABLED
+ unsigned checkLength = 0;
+#endif
+ bool hadVariableExpression = false;
+ if (length) {
+ for (ElementNode* n = elements; n; n = n->next()) {
+ if (!n->value()->isNumber() && !n->value()->isString()) {
+ hadVariableExpression = true;
+ break;
+ }
+ if (n->elision())
+ break;
+#if !ASSERT_DISABLED
+ checkLength++;
+#endif
+ }
+ if (!hadVariableExpression) {
+ ASSERT(length == checkLength);
+ unsigned constantBufferIndex = addConstantBuffer(length);
+ JSValue* constantBuffer = m_codeBlock->constantBuffer(constantBufferIndex);
+ unsigned index = 0;
+ for (ElementNode* n = elements; index < length; n = n->next()) {
+ if (n->value()->isNumber())
+ constantBuffer[index++] = jsNumber(static_cast<NumberNode*>(n->value())->value());
+ else {
+ ASSERT(n->value()->isString());
+ constantBuffer[index++] = addStringConstant(static_cast<StringNode*>(n->value())->value());
+ }
+ }
+ emitOpcode(op_new_array_buffer);
+ instructions().append(dst->index());
+ instructions().append(constantBufferIndex);
+ instructions().append(length);
+ return dst;
+ }
+ }
+
Vector<RefPtr<RegisterID>, 16> argv;
for (ElementNode* n = elements; n; n = n->next()) {
if (n->elision())
RegisterID* BytecodeGenerator::emitNewFunction(RegisterID* dst, FunctionBodyNode* function)
{
- unsigned index = m_codeBlock->addFunctionDecl(makeFunction(m_globalData, function));
+ return emitNewFunctionInternal(dst, m_codeBlock->addFunctionDecl(makeFunction(m_globalData, function)), false);
+}
+
+RegisterID* BytecodeGenerator::emitLazyNewFunction(RegisterID* dst, FunctionBodyNode* function)
+{
+ std::pair<FunctionOffsetMap::iterator, bool> ptr = m_functionOffsets.add(function, 0);
+ if (ptr.second)
+ ptr.first->second = m_codeBlock->addFunctionDecl(makeFunction(m_globalData, function));
+ return emitNewFunctionInternal(dst, ptr.first->second, true);
+}
+RegisterID* BytecodeGenerator::emitNewFunctionInternal(RegisterID* dst, unsigned index, bool doNullCheck)
+{
+ createActivationIfNecessary();
emitOpcode(op_new_func);
instructions().append(dst->index());
instructions().append(index);
+ instructions().append(doNullCheck);
return dst;
}
return dst;
}
-
RegisterID* BytecodeGenerator::emitNewFunctionExpression(RegisterID* r0, FuncExprNode* n)
{
FunctionBodyNode* function = n->body();
unsigned index = m_codeBlock->addFunctionExpr(makeFunction(m_globalData, function));
-
+
+ createActivationIfNecessary();
emitOpcode(op_new_func_exp);
instructions().append(r0->index());
instructions().append(index);
return r0;
}
-RegisterID* BytecodeGenerator::emitCall(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, ArgumentsNode* argumentsNode, unsigned divot, unsigned startOffset, unsigned endOffset)
+RegisterID* BytecodeGenerator::emitCall(RegisterID* dst, RegisterID* func, CallArguments& callArguments, unsigned divot, unsigned startOffset, unsigned endOffset)
{
- return emitCall(op_call, dst, func, thisRegister, argumentsNode, divot, startOffset, endOffset);
+ return emitCall(op_call, dst, func, callArguments, divot, startOffset, endOffset);
}
void BytecodeGenerator::createArgumentsIfNecessary()
{
- if (m_codeBlock->usesArguments() && m_codeType == FunctionCode)
- emitOpcode(op_create_arguments);
+ if (m_codeType != FunctionCode)
+ return;
+
+ if (!m_codeBlock->usesArguments())
+ return;
+
+ // If we're in strict mode we tear off the arguments on function
+ // entry, so there's no need to check if we need to create them
+ // now
+ if (m_codeBlock->isStrictMode())
+ return;
+
+ emitOpcode(op_create_arguments);
+ instructions().append(m_codeBlock->argumentsRegister());
}
-RegisterID* BytecodeGenerator::emitCallEval(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, ArgumentsNode* argumentsNode, unsigned divot, unsigned startOffset, unsigned endOffset)
+void BytecodeGenerator::createActivationIfNecessary()
{
- createArgumentsIfNecessary();
- return emitCall(op_call_eval, dst, func, thisRegister, argumentsNode, divot, startOffset, endOffset);
+ if (m_hasCreatedActivation)
+ return;
+ if (!m_codeBlock->needsFullScopeChain())
+ return;
+ emitOpcode(op_create_activation);
+ instructions().append(m_activationRegister->index());
}
-RegisterID* BytecodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, RegisterID* func, RegisterID* thisRegister, ArgumentsNode* argumentsNode, unsigned divot, unsigned startOffset, unsigned endOffset)
+RegisterID* BytecodeGenerator::emitCallEval(RegisterID* dst, RegisterID* func, CallArguments& callArguments, unsigned divot, unsigned startOffset, unsigned endOffset)
+{
+ return emitCall(op_call_eval, dst, func, callArguments, divot, startOffset, endOffset);
+}
+
+RegisterID* BytecodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, RegisterID* func, CallArguments& callArguments, unsigned divot, unsigned startOffset, unsigned endOffset)
{
ASSERT(opcodeID == op_call || opcodeID == op_call_eval);
ASSERT(func->refCount());
- ASSERT(thisRegister->refCount());
- RegisterID* originalFunc = func;
- if (m_shouldEmitProfileHooks) {
- // If codegen decided to recycle func as this call's destination register,
- // we need to undo that optimization here so that func will still be around
- // for the sake of op_profile_did_call.
- if (dst == func) {
- RefPtr<RegisterID> movedThisRegister = emitMove(newTemporary(), thisRegister);
- RefPtr<RegisterID> movedFunc = emitMove(thisRegister, func);
-
- thisRegister = movedThisRegister.release().releaseRef();
- func = movedFunc.release().releaseRef();
- }
- }
+ if (m_shouldEmitProfileHooks)
+ emitMove(callArguments.profileHookRegister(), func);
// Generate code for arguments.
- Vector<RefPtr<RegisterID>, 16> argv;
- argv.append(thisRegister);
- for (ArgumentListNode* n = argumentsNode->m_listNode; n; n = n->m_next) {
- argv.append(newTemporary());
- // op_call requires the arguments to be a sequential range of registers
- ASSERT(argv[argv.size() - 1]->index() == argv[argv.size() - 2]->index() + 1);
- emitNode(argv.last().get(), n);
- }
+ unsigned argumentIndex = 0;
+ for (ArgumentListNode* n = callArguments.argumentsNode()->m_listNode; n; n = n->m_next)
+ emitNode(callArguments.argumentRegister(argumentIndex++), n);
// Reserve space for call frame.
Vector<RefPtr<RegisterID>, RegisterFile::CallFrameHeaderSize> callFrame;
if (m_shouldEmitProfileHooks) {
emitOpcode(op_profile_will_call);
- instructions().append(func->index());
-
-#if ENABLE(JIT)
- m_codeBlock->addFunctionRegisterInfo(instructions().size(), func->index());
-#endif
+ instructions().append(callArguments.profileHookRegister()->index());
}
emitExpressionInfo(divot, startOffset, endOffset);
// Emit call.
emitOpcode(opcodeID);
- instructions().append(dst->index()); // dst
instructions().append(func->index()); // func
- instructions().append(argv.size()); // argCount
- instructions().append(argv[0]->index() + argv.size() + RegisterFile::CallFrameHeaderSize); // registerOffset
+ instructions().append(callArguments.count()); // argCount
+ instructions().append(callArguments.callFrame()); // registerOffset
+ if (dst != ignoredResult()) {
+ emitOpcode(op_call_put_result);
+ instructions().append(dst->index()); // dst
+ }
if (m_shouldEmitProfileHooks) {
emitOpcode(op_profile_did_call);
- instructions().append(func->index());
-
- if (dst == originalFunc) {
- thisRegister->deref();
- func->deref();
- }
+ instructions().append(callArguments.profileHookRegister()->index());
}
return dst;
}
-RegisterID* BytecodeGenerator::emitLoadVarargs(RegisterID* argCountDst, RegisterID* arguments)
+RegisterID* BytecodeGenerator::emitLoadVarargs(RegisterID* argCountDst, RegisterID* thisRegister, RegisterID* arguments)
{
ASSERT(argCountDst->index() < arguments->index());
emitOpcode(op_load_varargs);
instructions().append(argCountDst->index());
instructions().append(arguments->index());
+ instructions().append(thisRegister->index() + RegisterFile::CallFrameHeaderSize); // initial registerOffset
return argCountDst;
}
if (m_shouldEmitProfileHooks) {
emitOpcode(op_profile_will_call);
instructions().append(func->index());
-
-#if ENABLE(JIT)
- m_codeBlock->addFunctionRegisterInfo(instructions().size(), func->index());
-#endif
}
emitExpressionInfo(divot, startOffset, endOffset);
// Emit call.
emitOpcode(op_call_varargs);
- instructions().append(dst->index()); // dst
instructions().append(func->index()); // func
instructions().append(argCountRegister->index()); // arg count
instructions().append(thisRegister->index() + RegisterFile::CallFrameHeaderSize); // initial registerOffset
+ if (dst != ignoredResult()) {
+ emitOpcode(op_call_put_result);
+ instructions().append(dst->index()); // dst
+ }
if (m_shouldEmitProfileHooks) {
emitOpcode(op_profile_did_call);
instructions().append(func->index());
{
if (m_codeBlock->needsFullScopeChain()) {
emitOpcode(op_tear_off_activation);
- instructions().append(m_activationRegisterIndex);
- } else if (m_codeBlock->usesArguments() && m_codeBlock->m_numParameters > 1)
+ instructions().append(m_activationRegister->index());
+ instructions().append(m_codeBlock->argumentsRegister());
+ } else if (m_codeBlock->usesArguments() && m_codeBlock->m_numParameters > 1
+ && !m_codeBlock->isStrictMode()) { // If there are no named parameters, there's nothing to tear off, since extra / unnamed parameters get copied to the arguments object at construct time.
emitOpcode(op_tear_off_arguments);
+ instructions().append(m_codeBlock->argumentsRegister());
+ }
+ // Constructors use op_ret_object_or_this to check the result is an
+ // object, unless we can trivially determine the check is not
+ // necessary (currently, if the return value is 'this').
+ if (isConstructor() && (src->index() != m_thisRegister.index())) {
+ emitOpcode(op_ret_object_or_this);
+ instructions().append(src->index());
+ instructions().append(m_thisRegister.index());
+ return src;
+ }
return emitUnaryNoDstOp(op_ret, src);
}
return src;
}
-RegisterID* BytecodeGenerator::emitConstruct(RegisterID* dst, RegisterID* func, ArgumentsNode* argumentsNode, unsigned divot, unsigned startOffset, unsigned endOffset)
+RegisterID* BytecodeGenerator::emitConstruct(RegisterID* dst, RegisterID* func, CallArguments& callArguments, unsigned divot, unsigned startOffset, unsigned endOffset)
{
ASSERT(func->refCount());
- RegisterID* originalFunc = func;
- if (m_shouldEmitProfileHooks) {
- // If codegen decided to recycle func as this call's destination register,
- // we need to undo that optimization here so that func will still be around
- // for the sake of op_profile_did_call.
- if (dst == func) {
- RefPtr<RegisterID> movedFunc = emitMove(newTemporary(), func);
- func = movedFunc.release().releaseRef();
- }
- }
-
- RefPtr<RegisterID> funcProto = newTemporary();
+ if (m_shouldEmitProfileHooks)
+ emitMove(callArguments.profileHookRegister(), func);
// Generate code for arguments.
- Vector<RefPtr<RegisterID>, 16> argv;
- argv.append(newTemporary()); // reserve space for "this"
- for (ArgumentListNode* n = argumentsNode ? argumentsNode->m_listNode : 0; n; n = n->m_next) {
- argv.append(newTemporary());
- // op_construct requires the arguments to be a sequential range of registers
- ASSERT(argv[argv.size() - 1]->index() == argv[argv.size() - 2]->index() + 1);
- emitNode(argv.last().get(), n);
+ unsigned argumentIndex = 0;
+ if (ArgumentsNode* argumentsNode = callArguments.argumentsNode()) {
+ for (ArgumentListNode* n = argumentsNode->m_listNode; n; n = n->m_next)
+ emitNode(callArguments.argumentRegister(argumentIndex++), n);
}
if (m_shouldEmitProfileHooks) {
emitOpcode(op_profile_will_call);
- instructions().append(func->index());
+ instructions().append(callArguments.profileHookRegister()->index());
}
- // Load prototype.
- emitExpressionInfo(divot, startOffset, endOffset);
- emitGetByIdExceptionInfo(op_construct);
- emitGetById(funcProto.get(), func, globalData()->propertyNames->prototype);
-
// Reserve space for call frame.
Vector<RefPtr<RegisterID>, RegisterFile::CallFrameHeaderSize> callFrame;
for (int i = 0; i < RegisterFile::CallFrameHeaderSize; ++i)
#endif
emitOpcode(op_construct);
- instructions().append(dst->index()); // dst
instructions().append(func->index()); // func
- instructions().append(argv.size()); // argCount
- instructions().append(argv[0]->index() + argv.size() + RegisterFile::CallFrameHeaderSize); // registerOffset
- instructions().append(funcProto->index()); // proto
- instructions().append(argv[0]->index()); // thisRegister
-
- emitOpcode(op_construct_verify);
- instructions().append(dst->index());
- instructions().append(argv[0]->index());
+ instructions().append(callArguments.count()); // argCount
+ instructions().append(callArguments.callFrame()); // registerOffset
+ if (dst != ignoredResult()) {
+ emitOpcode(op_call_put_result);
+ instructions().append(dst->index()); // dst
+ }
if (m_shouldEmitProfileHooks) {
emitOpcode(op_profile_did_call);
- instructions().append(func->index());
-
- if (dst == originalFunc)
- func->deref();
+ instructions().append(callArguments.profileHookRegister()->index());
}
return dst;
context.isFinallyBlock = false;
m_scopeContextStack.append(context);
m_dynamicScopeDepth++;
- createArgumentsIfNecessary();
return emitUnaryNoDstOp(op_push_scope, scope);
}
RegisterID* BytecodeGenerator::emitCatch(RegisterID* targetRegister, Label* start, Label* end)
{
+ m_usesExceptions = true;
#if ENABLE(JIT)
HandlerInfo info = { start->bind(0, 0), end->bind(0, 0), instructions().size(), m_dynamicScopeDepth + m_baseScopeDepth, CodeLocationLabel() };
#else
return targetRegister;
}
-RegisterID* BytecodeGenerator::emitNewError(RegisterID* dst, ErrorType type, JSValue message)
+void BytecodeGenerator::emitThrowReferenceError(const UString& message)
{
- emitOpcode(op_new_error);
- instructions().append(dst->index());
- instructions().append(static_cast<int>(type));
- instructions().append(addConstantValue(message)->index());
- return dst;
+ emitOpcode(op_throw_reference_error);
+ instructions().append(addConstantValue(jsString(globalData(), message))->index());
}
PassRefPtr<Label> BytecodeGenerator::emitJumpSubroutine(RegisterID* retAddrDst, Label* finally)
context.isFinallyBlock = false;
m_scopeContextStack.append(context);
m_dynamicScopeDepth++;
-
- createArgumentsIfNecessary();
emitOpcode(op_push_new_scope);
instructions().append(dst->index());
{
UNUSED_PARAM(max);
ASSERT(node->isString());
- UString::Rep* clause = static_cast<StringNode*>(node)->value().ustring().rep();
+ StringImpl* clause = static_cast<StringNode*>(node)->value().impl();
ASSERT(clause->length() == 1);
int32_t key = clause->characters()[0];
ASSERT(!labels[i]->isForward());
ASSERT(nodes[i]->isString());
- UString::Rep* clause = static_cast<StringNode*>(nodes[i])->value().ustring().rep();
+ StringImpl* clause = static_cast<StringNode*>(nodes[i])->value().impl();
OffsetLocation location;
location.branchOffset = labels[i]->bind(switchAddress, switchAddress + 3);
jumpTable.offsetTable.add(clause, location);
// And we could make the caller pass the node pointer in, if there was some way of getting
// that from an arbitrary node. However, calling emitExpressionInfo without any useful data
// is still good enough to get us an accurate line number.
- emitExpressionInfo(0, 0, 0);
- RegisterID* exception = emitNewError(newTemporary(), SyntaxError, jsString(globalData(), "Expression too deep"));
- emitThrow(exception);
- return exception;
+ m_expressionTooDeep = true;
+ return newTemporary();
+}
+
+void BytecodeGenerator::setIsNumericCompareFunction(bool isNumericCompareFunction)
+{
+ m_codeBlock->setIsNumericCompareFunction(isNumericCompareFunction);
+}
+
+int BytecodeGenerator::argumentNumberFor(const Identifier& ident)
+{
+ int parameterCount = m_parameters.size(); // includes 'this'
+ RegisterID* registerID = registerFor(ident);
+ if (!registerID)
+ return 0;
+ int index = registerID->index() + RegisterFile::CallFrameHeaderSize + parameterCount;
+ return (index > 0 && index < parameterCount) ? index : 0;
}
} // namespace JSC
#include "SymbolTable.h"
#include "Debugger.h"
#include "Nodes.h"
-#include <wtf/FastAllocBase.h>
#include <wtf/PassRefPtr.h>
#include <wtf/SegmentedVector.h>
#include <wtf/Vector.h>
namespace JSC {
class Identifier;
- class ScopeChain;
- class ScopeNode;
+ class ScopeChainNode;
+
+ class CallArguments {
+ public:
+ CallArguments(BytecodeGenerator& generator, ArgumentsNode* argumentsNode);
+
+ RegisterID* thisRegister() { return m_argv[0].get(); }
+ RegisterID* argumentRegister(unsigned i) { return m_argv[i + 1].get(); }
+ unsigned callFrame() { return thisRegister()->index() + count() + RegisterFile::CallFrameHeaderSize; }
+ unsigned count() { return m_argv.size(); }
+ RegisterID* profileHookRegister() { return m_profileHookRegister.get(); }
+ ArgumentsNode* argumentsNode() { return m_argumentsNode; }
+
+ private:
+ RefPtr<RegisterID> m_profileHookRegister;
+ ArgumentsNode* m_argumentsNode;
+ Vector<RefPtr<RegisterID>, 16> m_argv;
+ };
struct FinallyContext {
Label* finallyAddr;
RefPtr<RegisterID> propertyRegister;
};
- class BytecodeGenerator : public FastAllocBase {
+ class BytecodeGenerator {
+ WTF_MAKE_FAST_ALLOCATED;
public:
typedef DeclarationStacks::VarStack VarStack;
typedef DeclarationStacks::FunctionStack FunctionStack;
static void setDumpsGeneratedCode(bool dumpsGeneratedCode);
static bool dumpsGeneratedCode();
- BytecodeGenerator(ProgramNode*, const Debugger*, const ScopeChain&, SymbolTable*, ProgramCodeBlock*);
- BytecodeGenerator(FunctionBodyNode*, const Debugger*, const ScopeChain&, SymbolTable*, CodeBlock*);
- BytecodeGenerator(EvalNode*, const Debugger*, const ScopeChain&, SymbolTable*, EvalCodeBlock*);
+ BytecodeGenerator(ProgramNode*, ScopeChainNode*, SymbolTable*, ProgramCodeBlock*);
+ BytecodeGenerator(FunctionBodyNode*, ScopeChainNode*, SymbolTable*, CodeBlock*);
+ BytecodeGenerator(EvalNode*, ScopeChainNode*, SymbolTable*, EvalCodeBlock*);
JSGlobalData* globalData() const { return m_globalData; }
const CommonIdentifiers& propertyNames() const { return *m_globalData->propertyNames; }
- void generate();
+ bool isConstructor() { return m_codeBlock->m_isConstructor; }
+
+ JSObject* generate();
// Returns the register corresponding to a local variable, or 0 if no
// such register exists. Registers returned by registerFor do not
// require explicit reference counting.
RegisterID* registerFor(const Identifier&);
-
+
+ // Returns the agument number if this is an argument, or 0 if not.
+ int argumentNumberFor(const Identifier&);
+
+ void setIsNumericCompareFunction(bool isNumericCompareFunction);
+
bool willResolveToArguments(const Identifier&);
RegisterID* uncheckedRegisterForArguments();
// VariableObject that defines the property. If the property cannot be found
// statically, depth will contain the depth of the scope chain where dynamic
// lookup must begin.
- //
- // NB: depth does _not_ include the local scope. eg. a depth of 0 refers
- // to the scope containing this codeblock.
bool findScopedProperty(const Identifier&, int& index, size_t& depth, bool forWriting, bool& includesDynamicScopes, JSObject*& globalObject);
// Returns the register storing "this"
return newTemporary();
}
+ // Returns the place to write the final output of an operation.
+ RegisterID* finalDestinationOrIgnored(RegisterID* originalDst, RegisterID* tempDst = 0)
+ {
+ if (originalDst)
+ return originalDst;
+ ASSERT(tempDst != ignoredResult());
+ if (tempDst && tempDst->isTemporary())
+ return tempDst;
+ return newTemporary();
+ }
+
RegisterID* destinationForAssignResult(RegisterID* dst)
{
if (dst && dst != ignoredResult() && m_codeBlock->needsFullScopeChain())
{
// Node::emitCode assumes that dst, if provided, is either a local or a referenced temporary.
ASSERT(!dst || dst == ignoredResult() || !dst->isTemporary() || dst->refCount());
- if (!m_codeBlock->numberOfLineInfos() || m_codeBlock->lastLineInfo().lineNumber != n->lineNo()) {
- LineInfo info = { instructions().size(), n->lineNo() };
- m_codeBlock->addLineInfo(info);
- }
- if (m_emitNodeDepth >= s_maxEmitNodeDepth)
- return emitThrowExpressionTooDeepException();
- ++m_emitNodeDepth;
- RegisterID* r = n->emitBytecode(*this, dst);
- --m_emitNodeDepth;
- return r;
+ addLineInfo(n->lineNo());
+ return m_stack.recursionCheck()
+ ? n->emitBytecode(*this, dst)
+ : emitThrowExpressionTooDeepException();
}
RegisterID* emitNode(Node* n)
void emitNodeInConditionContext(ExpressionNode* n, Label* trueTarget, Label* falseTarget, bool fallThroughMeansTrue)
{
- if (!m_codeBlock->numberOfLineInfos() || m_codeBlock->lastLineInfo().lineNumber != n->lineNo()) {
- LineInfo info = { instructions().size(), n->lineNo() };
- m_codeBlock->addLineInfo(info);
- }
- if (m_emitNodeDepth >= s_maxEmitNodeDepth)
+ addLineInfo(n->lineNo());
+ if (m_stack.recursionCheck())
+ n->emitBytecodeInConditionContext(*this, trueTarget, falseTarget, fallThroughMeansTrue);
+ else
emitThrowExpressionTooDeepException();
- ++m_emitNodeDepth;
- n->emitBytecodeInConditionContext(*this, trueTarget, falseTarget, fallThroughMeansTrue);
- --m_emitNodeDepth;
}
void emitExpressionInfo(unsigned divot, unsigned startOffset, unsigned endOffset)
- {
+ {
+ if (!m_shouldEmitRichSourceInfo)
+ return;
+
divot -= m_codeBlock->sourceOffset();
if (divot > ExpressionRangeInfo::MaxDivot) {
// Overflow has occurred, we can only give line number info for errors for this region
m_codeBlock->addExpressionInfo(info);
}
- void emitGetByIdExceptionInfo(OpcodeID opcodeID)
- {
- // Only op_construct and op_instanceof need exception info for
- // a preceding op_get_by_id.
- ASSERT(opcodeID == op_construct || opcodeID == op_instanceof);
- GetByIdExceptionInfo info;
- info.bytecodeOffset = instructions().size();
- info.isOpConstruct = (opcodeID == op_construct);
- m_codeBlock->addGetByIdExceptionInfo(info);
- }
-
ALWAYS_INLINE bool leftHandSideNeedsCopy(bool rightHasAssignments, bool rightIsPure)
{
return (m_codeType != FunctionCode || m_codeBlock->needsFullScopeChain() || rightHasAssignments) && !rightIsPure;
RegisterID* emitUnaryNoDstOp(OpcodeID, RegisterID* src);
RegisterID* emitNewObject(RegisterID* dst);
- RegisterID* emitNewArray(RegisterID* dst, ElementNode*); // stops at first elision
+ RegisterID* emitNewArray(RegisterID* dst, ElementNode*, unsigned length); // stops at first elision
RegisterID* emitNewFunction(RegisterID* dst, FunctionBodyNode* body);
+ RegisterID* emitLazyNewFunction(RegisterID* dst, FunctionBodyNode* body);
+ RegisterID* emitNewFunctionInternal(RegisterID* dst, unsigned index, bool shouldNullCheck);
RegisterID* emitNewFunctionExpression(RegisterID* dst, FuncExprNode* func);
- RegisterID* emitNewRegExp(RegisterID* dst, RegExp* regExp);
+ RegisterID* emitNewRegExp(RegisterID* dst, RegExp*);
RegisterID* emitMove(RegisterID* dst, RegisterID* src);
RegisterID* emitPostInc(RegisterID* dst, RegisterID* srcDst);
RegisterID* emitPostDec(RegisterID* dst, RegisterID* srcDst);
+ void emitCheckHasInstance(RegisterID* base);
RegisterID* emitInstanceOf(RegisterID* dst, RegisterID* value, RegisterID* base, RegisterID* basePrototype);
RegisterID* emitTypeOf(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_typeof, dst, src); }
RegisterID* emitIn(RegisterID* dst, RegisterID* property, RegisterID* base) { return emitBinaryOp(op_in, dst, property, base, OperandTypes()); }
RegisterID* emitPutScopedVar(size_t skip, int index, RegisterID* value, JSValue globalObject);
RegisterID* emitResolveBase(RegisterID* dst, const Identifier& property);
+ RegisterID* emitResolveBaseForPut(RegisterID* dst, const Identifier& property);
RegisterID* emitResolveWithBase(RegisterID* baseDst, RegisterID* propDst, const Identifier& property);
void emitMethodCheck();
RegisterID* emitGetById(RegisterID* dst, RegisterID* base, const Identifier& property);
+ RegisterID* emitGetArgumentsLength(RegisterID* dst, RegisterID* base);
RegisterID* emitPutById(RegisterID* base, const Identifier& property, RegisterID* value);
RegisterID* emitDirectPutById(RegisterID* base, const Identifier& property, RegisterID* value);
RegisterID* emitDeleteById(RegisterID* dst, RegisterID* base, const Identifier&);
RegisterID* emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property);
+ RegisterID* emitGetArgumentByVal(RegisterID* dst, RegisterID* base, RegisterID* property);
RegisterID* emitPutByVal(RegisterID* base, RegisterID* property, RegisterID* value);
RegisterID* emitDeleteByVal(RegisterID* dst, RegisterID* base, RegisterID* property);
RegisterID* emitPutByIndex(RegisterID* base, unsigned index, RegisterID* value);
RegisterID* emitPutGetter(RegisterID* base, const Identifier& property, RegisterID* value);
RegisterID* emitPutSetter(RegisterID* base, const Identifier& property, RegisterID* value);
- RegisterID* emitCall(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset);
- RegisterID* emitCallEval(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset);
+ RegisterID* emitCall(RegisterID* dst, RegisterID* func, CallArguments&, unsigned divot, unsigned startOffset, unsigned endOffset);
+ RegisterID* emitCallEval(RegisterID* dst, RegisterID* func, CallArguments&, unsigned divot, unsigned startOffset, unsigned endOffset);
RegisterID* emitCallVarargs(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* argCount, unsigned divot, unsigned startOffset, unsigned endOffset);
- RegisterID* emitLoadVarargs(RegisterID* argCountDst, RegisterID* args);
+ RegisterID* emitLoadVarargs(RegisterID* argCountDst, RegisterID* thisRegister, RegisterID* args);
RegisterID* emitReturn(RegisterID* src);
RegisterID* emitEnd(RegisterID* src) { return emitUnaryNoDstOp(op_end, src); }
- RegisterID* emitConstruct(RegisterID* dst, RegisterID* func, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset);
+ RegisterID* emitConstruct(RegisterID* dst, RegisterID* func, CallArguments&, unsigned divot, unsigned startOffset, unsigned endOffset);
RegisterID* emitStrcat(RegisterID* dst, RegisterID* src, int count);
void emitToPrimitive(RegisterID* dst, RegisterID* src);
RegisterID* emitNextPropertyName(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, RegisterID* iter, Label* target);
RegisterID* emitCatch(RegisterID*, Label* start, Label* end);
- void emitThrow(RegisterID* exc) { emitUnaryNoDstOp(op_throw, exc); }
- RegisterID* emitNewError(RegisterID* dst, ErrorType type, JSValue message);
+ void emitThrow(RegisterID* exc)
+ {
+ m_usesExceptions = true;
+ emitUnaryNoDstOp(op_throw, exc);
+ }
+
+ void emitThrowReferenceError(const UString& message);
+
void emitPushNewScope(RegisterID* dst, const Identifier& property, RegisterID* value);
RegisterID* emitPushScope(RegisterID* scope);
CodeType codeType() const { return m_codeType; }
- void setRegeneratingForExceptionInfo(CodeBlock* originalCodeBlock)
- {
- m_regeneratingForExceptionInfo = true;
- m_codeBlockBeingRegeneratedFrom = originalCodeBlock;
- }
+ bool shouldEmitProfileHooks() { return m_shouldEmitProfileHooks; }
+
+ bool isStrictMode() const { return m_codeBlock->isStrictMode(); }
private:
void emitOpcode(OpcodeID);
static const bool needsRef = false;
};
- typedef HashMap<RefPtr<UString::Rep>, int, IdentifierRepHash, HashTraits<RefPtr<UString::Rep> >, IdentifierMapIndexHashTraits> IdentifierMap;
+ typedef HashMap<RefPtr<StringImpl>, int, IdentifierRepHash, HashTraits<RefPtr<StringImpl> >, IdentifierMapIndexHashTraits> IdentifierMap;
typedef HashMap<double, JSValue> NumberMap;
- typedef HashMap<UString::Rep*, JSString*, IdentifierRepHash> IdentifierStringMap;
-
- RegisterID* emitCall(OpcodeID, RegisterID* dst, RegisterID* func, RegisterID* thisRegister, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset);
+ typedef HashMap<StringImpl*, JSString*, IdentifierRepHash> IdentifierStringMap;
+ RegisterID* emitCall(OpcodeID, RegisterID* dst, RegisterID* func, CallArguments&, unsigned divot, unsigned startOffset, unsigned endOffset);
+
RegisterID* newRegister();
- // Returns the RegisterID corresponding to ident.
+ // Adds a var slot and maps it to the name ident in symbolTable().
RegisterID* addVar(const Identifier& ident, bool isConstant)
{
RegisterID* local;
addVar(ident, isConstant, local);
return local;
}
- // Returns true if a new RegisterID was added, false if a pre-existing RegisterID was re-used.
+
+ // Ditto. Returns true if a new RegisterID was added, false if a pre-existing RegisterID was re-used.
bool addVar(const Identifier&, bool isConstant, RegisterID*&);
+
+ // Adds an anonymous var slot. To give this slot a name, add it to symbolTable().
+ RegisterID* addVar()
+ {
+ ++m_codeBlock->m_numVars;
+ return newRegister();
+ }
// Returns the RegisterID corresponding to ident.
RegisterID* addGlobalVar(const Identifier& ident, bool isConstant)
// Returns true if a new RegisterID was added, false if a pre-existing RegisterID was re-used.
bool addGlobalVar(const Identifier&, bool isConstant, RegisterID*&);
- RegisterID* addParameter(const Identifier&);
+ void addParameter(const Identifier&, int parameterIndex);
void preserveLastVar();
+ bool shouldAvoidResolveGlobal();
RegisterID& registerFor(int index)
{
if (index >= 0)
return m_calleeRegisters[index];
- if (index == RegisterFile::OptionalCalleeArguments)
- return m_argumentsRegister;
-
if (m_parameters.size()) {
ASSERT(!m_globals.size());
return m_parameters[index + m_parameters.size() + RegisterFile::CallFrameHeaderSize];
RegisterID* addConstantValue(JSValue);
unsigned addRegExp(RegExp*);
- PassRefPtr<FunctionExecutable> makeFunction(ExecState* exec, FunctionBodyNode* body)
+ unsigned addConstantBuffer(unsigned length);
+
+ FunctionExecutable* makeFunction(ExecState* exec, FunctionBodyNode* body)
{
- return FunctionExecutable::create(exec, body->ident(), body->source(), body->usesArguments(), body->parameters(), body->lineNo(), body->lastLine());
+ return FunctionExecutable::create(exec, body->ident(), body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine());
}
- PassRefPtr<FunctionExecutable> makeFunction(JSGlobalData* globalData, FunctionBodyNode* body)
+ FunctionExecutable* makeFunction(JSGlobalData* globalData, FunctionBodyNode* body)
{
- return FunctionExecutable::create(globalData, body->ident(), body->source(), body->usesArguments(), body->parameters(), body->lineNo(), body->lastLine());
+ return FunctionExecutable::create(globalData, body->ident(), body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine());
}
+ JSString* addStringConstant(const Identifier&);
+
+ void addLineInfo(unsigned lineNo)
+ {
+#if !ENABLE(OPCODE_SAMPLING)
+ if (m_shouldEmitRichSourceInfo)
+#endif
+ m_codeBlock->addLineInfo(instructions().size(), lineNo);
+ }
+
+ RegisterID* emitInitLazyRegister(RegisterID*);
+
Vector<Instruction>& instructions() { return m_codeBlock->instructions(); }
SymbolTable& symbolTable() { return *m_symbolTable; }
RegisterID* emitThrowExpressionTooDeepException();
void createArgumentsIfNecessary();
+ void createActivationIfNecessary();
+ RegisterID* createLazyRegisterIfNecessary(RegisterID*);
bool m_shouldEmitDebugHooks;
bool m_shouldEmitProfileHooks;
+ bool m_shouldEmitRichSourceInfo;
- const ScopeChain* m_scopeChain;
+ Strong<ScopeChainNode> m_scopeChain;
SymbolTable* m_symbolTable;
ScopeNode* m_scopeNode;
// Some of these objects keep pointers to one another. They are arranged
// to ensure a sane destruction order that avoids references to freed memory.
- HashSet<RefPtr<UString::Rep>, IdentifierRepHash> m_functions;
+ HashSet<RefPtr<StringImpl>, IdentifierRepHash> m_functions;
RegisterID m_ignoredResultRegister;
RegisterID m_thisRegister;
- RegisterID m_argumentsRegister;
- int m_activationRegisterIndex;
+ RegisterID* m_activationRegister;
SegmentedVector<RegisterID, 32> m_constantPoolRegisters;
SegmentedVector<RegisterID, 32> m_calleeRegisters;
SegmentedVector<RegisterID, 32> m_parameters;
Vector<ForInContext> m_forInContextStack;
int m_nextGlobalIndex;
- int m_nextParameterIndex;
int m_firstConstantIndex;
int m_nextConstantOffset;
unsigned m_globalConstantIndex;
int m_globalVarStorageOffset;
+ bool m_hasCreatedActivation;
+ int m_firstLazyFunction;
+ int m_lastLazyFunction;
+ HashMap<unsigned int, FunctionBodyNode*, WTF::IntHash<unsigned int>, WTF::UnsignedWithZeroKeyHashTraits<unsigned int> > m_lazyFunctions;
+ typedef HashMap<FunctionBodyNode*, unsigned> FunctionOffsetMap;
+ FunctionOffsetMap m_functionOffsets;
+
// Constant pool
IdentifierMap m_identifierMap;
JSValueMap m_jsValueMap;
JSGlobalData* m_globalData;
OpcodeID m_lastOpcodeID;
+#ifndef NDEBUG
+ size_t m_lastOpcodePosition;
+#endif
- unsigned m_emitNodeDepth;
-
- bool m_regeneratingForExceptionInfo;
- CodeBlock* m_codeBlockBeingRegeneratedFrom;
+ StackBounds m_stack;
- static const unsigned s_maxEmitNodeDepth = 3000;
-
- friend class IncreaseEmitNodeDepth;
- };
-
- class IncreaseEmitNodeDepth {
- public:
- IncreaseEmitNodeDepth(BytecodeGenerator& generator, unsigned count = 1)
- : m_generator(generator)
- , m_count(count)
- {
- m_generator.m_emitNodeDepth += count;
- }
-
- ~IncreaseEmitNodeDepth()
- {
- m_generator.m_emitNodeDepth -= m_count;
- }
-
- private:
- BytecodeGenerator& m_generator;
- unsigned m_count;
+ bool m_usesExceptions;
+ bool m_expressionTooDeep;
};
}
#include "RegExpCache.h"
#include "RegExpObject.h"
#include "SamplingTool.h"
+#include "UStringConcatenate.h"
#include <wtf/Assertions.h>
#include <wtf/RefCountedLeakCounter.h>
#include <wtf/Threading.h>
// ------------------------------ ThrowableExpressionData --------------------------------
-static void substitute(UString& string, const UString& substring)
+RegisterID* ThrowableExpressionData::emitThrowReferenceError(BytecodeGenerator& generator, const UString& message)
{
- unsigned position = string.find("%s");
- ASSERT(position != UString::NotFound);
- string = makeString(string.substr(0, position), substring, string.substr(position + 2));
-}
-
-RegisterID* ThrowableExpressionData::emitThrowError(BytecodeGenerator& generator, ErrorType type, const char* message)
-{
- generator.emitExpressionInfo(divot(), startOffset(), endOffset());
- RegisterID* exception = generator.emitNewError(generator.newTemporary(), type, jsString(generator.globalData(), message));
- generator.emitThrow(exception);
- return exception;
-}
-
-RegisterID* ThrowableExpressionData::emitThrowError(BytecodeGenerator& generator, ErrorType type, const char* messageTemplate, const UString& label)
-{
- UString message = messageTemplate;
- substitute(message, label);
generator.emitExpressionInfo(divot(), startOffset(), endOffset());
- RegisterID* exception = generator.emitNewError(generator.newTemporary(), type, jsString(generator.globalData(), message));
- generator.emitThrow(exception);
- return exception;
-}
-
-inline RegisterID* ThrowableExpressionData::emitThrowError(BytecodeGenerator& generator, ErrorType type, const char* messageTemplate, const Identifier& label)
-{
- return emitThrowError(generator, type, messageTemplate, label.ustring());
+ generator.emitThrowReferenceError(message);
+ return generator.newTemporary();
}
// ------------------------------ NullNode -------------------------------------
RegisterID* RegExpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
{
- RefPtr<RegExp> regExp = generator.globalData()->regExpCache()->lookupOrCreate(m_pattern.ustring(), m_flags.ustring());
- if (!regExp->isValid())
- return emitThrowError(generator, SyntaxError, "Invalid regular expression: %s", regExp->errorMessage());
if (dst == generator.ignoredResult())
return 0;
- return generator.emitNewRegExp(generator.finalDestination(dst), regExp.get());
+ return generator.emitNewRegExp(generator.finalDestination(dst), RegExp::create(generator.globalData(), m_pattern.ustring(), regExpFlags(m_flags.ustring())));
}
// ------------------------------ ThisNode -------------------------------------
return generator.moveToDestinationIfNeeded(dst, local);
}
- generator.emitExpressionInfo(m_startOffset + m_ident.size(), m_ident.size(), 0);
+ generator.emitExpressionInfo(m_startOffset + m_ident.length(), m_ident.length(), 0);
return generator.emitResolve(generator.finalDestination(dst), m_ident);
}
}
if (!firstPutElement && !m_elision)
- return generator.emitNewArray(generator.finalDestination(dst), m_element);
+ return generator.emitNewArray(generator.finalDestination(dst), m_element, length);
- RefPtr<RegisterID> array = generator.emitNewArray(generator.tempDestination(dst), m_element);
+ RefPtr<RegisterID> array = generator.emitNewArray(generator.tempDestination(dst), m_element, length);
for (ElementNode* n = firstPutElement; n; n = n->next()) {
RegisterID* value = generator.emitNode(n->value());
}
if (m_elision) {
- RegisterID* value = generator.emitLoad(0, jsNumber(generator.globalData(), m_elision + length));
+ RegisterID* value = generator.emitLoad(0, jsNumber(m_elision + length));
generator.emitPutById(array.get(), generator.propertyNames().length, value);
}
RegisterID* BracketAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
{
+ if (m_base->isResolveNode() && generator.willResolveToArguments(static_cast<ResolveNode*>(m_base)->identifier())) {
+ RegisterID* property = generator.emitNode(m_subscript);
+ generator.emitExpressionInfo(divot(), startOffset(), endOffset());
+ return generator.emitGetArgumentByVal(generator.finalDestination(dst), generator.uncheckedRegisterForArguments(), property);
+ }
+
RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments, m_subscript->isPure(generator));
RegisterID* property = generator.emitNode(m_subscript);
generator.emitExpressionInfo(divot(), startOffset(), endOffset());
RegisterID* DotAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
{
+ if (m_ident == generator.propertyNames().length) {
+ if (!m_base->isResolveNode())
+ goto nonArgumentsPath;
+ ResolveNode* resolveNode = static_cast<ResolveNode*>(m_base);
+ if (!generator.willResolveToArguments(resolveNode->identifier()))
+ goto nonArgumentsPath;
+ generator.emitExpressionInfo(divot(), startOffset(), endOffset());
+ return generator.emitGetArgumentsLength(generator.finalDestination(dst), generator.uncheckedRegisterForArguments());
+ }
+
+nonArgumentsPath:
RegisterID* base = generator.emitNode(m_base);
generator.emitExpressionInfo(divot(), startOffset(), endOffset());
return generator.emitGetById(generator.finalDestination(dst), base, m_ident);
RegisterID* NewExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
{
RefPtr<RegisterID> func = generator.emitNode(m_expr);
- return generator.emitConstruct(generator.finalDestination(dst), func.get(), m_args, divot(), startOffset(), endOffset());
+ CallArguments callArguments(generator, m_args);
+ return generator.emitConstruct(generator.finalDestinationOrIgnored(dst), func.get(), callArguments, divot(), startOffset(), endOffset());
+}
+
+CallArguments::CallArguments(BytecodeGenerator& generator, ArgumentsNode* argumentsNode)
+ : m_argumentsNode(argumentsNode)
+{
+ if (generator.shouldEmitProfileHooks())
+ m_profileHookRegister = generator.newTemporary();
+ m_argv.append(generator.newTemporary());
+ if (argumentsNode) {
+ for (ArgumentListNode* n = argumentsNode->m_listNode; n; n = n->m_next) {
+ m_argv.append(generator.newTemporary());
+ // op_call requires the arguments to be a sequential range of registers
+ ASSERT(m_argv[m_argv.size() - 1]->index() == m_argv[m_argv.size() - 2]->index() + 1);
+ }
+ }
}
// ------------------------------ EvalFunctionCallNode ----------------------------------
RegisterID* EvalFunctionCallNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
{
RefPtr<RegisterID> func = generator.tempDestination(dst);
- RefPtr<RegisterID> thisRegister = generator.newTemporary();
+ CallArguments callArguments(generator, m_args);
generator.emitExpressionInfo(divot() - startOffset() + 4, 4, 0);
- generator.emitResolveWithBase(thisRegister.get(), func.get(), generator.propertyNames().eval);
- return generator.emitCallEval(generator.finalDestination(dst, func.get()), func.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset());
+ generator.emitResolveWithBase(callArguments.thisRegister(), func.get(), generator.propertyNames().eval);
+ return generator.emitCallEval(generator.finalDestination(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset());
}
// ------------------------------ FunctionCallValueNode ----------------------------------
RegisterID* FunctionCallValueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
{
RefPtr<RegisterID> func = generator.emitNode(m_expr);
- RefPtr<RegisterID> thisRegister = generator.emitLoad(generator.newTemporary(), jsNull());
- return generator.emitCall(generator.finalDestination(dst, func.get()), func.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset());
+ CallArguments callArguments(generator, m_args);
+ generator.emitLoad(callArguments.thisRegister(), jsUndefined());
+ return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset());
}
// ------------------------------ FunctionCallResolveNode ----------------------------------
RegisterID* FunctionCallResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
{
if (RefPtr<RegisterID> local = generator.registerFor(m_ident)) {
- RefPtr<RegisterID> thisRegister = generator.emitLoad(generator.newTemporary(), jsNull());
- return generator.emitCall(generator.finalDestination(dst, thisRegister.get()), local.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset());
+ CallArguments callArguments(generator, m_args);
+ generator.emitLoad(callArguments.thisRegister(), jsUndefined());
+ return generator.emitCall(generator.finalDestinationOrIgnored(dst, callArguments.thisRegister()), local.get(), callArguments, divot(), startOffset(), endOffset());
}
int index = 0;
bool requiresDynamicChecks = false;
if (generator.findScopedProperty(m_ident, index, depth, false, requiresDynamicChecks, globalObject) && index != missingSymbolMarker() && !requiresDynamicChecks) {
RefPtr<RegisterID> func = generator.emitGetScopedVar(generator.newTemporary(), depth, index, globalObject);
- RefPtr<RegisterID> thisRegister = generator.emitLoad(generator.newTemporary(), jsNull());
- return generator.emitCall(generator.finalDestination(dst, func.get()), func.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset());
+ CallArguments callArguments(generator, m_args);
+ generator.emitLoad(callArguments.thisRegister(), jsUndefined());
+ return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset());
}
RefPtr<RegisterID> func = generator.newTemporary();
- RefPtr<RegisterID> thisRegister = generator.newTemporary();
+ CallArguments callArguments(generator, m_args);
int identifierStart = divot() - startOffset();
- generator.emitExpressionInfo(identifierStart + m_ident.size(), m_ident.size(), 0);
- generator.emitResolveWithBase(thisRegister.get(), func.get(), m_ident);
- return generator.emitCall(generator.finalDestination(dst, func.get()), func.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset());
+ generator.emitExpressionInfo(identifierStart + m_ident.length(), m_ident.length(), 0);
+ generator.emitResolveWithBase(callArguments.thisRegister(), func.get(), m_ident);
+ return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset());
}
// ------------------------------ FunctionCallBracketNode ----------------------------------
RegisterID* property = generator.emitNode(m_subscript);
generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset);
RefPtr<RegisterID> function = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property);
- RefPtr<RegisterID> thisRegister = generator.emitMove(generator.newTemporary(), base.get());
- return generator.emitCall(generator.finalDestination(dst, function.get()), function.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset());
+ CallArguments callArguments(generator, m_args);
+ generator.emitMove(callArguments.thisRegister(), base.get());
+ return generator.emitCall(generator.finalDestinationOrIgnored(dst, function.get()), function.get(), callArguments, divot(), startOffset(), endOffset());
}
// ------------------------------ FunctionCallDotNode ----------------------------------
RegisterID* FunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
{
RefPtr<RegisterID> function = generator.tempDestination(dst);
- RefPtr<RegisterID> thisRegister = generator.newTemporary();
- generator.emitNode(thisRegister.get(), m_base);
+ CallArguments callArguments(generator, m_args);
+ generator.emitNode(callArguments.thisRegister(), m_base);
generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset);
generator.emitMethodCheck();
- generator.emitGetById(function.get(), thisRegister.get(), m_ident);
- return generator.emitCall(generator.finalDestination(dst, function.get()), function.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset());
+ generator.emitGetById(function.get(), callArguments.thisRegister(), m_ident);
+ return generator.emitCall(generator.finalDestinationOrIgnored(dst, function.get()), function.get(), callArguments, divot(), startOffset(), endOffset());
}
RegisterID* CallFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
RefPtr<RegisterID> base = generator.emitNode(m_base);
generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset);
RefPtr<RegisterID> function = generator.emitGetById(generator.tempDestination(dst), base.get(), m_ident);
- RefPtr<RegisterID> finalDestination = generator.finalDestination(dst, function.get());
+ RefPtr<RegisterID> finalDestinationOrIgnored = generator.finalDestinationOrIgnored(dst, function.get());
generator.emitJumpIfNotFunctionCall(function.get(), realCall.get());
{
- RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get());
- RefPtr<RegisterID> thisRegister = generator.newTemporary();
- ArgumentListNode* oldList = m_args->m_listNode;
if (m_args->m_listNode && m_args->m_listNode->m_expr) {
- generator.emitNode(thisRegister.get(), m_args->m_listNode->m_expr);
+ ArgumentListNode* oldList = m_args->m_listNode;
m_args->m_listNode = m_args->m_listNode->m_next;
- } else
- generator.emitLoad(thisRegister.get(), jsNull());
- generator.emitCall(finalDestination.get(), realFunction.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset());
- generator.emitJump(end.get());
- m_args->m_listNode = oldList;
+ RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get());
+ CallArguments callArguments(generator, m_args);
+ generator.emitNode(callArguments.thisRegister(), oldList->m_expr);
+ generator.emitCall(finalDestinationOrIgnored.get(), realFunction.get(), callArguments, divot(), startOffset(), endOffset());
+ generator.emitJump(end.get());
+
+ m_args->m_listNode = oldList;
+
+ } else {
+ RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get());
+ CallArguments callArguments(generator, m_args);
+ generator.emitLoad(callArguments.thisRegister(), jsUndefined());
+ generator.emitCall(finalDestinationOrIgnored.get(), realFunction.get(), callArguments, divot(), startOffset(), endOffset());
+ generator.emitJump(end.get());
+ }
}
generator.emitLabel(realCall.get());
{
- RefPtr<RegisterID> thisRegister = generator.emitMove(generator.newTemporary(), base.get());
- generator.emitCall(finalDestination.get(), function.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset());
+ CallArguments callArguments(generator, m_args);
+ generator.emitMove(callArguments.thisRegister(), base.get());
+ generator.emitCall(finalDestinationOrIgnored.get(), function.get(), callArguments, divot(), startOffset(), endOffset());
}
generator.emitLabel(end.get());
- return finalDestination.get();
+ return finalDestinationOrIgnored.get();
}
-
+
static bool areTrivialApplyArguments(ArgumentsNode* args)
{
return !args->m_listNode || !args->m_listNode->m_expr || !args->m_listNode->m_next
RefPtr<RegisterID> base = generator.emitNode(m_base);
generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset);
RefPtr<RegisterID> function = generator.emitGetById(generator.tempDestination(dst), base.get(), m_ident);
- RefPtr<RegisterID> finalDestination = generator.finalDestination(dst, function.get());
+ RefPtr<RegisterID> finalDestinationOrIgnored = generator.finalDestinationOrIgnored(dst, function.get());
generator.emitJumpIfNotFunctionApply(function.get(), realCall.get());
{
if (mayBeCall) {
- RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get());
- RefPtr<RegisterID> thisRegister = generator.newTemporary();
- ArgumentListNode* oldList = m_args->m_listNode;
if (m_args->m_listNode && m_args->m_listNode->m_expr) {
- generator.emitNode(thisRegister.get(), m_args->m_listNode->m_expr);
- m_args->m_listNode = m_args->m_listNode->m_next;
- if (m_args->m_listNode) {
- ASSERT(m_args->m_listNode->m_expr->isSimpleArray());
- ASSERT(!m_args->m_listNode->m_next);
- m_args->m_listNode = static_cast<ArrayNode*>(m_args->m_listNode->m_expr)->toArgumentList(generator.globalData());
+ ArgumentListNode* oldList = m_args->m_listNode;
+ if (m_args->m_listNode->m_next) {
+ ASSERT(m_args->m_listNode->m_next->m_expr->isSimpleArray());
+ ASSERT(!m_args->m_listNode->m_next->m_next);
+ m_args->m_listNode = static_cast<ArrayNode*>(m_args->m_listNode->m_next->m_expr)->toArgumentList(generator.globalData());
+ RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get());
+ CallArguments callArguments(generator, m_args);
+ generator.emitNode(callArguments.thisRegister(), oldList->m_expr);
+ generator.emitCall(finalDestinationOrIgnored.get(), realFunction.get(), callArguments, divot(), startOffset(), endOffset());
+ } else {
+ m_args->m_listNode = m_args->m_listNode->m_next;
+ RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get());
+ CallArguments callArguments(generator, m_args);
+ generator.emitNode(callArguments.thisRegister(), oldList->m_expr);
+ generator.emitCall(finalDestinationOrIgnored.get(), realFunction.get(), callArguments, divot(), startOffset(), endOffset());
}
- } else
- generator.emitLoad(thisRegister.get(), jsNull());
- generator.emitCall(finalDestination.get(), realFunction.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset());
- m_args->m_listNode = oldList;
+ m_args->m_listNode = oldList;
+ } else {
+ RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get());
+ CallArguments callArguments(generator, m_args);
+ generator.emitLoad(callArguments.thisRegister(), jsUndefined());
+ generator.emitCall(finalDestinationOrIgnored.get(), realFunction.get(), callArguments, divot(), startOffset(), endOffset());
+ }
} else {
ASSERT(m_args->m_listNode && m_args->m_listNode->m_next);
RefPtr<RegisterID> realFunction = generator.emitMove(generator.newTemporary(), base.get());
while ((args = args->m_next))
generator.emitNode(args->m_expr);
- generator.emitLoadVarargs(argsCountRegister.get(), argsRegister.get());
- generator.emitCallVarargs(finalDestination.get(), realFunction.get(), thisRegister.get(), argsCountRegister.get(), divot(), startOffset(), endOffset());
+ generator.emitLoadVarargs(argsCountRegister.get(), thisRegister.get(), argsRegister.get());
+ generator.emitCallVarargs(finalDestinationOrIgnored.get(), realFunction.get(), thisRegister.get(), argsCountRegister.get(), divot(), startOffset(), endOffset());
}
generator.emitJump(end.get());
}
generator.emitLabel(realCall.get());
{
- RefPtr<RegisterID> thisRegister = generator.emitMove(generator.newTemporary(), base.get());
- generator.emitCall(finalDestination.get(), function.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset());
+ CallArguments callArguments(generator, m_args);
+ generator.emitMove(callArguments.thisRegister(), base.get());
+ generator.emitCall(finalDestinationOrIgnored.get(), function.get(), callArguments, divot(), startOffset(), endOffset());
}
generator.emitLabel(end.get());
- return finalDestination.get();
+ return finalDestinationOrIgnored.get();
}
// ------------------------------ PostfixResolveNode ----------------------------------
RegisterID* PostfixErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
{
- return emitThrowError(generator, ReferenceError, m_operator == OpPlusPlus
+ return emitThrowReferenceError(generator, m_operator == OpPlusPlus
? "Postfix ++ operator applied to value that is not a reference."
: "Postfix -- operator applied to value that is not a reference.");
}
RegisterID* PrefixErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
{
- return emitThrowError(generator, ReferenceError, m_operator == OpPlusPlus
+ return emitThrowReferenceError(generator, m_operator == OpPlusPlus
? "Prefix ++ operator applied to value that is not a reference."
: "Prefix -- operator applied to value that is not a reference.");
}
ASSERT(isAdd());
ASSERT(resultDescriptor().definitelyIsString());
- IncreaseEmitNodeDepth stackGuard(generator, 3);
-
// Create a list of expressions for all the adds in the tree of nodes we can convert into
// a string concatenation. The rightmost node (c) is added first. The rightmost node is
// added first, and the leftmost child is never added, so the vector produced for the
RefPtr<RegisterID> src2 = generator.emitNode(m_expr2);
generator.emitExpressionInfo(divot(), startOffset(), endOffset());
- generator.emitGetByIdExceptionInfo(op_instanceof);
+ generator.emitCheckHasInstance(src2.get());
+
+ generator.emitExpressionInfo(divot(), startOffset(), endOffset());
RegisterID* src2Prototype = generator.emitGetById(generator.newTemporary(), src2.get(), generator.globalData()->propertyNames->prototype);
generator.emitExpressionInfo(divot(), startOffset(), endOffset());
}
RefPtr<RegisterID> src1 = generator.tempDestination(dst);
- generator.emitExpressionInfo(divot() - startOffset() + m_ident.size(), m_ident.size(), 0);
+ generator.emitExpressionInfo(divot() - startOffset() + m_ident.length(), m_ident.length(), 0);
RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), src1.get(), m_ident);
RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()), this);
return generator.emitPutById(base.get(), m_ident, result);
return value;
}
- RefPtr<RegisterID> base = generator.emitResolveBase(generator.newTemporary(), m_ident);
+ RefPtr<RegisterID> base = generator.emitResolveBaseForPut(generator.newTemporary(), m_ident);
if (dst == generator.ignoredResult())
dst = 0;
RegisterID* value = generator.emitNode(dst, m_right);
RegisterID* AssignErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
{
- return emitThrowError(generator, ReferenceError, "Left side of assignment is not a reference.");
+ return emitThrowReferenceError(generator, "Left side of assignment is not a reference.");
}
// ------------------------------ AssignBracketNode -----------------------------------
return m_statements ? m_statements->lastStatement() : 0;
}
+inline StatementNode* BlockNode::singleStatement() const
+{
+ return m_statements ? m_statements->singleStatement() : 0;
+}
+
RegisterID* BlockNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
{
if (m_statements)
RegisterID* ForInNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
{
- IncreaseEmitNodeDepth stackGuard(generator);
-
RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Loop);
if (!m_lexpr->isLocation())
- return emitThrowError(generator, ReferenceError, "Left side of for-in statement is not a reference.");
+ return emitThrowReferenceError(generator, "Left side of for-in statement is not a reference.");
generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine());
if (!propertyName) {
propertyName = generator.newTemporary();
RefPtr<RegisterID> protect = propertyName;
- RegisterID* base = generator.emitResolveBase(generator.newTemporary(), ident);
+ RegisterID* base = generator.emitResolveBaseForPut(generator.newTemporary(), ident);
generator.emitExpressionInfo(divot(), startOffset(), endOffset());
generator.emitPutById(base, ident, propertyName);
generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine());
LabelScope* scope = generator.continueTarget(m_ident);
-
- if (!scope)
- return m_ident.isEmpty()
- ? emitThrowError(generator, SyntaxError, "Invalid continue statement.")
- : emitThrowError(generator, SyntaxError, "Undefined label: '%s'.", m_ident);
+ ASSERT(scope);
generator.emitJumpScopes(scope->continueTarget(), scope->scopeDepth());
return dst;
generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine());
LabelScope* scope = generator.breakTarget(m_ident);
-
- if (!scope)
- return m_ident.isEmpty()
- ? emitThrowError(generator, SyntaxError, "Invalid break statement.")
- : emitThrowError(generator, SyntaxError, "Undefined label: '%s'.", m_ident);
+ ASSERT(scope);
generator.emitJumpScopes(scope->breakTarget(), scope->scopeDepth());
return dst;
RegisterID* ReturnNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
{
generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine());
- if (generator.codeType() != FunctionCode)
- return emitThrowError(generator, SyntaxError, "Invalid return statement.");
+ ASSERT(generator.codeType() == FunctionCode);
if (dst == generator.ignoredResult())
dst = 0;
break;
}
const UString& value = static_cast<StringNode*>(clauseExpression)->value().ustring();
- if (singleCharacterSwitch &= value.size() == 1) {
- int32_t intVal = value.rep()->characters()[0];
+ if (singleCharacterSwitch &= value.length() == 1) {
+ int32_t intVal = value.impl()->characters()[0];
if (intVal < min_num)
min_num = intVal;
if (intVal > max_num)
{
generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine());
- if (generator.breakTarget(m_name))
- return emitThrowError(generator, SyntaxError, "Duplicate label: %s.", m_name);
+ ASSERT(!generator.breakTarget(m_name));
RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::NamedLabel, &m_name);
RegisterID* r0 = generator.emitNode(dst, m_statement);
// NOTE: The catch and finally blocks must be labeled explicitly, so the
// optimizer knows they may be jumped to from anywhere.
- IncreaseEmitNodeDepth stackGuard(generator);
-
generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine());
RefPtr<Label> tryStartLabel = generator.newLabel();
{
generator.emitDebugHook(DidEnterCallFrame, firstLine(), lastLine());
emitStatementsBytecode(generator, generator.ignoredResult());
+
StatementNode* singleStatement = this->singleStatement();
+ ReturnNode* returnNode = 0;
+
+ // Check for a return statement at the end of a function composed of a single block.
if (singleStatement && singleStatement->isBlock()) {
StatementNode* lastStatementInBlock = static_cast<BlockNode*>(singleStatement)->lastStatement();
if (lastStatementInBlock && lastStatementInBlock->isReturnNode())
- return 0;
+ returnNode = static_cast<ReturnNode*>(lastStatementInBlock);
+ }
+
+ // If there is no return we must automatically insert one.
+ if (!returnNode) {
+ RegisterID* r0 = generator.isConstructor() ? generator.thisRegister() : generator.emitLoad(0, jsUndefined());
+ generator.emitDebugHook(WillLeaveCallFrame, firstLine(), lastLine());
+ generator.emitReturn(r0);
+ return 0;
+ }
+
+ // If there is a return statment, and it is the only statement in the function, check if this is a numeric compare.
+ if (static_cast<BlockNode*>(singleStatement)->singleStatement()) {
+ ExpressionNode* returnValueExpression = returnNode->value();
+ if (returnValueExpression && returnValueExpression->isSubtract()) {
+ ExpressionNode* lhsExpression = static_cast<SubNode*>(returnValueExpression)->lhs();
+ ExpressionNode* rhsExpression = static_cast<SubNode*>(returnValueExpression)->rhs();
+ if (lhsExpression->isResolveNode() && rhsExpression->isResolveNode()) {
+ generator.setIsNumericCompareFunction(generator.argumentNumberFor(static_cast<ResolveNode*>(lhsExpression)->identifier()) == 1
+ && generator.argumentNumberFor(static_cast<ResolveNode*>(rhsExpression)->identifier()) == 2);
+ }
+ }
}
- RegisterID* r0 = generator.emitLoad(0, jsUndefined());
- generator.emitDebugHook(WillLeaveCallFrame, firstLine(), lastLine());
- generator.emitReturn(r0);
return 0;
}
#define RegisterID_h
#include <wtf/Assertions.h>
-#include <wtf/Noncopyable.h>
#include <wtf/VectorTraits.h>
namespace JSC {
- class RegisterID : public Noncopyable {
+ class RegisterID {
+ WTF_MAKE_NONCOPYABLE(RegisterID);
public:
RegisterID()
: m_refCount(0)
*/
#if defined(HAVE_CONFIG_H) && HAVE_CONFIG_H
+#ifdef BUILDING_WITH_CMAKE
+#include "cmakeconfig.h"
+#else
#include "autotoolsconfig.h"
#endif
+#endif
#include <wtf/Platform.h>
+/* See note in wtf/Platform.h for more info on EXPORT_MACROS. */
+#if USE(EXPORT_MACROS)
+
+#include <wtf/ExportMacros.h>
+
+#if defined(BUILDING_JavaScriptCore) || defined(BUILDING_WTF)
+#define WTF_EXPORT_PRIVATE WTF_EXPORT
+#define JS_EXPORT_PRIVATE WTF_EXPORT
+#else
+#define WTF_EXPORT_PRIVATE WTF_IMPORT
+#define JS_EXPORT_PRIVATE WTF_IMPORT
+#endif
+
+#define JS_EXPORTDATA JS_EXPORT_PRIVATE
+#define JS_EXPORTCLASS JS_EXPORT_PRIVATE
+
+#else /* !USE(EXPORT_MACROS) */
+
#if !PLATFORM(CHROMIUM) && OS(WINDOWS) && !defined(BUILDING_WX__) && !COMPILER(GCC)
#if defined(BUILDING_JavaScriptCore) || defined(BUILDING_WTF)
#define JS_EXPORTDATA __declspec(dllexport)
#define JS_EXPORTCLASS
#endif
+#define WTF_EXPORT_PRIVATE
+#define JS_EXPORT_PRIVATE
+
+#endif /* USE(EXPORT_MACROS) */
+
#if OS(WINDOWS)
// If we don't define these, they get defined in windef.h.
#endif
+#if OS(UNIX) || OS(WINDOWS)
+#define WTF_USE_OS_RANDOMNESS 1
+#endif
+
#if OS(FREEBSD) || OS(OPENBSD)
#define HAVE_PTHREAD_NP_H 1
#endif
if ($key eq "pow") {
$thunkGenerator = "powThunkGenerator";
}
+ if ($key eq "fromCharCode") {
+ $thunkGenerator = "fromCharCodeThunkGenerator";
+ }
print " { \"$key\", $attrs[$i], (intptr_t)" . $castStr . "($firstValue), (intptr_t)$secondValue THUNK_GENERATOR($thunkGenerator) },\n";
$i++;
}
use File::Basename;
use Getopt::Long;
-my $usage = basename($0) . " --prefix prefix [--offset offset] file";
+my $usage = basename($0) . " --prefix prefix file";
my $rtype_template = quotemeta("#rtype#");
-my $offset_template = quotemeta("#offset#");
my $op_template = quotemeta("#op#");
my $prefix;
-my $offset = 32;
my $file;
my $getOptionsResult = GetOptions(
- 'prefix=s' => \$prefix,
- 'offset=i' => \$offset
+ 'prefix=s' => \$prefix
);
$file = $ARGV[0];
die "$usage\n" unless ($prefix and $file);
my $stub_template = "";
+my $output_end = "";
my $stub = "";
my $rtype = "";
open(IN, $file) or die "No such file $file";
while ( $_ = <IN> ) {
+ if ( /^$prefix\_BEGIN\((.*)\)/ ) {
+ $stub = $1;
+ print $stub . "\n";
+ }
if ( /^$prefix\((.*)\)/ ) {
$stub_template .= $1 . "\n";
}
+ if ( /^$prefix\_END\((.*)\)/ ) {
+ $output_end .= $1 . "\n";
+ }
if ( /^DEFINE_STUB_FUNCTION\((.*), (.*)\)/ ) {
$stub = $stub_template;
$rtype = quotemeta($1);
$op = quotemeta($2);
- $stub =~ s/$offset_template/$offset/g;
$stub =~ s/$rtype_template/$rtype/g;
$stub =~ s/$op_template/$op/g;
$stub =~ s/\\\*/\*/g;
}
}
+print $output_end;
+
close(IN);
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+import sys
+
types = {
"wordchar": { "UseTable" : True, "data": ['_', ('0','9'), ('A', 'Z'), ('a','z')]},
"nonwordchar": { "UseTable" : True, "Inverse": "wordchar", "data": ['`', (0, ord('0') - 1), (ord('9') + 1, ord('A') - 1), (ord('Z') + 1, ord('_') - 1), (ord('z') + 1, 0xffff)]},
"newline": { "UseTable" : False, "data": ['\n', '\r', 0x2028, 0x2029]},
- "spaces": { "UseTable" : True, "data": [' ', ('\t', '\r'), 0xa0, 0x1680, 0x180e, 0x2028, 0x2029, 0x202f, 0x205f, 0x3000, (0x2000, 0x200a)]},
- "nonspaces": { "UseTable" : True, "Inverse": "spaces", "data": [(0, ord('\t') - 1), (ord('\r') + 1, ord(' ') - 1), (ord(' ') + 1, 0x009f), (0x00a1, 0x167f), (0x1681, 0x180d), (0x180f, 0x1fff), (0x200b, 0x2027), (0x202a, 0x202e), (0x2030, 0x205e), (0x2060, 0x2fff), (0x3001, 0xffff)]},
+ "spaces": { "UseTable" : True, "data": [' ', ('\t', '\r'), 0xa0, 0x1680, 0x180e, 0x2028, 0x2029, 0x202f, 0x205f, 0x3000, (0x2000, 0x200a), 0xfeff]},
+ "nonspaces": { "UseTable" : True, "Inverse": "spaces", "data": [(0, ord('\t') - 1), (ord('\r') + 1, ord(' ') - 1), (ord(' ') + 1, 0x009f), (0x00a1, 0x167f), (0x1681, 0x180d), (0x180f, 0x1fff), (0x200b, 0x2027), (0x202a, 0x202e), (0x2030, 0x205e), (0x2060, 0x2fff), (0x3001, 0xfefe), (0xff00, 0xffff)]},
"digits": { "UseTable" : False, "data": [('0', '9')]},
"nondigits": { "UseTable" : False, "Inverse": "digits", "data": [(0, ord('0') - 1), (ord('9') + 1, 0xffff)] }
}
entriesPerLine = 50
arrays = "";
functions = "";
+emitTables = (len(sys.argv) < 2 or sys.argv[1] != "--no-tables")
for name, classes in types.items():
ranges = [];
ranges.append((min,max))
ranges.sort();
- if classes["UseTable"] and (not "Inverse" in classes):
+ if emitTables and classes["UseTable"] and (not "Inverse" in classes):
array = ("static const char _%sData[65536] = {\n" % name);
i = 0
for (min,max) in ranges:
function = "";
function += ("CharacterClass* %sCreate()\n" % name)
function += ("{\n")
- if classes["UseTable"]:
+ if emitTables and classes["UseTable"]:
if "Inverse" in classes:
function += (" CharacterClass* characterClass = new CharacterClass(CharacterClassTable::create(_%sData, true));\n" % (classes["Inverse"]))
else:
function += ("}\n\n")
functions += function
-print(arrays)
-print(functions)
+if (len(sys.argv) > 1):
+ f = open(sys.argv[-1], "w")
+ f.write(arrays)
+ f.write(functions)
+ f.close()
+else:
+ print(arrays)
+ print(functions)
#include "config.h"
#include "Debugger.h"
-#include "CollectorHeapIterator.h"
#include "Error.h"
#include "Interpreter.h"
#include "JSFunction.h"
#include "Parser.h"
#include "Protect.h"
+namespace {
+
+using namespace JSC;
+
+class Recompiler {
+public:
+ Recompiler(Debugger*);
+ ~Recompiler();
+ void operator()(JSCell*);
+
+private:
+ typedef HashSet<FunctionExecutable*> FunctionExecutableSet;
+ typedef HashMap<SourceProvider*, ExecState*> SourceProviderMap;
+
+ Debugger* m_debugger;
+ FunctionExecutableSet m_functionExecutables;
+ SourceProviderMap m_sourceProviders;
+};
+
+inline Recompiler::Recompiler(Debugger* debugger)
+ : m_debugger(debugger)
+{
+}
+
+inline Recompiler::~Recompiler()
+{
+ // Call sourceParsed() after reparsing all functions because it will execute
+ // JavaScript in the inspector.
+ SourceProviderMap::const_iterator end = m_sourceProviders.end();
+ for (SourceProviderMap::const_iterator iter = m_sourceProviders.begin(); iter != end; ++iter)
+ m_debugger->sourceParsed(iter->second, iter->first, -1, UString());
+}
+
+inline void Recompiler::operator()(JSCell* cell)
+{
+ if (!cell->inherits(&JSFunction::s_info))
+ return;
+
+ JSFunction* function = asFunction(cell);
+ if (function->executable()->isHostFunction())
+ return;
+
+ FunctionExecutable* executable = function->jsExecutable();
+
+ // Check if the function is already in the set - if so,
+ // we've already retranslated it, nothing to do here.
+ if (!m_functionExecutables.add(executable).second)
+ return;
+
+ ExecState* exec = function->scope()->globalObject->JSGlobalObject::globalExec();
+ executable->discardCode();
+ if (m_debugger == function->scope()->globalObject->debugger())
+ m_sourceProviders.add(executable->source().provider(), exec);
+}
+
+} // namespace
+
namespace JSC {
Debugger::~Debugger()
if (globalData->dynamicGlobalObject)
return;
- typedef HashSet<FunctionExecutable*> FunctionExecutableSet;
- typedef HashMap<SourceProvider*, ExecState*> SourceProviderMap;
-
- FunctionExecutableSet functionExecutables;
- SourceProviderMap sourceProviders;
-
- LiveObjectIterator it = globalData->heap.primaryHeapBegin();
- LiveObjectIterator heapEnd = globalData->heap.primaryHeapEnd();
- for ( ; it != heapEnd; ++it) {
- if (!(*it)->inherits(&JSFunction::info))
- continue;
-
- JSFunction* function = asFunction(*it);
- if (function->executable()->isHostFunction())
- continue;
-
- FunctionExecutable* executable = function->jsExecutable();
-
- // Check if the function is already in the set - if so,
- // we've already retranslated it, nothing to do here.
- if (!functionExecutables.add(executable).second)
- continue;
-
- ExecState* exec = function->scope().globalObject()->JSGlobalObject::globalExec();
- executable->recompile();
- if (function->scope().globalObject()->debugger() == this)
- sourceProviders.add(executable->source().provider(), exec);
- }
-
- // Call sourceParsed() after reparsing all functions because it will execute
- // JavaScript in the inspector.
- SourceProviderMap::const_iterator end = sourceProviders.end();
- for (SourceProviderMap::const_iterator iter = sourceProviders.begin(); iter != end; ++iter)
- sourceParsed(iter->second, SourceCode(iter->first), -1, UString());
+ Recompiler recompiler(this);
+ globalData->heap.forEach(recompiler);
}
JSValue evaluateInGlobalCallFrame(const UString& script, JSValue& exception, JSGlobalObject* globalObject)
{
CallFrame* globalCallFrame = globalObject->globalExec();
+ JSGlobalData& globalData = globalObject->globalData();
- RefPtr<EvalExecutable> eval = EvalExecutable::create(globalCallFrame, makeSource(script));
- JSObject* error = eval->compile(globalCallFrame, globalCallFrame->scopeChain());
- if (error)
- return error;
+ EvalExecutable* eval = EvalExecutable::create(globalCallFrame, makeSource(script), false);
+ if (!eval) {
+ exception = globalData.exception;
+ globalData.exception = JSValue();
+ return exception;
+ }
- return globalObject->globalData()->interpreter->execute(eval.get(), globalCallFrame, globalObject, globalCallFrame->scopeChain(), &exception);
+ JSValue result = globalData.interpreter->execute(eval, globalCallFrame, globalObject, globalCallFrame->scopeChain());
+ if (globalData.exception) {
+ exception = globalData.exception;
+ globalData.exception = JSValue();
+ }
+ ASSERT(result);
+ return result;
}
} // namespace JSC
class JSGlobalData;
class JSGlobalObject;
class JSValue;
- class SourceCode;
+ class SourceProvider;
class UString;
class Debugger {
void attach(JSGlobalObject*);
virtual void detach(JSGlobalObject*);
- virtual void sourceParsed(ExecState*, const SourceCode&, int errorLineNumber, const UString& errorMessage) = 0;
+ virtual void sourceParsed(ExecState*, SourceProvider*, int errorLineNumber, const UString& errorMessage) = 0;
virtual void exception(const DebuggerCallFrame&, intptr_t sourceID, int lineNumber, bool hasHandler) = 0;
virtual void atStatement(const DebuggerCallFrame&, intptr_t sourceID, int lineNumber) = 0;
virtual void callEvent(const DebuggerCallFrame&, intptr_t sourceID, int lineNumber) = 0;
namespace JSC {
-DebuggerActivation::DebuggerActivation(JSObject* activation)
- : JSObject(DebuggerActivation::createStructure(jsNull()))
+DebuggerActivation::DebuggerActivation(JSGlobalData& globalData, JSObject* activation)
+ : JSNonFinalObject(globalData, globalData.debuggerActivationStructure.get())
{
ASSERT(activation);
ASSERT(activation->isActivationObject());
- m_activation = static_cast<JSActivation*>(activation);
+ m_activation.set(globalData, this, static_cast<JSActivation*>(activation));
}
-void DebuggerActivation::markChildren(MarkStack& markStack)
+void DebuggerActivation::visitChildren(SlotVisitor& visitor)
{
- JSObject::markChildren(markStack);
+ ASSERT_GC_OBJECT_INHERITS(this, &s_info);
+ COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
+ ASSERT(structure()->typeInfo().overridesVisitChildren());
+ JSObject::visitChildren(visitor);
if (m_activation)
- markStack.append(m_activation);
+ visitor.append(&m_activation);
}
UString DebuggerActivation::className() const
class JSActivation;
- class DebuggerActivation : public JSObject {
+ class DebuggerActivation : public JSNonFinalObject {
public:
- DebuggerActivation(JSObject*);
+ DebuggerActivation(JSGlobalData&, JSObject*);
- virtual void markChildren(MarkStack&);
+ virtual void visitChildren(SlotVisitor&);
virtual UString className() const;
virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
virtual JSValue lookupGetter(ExecState*, const Identifier& propertyName);
virtual JSValue lookupSetter(ExecState*, const Identifier& propertyName);
- static PassRefPtr<Structure> createStructure(JSValue prototype)
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
+ return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
}
protected:
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesMarkChildren | JSObject::StructureFlags;
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | JSObject::StructureFlags;
private:
- JSActivation* m_activation;
+ WriteBarrier<JSActivation> m_activation;
};
} // namespace JSC
if (!m_callFrame->callee())
return 0;
- JSFunction* function = asFunction(m_callFrame->callee());
- if (!function)
+ JSObject* function = m_callFrame->callee();
+ if (!function || !function->inherits(&JSFunction::s_info))
return 0;
- return &function->name(m_callFrame);
+ return &asFunction(function)->name(m_callFrame);
}
UString DebuggerCallFrame::calculatedFunctionName() const
if (!m_callFrame->codeBlock())
return UString();
- if (!m_callFrame->callee())
+ JSObject* function = m_callFrame->callee();
+ if (!function || !function->inherits(&JSFunction::s_info))
return UString();
- JSFunction* function = asFunction(m_callFrame->callee());
- if (!function)
- return UString();
- return function->calculatedDisplayName(m_callFrame);
+ return asFunction(function)->calculatedDisplayName(m_callFrame);
}
DebuggerCallFrame::Type DebuggerCallFrame::type() const
JSObject* DebuggerCallFrame::thisObject() const
{
- if (!m_callFrame->codeBlock())
+ CodeBlock* codeBlock = m_callFrame->codeBlock();
+ if (!codeBlock)
+ return 0;
+
+ JSValue thisValue = m_callFrame->uncheckedR(codeBlock->thisRegister()).jsValue();
+ if (!thisValue.isObject())
return 0;
- return asObject(m_callFrame->thisValue());
+ return asObject(thisValue);
}
JSValue DebuggerCallFrame::evaluate(const UString& script, JSValue& exception) const
{
if (!m_callFrame->codeBlock())
return JSValue();
-
- RefPtr<EvalExecutable> eval = EvalExecutable::create(m_callFrame, makeSource(script));
- JSObject* error = eval->compile(m_callFrame, m_callFrame->scopeChain());
- if (error)
- return error;
-
- return m_callFrame->scopeChain()->globalData->interpreter->execute(eval.get(), m_callFrame, thisObject(), m_callFrame->scopeChain(), &exception);
+
+ JSGlobalData& globalData = m_callFrame->globalData();
+ EvalExecutable* eval = EvalExecutable::create(m_callFrame, makeSource(script), m_callFrame->codeBlock()->isStrictMode());
+ if (globalData.exception) {
+ exception = globalData.exception;
+ globalData.exception = JSValue();
+ }
+
+ JSValue result = globalData.interpreter->execute(eval, m_callFrame, thisObject(), m_callFrame->scopeChain());
+ if (globalData.exception) {
+ exception = globalData.exception;
+ globalData.exception = JSValue();
+ }
+ ASSERT(result);
+ return result;
}
} // namespace JSC
}
JSGlobalObject* dynamicGlobalObject() const { return m_callFrame->dynamicGlobalObject(); }
- const ScopeChainNode* scopeChain() const { return m_callFrame->scopeChain(); }
+ ScopeChainNode* scopeChain() const { return m_callFrame->scopeChain(); }
const UString* functionName() const;
UString calculatedFunctionName() const;
Type type() const;
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DFGAliasTracker_h
+#define DFGAliasTracker_h
+
+#if ENABLE(DFG_JIT)
+
+#include <dfg/DFGGraph.h>
+#include <wtf/Vector.h>
+
+namespace JSC { namespace DFG {
+
+// === AliasTracker ===
+//
+// This class id used to detect aliasing property accesses, which we may
+// be able to speculatively optimize (for example removing redundant loads
+// where we know a getter will not be called, or optimizing puts to arrays
+// where we know the value being written to in within length and is not a
+// hole value). In time, this should be more than a 1-deep buffer!
+class AliasTracker {
+public:
+ AliasTracker(Graph& graph)
+ : m_graph(graph)
+ , m_candidateAliasGetByVal(NoNode)
+ {
+ }
+
+ NodeIndex lookupGetByVal(NodeIndex base, NodeIndex property)
+ {
+ // Try to detect situations where a GetByVal follows another GetByVal to the same
+ // property; in these cases, we may be able to omit the subsequent get on the
+ // speculative path, where we know conditions hold to make this safe (for example,
+ // on the speculative path we will not have allowed getter access).
+ if (m_candidateAliasGetByVal != NoNode) {
+ Node& possibleAlias = m_graph[m_candidateAliasGetByVal];
+ ASSERT(possibleAlias.op == GetByVal);
+ // This check ensures the accesses alias, provided that the subscript is an
+ // integer index (this is good enough; the speculative path will only generate
+ // optimized accesses to handle integer subscripts).
+ if (possibleAlias.child1 == base && equalIgnoringLaterNumericConversion(possibleAlias.child2, property))
+ return m_candidateAliasGetByVal;
+ }
+ return NoNode;
+ }
+
+ void recordGetByVal(NodeIndex getByVal)
+ {
+ m_candidateAliasGetByVal = getByVal;
+ }
+
+ void recordPutByVal(NodeIndex putByVal)
+ {
+ ASSERT_UNUSED(putByVal, m_graph[putByVal].op == PutByVal || m_graph[putByVal].op == PutByValAlias);
+ m_candidateAliasGetByVal = NoNode;
+ }
+
+ void recordGetById(NodeIndex getById)
+ {
+ ASSERT_UNUSED(getById, m_graph[getById].op == GetById);
+ m_candidateAliasGetByVal = NoNode;
+ }
+
+ void recordPutById(NodeIndex putById)
+ {
+ ASSERT_UNUSED(putById, m_graph[putById].op == PutById);
+ m_candidateAliasGetByVal = NoNode;
+ }
+
+ void recordPutByIdDirect(NodeIndex putByVal)
+ {
+ ASSERT_UNUSED(putByVal, m_graph[putByVal].op == PutByIdDirect);
+ m_candidateAliasGetByVal = NoNode;
+ }
+
+private:
+ // This method returns true for arguments:
+ // - (X, X)
+ // - (X, ValueToNumber(X))
+ // - (X, ValueToInt32(X))
+ // - (X, NumberToInt32(X))
+ bool equalIgnoringLaterNumericConversion(NodeIndex op1, NodeIndex op2)
+ {
+ if (op1 == op2)
+ return true;
+ Node& node2 = m_graph[op2];
+ return (node2.op == ValueToNumber || node2.op == ValueToInt32 || node2.op == NumberToInt32) && op1 == node2.child1;
+ }
+
+ // The graph, to look up potentially aliasing nodes.
+ Graph& m_graph;
+ // Currently a 1-deep buffer!
+ NodeIndex m_candidateAliasGetByVal;
+};
+
+} } // namespace JSC::DFG
+
+#endif
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DFGByteCodeParser.h"
+
+#if ENABLE(DFG_JIT)
+
+#include "DFGAliasTracker.h"
+#include "DFGScoreBoard.h"
+#include "CodeBlock.h"
+
+namespace JSC { namespace DFG {
+
+#if ENABLE(DFG_JIT_RESTRICTIONS)
+// FIXME: Temporarily disable arithmetic, until we fix associated performance regressions.
+#define ARITHMETIC_OP() m_parseFailed = true
+#else
+#define ARITHMETIC_OP() ((void)0)
+#endif
+
+// === ByteCodeParser ===
+//
+// This class is used to compile the dataflow graph from a CodeBlock.
+class ByteCodeParser {
+public:
+ ByteCodeParser(JSGlobalData* globalData, CodeBlock* codeBlock, Graph& graph)
+ : m_globalData(globalData)
+ , m_codeBlock(codeBlock)
+ , m_graph(graph)
+ , m_currentIndex(0)
+ , m_parseFailed(false)
+ , m_constantUndefined(UINT_MAX)
+ , m_constantNull(UINT_MAX)
+ , m_constant1(UINT_MAX)
+ , m_constants(codeBlock->numberOfConstantRegisters())
+ , m_numArguments(codeBlock->m_numParameters)
+ , m_numLocals(codeBlock->m_numCalleeRegisters)
+ , m_preservedVars(codeBlock->m_numVars)
+ {
+ }
+
+ // Parse a full CodeBlock of bytecode.
+ bool parse();
+
+private:
+ // Parse a single basic block of bytecode instructions.
+ bool parseBlock(unsigned limit);
+ // Setup predecessor links in the graph's BasicBlocks.
+ void setupPredecessors();
+ // Link GetLocal & SetLocal nodes, to ensure live values are generated.
+ enum PhiStackType {
+ LocalPhiStack,
+ ArgumentPhiStack
+ };
+ template<PhiStackType stackType>
+ void processPhiStack();
+ // Add spill locations to nodes.
+ void allocateVirtualRegisters();
+
+ // Get/Set the operands/result of a bytecode instruction.
+ NodeIndex get(int operand)
+ {
+ // Is this a constant?
+ if (operand >= FirstConstantRegisterIndex) {
+ unsigned constant = operand - FirstConstantRegisterIndex;
+ ASSERT(constant < m_constants.size());
+ return getJSConstant(constant);
+ }
+
+ // Is this an argument?
+ if (operandIsArgument(operand))
+ return getArgument(operand);
+
+ // Must be a local.
+ return getLocal((unsigned)operand);
+ }
+ void set(int operand, NodeIndex value, PredictedType prediction = PredictNone)
+ {
+ m_graph.predict(operand, prediction);
+
+ // Is this an argument?
+ if (operandIsArgument(operand)) {
+ setArgument(operand, value);
+ return;
+ }
+
+ // Must be a local.
+ setLocal((unsigned)operand, value);
+ }
+
+ // Used in implementing get/set, above, where the operand is a local variable.
+ NodeIndex getLocal(unsigned operand)
+ {
+ NodeIndex nodeIndex = m_currentBlock->m_locals[operand].value;
+
+ if (nodeIndex != NoNode) {
+ Node& node = m_graph[nodeIndex];
+ if (node.op == GetLocal)
+ return nodeIndex;
+ ASSERT(node.op == SetLocal);
+ return node.child1;
+ }
+
+ // Check for reads of temporaries from prior blocks,
+ // expand m_preservedVars to cover these.
+ m_preservedVars = std::max(m_preservedVars, operand + 1);
+
+ NodeIndex phi = addToGraph(Phi);
+ m_localPhiStack.append(PhiStackEntry(m_currentBlock, phi, operand));
+ nodeIndex = addToGraph(GetLocal, OpInfo(operand), phi);
+ m_currentBlock->m_locals[operand].value = nodeIndex;
+ return nodeIndex;
+ }
+ void setLocal(unsigned operand, NodeIndex value)
+ {
+ m_currentBlock->m_locals[operand].value = addToGraph(SetLocal, OpInfo(operand), value);
+ }
+
+ // Used in implementing get/set, above, where the operand is an argument.
+ NodeIndex getArgument(unsigned operand)
+ {
+ unsigned argument = operand + m_codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize;
+ ASSERT(argument < m_numArguments);
+
+ NodeIndex nodeIndex = m_currentBlock->m_arguments[argument].value;
+
+ if (nodeIndex != NoNode) {
+ Node& node = m_graph[nodeIndex];
+ if (node.op == GetLocal)
+ return nodeIndex;
+ ASSERT(node.op == SetLocal);
+ return node.child1;
+ }
+
+ NodeIndex phi = addToGraph(Phi);
+ m_argumentPhiStack.append(PhiStackEntry(m_currentBlock, phi, argument));
+ nodeIndex = addToGraph(GetLocal, OpInfo(operand), phi);
+ m_currentBlock->m_arguments[argument].value = nodeIndex;
+ return nodeIndex;
+ }
+ void setArgument(int operand, NodeIndex value)
+ {
+ unsigned argument = operand + m_codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize;
+ ASSERT(argument < m_numArguments);
+
+ m_currentBlock->m_arguments[argument].value = addToGraph(SetLocal, OpInfo(operand), value);
+ }
+
+ // Get an operand, and perform a ToInt32/ToNumber conversion on it.
+ NodeIndex getToInt32(int operand)
+ {
+ // Avoid wastefully adding a JSConstant node to the graph, only to
+ // replace it with a Int32Constant (which is what would happen if
+ // we called 'toInt32(get(operand))' in this case).
+ if (operand >= FirstConstantRegisterIndex) {
+ JSValue v = m_codeBlock->getConstant(operand);
+ if (v.isInt32())
+ return getInt32Constant(v.asInt32(), operand - FirstConstantRegisterIndex);
+ }
+ return toInt32(get(operand));
+ }
+ NodeIndex getToNumber(int operand)
+ {
+ // Avoid wastefully adding a JSConstant node to the graph, only to
+ // replace it with a DoubleConstant (which is what would happen if
+ // we called 'toNumber(get(operand))' in this case).
+ if (operand >= FirstConstantRegisterIndex) {
+ JSValue v = m_codeBlock->getConstant(operand);
+ if (v.isNumber())
+ return getDoubleConstant(v.uncheckedGetNumber(), operand - FirstConstantRegisterIndex);
+ }
+ return toNumber(get(operand));
+ }
+
+ // Perform an ES5 ToInt32 operation - returns a node of type NodeResultInt32.
+ NodeIndex toInt32(NodeIndex index)
+ {
+ Node& node = m_graph[index];
+
+ if (node.hasInt32Result())
+ return index;
+
+ if (node.hasDoubleResult()) {
+ if (node.op == DoubleConstant)
+ return getInt32Constant(JSC::toInt32(valueOfDoubleConstant(index)), node.constantNumber());
+ // 'NumberToInt32(Int32ToNumber(X))' == X, and 'NumberToInt32(UInt32ToNumber(X)) == X'
+ if (node.op == Int32ToNumber || node.op == UInt32ToNumber)
+ return node.child1;
+
+ // We unique NumberToInt32 nodes in a map to prevent duplicate conversions.
+ pair<UnaryOpMap::iterator, bool> result = m_numberToInt32Nodes.add(index, NoNode);
+ // Either we added a new value, or the existing value in the map is non-zero.
+ ASSERT(result.second == (result.first->second == NoNode));
+ if (result.second)
+ result.first->second = addToGraph(NumberToInt32, index);
+ return result.first->second;
+ }
+
+ // Check for numeric constants boxed as JSValues.
+ if (node.op == JSConstant) {
+ JSValue v = valueOfJSConstant(index);
+ if (v.isInt32())
+ return getInt32Constant(v.asInt32(), node.constantNumber());
+ if (v.isNumber())
+ return getInt32Constant(JSC::toInt32(v.uncheckedGetNumber()), node.constantNumber());
+ }
+
+ return addToGraph(ValueToInt32, index);
+ }
+
+ // Perform an ES5 ToNumber operation - returns a node of type NodeResultDouble.
+ NodeIndex toNumber(NodeIndex index)
+ {
+ Node& node = m_graph[index];
+
+ if (node.hasDoubleResult())
+ return index;
+
+ if (node.hasInt32Result()) {
+ if (node.op == Int32Constant)
+ return getDoubleConstant(valueOfInt32Constant(index), node.constantNumber());
+
+ // We unique Int32ToNumber nodes in a map to prevent duplicate conversions.
+ pair<UnaryOpMap::iterator, bool> result = m_int32ToNumberNodes.add(index, NoNode);
+ // Either we added a new value, or the existing value in the map is non-zero.
+ ASSERT(result.second == (result.first->second == NoNode));
+ if (result.second)
+ result.first->second = addToGraph(Int32ToNumber, index);
+ return result.first->second;
+ }
+
+ if (node.op == JSConstant) {
+ JSValue v = valueOfJSConstant(index);
+ if (v.isNumber())
+ return getDoubleConstant(v.uncheckedGetNumber(), node.constantNumber());
+ }
+
+ return addToGraph(ValueToNumber, index);
+ }
+
+
+ // Used in implementing get, above, where the operand is a constant.
+ NodeIndex getInt32Constant(int32_t value, unsigned constant)
+ {
+ NodeIndex index = m_constants[constant].asInt32;
+ if (index != NoNode)
+ return index;
+ NodeIndex resultIndex = addToGraph(Int32Constant, OpInfo(constant));
+ m_graph[resultIndex].setInt32Constant(value);
+ m_constants[constant].asInt32 = resultIndex;
+ return resultIndex;
+ }
+ NodeIndex getDoubleConstant(double value, unsigned constant)
+ {
+ NodeIndex index = m_constants[constant].asNumeric;
+ if (index != NoNode)
+ return index;
+ NodeIndex resultIndex = addToGraph(DoubleConstant, OpInfo(constant));
+ m_graph[resultIndex].setDoubleConstant(value);
+ m_constants[constant].asNumeric = resultIndex;
+ return resultIndex;
+ }
+ NodeIndex getJSConstant(unsigned constant)
+ {
+ NodeIndex index = m_constants[constant].asJSValue;
+ if (index != NoNode)
+ return index;
+
+ NodeIndex resultIndex = addToGraph(JSConstant, OpInfo(constant));
+ m_constants[constant].asJSValue = resultIndex;
+ return resultIndex;
+ }
+
+ // Helper functions to get/set the this value.
+ NodeIndex getThis()
+ {
+ return getArgument(m_codeBlock->thisRegister());
+ }
+ void setThis(NodeIndex value)
+ {
+ setArgument(m_codeBlock->thisRegister(), value);
+ }
+
+ // Convenience methods for checking nodes for constants.
+ bool isInt32Constant(NodeIndex index)
+ {
+ return m_graph[index].op == Int32Constant;
+ }
+ bool isDoubleConstant(NodeIndex index)
+ {
+ return m_graph[index].op == DoubleConstant;
+ }
+ bool isJSConstant(NodeIndex index)
+ {
+ return m_graph[index].op == JSConstant;
+ }
+
+ // Convenience methods for getting constant values.
+ int32_t valueOfInt32Constant(NodeIndex index)
+ {
+ ASSERT(isInt32Constant(index));
+ return m_graph[index].int32Constant();
+ }
+ double valueOfDoubleConstant(NodeIndex index)
+ {
+ ASSERT(isDoubleConstant(index));
+ return m_graph[index].numericConstant();
+ }
+ JSValue valueOfJSConstant(NodeIndex index)
+ {
+ ASSERT(isJSConstant(index));
+ return m_codeBlock->getConstant(FirstConstantRegisterIndex + m_graph[index].constantNumber());
+ }
+
+ // This method returns a JSConstant with the value 'undefined'.
+ NodeIndex constantUndefined()
+ {
+ // Has m_constantUndefined been set up yet?
+ if (m_constantUndefined == UINT_MAX) {
+ // Search the constant pool for undefined, if we find it, we can just reuse this!
+ unsigned numberOfConstants = m_codeBlock->numberOfConstantRegisters();
+ for (m_constantUndefined = 0; m_constantUndefined < numberOfConstants; ++m_constantUndefined) {
+ JSValue testMe = m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantUndefined);
+ if (testMe.isUndefined())
+ return getJSConstant(m_constantUndefined);
+ }
+
+ // Add undefined to the CodeBlock's constants, and add a corresponding slot in m_constants.
+ ASSERT(m_constants.size() == numberOfConstants);
+ m_codeBlock->addConstant(jsUndefined());
+ m_constants.append(ConstantRecord());
+ ASSERT(m_constants.size() == m_codeBlock->numberOfConstantRegisters());
+ }
+
+ // m_constantUndefined must refer to an entry in the CodeBlock's constant pool that has the value 'undefined'.
+ ASSERT(m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantUndefined).isUndefined());
+ return getJSConstant(m_constantUndefined);
+ }
+
+ // This method returns a JSConstant with the value 'null'.
+ NodeIndex constantNull()
+ {
+ // Has m_constantNull been set up yet?
+ if (m_constantNull == UINT_MAX) {
+ // Search the constant pool for null, if we find it, we can just reuse this!
+ unsigned numberOfConstants = m_codeBlock->numberOfConstantRegisters();
+ for (m_constantNull = 0; m_constantNull < numberOfConstants; ++m_constantNull) {
+ JSValue testMe = m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantNull);
+ if (testMe.isNull())
+ return getJSConstant(m_constantNull);
+ }
+
+ // Add null to the CodeBlock's constants, and add a corresponding slot in m_constants.
+ ASSERT(m_constants.size() == numberOfConstants);
+ m_codeBlock->addConstant(jsNull());
+ m_constants.append(ConstantRecord());
+ ASSERT(m_constants.size() == m_codeBlock->numberOfConstantRegisters());
+ }
+
+ // m_constantNull must refer to an entry in the CodeBlock's constant pool that has the value 'null'.
+ ASSERT(m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantNull).isNull());
+ return getJSConstant(m_constantNull);
+ }
+
+ // This method returns a DoubleConstant with the value 1.
+ NodeIndex one()
+ {
+ // Has m_constant1 been set up yet?
+ if (m_constant1 == UINT_MAX) {
+ // Search the constant pool for the value 1, if we find it, we can just reuse this!
+ unsigned numberOfConstants = m_codeBlock->numberOfConstantRegisters();
+ for (m_constant1 = 0; m_constant1 < numberOfConstants; ++m_constant1) {
+ JSValue testMe = m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constant1);
+ if (testMe.isInt32() && testMe.asInt32() == 1)
+ return getDoubleConstant(1, m_constant1);
+ }
+
+ // Add the value 1 to the CodeBlock's constants, and add a corresponding slot in m_constants.
+ ASSERT(m_constants.size() == numberOfConstants);
+ m_codeBlock->addConstant(jsNumber(1));
+ m_constants.append(ConstantRecord());
+ ASSERT(m_constants.size() == m_codeBlock->numberOfConstantRegisters());
+ }
+
+ // m_constant1 must refer to an entry in the CodeBlock's constant pool that has the integer value 1.
+ ASSERT(m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constant1).isInt32());
+ ASSERT(m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constant1).asInt32() == 1);
+ return getDoubleConstant(1, m_constant1);
+ }
+
+
+ // These methods create a node and add it to the graph. If nodes of this type are
+ // 'mustGenerate' then the node will implicitly be ref'ed to ensure generation.
+ NodeIndex addToGraph(NodeType op, NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode)
+ {
+ NodeIndex resultIndex = (NodeIndex)m_graph.size();
+ m_graph.append(Node(op, m_currentIndex, child1, child2, child3));
+
+ if (op & NodeMustGenerate)
+ m_graph.ref(resultIndex);
+ return resultIndex;
+ }
+ NodeIndex addToGraph(NodeType op, OpInfo info, NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode)
+ {
+ NodeIndex resultIndex = (NodeIndex)m_graph.size();
+ m_graph.append(Node(op, m_currentIndex, info, child1, child2, child3));
+
+ if (op & NodeMustGenerate)
+ m_graph.ref(resultIndex);
+ return resultIndex;
+ }
+ NodeIndex addToGraph(NodeType op, OpInfo info1, OpInfo info2, NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode)
+ {
+ NodeIndex resultIndex = (NodeIndex)m_graph.size();
+ m_graph.append(Node(op, m_currentIndex, info1, info2, child1, child2, child3));
+
+ if (op & NodeMustGenerate)
+ m_graph.ref(resultIndex);
+ return resultIndex;
+ }
+
+ void predictArray(NodeIndex nodeIndex)
+ {
+ Node* nodePtr = &m_graph[nodeIndex];
+
+ if (nodePtr->op == GetLocal)
+ m_graph.predict(nodePtr->local(), PredictArray);
+ }
+
+ void predictInt32(NodeIndex nodeIndex)
+ {
+ Node* nodePtr = &m_graph[nodeIndex];
+
+ if (nodePtr->op == ValueToNumber)
+ nodePtr = &m_graph[nodePtr->child1];
+
+ if (nodePtr->op == ValueToInt32)
+ nodePtr = &m_graph[nodePtr->child1];
+
+ if (nodePtr->op == NumberToInt32)
+ nodePtr = &m_graph[nodePtr->child1];
+
+ if (nodePtr->op == GetLocal)
+ m_graph.predict(nodePtr->local(), PredictInt32);
+ }
+
+ JSGlobalData* m_globalData;
+ CodeBlock* m_codeBlock;
+ Graph& m_graph;
+
+ // The current block being generated.
+ BasicBlock* m_currentBlock;
+ // The bytecode index of the current instruction being generated.
+ unsigned m_currentIndex;
+
+ // Record failures due to unimplemented functionality or regressions.
+ bool m_parseFailed;
+
+ // We use these values during code generation, and to avoid the need for
+ // special handling we make sure they are available as constants in the
+ // CodeBlock's constant pool. These variables are initialized to
+ // UINT_MAX, and lazily updated to hold an index into the CodeBlock's
+ // constant pool, as necessary.
+ unsigned m_constantUndefined;
+ unsigned m_constantNull;
+ unsigned m_constant1;
+
+ // A constant in the constant pool may be represented by more than one
+ // node in the graph, depending on the context in which it is being used.
+ struct ConstantRecord {
+ ConstantRecord()
+ : asInt32(NoNode)
+ , asNumeric(NoNode)
+ , asJSValue(NoNode)
+ {
+ }
+
+ NodeIndex asInt32;
+ NodeIndex asNumeric;
+ NodeIndex asJSValue;
+ };
+
+ // Track the index of the node whose result is the current value for every
+ // register value in the bytecode - argument, local, and temporary.
+ Vector<ConstantRecord, 16> m_constants;
+
+ // The number of arguments passed to the function.
+ unsigned m_numArguments;
+ // The number of locals (vars + temporaries) used in the function.
+ unsigned m_numLocals;
+ // The number of registers we need to preserve across BasicBlock boundaries;
+ // typically equal to the number vars, but we expand this to cover all
+ // temporaries that persist across blocks (dues to ?:, &&, ||, etc).
+ unsigned m_preservedVars;
+
+ struct PhiStackEntry {
+ PhiStackEntry(BasicBlock* block, NodeIndex phi, unsigned varNo)
+ : m_block(block)
+ , m_phi(phi)
+ , m_varNo(varNo)
+ {
+ }
+
+ BasicBlock* m_block;
+ NodeIndex m_phi;
+ unsigned m_varNo;
+ };
+ Vector<PhiStackEntry, 16> m_argumentPhiStack;
+ Vector<PhiStackEntry, 16> m_localPhiStack;
+
+ // These maps are used to unique ToNumber and ToInt32 operations.
+ typedef HashMap<NodeIndex, NodeIndex> UnaryOpMap;
+ UnaryOpMap m_int32ToNumberNodes;
+ UnaryOpMap m_numberToInt32Nodes;
+};
+
+#define NEXT_OPCODE(name) \
+ m_currentIndex += OPCODE_LENGTH(name); \
+ continue
+
+#define LAST_OPCODE(name) \
+ m_currentIndex += OPCODE_LENGTH(name); \
+ return !m_parseFailed
+
+bool ByteCodeParser::parseBlock(unsigned limit)
+{
+ // No need to reset state initially, since it has been set by the constructor.
+ if (m_currentIndex) {
+ for (unsigned i = 0; i < m_constants.size(); ++i)
+ m_constants[i] = ConstantRecord();
+ }
+
+ AliasTracker aliases(m_graph);
+
+ Interpreter* interpreter = m_globalData->interpreter;
+ Instruction* instructionsBegin = m_codeBlock->instructions().begin();
+ while (true) {
+ // Don't extend over jump destinations.
+ if (m_currentIndex == limit) {
+ addToGraph(Jump, OpInfo(m_currentIndex));
+ return !m_parseFailed;
+ }
+
+ // Switch on the current bytecode opcode.
+ Instruction* currentInstruction = instructionsBegin + m_currentIndex;
+ switch (interpreter->getOpcodeID(currentInstruction->u.opcode)) {
+
+ // === Function entry opcodes ===
+
+ case op_enter:
+ // Initialize all locals to undefined.
+ for (int i = 0; i < m_codeBlock->m_numVars; ++i)
+ set(i, constantUndefined());
+ NEXT_OPCODE(op_enter);
+
+ case op_convert_this: {
+ NodeIndex op1 = getThis();
+ setThis(addToGraph(ConvertThis, op1));
+ NEXT_OPCODE(op_convert_this);
+ }
+
+ // === Bitwise operations ===
+
+ case op_bitand: {
+ NodeIndex op1 = getToInt32(currentInstruction[2].u.operand);
+ NodeIndex op2 = getToInt32(currentInstruction[3].u.operand);
+ predictInt32(op1);
+ predictInt32(op2);
+ set(currentInstruction[1].u.operand, addToGraph(BitAnd, op1, op2), PredictInt32);
+ NEXT_OPCODE(op_bitand);
+ }
+
+ case op_bitor: {
+ NodeIndex op1 = getToInt32(currentInstruction[2].u.operand);
+ NodeIndex op2 = getToInt32(currentInstruction[3].u.operand);
+ predictInt32(op1);
+ predictInt32(op2);
+ set(currentInstruction[1].u.operand, addToGraph(BitOr, op1, op2), PredictInt32);
+ NEXT_OPCODE(op_bitor);
+ }
+
+ case op_bitxor: {
+ NodeIndex op1 = getToInt32(currentInstruction[2].u.operand);
+ NodeIndex op2 = getToInt32(currentInstruction[3].u.operand);
+ predictInt32(op1);
+ predictInt32(op2);
+ set(currentInstruction[1].u.operand, addToGraph(BitXor, op1, op2), PredictInt32);
+ NEXT_OPCODE(op_bitxor);
+ }
+
+ case op_rshift: {
+ NodeIndex op1 = getToInt32(currentInstruction[2].u.operand);
+ NodeIndex op2 = getToInt32(currentInstruction[3].u.operand);
+ predictInt32(op1);
+ predictInt32(op2);
+ NodeIndex result;
+ // Optimize out shifts by zero.
+ if (isInt32Constant(op2) && !(valueOfInt32Constant(op2) & 0x1f))
+ result = op1;
+ else
+ result = addToGraph(BitRShift, op1, op2);
+ set(currentInstruction[1].u.operand, result, PredictInt32);
+ NEXT_OPCODE(op_rshift);
+ }
+
+ case op_lshift: {
+ NodeIndex op1 = getToInt32(currentInstruction[2].u.operand);
+ NodeIndex op2 = getToInt32(currentInstruction[3].u.operand);
+ predictInt32(op1);
+ predictInt32(op2);
+ NodeIndex result;
+ // Optimize out shifts by zero.
+ if (isInt32Constant(op2) && !(valueOfInt32Constant(op2) & 0x1f))
+ result = op1;
+ else
+ result = addToGraph(BitLShift, op1, op2);
+ set(currentInstruction[1].u.operand, result, PredictInt32);
+ NEXT_OPCODE(op_lshift);
+ }
+
+ case op_urshift: {
+ NodeIndex op1 = getToInt32(currentInstruction[2].u.operand);
+ NodeIndex op2 = getToInt32(currentInstruction[3].u.operand);
+ predictInt32(op1);
+ predictInt32(op2);
+ NodeIndex result;
+ // The result of a zero-extending right shift is treated as an unsigned value.
+ // This means that if the top bit is set, the result is not in the int32 range,
+ // and as such must be stored as a double. If the shift amount is a constant,
+ // we may be able to optimize.
+ if (isInt32Constant(op2)) {
+ // If we know we are shifting by a non-zero amount, then since the operation
+ // zero fills we know the top bit of the result must be zero, and as such the
+ // result must be within the int32 range. Conversely, if this is a shift by
+ // zero, then the result may be changed by the conversion to unsigned, but it
+ // is not necessary to perform the shift!
+ if (valueOfInt32Constant(op2) & 0x1f)
+ result = addToGraph(BitURShift, op1, op2);
+ else
+ result = addToGraph(UInt32ToNumber, op1);
+ } else {
+ // Cannot optimize at this stage; shift & potentially rebox as a double.
+ result = addToGraph(BitURShift, op1, op2);
+ result = addToGraph(UInt32ToNumber, result);
+ }
+ set(currentInstruction[1].u.operand, result, PredictInt32);
+ NEXT_OPCODE(op_urshift);
+ }
+
+ // === Increment/Decrement opcodes ===
+
+ case op_pre_inc: {
+ unsigned srcDst = currentInstruction[1].u.operand;
+ NodeIndex op = getToNumber(srcDst);
+ predictInt32(op);
+ set(srcDst, addToGraph(ArithAdd, op, one()));
+ NEXT_OPCODE(op_pre_inc);
+ }
+
+ case op_post_inc: {
+ unsigned result = currentInstruction[1].u.operand;
+ unsigned srcDst = currentInstruction[2].u.operand;
+ NodeIndex op = getToNumber(srcDst);
+ predictInt32(op);
+ set(result, op);
+ set(srcDst, addToGraph(ArithAdd, op, one()));
+ NEXT_OPCODE(op_post_inc);
+ }
+
+ case op_pre_dec: {
+ unsigned srcDst = currentInstruction[1].u.operand;
+ NodeIndex op = getToNumber(srcDst);
+ predictInt32(op);
+ set(srcDst, addToGraph(ArithSub, op, one()));
+ NEXT_OPCODE(op_pre_dec);
+ }
+
+ case op_post_dec: {
+ unsigned result = currentInstruction[1].u.operand;
+ unsigned srcDst = currentInstruction[2].u.operand;
+ NodeIndex op = getToNumber(srcDst);
+ predictInt32(op);
+ set(result, op);
+ set(srcDst, addToGraph(ArithSub, op, one()));
+ NEXT_OPCODE(op_post_dec);
+ }
+
+ // === Arithmetic operations ===
+
+ case op_add: {
+ ARITHMETIC_OP();
+ NodeIndex op1 = get(currentInstruction[2].u.operand);
+ NodeIndex op2 = get(currentInstruction[3].u.operand);
+ // If both operands can statically be determined to the numbers, then this is an arithmetic add.
+ // Otherwise, we must assume this may be performing a concatenation to a string.
+ if (m_graph[op1].hasNumericResult() && m_graph[op2].hasNumericResult())
+ set(currentInstruction[1].u.operand, addToGraph(ArithAdd, toNumber(op1), toNumber(op2)));
+ else
+ set(currentInstruction[1].u.operand, addToGraph(ValueAdd, op1, op2));
+ NEXT_OPCODE(op_add);
+ }
+
+ case op_sub: {
+ ARITHMETIC_OP();
+ NodeIndex op1 = getToNumber(currentInstruction[2].u.operand);
+ NodeIndex op2 = getToNumber(currentInstruction[3].u.operand);
+ set(currentInstruction[1].u.operand, addToGraph(ArithSub, op1, op2));
+ NEXT_OPCODE(op_sub);
+ }
+
+ case op_mul: {
+ ARITHMETIC_OP();
+ NodeIndex op1 = getToNumber(currentInstruction[2].u.operand);
+ NodeIndex op2 = getToNumber(currentInstruction[3].u.operand);
+ set(currentInstruction[1].u.operand, addToGraph(ArithMul, op1, op2));
+ NEXT_OPCODE(op_mul);
+ }
+
+ case op_mod: {
+ ARITHMETIC_OP();
+ NodeIndex op1 = getToNumber(currentInstruction[2].u.operand);
+ NodeIndex op2 = getToNumber(currentInstruction[3].u.operand);
+ set(currentInstruction[1].u.operand, addToGraph(ArithMod, op1, op2));
+ NEXT_OPCODE(op_mod);
+ }
+
+ case op_div: {
+ ARITHMETIC_OP();
+ NodeIndex op1 = getToNumber(currentInstruction[2].u.operand);
+ NodeIndex op2 = getToNumber(currentInstruction[3].u.operand);
+ set(currentInstruction[1].u.operand, addToGraph(ArithDiv, op1, op2));
+ NEXT_OPCODE(op_div);
+ }
+
+ // === Misc operations ===
+
+ case op_mov: {
+ NodeIndex op = get(currentInstruction[2].u.operand);
+ set(currentInstruction[1].u.operand, op);
+ NEXT_OPCODE(op_mov);
+ }
+
+ case op_not: {
+ ARITHMETIC_OP();
+ NodeIndex value = get(currentInstruction[2].u.operand);
+ set(currentInstruction[1].u.operand, addToGraph(LogicalNot, value));
+ NEXT_OPCODE(op_not);
+ }
+
+ case op_less: {
+ ARITHMETIC_OP();
+ NodeIndex op1 = get(currentInstruction[2].u.operand);
+ NodeIndex op2 = get(currentInstruction[3].u.operand);
+ set(currentInstruction[1].u.operand, addToGraph(CompareLess, op1, op2));
+ NEXT_OPCODE(op_less);
+ }
+
+ case op_lesseq: {
+ ARITHMETIC_OP();
+ NodeIndex op1 = get(currentInstruction[2].u.operand);
+ NodeIndex op2 = get(currentInstruction[3].u.operand);
+ set(currentInstruction[1].u.operand, addToGraph(CompareLessEq, op1, op2));
+ NEXT_OPCODE(op_lesseq);
+ }
+
+ case op_eq: {
+ ARITHMETIC_OP();
+ NodeIndex op1 = get(currentInstruction[2].u.operand);
+ NodeIndex op2 = get(currentInstruction[3].u.operand);
+ set(currentInstruction[1].u.operand, addToGraph(CompareEq, op1, op2));
+ NEXT_OPCODE(op_eq);
+ }
+
+ case op_eq_null: {
+ ARITHMETIC_OP();
+ NodeIndex value = get(currentInstruction[2].u.operand);
+ set(currentInstruction[1].u.operand, addToGraph(CompareEq, value, constantNull()));
+ NEXT_OPCODE(op_eq_null);
+ }
+
+ case op_stricteq: {
+ ARITHMETIC_OP();
+ NodeIndex op1 = get(currentInstruction[2].u.operand);
+ NodeIndex op2 = get(currentInstruction[3].u.operand);
+ set(currentInstruction[1].u.operand, addToGraph(CompareStrictEq, op1, op2));
+ NEXT_OPCODE(op_stricteq);
+ }
+
+ case op_neq: {
+ ARITHMETIC_OP();
+ NodeIndex op1 = get(currentInstruction[2].u.operand);
+ NodeIndex op2 = get(currentInstruction[3].u.operand);
+ set(currentInstruction[1].u.operand, addToGraph(LogicalNot, addToGraph(CompareEq, op1, op2)));
+ NEXT_OPCODE(op_neq);
+ }
+
+ case op_neq_null: {
+ ARITHMETIC_OP();
+ NodeIndex value = get(currentInstruction[2].u.operand);
+ set(currentInstruction[1].u.operand, addToGraph(LogicalNot, addToGraph(CompareEq, value, constantNull())));
+ NEXT_OPCODE(op_neq_null);
+ }
+
+ case op_nstricteq: {
+ ARITHMETIC_OP();
+ NodeIndex op1 = get(currentInstruction[2].u.operand);
+ NodeIndex op2 = get(currentInstruction[3].u.operand);
+ set(currentInstruction[1].u.operand, addToGraph(LogicalNot, addToGraph(CompareStrictEq, op1, op2)));
+ NEXT_OPCODE(op_nstricteq);
+ }
+
+ // === Property access operations ===
+
+ case op_get_by_val: {
+ NodeIndex base = get(currentInstruction[2].u.operand);
+ NodeIndex property = get(currentInstruction[3].u.operand);
+ predictArray(base);
+ predictInt32(property);
+
+ NodeIndex getByVal = addToGraph(GetByVal, base, property, aliases.lookupGetByVal(base, property));
+ set(currentInstruction[1].u.operand, getByVal);
+ aliases.recordGetByVal(getByVal);
+
+ NEXT_OPCODE(op_get_by_val);
+ }
+
+ case op_put_by_val: {
+ NodeIndex base = get(currentInstruction[1].u.operand);
+ NodeIndex property = get(currentInstruction[2].u.operand);
+ NodeIndex value = get(currentInstruction[3].u.operand);
+ predictArray(base);
+ predictInt32(property);
+
+ NodeIndex aliasedGet = aliases.lookupGetByVal(base, property);
+ NodeIndex putByVal = addToGraph(aliasedGet != NoNode ? PutByValAlias : PutByVal, base, property, value);
+ aliases.recordPutByVal(putByVal);
+
+ NEXT_OPCODE(op_put_by_val);
+ }
+
+ case op_get_by_id: {
+ NodeIndex base = get(currentInstruction[2].u.operand);
+ unsigned identifier = currentInstruction[3].u.operand;
+
+ NodeIndex getById = addToGraph(GetById, OpInfo(identifier), base);
+ set(currentInstruction[1].u.operand, getById);
+ aliases.recordGetById(getById);
+
+ NEXT_OPCODE(op_get_by_id);
+ }
+
+ case op_put_by_id: {
+ NodeIndex value = get(currentInstruction[3].u.operand);
+ NodeIndex base = get(currentInstruction[1].u.operand);
+ unsigned identifier = currentInstruction[2].u.operand;
+ bool direct = currentInstruction[8].u.operand;
+
+ if (direct) {
+ NodeIndex putByIdDirect = addToGraph(PutByIdDirect, OpInfo(identifier), base, value);
+ aliases.recordPutByIdDirect(putByIdDirect);
+ } else {
+ NodeIndex putById = addToGraph(PutById, OpInfo(identifier), base, value);
+ aliases.recordPutById(putById);
+ }
+
+ NEXT_OPCODE(op_put_by_id);
+ }
+
+ case op_get_global_var: {
+ NodeIndex getGlobalVar = addToGraph(GetGlobalVar, OpInfo(currentInstruction[2].u.operand));
+ set(currentInstruction[1].u.operand, getGlobalVar);
+ NEXT_OPCODE(op_get_global_var);
+ }
+
+ case op_put_global_var: {
+ NodeIndex value = get(currentInstruction[2].u.operand);
+ addToGraph(PutGlobalVar, OpInfo(currentInstruction[1].u.operand), value);
+ NEXT_OPCODE(op_put_global_var);
+ }
+
+ // === Block terminators. ===
+
+ case op_jmp: {
+ unsigned relativeOffset = currentInstruction[1].u.operand;
+ addToGraph(Jump, OpInfo(m_currentIndex + relativeOffset));
+ LAST_OPCODE(op_jmp);
+ }
+
+ case op_loop: {
+ unsigned relativeOffset = currentInstruction[1].u.operand;
+ addToGraph(Jump, OpInfo(m_currentIndex + relativeOffset));
+ LAST_OPCODE(op_loop);
+ }
+
+ case op_jtrue: {
+ unsigned relativeOffset = currentInstruction[2].u.operand;
+ NodeIndex condition = get(currentInstruction[1].u.operand);
+ addToGraph(Branch, OpInfo(m_currentIndex + relativeOffset), OpInfo(m_currentIndex + OPCODE_LENGTH(op_jtrue)), condition);
+ LAST_OPCODE(op_jtrue);
+ }
+
+ case op_jfalse: {
+ unsigned relativeOffset = currentInstruction[2].u.operand;
+ NodeIndex condition = get(currentInstruction[1].u.operand);
+ addToGraph(Branch, OpInfo(m_currentIndex + OPCODE_LENGTH(op_jfalse)), OpInfo(m_currentIndex + relativeOffset), condition);
+ LAST_OPCODE(op_jfalse);
+ }
+
+ case op_loop_if_true: {
+ unsigned relativeOffset = currentInstruction[2].u.operand;
+ NodeIndex condition = get(currentInstruction[1].u.operand);
+ addToGraph(Branch, OpInfo(m_currentIndex + relativeOffset), OpInfo(m_currentIndex + OPCODE_LENGTH(op_loop_if_true)), condition);
+ LAST_OPCODE(op_loop_if_true);
+ }
+
+ case op_loop_if_false: {
+ unsigned relativeOffset = currentInstruction[2].u.operand;
+ NodeIndex condition = get(currentInstruction[1].u.operand);
+ addToGraph(Branch, OpInfo(m_currentIndex + OPCODE_LENGTH(op_loop_if_false)), OpInfo(m_currentIndex + relativeOffset), condition);
+ LAST_OPCODE(op_loop_if_false);
+ }
+
+ case op_jeq_null: {
+ unsigned relativeOffset = currentInstruction[2].u.operand;
+ NodeIndex value = get(currentInstruction[1].u.operand);
+ NodeIndex condition = addToGraph(CompareEq, value, constantNull());
+ addToGraph(Branch, OpInfo(m_currentIndex + relativeOffset), OpInfo(m_currentIndex + OPCODE_LENGTH(op_jeq_null)), condition);
+ LAST_OPCODE(op_jeq_null);
+ }
+
+ case op_jneq_null: {
+ unsigned relativeOffset = currentInstruction[2].u.operand;
+ NodeIndex value = get(currentInstruction[1].u.operand);
+ NodeIndex condition = addToGraph(CompareEq, value, constantNull());
+ addToGraph(Branch, OpInfo(m_currentIndex + OPCODE_LENGTH(op_jneq_null)), OpInfo(m_currentIndex + relativeOffset), condition);
+ LAST_OPCODE(op_jneq_null);
+ }
+
+ case op_jnless: {
+ unsigned relativeOffset = currentInstruction[3].u.operand;
+ NodeIndex op1 = get(currentInstruction[1].u.operand);
+ NodeIndex op2 = get(currentInstruction[2].u.operand);
+ NodeIndex condition = addToGraph(CompareLess, op1, op2);
+ addToGraph(Branch, OpInfo(m_currentIndex + OPCODE_LENGTH(op_jnless)), OpInfo(m_currentIndex + relativeOffset), condition);
+ LAST_OPCODE(op_jnless);
+ }
+
+ case op_jnlesseq: {
+ unsigned relativeOffset = currentInstruction[3].u.operand;
+ NodeIndex op1 = get(currentInstruction[1].u.operand);
+ NodeIndex op2 = get(currentInstruction[2].u.operand);
+ NodeIndex condition = addToGraph(CompareLessEq, op1, op2);
+ addToGraph(Branch, OpInfo(m_currentIndex + OPCODE_LENGTH(op_jnlesseq)), OpInfo(m_currentIndex + relativeOffset), condition);
+ LAST_OPCODE(op_jnlesseq);
+ }
+
+ case op_jless: {
+ unsigned relativeOffset = currentInstruction[3].u.operand;
+ NodeIndex op1 = get(currentInstruction[1].u.operand);
+ NodeIndex op2 = get(currentInstruction[2].u.operand);
+ NodeIndex condition = addToGraph(CompareLess, op1, op2);
+ addToGraph(Branch, OpInfo(m_currentIndex + relativeOffset), OpInfo(m_currentIndex + OPCODE_LENGTH(op_jless)), condition);
+ LAST_OPCODE(op_jless);
+ }
+
+ case op_jlesseq: {
+ unsigned relativeOffset = currentInstruction[3].u.operand;
+ NodeIndex op1 = get(currentInstruction[1].u.operand);
+ NodeIndex op2 = get(currentInstruction[2].u.operand);
+ NodeIndex condition = addToGraph(CompareLessEq, op1, op2);
+ addToGraph(Branch, OpInfo(m_currentIndex + relativeOffset), OpInfo(m_currentIndex + OPCODE_LENGTH(op_jlesseq)), condition);
+ LAST_OPCODE(op_jlesseq);
+ }
+
+ case op_loop_if_less: {
+ unsigned relativeOffset = currentInstruction[3].u.operand;
+ NodeIndex op1 = get(currentInstruction[1].u.operand);
+ NodeIndex op2 = get(currentInstruction[2].u.operand);
+ NodeIndex condition = addToGraph(CompareLess, op1, op2);
+ addToGraph(Branch, OpInfo(m_currentIndex + relativeOffset), OpInfo(m_currentIndex + OPCODE_LENGTH(op_loop_if_less)), condition);
+ LAST_OPCODE(op_loop_if_less);
+ }
+
+ case op_loop_if_lesseq: {
+ unsigned relativeOffset = currentInstruction[3].u.operand;
+ NodeIndex op1 = get(currentInstruction[1].u.operand);
+ NodeIndex op2 = get(currentInstruction[2].u.operand);
+ NodeIndex condition = addToGraph(CompareLessEq, op1, op2);
+ addToGraph(Branch, OpInfo(m_currentIndex + relativeOffset), OpInfo(m_currentIndex + OPCODE_LENGTH(op_loop_if_lesseq)), condition);
+ LAST_OPCODE(op_loop_if_lesseq);
+ }
+
+ case op_ret: {
+ addToGraph(Return, get(currentInstruction[1].u.operand));
+ LAST_OPCODE(op_ret);
+ }
+
+ default:
+ // Parse failed!
+ return false;
+ }
+ }
+}
+
+template<ByteCodeParser::PhiStackType stackType>
+void ByteCodeParser::processPhiStack()
+{
+ Vector<PhiStackEntry, 16>& phiStack = (stackType == ArgumentPhiStack) ? m_argumentPhiStack : m_localPhiStack;
+
+ while (!phiStack.isEmpty()) {
+ PhiStackEntry entry = phiStack.last();
+ phiStack.removeLast();
+
+ Node& phiNode = m_graph[entry.m_phi];
+ PredecessorList& predecessors = entry.m_block->m_predecessors;
+ unsigned varNo = entry.m_varNo;
+
+ for (size_t i = 0; i < predecessors.size(); ++i) {
+ BasicBlock* predecessorBlock = m_graph.m_blocks[predecessors[i]].get();
+
+ VariableRecord& var = (stackType == ArgumentPhiStack) ? predecessorBlock->m_arguments[varNo] : predecessorBlock->m_locals[varNo];
+
+ NodeIndex valueInPredecessor = var.value;
+ if (valueInPredecessor == NoNode) {
+ valueInPredecessor = addToGraph(Phi);
+ var.value = valueInPredecessor;
+ phiStack.append(PhiStackEntry(predecessorBlock, valueInPredecessor, varNo));
+ } else if (m_graph[valueInPredecessor].op == GetLocal)
+ valueInPredecessor = m_graph[valueInPredecessor].child1;
+ ASSERT(m_graph[valueInPredecessor].op == SetLocal || m_graph[valueInPredecessor].op == Phi);
+
+ if (phiNode.refCount())
+ m_graph.ref(valueInPredecessor);
+
+ if (phiNode.child1 == NoNode) {
+ phiNode.child1 = valueInPredecessor;
+ continue;
+ }
+ if (phiNode.child2 == NoNode) {
+ phiNode.child2 = valueInPredecessor;
+ continue;
+ }
+ if (phiNode.child3 == NoNode) {
+ phiNode.child3 = valueInPredecessor;
+ continue;
+ }
+
+ NodeIndex newPhi = addToGraph(Phi);
+ Node& newPhiNode = m_graph[newPhi];
+ if (phiNode.refCount())
+ m_graph.ref(newPhi);
+
+ newPhiNode.child1 = phiNode.child1;
+ newPhiNode.child2 = phiNode.child2;
+ newPhiNode.child3 = phiNode.child3;
+
+ phiNode.child1 = newPhi;
+ phiNode.child1 = valueInPredecessor;
+ phiNode.child3 = NoNode;
+ }
+ }
+}
+
+void ByteCodeParser::setupPredecessors()
+{
+ for (BlockIndex index = 0; index < m_graph.m_blocks.size(); ++index) {
+ BasicBlock* block = m_graph.m_blocks[index].get();
+ ASSERT(block->end != NoNode);
+ Node& node = m_graph[block->end - 1];
+ ASSERT(node.isTerminal());
+
+ if (node.isJump())
+ m_graph.blockForBytecodeOffset(node.takenBytecodeOffset()).m_predecessors.append(index);
+ else if (node.isBranch()) {
+ m_graph.blockForBytecodeOffset(node.takenBytecodeOffset()).m_predecessors.append(index);
+ m_graph.blockForBytecodeOffset(node.notTakenBytecodeOffset()).m_predecessors.append(index);
+ }
+ }
+}
+
+void ByteCodeParser::allocateVirtualRegisters()
+{
+ ScoreBoard scoreBoard(m_graph, m_preservedVars);
+ unsigned sizeExcludingPhiNodes = m_graph.m_blocks.last()->end;
+ for (size_t i = 0; i < sizeExcludingPhiNodes; ++i) {
+ Node& node = m_graph[i];
+ if (!node.shouldGenerate())
+ continue;
+
+ // GetLocal nodes are effectively phi nodes in the graph, referencing
+ // results from prior blocks.
+ if (node.op != GetLocal) {
+ // First, call use on all of the current node's children, then
+ // allocate a VirtualRegister for this node. We do so in this
+ // order so that if a child is on its last use, and a
+ // VirtualRegister is freed, then it may be reused for node.
+ scoreBoard.use(node.child1);
+ scoreBoard.use(node.child2);
+ scoreBoard.use(node.child3);
+ }
+
+ if (!node.hasResult())
+ continue;
+
+ node.setVirtualRegister(scoreBoard.allocate());
+ // 'mustGenerate' nodes have their useCount artificially elevated,
+ // call use now to account for this.
+ if (node.mustGenerate())
+ scoreBoard.use(i);
+ }
+
+ // 'm_numCalleeRegisters' is the number of locals and temporaries allocated
+ // for the function (and checked for on entry). Since we perform a new and
+ // different allocation of temporaries, more registers may now be required.
+ unsigned calleeRegisters = scoreBoard.allocatedCount() + m_preservedVars;
+ if ((unsigned)m_codeBlock->m_numCalleeRegisters < calleeRegisters)
+ m_codeBlock->m_numCalleeRegisters = calleeRegisters;
+}
+
+bool ByteCodeParser::parse()
+{
+ // Set during construction.
+ ASSERT(!m_currentIndex);
+
+ for (unsigned jumpTargetIndex = 0; jumpTargetIndex <= m_codeBlock->numberOfJumpTargets(); ++jumpTargetIndex) {
+ // The maximum bytecode offset to go into the current basicblock is either the next jump target, or the end of the instructions.
+ unsigned limit = jumpTargetIndex < m_codeBlock->numberOfJumpTargets() ? m_codeBlock->jumpTarget(jumpTargetIndex) : m_codeBlock->instructions().size();
+ ASSERT(m_currentIndex < limit);
+
+ // Loop until we reach the current limit (i.e. next jump target).
+ do {
+ OwnPtr<BasicBlock> block = adoptPtr(new BasicBlock(m_currentIndex, m_graph.size(), m_numArguments, m_numLocals));
+ m_currentBlock = block.get();
+ m_graph.m_blocks.append(block.release());
+
+ if (!parseBlock(limit))
+ return false;
+ // We should not have gone beyond the limit.
+ ASSERT(m_currentIndex <= limit);
+
+ m_currentBlock->end = m_graph.size();
+ } while (m_currentIndex < limit);
+ }
+
+ // Should have reached the end of the instructions.
+ ASSERT(m_currentIndex == m_codeBlock->instructions().size());
+
+ setupPredecessors();
+ processPhiStack<LocalPhiStack>();
+ processPhiStack<ArgumentPhiStack>();
+
+ allocateVirtualRegisters();
+
+#if DFG_DEBUG_VERBOSE
+ m_graph.dump(m_codeBlock);
+#endif
+
+ return true;
+}
+
+bool parse(Graph& graph, JSGlobalData* globalData, CodeBlock* codeBlock)
+{
+#if DFG_DEBUG_LOCAL_DISBALE
+ UNUSED_PARAM(graph);
+ UNUSED_PARAM(globalData);
+ UNUSED_PARAM(codeBlock);
+ return false;
+#else
+ return ByteCodeParser(globalData, codeBlock, graph).parse();
+#endif
+}
+
+} } // namespace JSC::DFG
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DFGByteCodeParser_h
+#define DFGByteCodeParser_h
+
+#if ENABLE(DFG_JIT)
+
+#include <dfg/DFGGraph.h>
+
+namespace JSC {
+
+class CodeBlock;
+class JSGlobalData;
+
+namespace DFG {
+
+// Populate the Graph with a basic block of code from the CodeBlock,
+// starting at the provided bytecode index.
+bool parse(Graph&, JSGlobalData*, CodeBlock*);
+
+} } // namespace JSC::DFG
+
+#endif
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DFGFPRInfo_h
+#define DFGFPRInfo_h
+
+#if ENABLE(DFG_JIT)
+
+#include <assembler/MacroAssembler.h>
+#include <dfg/DFGRegisterBank.h>
+
+namespace JSC { namespace DFG {
+
+typedef MacroAssembler::FPRegisterID FPRReg;
+#define InvalidFPRReg ((FPRReg)-1)
+
+class FPRInfo {
+public:
+ typedef FPRReg RegisterType;
+ static const unsigned numberOfRegisters = 6;
+
+ // Temporary registers.
+ static const FPRReg fpRegT0 = X86Registers::xmm0;
+ static const FPRReg fpRegT1 = X86Registers::xmm1;
+ static const FPRReg fpRegT2 = X86Registers::xmm2;
+ static const FPRReg fpRegT3 = X86Registers::xmm3;
+ static const FPRReg fpRegT4 = X86Registers::xmm4;
+ static const FPRReg fpRegT5 = X86Registers::xmm5;
+ // These constants provide the names for the general purpose argument & return value registers.
+ static const FPRReg argumentFPR0 = X86Registers::xmm0; // fpRegT0
+ static const FPRReg argumentFPR1 = X86Registers::xmm1; // fpRegT1
+ static const FPRReg argumentFPR2 = X86Registers::xmm2; // fpRegT2
+ static const FPRReg argumentFPR3 = X86Registers::xmm3; // fpRegT3
+ static const FPRReg returnValueFPR = X86Registers::xmm0; // fpRegT0
+
+ // FPRReg mapping is direct, the machine regsiter numbers can
+ // be used directly as indices into the FPR RegisterBank.
+ COMPILE_ASSERT(X86Registers::xmm0 == 0, xmm0_is_0);
+ COMPILE_ASSERT(X86Registers::xmm1 == 1, xmm1_is_1);
+ COMPILE_ASSERT(X86Registers::xmm2 == 2, xmm2_is_2);
+ COMPILE_ASSERT(X86Registers::xmm3 == 3, xmm3_is_3);
+ COMPILE_ASSERT(X86Registers::xmm4 == 4, xmm4_is_4);
+ COMPILE_ASSERT(X86Registers::xmm5 == 5, xmm5_is_5);
+ static FPRReg toRegister(unsigned index)
+ {
+ return (FPRReg)index;
+ }
+ static unsigned toIndex(FPRReg reg)
+ {
+ return (unsigned)reg;
+ }
+
+#ifndef NDEBUG
+ static const char* debugName(FPRReg reg)
+ {
+ ASSERT(reg != InvalidFPRReg);
+ ASSERT(reg < 16);
+ static const char* nameForRegister[16] = {
+ "xmm0", "xmm1", "xmm2", "xmm3",
+ "xmm4", "xmm5", "xmm6", "xmm7",
+ "xmm8", "xmm9", "xmm10", "xmm11",
+ "xmm12", "xmm13", "xmm14", "xmm15"
+ };
+ return nameForRegister[reg];
+ }
+#endif
+};
+
+typedef RegisterBank<FPRInfo>::iterator fpr_iterator;
+
+} } // namespace JSC::DFG
+
+#endif
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DFGGPRInfo_h
+#define DFGGPRInfo_h
+
+#if ENABLE(DFG_JIT)
+
+#include <assembler/MacroAssembler.h>
+#include <dfg/DFGRegisterBank.h>
+
+namespace JSC { namespace DFG {
+
+typedef MacroAssembler::RegisterID GPRReg;
+#define InvalidGPRReg ((GPRReg)-1)
+
+class GPRInfo {
+public:
+ typedef GPRReg RegisterType;
+ static const unsigned numberOfRegisters = 9;
+
+ // These registers match the old JIT.
+ static const GPRReg timeoutCheckRegister = X86Registers::r12;
+ static const GPRReg callFrameRegister = X86Registers::r13;
+ static const GPRReg tagTypeNumberRegister = X86Registers::r14;
+ static const GPRReg tagMaskRegister = X86Registers::r15;
+ // Temporary registers.
+ static const GPRReg regT0 = X86Registers::eax;
+ static const GPRReg regT1 = X86Registers::edx;
+ static const GPRReg regT2 = X86Registers::ecx;
+ static const GPRReg regT3 = X86Registers::ebx;
+ static const GPRReg regT4 = X86Registers::edi;
+ static const GPRReg regT5 = X86Registers::esi;
+ static const GPRReg regT6 = X86Registers::r8;
+ static const GPRReg regT7 = X86Registers::r9;
+ static const GPRReg regT8 = X86Registers::r10;
+ // These constants provide the names for the general purpose argument & return value registers.
+ static const GPRReg argumentGPR0 = X86Registers::edi; // regT4
+ static const GPRReg argumentGPR1 = X86Registers::esi; // regT5
+ static const GPRReg argumentGPR2 = X86Registers::edx; // regT1
+ static const GPRReg argumentGPR3 = X86Registers::ecx; // regT2
+ static const GPRReg returnValueGPR = X86Registers::eax; // regT0
+ static const GPRReg returnValueGPR2 = X86Registers::edx; // regT1
+
+ static GPRReg toRegister(unsigned index)
+ {
+ ASSERT(index < numberOfRegisters);
+ static const GPRReg registerForIndex[numberOfRegisters] = { regT0, regT1, regT2, regT3, regT4, regT5, regT6, regT7, regT8 };
+ return registerForIndex[index];
+ }
+
+ static unsigned toIndex(GPRReg reg)
+ {
+ ASSERT(reg != InvalidGPRReg);
+ ASSERT(reg < 16);
+ static const unsigned indexForRegister[16] = { 0, 2, 1, 3, InvalidIndex, InvalidIndex, 5, 4, 6, 7, 8, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex };
+ unsigned result = indexForRegister[reg];
+ ASSERT(result != InvalidIndex);
+ return result;
+ }
+
+#ifndef NDEBUG
+ static const char* debugName(GPRReg reg)
+ {
+ ASSERT(reg != InvalidGPRReg);
+ ASSERT(reg < 16);
+ static const char* nameForRegister[16] = {
+ "rax", "rcx", "rdx", "rbx",
+ "rsp", "rbp", "rsi", "rdi",
+ "r8", "r9", "r10", "r11",
+ "r12", "r13", "r14", "r15"
+ };
+ return nameForRegister[reg];
+ }
+#endif
+private:
+
+ static const unsigned InvalidIndex = 0xffffffff;
+};
+
+typedef RegisterBank<GPRInfo>::iterator gpr_iterator;
+
+} } // namespace JSC::DFG
+
+#endif
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DFGGenerationInfo_h
+#define DFGGenerationInfo_h
+
+#if ENABLE(DFG_JIT)
+
+#include <dfg/DFGJITCompiler.h>
+
+namespace JSC { namespace DFG {
+
+// === DataFormat ===
+//
+// This enum tracks the current representation in which a value is being held.
+// Values may be unboxed primitives (int32, double, or cell), or boxed as a JSValue.
+// For boxed values, we may know the type of boxing that has taken place.
+// (May also need bool, array, object, string types!)
+enum DataFormat {
+ DataFormatNone = 0,
+ DataFormatInteger = 1,
+ DataFormatDouble = 2,
+ DataFormatCell = 3,
+ DataFormatJS = 8,
+ DataFormatJSInteger = DataFormatJS | DataFormatInteger,
+ DataFormatJSDouble = DataFormatJS | DataFormatDouble,
+ DataFormatJSCell = DataFormatJS | DataFormatCell,
+};
+
+// === GenerationInfo ===
+//
+// This class is used to track the current status of a live values during code generation.
+// Can provide information as to whether a value is in machine registers, and if so which,
+// whether a value has been spilled to the RegsiterFile, and if so may be able to provide
+// details of the format in memory (all values are spilled in a boxed form, but we may be
+// able to track the type of box), and tracks how many outstanding uses of a value remain,
+// so that we know when the value is dead and the machine registers associated with it
+// may be released.
+class GenerationInfo {
+public:
+ GenerationInfo()
+ : m_nodeIndex(NoNode)
+ , m_useCount(0)
+ , m_registerFormat(DataFormatNone)
+ , m_spillFormat(DataFormatNone)
+ , m_canFill(false)
+ {
+ }
+
+ void initConstant(NodeIndex nodeIndex, uint32_t useCount)
+ {
+ m_nodeIndex = nodeIndex;
+ m_useCount = useCount;
+ m_registerFormat = DataFormatNone;
+ m_spillFormat = DataFormatNone;
+ m_canFill = true;
+ }
+ void initInteger(NodeIndex nodeIndex, uint32_t useCount, GPRReg gpr)
+ {
+ m_nodeIndex = nodeIndex;
+ m_useCount = useCount;
+ m_registerFormat = DataFormatInteger;
+ m_spillFormat = DataFormatNone;
+ m_canFill = false;
+ u.gpr = gpr;
+ }
+ void initJSValue(NodeIndex nodeIndex, uint32_t useCount, GPRReg gpr, DataFormat format = DataFormatJS)
+ {
+ ASSERT(format & DataFormatJS);
+
+ m_nodeIndex = nodeIndex;
+ m_useCount = useCount;
+ m_registerFormat = format;
+ m_spillFormat = DataFormatNone;
+ m_canFill = false;
+ u.gpr = gpr;
+ }
+ void initCell(NodeIndex nodeIndex, uint32_t useCount, GPRReg gpr)
+ {
+ m_nodeIndex = nodeIndex;
+ m_useCount = useCount;
+ m_registerFormat = DataFormatCell;
+ m_spillFormat = DataFormatNone;
+ m_canFill = false;
+ u.gpr = gpr;
+ }
+ void initDouble(NodeIndex nodeIndex, uint32_t useCount, FPRReg fpr)
+ {
+ m_nodeIndex = nodeIndex;
+ m_useCount = useCount;
+ m_registerFormat = DataFormatDouble;
+ m_spillFormat = DataFormatNone;
+ m_canFill = false;
+ u.fpr = fpr;
+ }
+
+ // Get the index of the node that produced this value.
+ NodeIndex nodeIndex() { return m_nodeIndex; }
+
+ // Mark the value as having been used (decrement the useCount).
+ // Returns true if this was the last use of the value, and any
+ // associated machine registers may be freed.
+ bool use()
+ {
+ return !--m_useCount;
+ }
+
+ // Used to check the operands of operations to see if they are on
+ // their last use; in some cases it may be safe to reuse the same
+ // machine register for the result of the operation.
+ bool canReuse()
+ {
+ ASSERT(m_useCount);
+ return m_useCount == 1;
+ }
+
+ // Get the format of the value in machine registers (or 'none').
+ DataFormat registerFormat() { return m_registerFormat; }
+ // Get the format of the value as it is spilled in the RegisterFile (or 'none').
+ DataFormat spillFormat() { return m_spillFormat; }
+
+ // Get the machine resister currently holding the value.
+ GPRReg gpr() { ASSERT(m_registerFormat && m_registerFormat != DataFormatDouble); return u.gpr; }
+ FPRReg fpr() { ASSERT(m_registerFormat == DataFormatDouble); return u.fpr; }
+
+ // Check whether a value needs spilling in order to free up any associated machine registers.
+ bool needsSpill()
+ {
+ // This should only be called on values that are currently in a register.
+ ASSERT(m_registerFormat != DataFormatNone);
+ // Constants do not need spilling, nor do values that have already been
+ // spilled to the RegisterFile.
+ return !m_canFill;
+ }
+
+ // Called when a VirtualRegister is being spilled to the RegisterFile for the first time.
+ void spill(DataFormat spillFormat)
+ {
+ // We shouldn't be spill values that don't need spilling.
+ ASSERT(!m_canFill);
+ ASSERT(m_spillFormat == DataFormatNone);
+ // We should only be spilling values that are currently in machine registers.
+ ASSERT(m_registerFormat != DataFormatNone);
+ // We only spill values that have been boxed as a JSValue; otherwise the GC
+ // would need a way to distinguish cell pointers from numeric primitives.
+ ASSERT(spillFormat & DataFormatJS);
+
+ m_registerFormat = DataFormatNone;
+ m_spillFormat = spillFormat;
+ m_canFill = true;
+ }
+
+ // Called on values that don't need spilling (constants and values that have
+ // already been spilled), to mark them as no longer being in machine registers.
+ void setSpilled()
+ {
+ // Should only be called on values that don't need spilling, and are currently in registers.
+ ASSERT(m_canFill && m_registerFormat != DataFormatNone);
+ m_registerFormat = DataFormatNone;
+ }
+
+ // Record that this value is filled into machine registers,
+ // tracking which registers, and what format the value has.
+ void fillJSValue(GPRReg gpr, DataFormat format = DataFormatJS)
+ {
+ ASSERT(format & DataFormatJS);
+ m_registerFormat = format;
+ u.gpr = gpr;
+ }
+ void fillInteger(GPRReg gpr)
+ {
+ m_registerFormat = DataFormatInteger;
+ u.gpr = gpr;
+ }
+ void fillDouble(FPRReg fpr)
+ {
+ m_registerFormat = DataFormatDouble;
+ u.fpr = fpr;
+ }
+
+#ifndef NDEBUG
+ bool alive()
+ {
+ return m_useCount;
+ }
+#endif
+
+private:
+ // The index of the node whose result is stored in this virtual register.
+ // FIXME: Can we remove this? - this is currently only used when collecting
+ // snapshots of the RegisterBank for SpeculationCheck/EntryLocation. Could
+ // investigate storing NodeIndex as the name in RegsiterBank, instead of
+ // VirtualRegister.
+ NodeIndex m_nodeIndex;
+ uint32_t m_useCount;
+ DataFormat m_registerFormat;
+ DataFormat m_spillFormat;
+ bool m_canFill;
+ union {
+ GPRReg gpr;
+ FPRReg fpr;
+ } u;
+};
+
+} } // namespace JSC::DFG
+
+#endif
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DFGGraph.h"
+
+#include "CodeBlock.h"
+
+#if ENABLE(DFG_JIT)
+
+namespace JSC { namespace DFG {
+
+#ifndef NDEBUG
+
+// Creates an array of stringized names.
+static const char* dfgOpNames[] = {
+#define STRINGIZE_DFG_OP_ENUM(opcode, flags) #opcode ,
+ FOR_EACH_DFG_OP(STRINGIZE_DFG_OP_ENUM)
+#undef STRINGIZE_DFG_OP_ENUM
+};
+
+void Graph::dump(NodeIndex nodeIndex, CodeBlock* codeBlock)
+{
+ Node& node = at(nodeIndex);
+ NodeType op = node.op;
+
+ unsigned refCount = node.refCount();
+ if (!refCount)
+ return;
+ bool mustGenerate = node.mustGenerate();
+ if (mustGenerate)
+ --refCount;
+
+ // Example/explanation of dataflow dump output
+ //
+ // 14: <!2:7> GetByVal(@3, @13)
+ // ^1 ^2 ^3 ^4 ^5
+ //
+ // (1) The nodeIndex of this operation.
+ // (2) The reference count. The number printed is the 'real' count,
+ // not including the 'mustGenerate' ref. If the node is
+ // 'mustGenerate' then the count it prefixed with '!'.
+ // (3) The virtual register slot assigned to this node.
+ // (4) The name of the operation.
+ // (5) The arguments to the operation. The may be of the form:
+ // @# - a NodeIndex referencing a prior node in the graph.
+ // arg# - an argument number.
+ // $# - the index in the CodeBlock of a constant { for numeric constants the value is displayed | for integers, in both decimal and hex }.
+ // id# - the index in the CodeBlock of an identifier { if codeBlock is passed to dump(), the string representation is displayed }.
+ // var# - the index of a var on the global object, used by GetGlobalVar/PutGlobalVar operations.
+ printf("% 4d:\t<%c%u:", (int)nodeIndex, mustGenerate ? '!' : ' ', refCount);
+ if (node.hasResult())
+ printf("%u", node.virtualRegister());
+ else
+ printf("-");
+ printf(">\t%s(", dfgOpNames[op & NodeIdMask]);
+ if (node.child1 != NoNode)
+ printf("@%u", node.child1);
+ if (node.child2 != NoNode)
+ printf(", @%u", node.child2);
+ if (node.child3 != NoNode)
+ printf(", @%u", node.child3);
+ bool hasPrinted = node.child1 != NoNode;
+
+ if (node.hasVarNumber()) {
+ printf("%svar%u", hasPrinted ? ", " : "", node.varNumber());
+ hasPrinted = true;
+ }
+ if (node.hasIdentifier()) {
+ if (codeBlock)
+ printf("%sid%u{%s}", hasPrinted ? ", " : "", node.identifierNumber(), codeBlock->identifier(node.identifierNumber()).ustring().utf8().data());
+ else
+ printf("%sid%u", hasPrinted ? ", " : "", node.identifierNumber());
+ hasPrinted = true;
+ }
+ if (node.hasLocal()) {
+ int local = node.local();
+ if (operandIsArgument(local))
+ printf("%sarg%u", hasPrinted ? ", " : "", local - codeBlock->thisRegister());
+ else
+ printf("%sr%u", hasPrinted ? ", " : "", local);
+ hasPrinted = true;
+ }
+ if (op == Int32Constant) {
+ printf("%s$%u{%d|0x%08x}", hasPrinted ? ", " : "", node.constantNumber(), node.int32Constant(), node.int32Constant());
+ hasPrinted = true;
+ }
+ if (op == DoubleConstant) {
+ printf("%s$%u{%f})", hasPrinted ? ", " : "", node.constantNumber(), node.numericConstant());
+ hasPrinted = true;
+ }
+ if (op == JSConstant) {
+ printf("%s$%u", hasPrinted ? ", " : "", node.constantNumber());
+ hasPrinted = true;
+ }
+ if (node.isBranch() || node.isJump()) {
+ printf("%sT:#%u", hasPrinted ? ", " : "", blockIndexForBytecodeOffset(node.takenBytecodeOffset()));
+ hasPrinted = true;
+ }
+ if (node.isBranch()) {
+ printf("%sF:#%u", hasPrinted ? ", " : "", blockIndexForBytecodeOffset(node.notTakenBytecodeOffset()));
+ hasPrinted = true;
+ }
+
+ printf(")\n");
+}
+
+void Graph::dump(CodeBlock* codeBlock)
+{
+ for (size_t b = 0; b < m_blocks.size(); ++b) {
+ printf("Block #%u:\n", (int)b);
+ for (size_t i = m_blocks[b]->begin; i < m_blocks[b]->end; ++i)
+ dump(i, codeBlock);
+ }
+ printf("Phi Nodes:\n");
+ for (size_t i = m_blocks.last()->end; i < size(); ++i)
+ dump(i, codeBlock);
+}
+
+#endif
+
+// FIXME: Convert this method to be iterative, not recursive.
+void Graph::refChildren(NodeIndex op)
+{
+ Node& node = at(op);
+
+ if (node.child1 == NoNode) {
+ ASSERT(node.child2 == NoNode && node.child3 == NoNode);
+ return;
+ }
+ ref(node.child1);
+
+ if (node.child2 == NoNode) {
+ ASSERT(node.child3 == NoNode);
+ return;
+ }
+ ref(node.child2);
+
+ if (node.child3 == NoNode)
+ return;
+ ref(node.child3);
+}
+
+} } // namespace JSC::DFG
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DFGGraph_h
+#define DFGGraph_h
+
+#if ENABLE(DFG_JIT)
+
+#include <RegisterFile.h>
+#include <dfg/DFGNode.h>
+#include <wtf/Vector.h>
+#include <wtf/StdLibExtras.h>
+
+namespace JSC {
+
+class CodeBlock;
+
+namespace DFG {
+
+// helper function to distinguish vars & temporaries from arguments.
+inline bool operandIsArgument(int operand) { return operand < 0; }
+
+typedef uint8_t PredictedType;
+static const PredictedType PredictNone = 0;
+static const PredictedType PredictCell = 0x01;
+static const PredictedType PredictArray = 0x03;
+static const PredictedType PredictInt32 = 0x04;
+
+struct PredictionSlot {
+public:
+ PredictionSlot()
+ : m_value(PredictNone)
+ {
+ }
+ PredictedType m_value;
+};
+
+typedef uint32_t BlockIndex;
+
+// For every local variable we track any existing get or set of the value.
+// We track the get so that these may be shared, and we track the set to
+// retrieve the current value, and to reference the final definition.
+struct VariableRecord {
+ VariableRecord()
+ : value(NoNode)
+ {
+ }
+
+ NodeIndex value;
+};
+
+typedef Vector <BlockIndex, 2> PredecessorList;
+
+struct BasicBlock {
+ BasicBlock(unsigned bytecodeBegin, NodeIndex begin, unsigned numArguments, unsigned numLocals)
+ : bytecodeBegin(bytecodeBegin)
+ , begin(begin)
+ , end(NoNode)
+ , m_arguments(numArguments)
+ , m_locals(numLocals)
+ {
+ }
+
+ static inline BlockIndex getBytecodeBegin(OwnPtr<BasicBlock>* block)
+ {
+ return (*block)->bytecodeBegin;
+ }
+
+ unsigned bytecodeBegin;
+ NodeIndex begin;
+ NodeIndex end;
+
+ PredecessorList m_predecessors;
+ Vector <VariableRecord, 8> m_arguments;
+ Vector <VariableRecord, 16> m_locals;
+};
+
+//
+// === Graph ===
+//
+// The dataflow graph is an ordered vector of nodes.
+// The order may be significant for nodes with side-effects (property accesses, value conversions).
+// Nodes that are 'dead' remain in the vector with refCount 0.
+class Graph : public Vector<Node, 64> {
+public:
+ Graph(unsigned numArguments, unsigned numVariables)
+ : m_argumentPredictions(numArguments)
+ , m_variablePredictions(numVariables)
+ {
+ }
+
+ // Mark a node as being referenced.
+ void ref(NodeIndex nodeIndex)
+ {
+ Node& node = at(nodeIndex);
+ // If the value (before incrementing) was at refCount zero then we need to ref its children.
+ if (node.ref())
+ refChildren(nodeIndex);
+ }
+
+#ifndef NDEBUG
+ // CodeBlock is optional, but may allow additional information to be dumped (e.g. Identifier names).
+ void dump(CodeBlock* = 0);
+ void dump(NodeIndex, CodeBlock* = 0);
+#endif
+
+ BlockIndex blockIndexForBytecodeOffset(unsigned bytecodeBegin)
+ {
+ OwnPtr<BasicBlock>* begin = m_blocks.begin();
+ OwnPtr<BasicBlock>* block = binarySearch<OwnPtr<BasicBlock>, unsigned, BasicBlock::getBytecodeBegin>(begin, m_blocks.size(), bytecodeBegin);
+ ASSERT(block >= m_blocks.begin() && block < m_blocks.end());
+ return static_cast<BlockIndex>(block - begin);
+ }
+
+ BasicBlock& blockForBytecodeOffset(unsigned bytecodeBegin)
+ {
+ return *m_blocks[blockIndexForBytecodeOffset(bytecodeBegin)];
+ }
+
+ void predict(int operand, PredictedType prediction)
+ {
+ if (operandIsArgument(operand)) {
+ unsigned argument = operand + m_argumentPredictions.size() + RegisterFile::CallFrameHeaderSize;
+ m_argumentPredictions[argument].m_value |= prediction;
+ } else if ((unsigned)operand < m_variablePredictions.size())
+ m_variablePredictions[operand].m_value |= prediction;
+
+ }
+
+ PredictedType getPrediction(int operand)
+ {
+ if (operandIsArgument(operand)) {
+ unsigned argument = operand + m_argumentPredictions.size() + RegisterFile::CallFrameHeaderSize;
+ return m_argumentPredictions[argument].m_value;
+ }
+ if ((unsigned)operand < m_variablePredictions.size())
+ return m_variablePredictions[operand].m_value;
+ return PredictNone;
+ }
+
+ Vector< OwnPtr<BasicBlock> , 8> m_blocks;
+private:
+
+ // When a node's refCount goes from 0 to 1, it must (logically) recursively ref all of its children, and vice versa.
+ void refChildren(NodeIndex);
+
+ Vector<PredictionSlot, 16> m_argumentPredictions;
+ Vector<PredictionSlot, 16> m_variablePredictions;
+};
+
+} } // namespace JSC::DFG
+
+#endif
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DFGJITCodeGenerator.h"
+
+#if ENABLE(DFG_JIT)
+
+#include "DFGNonSpeculativeJIT.h"
+#include "DFGSpeculativeJIT.h"
+#include "LinkBuffer.h"
+
+namespace JSC { namespace DFG {
+
+GPRReg JITCodeGenerator::fillInteger(NodeIndex nodeIndex, DataFormat& returnFormat)
+{
+ Node& node = m_jit.graph()[nodeIndex];
+ VirtualRegister virtualRegister = node.virtualRegister();
+ GenerationInfo& info = m_generationInfo[virtualRegister];
+
+ if (info.registerFormat() == DataFormatNone) {
+ GPRReg gpr = allocate();
+
+ if (node.isConstant()) {
+ m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
+ if (isInt32Constant(nodeIndex)) {
+ m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(nodeIndex)), gpr);
+ info.fillInteger(gpr);
+ returnFormat = DataFormatInteger;
+ return gpr;
+ }
+ if (isDoubleConstant(nodeIndex)) {
+ JSValue jsValue = jsNumber(valueOfDoubleConstant(nodeIndex));
+ m_jit.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), gpr);
+ } else {
+ ASSERT(isJSConstant(nodeIndex));
+ JSValue jsValue = valueOfJSConstant(nodeIndex);
+ m_jit.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), gpr);
+ }
+ } else {
+ ASSERT(info.spillFormat() == DataFormatJS || info.spillFormat() == DataFormatJSInteger);
+ m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
+ m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr);
+ }
+
+ // Since we statically know that we're filling an integer, and values
+ // in the RegisterFile are boxed, this must be DataFormatJSInteger.
+ // We will check this with a jitAssert below.
+ info.fillJSValue(gpr, DataFormatJSInteger);
+ unlock(gpr);
+ }
+
+ switch (info.registerFormat()) {
+ case DataFormatNone:
+ // Should have filled, above.
+ case DataFormatJSDouble:
+ case DataFormatDouble:
+ case DataFormatJS:
+ case DataFormatCell:
+ case DataFormatJSCell:
+ // Should only be calling this function if we know this operand to be integer.
+ ASSERT_NOT_REACHED();
+
+ case DataFormatJSInteger: {
+ GPRReg gpr = info.gpr();
+ m_gprs.lock(gpr);
+ m_jit.jitAssertIsJSInt32(gpr);
+ returnFormat = DataFormatJSInteger;
+ return gpr;
+ }
+
+ case DataFormatInteger: {
+ GPRReg gpr = info.gpr();
+ m_gprs.lock(gpr);
+ m_jit.jitAssertIsInt32(gpr);
+ returnFormat = DataFormatInteger;
+ return gpr;
+ }
+ }
+
+ ASSERT_NOT_REACHED();
+ return InvalidGPRReg;
+}
+
+FPRReg JITCodeGenerator::fillDouble(NodeIndex nodeIndex)
+{
+ Node& node = m_jit.graph()[nodeIndex];
+ VirtualRegister virtualRegister = node.virtualRegister();
+ GenerationInfo& info = m_generationInfo[virtualRegister];
+
+ if (info.registerFormat() == DataFormatNone) {
+ GPRReg gpr = allocate();
+
+ if (node.isConstant()) {
+ if (isInt32Constant(nodeIndex)) {
+ // FIXME: should not be reachable?
+ m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(nodeIndex)), gpr);
+ m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
+ info.fillInteger(gpr);
+ unlock(gpr);
+ } else if (isDoubleConstant(nodeIndex)) {
+ FPRReg fpr = fprAllocate();
+ m_jit.move(MacroAssembler::ImmPtr(reinterpret_cast<void*>(reinterpretDoubleToIntptr(valueOfDoubleConstant(nodeIndex)))), gpr);
+ m_jit.movePtrToDouble(gpr, fpr);
+ unlock(gpr);
+
+ m_fprs.retain(fpr, virtualRegister, SpillOrderDouble);
+ info.fillDouble(fpr);
+ return fpr;
+ } else {
+ // FIXME: should not be reachable?
+ ASSERT(isJSConstant(nodeIndex));
+ JSValue jsValue = valueOfJSConstant(nodeIndex);
+ m_jit.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), gpr);
+ m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
+ info.fillJSValue(gpr, DataFormatJS);
+ unlock(gpr);
+ }
+ } else {
+ DataFormat spillFormat = info.spillFormat();
+ ASSERT(spillFormat & DataFormatJS);
+ m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
+ m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr);
+ info.fillJSValue(gpr, m_isSpeculative ? spillFormat : DataFormatJS);
+ unlock(gpr);
+ }
+ }
+
+ switch (info.registerFormat()) {
+ case DataFormatNone:
+ // Should have filled, above.
+ case DataFormatCell:
+ case DataFormatJSCell:
+ // Should only be calling this function if we know this operand to be numeric.
+ ASSERT_NOT_REACHED();
+
+ case DataFormatJS: {
+ GPRReg jsValueGpr = info.gpr();
+ m_gprs.lock(jsValueGpr);
+ FPRReg fpr = fprAllocate();
+ GPRReg tempGpr = allocate(); // FIXME: can we skip this allocation on the last use of the virtual register?
+
+ JITCompiler::Jump isInteger = m_jit.branchPtr(MacroAssembler::AboveOrEqual, jsValueGpr, GPRInfo::tagTypeNumberRegister);
+
+ m_jit.jitAssertIsJSDouble(jsValueGpr);
+
+ // First, if we get here we have a double encoded as a JSValue
+ m_jit.move(jsValueGpr, tempGpr);
+ m_jit.addPtr(GPRInfo::tagTypeNumberRegister, tempGpr);
+ m_jit.movePtrToDouble(tempGpr, fpr);
+ JITCompiler::Jump hasUnboxedDouble = m_jit.jump();
+
+ // Finally, handle integers.
+ isInteger.link(&m_jit);
+ m_jit.convertInt32ToDouble(jsValueGpr, fpr);
+ hasUnboxedDouble.link(&m_jit);
+
+ m_gprs.release(jsValueGpr);
+ m_gprs.unlock(jsValueGpr);
+ m_gprs.unlock(tempGpr);
+ m_fprs.retain(fpr, virtualRegister, SpillOrderDouble);
+ info.fillDouble(fpr);
+ return fpr;
+ }
+
+ case DataFormatJSInteger:
+ case DataFormatInteger: {
+ FPRReg fpr = fprAllocate();
+ GPRReg gpr = info.gpr();
+ m_gprs.lock(gpr);
+
+ m_jit.convertInt32ToDouble(gpr, fpr);
+
+ m_gprs.release(gpr);
+ m_gprs.unlock(gpr);
+ m_fprs.retain(fpr, virtualRegister, SpillOrderDouble);
+ info.fillDouble(fpr);
+ return fpr;
+ }
+
+ // Unbox the double
+ case DataFormatJSDouble: {
+ GPRReg gpr = info.gpr();
+ FPRReg fpr = unboxDouble(gpr);
+
+ m_gprs.release(gpr);
+ m_fprs.retain(fpr, virtualRegister, SpillOrderDouble);
+
+ info.fillDouble(fpr);
+ return fpr;
+ }
+
+ case DataFormatDouble: {
+ FPRReg fpr = info.fpr();
+ m_fprs.lock(fpr);
+ return fpr;
+ }
+ }
+
+ ASSERT_NOT_REACHED();
+ return InvalidFPRReg;
+}
+
+GPRReg JITCodeGenerator::fillJSValue(NodeIndex nodeIndex)
+{
+ Node& node = m_jit.graph()[nodeIndex];
+ VirtualRegister virtualRegister = node.virtualRegister();
+ GenerationInfo& info = m_generationInfo[virtualRegister];
+
+ switch (info.registerFormat()) {
+ case DataFormatNone: {
+ GPRReg gpr = allocate();
+
+ if (node.isConstant()) {
+ if (isInt32Constant(nodeIndex)) {
+ info.fillJSValue(gpr, DataFormatJSInteger);
+ JSValue jsValue = jsNumber(valueOfInt32Constant(nodeIndex));
+ m_jit.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), gpr);
+ } else if (isDoubleConstant(nodeIndex)) {
+ info.fillJSValue(gpr, DataFormatJSDouble);
+ JSValue jsValue(JSValue::EncodeAsDouble, valueOfDoubleConstant(nodeIndex));
+ m_jit.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), gpr);
+ } else {
+ ASSERT(isJSConstant(nodeIndex));
+ JSValue jsValue = valueOfJSConstant(nodeIndex);
+ m_jit.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), gpr);
+ info.fillJSValue(gpr, DataFormatJS);
+ }
+
+ m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
+ } else {
+ DataFormat spillFormat = info.spillFormat();
+ ASSERT(spillFormat & DataFormatJS);
+ m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
+ m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr);
+ info.fillJSValue(gpr, m_isSpeculative ? spillFormat : DataFormatJS);
+ }
+ return gpr;
+ }
+
+ case DataFormatInteger: {
+ GPRReg gpr = info.gpr();
+ // If the register has already been locked we need to take a copy.
+ // If not, we'll zero extend in place, so mark on the info that this is now type DataFormatInteger, not DataFormatJSInteger.
+ if (m_gprs.isLocked(gpr)) {
+ GPRReg result = allocate();
+ m_jit.orPtr(GPRInfo::tagTypeNumberRegister, gpr, result);
+ return result;
+ }
+ m_gprs.lock(gpr);
+ m_jit.orPtr(GPRInfo::tagTypeNumberRegister, gpr);
+ info.fillJSValue(gpr, DataFormatJSInteger);
+ return gpr;
+ }
+
+ case DataFormatDouble: {
+ FPRReg fpr = info.fpr();
+ GPRReg gpr = boxDouble(fpr);
+
+ // Update all info
+ info.fillJSValue(gpr, DataFormatJSDouble);
+ m_fprs.release(fpr);
+ m_gprs.retain(gpr, virtualRegister, SpillOrderJS);
+
+ return gpr;
+ }
+
+ case DataFormatCell:
+ // No retag required on JSVALUE64!
+ case DataFormatJS:
+ case DataFormatJSInteger:
+ case DataFormatJSDouble:
+ case DataFormatJSCell: {
+ GPRReg gpr = info.gpr();
+ m_gprs.lock(gpr);
+ return gpr;
+ }
+ }
+
+ ASSERT_NOT_REACHED();
+ return InvalidGPRReg;
+}
+
+void JITCodeGenerator::useChildren(Node& node)
+{
+ NodeIndex child1 = node.child1;
+ if (child1 == NoNode) {
+ ASSERT(node.child2 == NoNode && node.child3 == NoNode);
+ return;
+ }
+ use(child1);
+
+ NodeIndex child2 = node.child2;
+ if (child2 == NoNode) {
+ ASSERT(node.child3 == NoNode);
+ return;
+ }
+ use(child2);
+
+ NodeIndex child3 = node.child3;
+ if (child3 == NoNode)
+ return;
+ use(child3);
+}
+
+#ifndef NDEBUG
+static const char* dataFormatString(DataFormat format)
+{
+ // These values correspond to the DataFormat enum.
+ const char* strings[] = {
+ "[ ]",
+ "[ i]",
+ "[ d]",
+ "[ c]",
+ "Err!",
+ "Err!",
+ "Err!",
+ "Err!",
+ "[J ]",
+ "[Ji]",
+ "[Jd]",
+ "[Jc]",
+ "Err!",
+ "Err!",
+ "Err!",
+ "Err!",
+ };
+ return strings[format];
+}
+
+void JITCodeGenerator::dump(const char* label)
+{
+ if (label)
+ fprintf(stderr, "<%s>\n", label);
+
+ fprintf(stderr, " gprs:\n");
+ m_gprs.dump();
+ fprintf(stderr, " fprs:\n");
+ m_fprs.dump();
+ fprintf(stderr, " VirtualRegisters:\n");
+ for (unsigned i = 0; i < m_generationInfo.size(); ++i) {
+ GenerationInfo& info = m_generationInfo[i];
+ if (info.alive())
+ fprintf(stderr, " % 3d:%s%s", i, dataFormatString(info.registerFormat()), dataFormatString(info.spillFormat()));
+ else
+ fprintf(stderr, " % 3d:[__][__]", i);
+ if (info.registerFormat() == DataFormatDouble)
+ fprintf(stderr, ":fpr%d\n", info.fpr());
+ else if (info.registerFormat() != DataFormatNone) {
+ ASSERT(info.gpr() != InvalidGPRReg);
+ fprintf(stderr, ":%s\n", GPRInfo::debugName(info.gpr()));
+ } else
+ fprintf(stderr, "\n");
+ }
+ if (label)
+ fprintf(stderr, "</%s>\n", label);
+}
+#endif
+
+
+#if DFG_CONSISTENCY_CHECK
+void JITCodeGenerator::checkConsistency()
+{
+ bool failed = false;
+
+ for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
+ if (iter.isLocked()) {
+ fprintf(stderr, "DFG_CONSISTENCY_CHECK failed: gpr %s is locked.\n", iter.debugName());
+ failed = true;
+ }
+ }
+ for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
+ if (iter.isLocked()) {
+ fprintf(stderr, "DFG_CONSISTENCY_CHECK failed: fpr %s is locked.\n", iter.debugName());
+ failed = true;
+ }
+ }
+
+ for (unsigned i = 0; i < m_generationInfo.size(); ++i) {
+ VirtualRegister virtualRegister = (VirtualRegister)i;
+ GenerationInfo& info = m_generationInfo[virtualRegister];
+ if (!info.alive())
+ continue;
+ switch (info.registerFormat()) {
+ case DataFormatNone:
+ break;
+ case DataFormatInteger:
+ case DataFormatCell:
+ case DataFormatJS:
+ case DataFormatJSInteger:
+ case DataFormatJSDouble:
+ case DataFormatJSCell: {
+ GPRReg gpr = info.gpr();
+ ASSERT(gpr != InvalidGPRReg);
+ if (m_gprs.name(gpr) != virtualRegister) {
+ fprintf(stderr, "DFG_CONSISTENCY_CHECK failed: name mismatch for virtual register %d (gpr %s).\n", virtualRegister, GPRInfo::debugName(gpr));
+ failed = true;
+ }
+ break;
+ }
+ case DataFormatDouble: {
+ FPRReg fpr = info.fpr();
+ ASSERT(fpr != InvalidFPRReg);
+ if (m_fprs.name(fpr) != virtualRegister) {
+ fprintf(stderr, "DFG_CONSISTENCY_CHECK failed: name mismatch for virtual register %d (fpr %s).\n", virtualRegister, FPRInfo::debugName(fpr));
+ failed = true;
+ }
+ break;
+ }
+ }
+ }
+
+ for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
+ VirtualRegister virtualRegister = iter.name();
+ if (virtualRegister == InvalidVirtualRegister)
+ continue;
+
+ GenerationInfo& info = m_generationInfo[virtualRegister];
+ if (iter.regID() != info.gpr()) {
+ fprintf(stderr, "DFG_CONSISTENCY_CHECK failed: name mismatch for gpr %s (virtual register %d).\n", iter.debugName(), virtualRegister);
+ failed = true;
+ }
+ }
+
+ for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
+ VirtualRegister virtualRegister = iter.name();
+ if (virtualRegister == InvalidVirtualRegister)
+ continue;
+
+ GenerationInfo& info = m_generationInfo[virtualRegister];
+ if (iter.regID() != info.fpr()) {
+ fprintf(stderr, "DFG_CONSISTENCY_CHECK failed: name mismatch for fpr %s (virtual register %d).\n", iter.debugName(), virtualRegister);
+ failed = true;
+ }
+ }
+
+ if (failed) {
+ dump();
+ CRASH();
+ }
+}
+#endif
+
+GPRTemporary::GPRTemporary(JITCodeGenerator* jit)
+ : m_jit(jit)
+ , m_gpr(InvalidGPRReg)
+{
+ m_gpr = m_jit->allocate();
+}
+
+GPRTemporary::GPRTemporary(JITCodeGenerator* jit, SpeculateIntegerOperand& op1)
+ : m_jit(jit)
+ , m_gpr(InvalidGPRReg)
+{
+ if (m_jit->canReuse(op1.index()))
+ m_gpr = m_jit->reuse(op1.gpr());
+ else
+ m_gpr = m_jit->allocate();
+}
+
+GPRTemporary::GPRTemporary(JITCodeGenerator* jit, SpeculateIntegerOperand& op1, SpeculateIntegerOperand& op2)
+ : m_jit(jit)
+ , m_gpr(InvalidGPRReg)
+{
+ if (m_jit->canReuse(op1.index()))
+ m_gpr = m_jit->reuse(op1.gpr());
+ else if (m_jit->canReuse(op2.index()))
+ m_gpr = m_jit->reuse(op2.gpr());
+ else
+ m_gpr = m_jit->allocate();
+}
+
+GPRTemporary::GPRTemporary(JITCodeGenerator* jit, IntegerOperand& op1)
+ : m_jit(jit)
+ , m_gpr(InvalidGPRReg)
+{
+ if (m_jit->canReuse(op1.index()))
+ m_gpr = m_jit->reuse(op1.gpr());
+ else
+ m_gpr = m_jit->allocate();
+}
+
+GPRTemporary::GPRTemporary(JITCodeGenerator* jit, IntegerOperand& op1, IntegerOperand& op2)
+ : m_jit(jit)
+ , m_gpr(InvalidGPRReg)
+{
+ if (m_jit->canReuse(op1.index()))
+ m_gpr = m_jit->reuse(op1.gpr());
+ else if (m_jit->canReuse(op2.index()))
+ m_gpr = m_jit->reuse(op2.gpr());
+ else
+ m_gpr = m_jit->allocate();
+}
+
+GPRTemporary::GPRTemporary(JITCodeGenerator* jit, SpeculateCellOperand& op1)
+ : m_jit(jit)
+ , m_gpr(InvalidGPRReg)
+{
+ if (m_jit->canReuse(op1.index()))
+ m_gpr = m_jit->reuse(op1.gpr());
+ else
+ m_gpr = m_jit->allocate();
+}
+
+GPRTemporary::GPRTemporary(JITCodeGenerator* jit, JSValueOperand& op1)
+ : m_jit(jit)
+ , m_gpr(InvalidGPRReg)
+{
+ if (m_jit->canReuse(op1.index()))
+ m_gpr = m_jit->reuse(op1.gpr());
+ else
+ m_gpr = m_jit->allocate();
+}
+
+FPRTemporary::FPRTemporary(JITCodeGenerator* jit)
+ : m_jit(jit)
+ , m_fpr(InvalidFPRReg)
+{
+ m_fpr = m_jit->fprAllocate();
+}
+
+FPRTemporary::FPRTemporary(JITCodeGenerator* jit, DoubleOperand& op1)
+ : m_jit(jit)
+ , m_fpr(InvalidFPRReg)
+{
+ if (m_jit->canReuse(op1.index()))
+ m_fpr = m_jit->reuse(op1.fpr());
+ else
+ m_fpr = m_jit->fprAllocate();
+}
+
+FPRTemporary::FPRTemporary(JITCodeGenerator* jit, DoubleOperand& op1, DoubleOperand& op2)
+ : m_jit(jit)
+ , m_fpr(InvalidFPRReg)
+{
+ if (m_jit->canReuse(op1.index()))
+ m_fpr = m_jit->reuse(op1.fpr());
+ else if (m_jit->canReuse(op2.index()))
+ m_fpr = m_jit->reuse(op2.fpr());
+ else
+ m_fpr = m_jit->fprAllocate();
+}
+
+} } // namespace JSC::DFG
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DFGJITCodeGenerator_h
+#define DFGJITCodeGenerator_h
+
+#if ENABLE(DFG_JIT)
+
+#include "CodeBlock.h"
+#include <dfg/DFGGenerationInfo.h>
+#include <dfg/DFGGraph.h>
+#include <dfg/DFGJITCompiler.h>
+#include <dfg/DFGOperations.h>
+#include <dfg/DFGRegisterBank.h>
+
+namespace JSC { namespace DFG {
+
+class SpeculateIntegerOperand;
+class SpeculateStrictInt32Operand;
+class SpeculateCellOperand;
+
+
+// === JITCodeGenerator ===
+//
+// This class provides common infrastructure used by the speculative &
+// non-speculative JITs. Provides common mechanisms for virtual and
+// physical register management, calls out from JIT code to helper
+// functions, etc.
+class JITCodeGenerator {
+protected:
+ typedef MacroAssembler::TrustedImm32 TrustedImm32;
+ typedef MacroAssembler::Imm32 Imm32;
+
+ // These constants are used to set priorities for spill order for
+ // the register allocator.
+ enum SpillOrder {
+ SpillOrderConstant = 1, // no spill, and cheap fill
+ SpillOrderSpilled = 2, // no spill
+ SpillOrderJS = 4, // needs spill
+ SpillOrderCell = 4, // needs spill
+ SpillOrderInteger = 5, // needs spill and box
+ SpillOrderDouble = 6, // needs spill and convert
+ };
+
+
+public:
+ GPRReg fillInteger(NodeIndex, DataFormat& returnFormat);
+ FPRReg fillDouble(NodeIndex);
+ GPRReg fillJSValue(NodeIndex);
+
+ // lock and unlock GPR & FPR registers.
+ void lock(GPRReg reg)
+ {
+ m_gprs.lock(reg);
+ }
+ void lock(FPRReg reg)
+ {
+ m_fprs.lock(reg);
+ }
+ void unlock(GPRReg reg)
+ {
+ m_gprs.unlock(reg);
+ }
+ void unlock(FPRReg reg)
+ {
+ m_fprs.unlock(reg);
+ }
+
+ // Used to check whether a child node is on its last use,
+ // and its machine registers may be reused.
+ bool canReuse(NodeIndex nodeIndex)
+ {
+ VirtualRegister virtualRegister = m_jit.graph()[nodeIndex].virtualRegister();
+ GenerationInfo& info = m_generationInfo[virtualRegister];
+ return info.canReuse();
+ }
+ GPRReg reuse(GPRReg reg)
+ {
+ m_gprs.lock(reg);
+ return reg;
+ }
+ FPRReg reuse(FPRReg reg)
+ {
+ m_fprs.lock(reg);
+ return reg;
+ }
+
+ // Allocate a gpr/fpr.
+ GPRReg allocate()
+ {
+ VirtualRegister spillMe;
+ GPRReg gpr = m_gprs.allocate(spillMe);
+ if (spillMe != InvalidVirtualRegister)
+ spill(spillMe);
+ return gpr;
+ }
+ FPRReg fprAllocate()
+ {
+ VirtualRegister spillMe;
+ FPRReg fpr = m_fprs.allocate(spillMe);
+ if (spillMe != InvalidVirtualRegister)
+ spill(spillMe);
+ return fpr;
+ }
+
+ // Check whether a VirtualRegsiter is currently in a machine register.
+ // We use this when filling operands to fill those that are already in
+ // machine registers first (by locking VirtualRegsiters that are already
+ // in machine register before filling those that are not we attempt to
+ // avoid spilling values we will need immediately).
+ bool isFilled(NodeIndex nodeIndex)
+ {
+ VirtualRegister virtualRegister = m_jit.graph()[nodeIndex].virtualRegister();
+ GenerationInfo& info = m_generationInfo[virtualRegister];
+ return info.registerFormat() != DataFormatNone;
+ }
+ bool isFilledDouble(NodeIndex nodeIndex)
+ {
+ VirtualRegister virtualRegister = m_jit.graph()[nodeIndex].virtualRegister();
+ GenerationInfo& info = m_generationInfo[virtualRegister];
+ return info.registerFormat() == DataFormatDouble;
+ }
+
+protected:
+ JITCodeGenerator(JITCompiler& jit, bool isSpeculative)
+ : m_jit(jit)
+ , m_isSpeculative(isSpeculative)
+ , m_compileIndex(0)
+ , m_generationInfo(m_jit.codeBlock()->m_numCalleeRegisters)
+ , m_blockHeads(jit.graph().m_blocks.size())
+ {
+ }
+
+ // These methods convert between doubles, and doubles boxed and JSValues.
+ GPRReg boxDouble(FPRReg fpr, GPRReg gpr)
+ {
+ m_jit.moveDoubleToPtr(fpr, gpr);
+ m_jit.subPtr(GPRInfo::tagTypeNumberRegister, gpr);
+ return gpr;
+ }
+ FPRReg unboxDouble(GPRReg gpr, FPRReg fpr)
+ {
+ m_jit.addPtr(GPRInfo::tagTypeNumberRegister, gpr);
+ m_jit.movePtrToDouble(gpr, fpr);
+ return fpr;
+ }
+ GPRReg boxDouble(FPRReg fpr)
+ {
+ return boxDouble(fpr, allocate());
+ }
+ FPRReg unboxDouble(GPRReg gpr)
+ {
+ return unboxDouble(gpr, fprAllocate());
+ }
+
+ // Called on an operand once it has been consumed by a parent node.
+ void use(NodeIndex nodeIndex)
+ {
+ VirtualRegister virtualRegister = m_jit.graph()[nodeIndex].virtualRegister();
+ GenerationInfo& info = m_generationInfo[virtualRegister];
+
+ // use() returns true when the value becomes dead, and any
+ // associated resources may be freed.
+ if (!info.use())
+ return;
+
+ // Release the associated machine registers.
+ DataFormat registerFormat = info.registerFormat();
+ if (registerFormat == DataFormatDouble)
+ m_fprs.release(info.fpr());
+ else if (registerFormat != DataFormatNone)
+ m_gprs.release(info.gpr());
+ }
+
+ // Spill a VirtualRegister to the RegisterFile.
+ void spill(VirtualRegister spillMe)
+ {
+ GenerationInfo& info = m_generationInfo[spillMe];
+
+ // Check the GenerationInfo to see if this value need writing
+ // to the RegisterFile - if not, mark it as spilled & return.
+ if (!info.needsSpill()) {
+ info.setSpilled();
+ return;
+ }
+
+ DataFormat spillFormat = info.registerFormat();
+ if (spillFormat == DataFormatDouble) {
+ // All values are spilled as JSValues, so box the double via a temporary gpr.
+ GPRReg gpr = boxDouble(info.fpr());
+ m_jit.storePtr(gpr, JITCompiler::addressFor(spillMe));
+ unlock(gpr);
+ info.spill(DataFormatJSDouble);
+ return;
+ }
+
+ // The following code handles JSValues, int32s, and cells.
+ ASSERT(spillFormat == DataFormatInteger || spillFormat == DataFormatCell || spillFormat & DataFormatJS);
+
+ GPRReg reg = info.gpr();
+ // We need to box int32 and cell values ...
+ // but on JSVALUE64 boxing a cell is a no-op!
+ if (spillFormat == DataFormatInteger)
+ m_jit.orPtr(GPRInfo::tagTypeNumberRegister, reg);
+
+ // Spill the value, and record it as spilled in its boxed form.
+ m_jit.storePtr(reg, JITCompiler::addressFor(spillMe));
+ info.spill((DataFormat)(spillFormat | DataFormatJS));
+ }
+
+ // Checks/accessors for constant values.
+ bool isConstant(NodeIndex nodeIndex) { return m_jit.isConstant(nodeIndex); }
+ bool isInt32Constant(NodeIndex nodeIndex) { return m_jit.isInt32Constant(nodeIndex); }
+ bool isDoubleConstant(NodeIndex nodeIndex) { return m_jit.isDoubleConstant(nodeIndex); }
+ bool isJSConstant(NodeIndex nodeIndex) { return m_jit.isJSConstant(nodeIndex); }
+ int32_t valueOfInt32Constant(NodeIndex nodeIndex) { return m_jit.valueOfInt32Constant(nodeIndex); }
+ double valueOfDoubleConstant(NodeIndex nodeIndex) { return m_jit.valueOfDoubleConstant(nodeIndex); }
+ JSValue valueOfJSConstant(NodeIndex nodeIndex) { return m_jit.valueOfJSConstant(nodeIndex); }
+
+ Identifier* identifier(unsigned index)
+ {
+ return &m_jit.codeBlock()->identifier(index);
+ }
+
+ // Spill all VirtualRegisters back to the RegisterFile.
+ void flushRegisters()
+ {
+ for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
+ if (iter.name() != InvalidVirtualRegister) {
+ spill(iter.name());
+ iter.release();
+ }
+ }
+ for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
+ if (iter.name() != InvalidVirtualRegister) {
+ spill(iter.name());
+ iter.release();
+ }
+ }
+ }
+
+#ifndef NDEBUG
+ // Used to ASSERT flushRegisters() has been called prior to
+ // calling out from JIT code to a C helper function.
+ bool isFlushed()
+ {
+ for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
+ if (iter.name() != InvalidVirtualRegister)
+ return false;
+ }
+ for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
+ if (iter.name() != InvalidVirtualRegister)
+ return false;
+ }
+ return true;
+ }
+#endif
+
+ // Get the JSValue representation of a constant.
+ JSValue constantAsJSValue(NodeIndex nodeIndex)
+ {
+ Node& node = m_jit.graph()[nodeIndex];
+ if (isInt32Constant(nodeIndex))
+ return jsNumber(node.int32Constant());
+ if (isDoubleConstant(nodeIndex))
+ return JSValue(JSValue::EncodeAsDouble, node.numericConstant());
+ ASSERT(isJSConstant(nodeIndex));
+ return valueOfJSConstant(nodeIndex);
+ }
+ MacroAssembler::ImmPtr constantAsJSValueAsImmPtr(NodeIndex nodeIndex)
+ {
+ return MacroAssembler::ImmPtr(JSValue::encode(constantAsJSValue(nodeIndex)));
+ }
+
+ // Helper functions to enable code sharing in implementations of bit/shift ops.
+ void bitOp(NodeType op, int32_t imm, GPRReg op1, GPRReg result)
+ {
+ switch (op) {
+ case BitAnd:
+ m_jit.and32(Imm32(imm), op1, result);
+ break;
+ case BitOr:
+ m_jit.or32(Imm32(imm), op1, result);
+ break;
+ case BitXor:
+ m_jit.xor32(Imm32(imm), op1, result);
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ }
+ void bitOp(NodeType op, GPRReg op1, GPRReg op2, GPRReg result)
+ {
+ switch (op) {
+ case BitAnd:
+ m_jit.and32(op1, op2, result);
+ break;
+ case BitOr:
+ m_jit.or32(op1, op2, result);
+ break;
+ case BitXor:
+ m_jit.xor32(op1, op2, result);
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ }
+ void shiftOp(NodeType op, GPRReg op1, int32_t shiftAmount, GPRReg result)
+ {
+ switch (op) {
+ case BitRShift:
+ m_jit.rshift32(op1, Imm32(shiftAmount), result);
+ break;
+ case BitLShift:
+ m_jit.lshift32(op1, Imm32(shiftAmount), result);
+ break;
+ case BitURShift:
+ m_jit.urshift32(op1, Imm32(shiftAmount), result);
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ }
+ void shiftOp(NodeType op, GPRReg op1, GPRReg shiftAmount, GPRReg result)
+ {
+ switch (op) {
+ case BitRShift:
+ m_jit.rshift32(op1, shiftAmount, result);
+ break;
+ case BitLShift:
+ m_jit.lshift32(op1, shiftAmount, result);
+ break;
+ case BitURShift:
+ m_jit.urshift32(op1, shiftAmount, result);
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ }
+
+ // Called once a node has completed code generation but prior to setting
+ // its result, to free up its children. (This must happen prior to setting
+ // the nodes result, since the node may have the same VirtualRegister as
+ // a child, and as such will use the same GeneratioInfo).
+ void useChildren(Node&);
+
+ // These method called to initialize the the GenerationInfo
+ // to describe the result of an operation.
+ void integerResult(GPRReg reg, NodeIndex nodeIndex, DataFormat format = DataFormatInteger)
+ {
+ Node& node = m_jit.graph()[nodeIndex];
+ useChildren(node);
+
+ VirtualRegister virtualRegister = node.virtualRegister();
+ GenerationInfo& info = m_generationInfo[virtualRegister];
+
+ if (format == DataFormatInteger) {
+ m_jit.jitAssertIsInt32(reg);
+ m_gprs.retain(reg, virtualRegister, SpillOrderInteger);
+ info.initInteger(nodeIndex, node.refCount(), reg);
+ } else {
+ ASSERT(format == DataFormatJSInteger);
+ m_jit.jitAssertIsJSInt32(reg);
+ m_gprs.retain(reg, virtualRegister, SpillOrderJS);
+ info.initJSValue(nodeIndex, node.refCount(), reg, format);
+ }
+ }
+ void noResult(NodeIndex nodeIndex)
+ {
+ Node& node = m_jit.graph()[nodeIndex];
+ useChildren(node);
+ }
+ void cellResult(GPRReg reg, NodeIndex nodeIndex)
+ {
+ Node& node = m_jit.graph()[nodeIndex];
+ useChildren(node);
+
+ VirtualRegister virtualRegister = node.virtualRegister();
+ m_gprs.retain(reg, virtualRegister, SpillOrderCell);
+ GenerationInfo& info = m_generationInfo[virtualRegister];
+ info.initCell(nodeIndex, node.refCount(), reg);
+ }
+ void jsValueResult(GPRReg reg, NodeIndex nodeIndex, DataFormat format = DataFormatJS)
+ {
+ if (format == DataFormatJSInteger)
+ m_jit.jitAssertIsJSInt32(reg);
+
+ Node& node = m_jit.graph()[nodeIndex];
+ useChildren(node);
+
+ VirtualRegister virtualRegister = node.virtualRegister();
+ m_gprs.retain(reg, virtualRegister, SpillOrderJS);
+ GenerationInfo& info = m_generationInfo[virtualRegister];
+ info.initJSValue(nodeIndex, node.refCount(), reg, format);
+ }
+ void doubleResult(FPRReg reg, NodeIndex nodeIndex)
+ {
+ Node& node = m_jit.graph()[nodeIndex];
+ useChildren(node);
+
+ VirtualRegister virtualRegister = node.virtualRegister();
+ m_fprs.retain(reg, virtualRegister, SpillOrderDouble);
+ GenerationInfo& info = m_generationInfo[virtualRegister];
+ info.initDouble(nodeIndex, node.refCount(), reg);
+ }
+ void initConstantInfo(NodeIndex nodeIndex)
+ {
+ ASSERT(isInt32Constant(nodeIndex) || isDoubleConstant(nodeIndex) || isJSConstant(nodeIndex));
+ Node& node = m_jit.graph()[nodeIndex];
+ m_generationInfo[node.virtualRegister()].initConstant(nodeIndex, node.refCount());
+ }
+
+ // These methods used to sort arguments into the correct registers.
+ template<GPRReg destA, GPRReg destB>
+ void setupTwoStubArgs(GPRReg srcA, GPRReg srcB)
+ {
+ // Assuming that srcA != srcB, there are 7 interesting states the registers may be in:
+ // (1) both are already in arg regs, the right way around.
+ // (2) both are already in arg regs, the wrong way around.
+ // (3) neither are currently in arg registers.
+ // (4) srcA in in its correct reg.
+ // (5) srcA in in the incorrect reg.
+ // (6) srcB in in its correct reg.
+ // (7) srcB in in the incorrect reg.
+ //
+ // The trivial approach is to simply emit two moves, to put srcA in place then srcB in
+ // place (the MacroAssembler will omit redundant moves). This apporach will be safe in
+ // cases 1, 3, 4, 5, 6, and in cases where srcA==srcB. The two problem cases are 2
+ // (requires a swap) and 7 (must move srcB first, to avoid trampling.)
+
+ if (srcB != destA) {
+ // Handle the easy cases - two simple moves.
+ m_jit.move(srcA, destA);
+ m_jit.move(srcB, destB);
+ } else if (srcA != destB) {
+ // Handle the non-swap case - just put srcB in place first.
+ m_jit.move(srcB, destB);
+ m_jit.move(srcA, destA);
+ } else
+ m_jit.swap(destB, destB);
+ }
+ template<FPRReg destA, FPRReg destB>
+ void setupTwoStubArgs(FPRReg srcA, FPRReg srcB)
+ {
+ // Assuming that srcA != srcB, there are 7 interesting states the registers may be in:
+ // (1) both are already in arg regs, the right way around.
+ // (2) both are already in arg regs, the wrong way around.
+ // (3) neither are currently in arg registers.
+ // (4) srcA in in its correct reg.
+ // (5) srcA in in the incorrect reg.
+ // (6) srcB in in its correct reg.
+ // (7) srcB in in the incorrect reg.
+ //
+ // The trivial approach is to simply emit two moves, to put srcA in place then srcB in
+ // place (the MacroAssembler will omit redundant moves). This apporach will be safe in
+ // cases 1, 3, 4, 5, 6, and in cases where srcA==srcB. The two problem cases are 2
+ // (requires a swap) and 7 (must move srcB first, to avoid trampling.)
+
+ if (srcB != destA) {
+ // Handle the easy cases - two simple moves.
+ m_jit.moveDouble(srcA, destA);
+ m_jit.moveDouble(srcB, destB);
+ return;
+ }
+
+ if (srcA != destB) {
+ // Handle the non-swap case - just put srcB in place first.
+ m_jit.moveDouble(srcB, destB);
+ m_jit.moveDouble(srcA, destA);
+ return;
+ }
+
+ ASSERT(srcB == destA && srcA == destB);
+ // Need to swap; pick a temporary register.
+ FPRReg temp;
+ if (destA != FPRInfo::argumentFPR3 && destA != FPRInfo::argumentFPR3)
+ temp = FPRInfo::argumentFPR3;
+ else if (destA != FPRInfo::argumentFPR2 && destA != FPRInfo::argumentFPR2)
+ temp = FPRInfo::argumentFPR2;
+ else {
+ ASSERT(destA != FPRInfo::argumentFPR1 && destA != FPRInfo::argumentFPR1);
+ temp = FPRInfo::argumentFPR1;
+ }
+ m_jit.moveDouble(destA, temp);
+ m_jit.moveDouble(destB, destA);
+ m_jit.moveDouble(temp, destB);
+ }
+ void setupStubArguments(GPRReg arg1, GPRReg arg2)
+ {
+ setupTwoStubArgs<GPRInfo::argumentGPR1, GPRInfo::argumentGPR2>(arg1, arg2);
+ }
+ void setupStubArguments(GPRReg arg1, GPRReg arg2, GPRReg arg3)
+ {
+ // If neither of arg2/arg3 are in our way, then we can move arg1 into place.
+ // Then we can use setupTwoStubArgs to fix arg2/arg3.
+ if (arg2 != GPRInfo::argumentGPR1 && arg3 != GPRInfo::argumentGPR1) {
+ m_jit.move(arg1, GPRInfo::argumentGPR1);
+ setupTwoStubArgs<GPRInfo::argumentGPR2, GPRInfo::argumentGPR3>(arg2, arg3);
+ return;
+ }
+
+ // If neither of arg1/arg3 are in our way, then we can move arg2 into place.
+ // Then we can use setupTwoStubArgs to fix arg1/arg3.
+ if (arg1 != GPRInfo::argumentGPR2 && arg3 != GPRInfo::argumentGPR2) {
+ m_jit.move(arg2, GPRInfo::argumentGPR2);
+ setupTwoStubArgs<GPRInfo::argumentGPR1, GPRInfo::argumentGPR3>(arg1, arg3);
+ return;
+ }
+
+ // If neither of arg1/arg2 are in our way, then we can move arg3 into place.
+ // Then we can use setupTwoStubArgs to fix arg1/arg2.
+ if (arg1 != GPRInfo::argumentGPR3 && arg2 != GPRInfo::argumentGPR3) {
+ m_jit.move(arg3, GPRInfo::argumentGPR3);
+ setupTwoStubArgs<GPRInfo::argumentGPR1, GPRInfo::argumentGPR2>(arg1, arg2);
+ return;
+ }
+
+ // If we get here, we haven't been able to move any of arg1/arg2/arg3.
+ // Since all three are blocked, then all three must already be in the argument register.
+ // But are they in the right ones?
+
+ // First, ensure arg1 is in place.
+ if (arg1 != GPRInfo::argumentGPR1) {
+ m_jit.swap(arg1, GPRInfo::argumentGPR1);
+
+ // If arg1 wasn't in argumentGPR1, one of arg2/arg3 must be.
+ ASSERT(arg2 == GPRInfo::argumentGPR1 || arg3 == GPRInfo::argumentGPR1);
+ // If arg2 was in argumentGPR1 it no longer is (due to the swap).
+ // Otherwise arg3 must have been. Mark him as moved.
+ if (arg2 == GPRInfo::argumentGPR1)
+ arg2 = arg1;
+ else
+ arg3 = arg1;
+ }
+
+ // Either arg2 & arg3 need swapping, or we're all done.
+ ASSERT((arg2 == GPRInfo::argumentGPR2 || arg3 == GPRInfo::argumentGPR3)
+ || (arg2 == GPRInfo::argumentGPR3 || arg3 == GPRInfo::argumentGPR2));
+
+ if (arg2 != GPRInfo::argumentGPR2)
+ m_jit.swap(GPRInfo::argumentGPR2, GPRInfo::argumentGPR3);
+ }
+
+ // These methods add calls to C++ helper functions.
+ void callOperation(J_DFGOperation_EJP operation, GPRReg result, GPRReg arg1, void* pointer)
+ {
+ ASSERT(isFlushed());
+
+ m_jit.move(arg1, GPRInfo::argumentGPR1);
+ m_jit.move(JITCompiler::TrustedImmPtr(pointer), GPRInfo::argumentGPR2);
+ m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+
+ appendCallWithExceptionCheck(operation);
+ m_jit.move(GPRInfo::returnValueGPR, result);
+ }
+ void callOperation(J_DFGOperation_EJI operation, GPRReg result, GPRReg arg1, Identifier* identifier)
+ {
+ callOperation((J_DFGOperation_EJP)operation, result, arg1, identifier);
+ }
+ void callOperation(J_DFGOperation_EJ operation, GPRReg result, GPRReg arg1)
+ {
+ ASSERT(isFlushed());
+
+ m_jit.move(arg1, GPRInfo::argumentGPR1);
+ m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+
+ appendCallWithExceptionCheck(operation);
+ m_jit.move(GPRInfo::returnValueGPR, result);
+ }
+ void callOperation(Z_DFGOperation_EJ operation, GPRReg result, GPRReg arg1)
+ {
+ ASSERT(isFlushed());
+
+ m_jit.move(arg1, GPRInfo::argumentGPR1);
+ m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+
+ appendCallWithExceptionCheck(operation);
+ m_jit.move(GPRInfo::returnValueGPR, result);
+ }
+ void callOperation(Z_DFGOperation_EJJ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
+ {
+ ASSERT(isFlushed());
+
+ setupStubArguments(arg1, arg2);
+ m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+
+ appendCallWithExceptionCheck(operation);
+ m_jit.move(GPRInfo::returnValueGPR, result);
+ }
+ void callOperation(J_DFGOperation_EJJ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
+ {
+ ASSERT(isFlushed());
+
+ setupStubArguments(arg1, arg2);
+ m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+
+ appendCallWithExceptionCheck(operation);
+ m_jit.move(GPRInfo::returnValueGPR, result);
+ }
+ void callOperation(V_DFGOperation_EJJP operation, GPRReg arg1, GPRReg arg2, void* pointer)
+ {
+ ASSERT(isFlushed());
+
+ setupStubArguments(arg1, arg2);
+ m_jit.move(JITCompiler::TrustedImmPtr(pointer), GPRInfo::argumentGPR3);
+ m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+
+ appendCallWithExceptionCheck(operation);
+ }
+ void callOperation(V_DFGOperation_EJJI operation, GPRReg arg1, GPRReg arg2, Identifier* identifier)
+ {
+ callOperation((V_DFGOperation_EJJP)operation, arg1, arg2, identifier);
+ }
+ void callOperation(V_DFGOperation_EJJJ operation, GPRReg arg1, GPRReg arg2, GPRReg arg3)
+ {
+ ASSERT(isFlushed());
+
+ setupStubArguments(arg1, arg2, arg3);
+ m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+
+ appendCallWithExceptionCheck(operation);
+ }
+ void callOperation(D_DFGOperation_DD operation, FPRReg result, FPRReg arg1, FPRReg arg2)
+ {
+ ASSERT(isFlushed());
+
+ setupTwoStubArgs<FPRInfo::argumentFPR0, FPRInfo::argumentFPR1>(arg1, arg2);
+
+ m_jit.appendCall(operation);
+ m_jit.moveDouble(FPRInfo::returnValueFPR, result);
+ }
+
+ void appendCallWithExceptionCheck(const FunctionPtr& function)
+ {
+ m_jit.appendCallWithExceptionCheck(function, m_jit.graph()[m_compileIndex].exceptionInfo);
+ }
+
+ void addBranch(const MacroAssembler::Jump& jump, BlockIndex destination)
+ {
+ m_branches.append(BranchRecord(jump, destination));
+ }
+
+ void linkBranches()
+ {
+ for (size_t i = 0; i < m_branches.size(); ++i) {
+ BranchRecord& branch = m_branches[i];
+ branch.jump.linkTo(m_blockHeads[branch.destination], &m_jit);
+ }
+ }
+
+#ifndef NDEBUG
+ void dump(const char* label = 0);
+#endif
+
+#if DFG_CONSISTENCY_CHECK
+ void checkConsistency();
+#else
+ void checkConsistency() {}
+#endif
+
+ // The JIT, while also provides MacroAssembler functionality.
+ JITCompiler& m_jit;
+ // This flag is used to distinguish speculative and non-speculative
+ // code generation. This is significant when filling spilled values
+ // from the RegisterFile. When spilling we attempt to store information
+ // as to the type of boxed value being stored (int32, double, cell), and
+ // when filling on the speculative path we will retrieve this type info
+ // where available. On the non-speculative path, however, we cannot rely
+ // on the spill format info, since the a value being loaded might have
+ // been spilled by either the speculative or non-speculative paths (where
+ // we entered the non-speculative path on an intervening bail-out), and
+ // the value may have been boxed differently on the two paths.
+ bool m_isSpeculative;
+ // The current node being generated.
+ BlockIndex m_block;
+ NodeIndex m_compileIndex;
+ // Virtual and physical register maps.
+ Vector<GenerationInfo, 32> m_generationInfo;
+ RegisterBank<GPRInfo> m_gprs;
+ RegisterBank<FPRInfo> m_fprs;
+
+ Vector<MacroAssembler::Label> m_blockHeads;
+ struct BranchRecord {
+ BranchRecord(MacroAssembler::Jump jump, BlockIndex destination)
+ : jump(jump)
+ , destination(destination)
+ {
+ }
+
+ MacroAssembler::Jump jump;
+ BlockIndex destination;
+ };
+ Vector<BranchRecord, 8> m_branches;
+};
+
+// === Operand types ===
+//
+// IntegerOperand, DoubleOperand and JSValueOperand.
+//
+// These classes are used to lock the operands to a node into machine
+// registers. These classes implement of pattern of locking a value
+// into register at the point of construction only if it is already in
+// registers, and otherwise loading it lazily at the point it is first
+// used. We do so in order to attempt to avoid spilling one operand
+// in order to make space available for another.
+
+class IntegerOperand {
+public:
+ explicit IntegerOperand(JITCodeGenerator* jit, NodeIndex index)
+ : m_jit(jit)
+ , m_index(index)
+ , m_gprOrInvalid(InvalidGPRReg)
+#ifndef NDEBUG
+ , m_format(DataFormatNone)
+#endif
+ {
+ ASSERT(m_jit);
+ if (jit->isFilled(index))
+ gpr();
+ }
+
+ ~IntegerOperand()
+ {
+ ASSERT(m_gprOrInvalid != InvalidGPRReg);
+ m_jit->unlock(m_gprOrInvalid);
+ }
+
+ NodeIndex index() const
+ {
+ return m_index;
+ }
+
+ DataFormat format()
+ {
+ gpr(); // m_format is set when m_gpr is locked.
+ ASSERT(m_format == DataFormatInteger || m_format == DataFormatJSInteger);
+ return m_format;
+ }
+
+ GPRReg gpr()
+ {
+ if (m_gprOrInvalid == InvalidGPRReg)
+ m_gprOrInvalid = m_jit->fillInteger(index(), m_format);
+ return m_gprOrInvalid;
+ }
+
+private:
+ JITCodeGenerator* m_jit;
+ NodeIndex m_index;
+ GPRReg m_gprOrInvalid;
+ DataFormat m_format;
+};
+
+class DoubleOperand {
+public:
+ explicit DoubleOperand(JITCodeGenerator* jit, NodeIndex index)
+ : m_jit(jit)
+ , m_index(index)
+ , m_fprOrInvalid(InvalidFPRReg)
+ {
+ ASSERT(m_jit);
+ if (jit->isFilledDouble(index))
+ fpr();
+ }
+
+ ~DoubleOperand()
+ {
+ ASSERT(m_fprOrInvalid != InvalidFPRReg);
+ m_jit->unlock(m_fprOrInvalid);
+ }
+
+ NodeIndex index() const
+ {
+ return m_index;
+ }
+
+ FPRReg fpr()
+ {
+ if (m_fprOrInvalid == InvalidFPRReg)
+ m_fprOrInvalid = m_jit->fillDouble(index());
+ return m_fprOrInvalid;
+ }
+
+private:
+ JITCodeGenerator* m_jit;
+ NodeIndex m_index;
+ FPRReg m_fprOrInvalid;
+};
+
+class JSValueOperand {
+public:
+ explicit JSValueOperand(JITCodeGenerator* jit, NodeIndex index)
+ : m_jit(jit)
+ , m_index(index)
+ , m_gprOrInvalid(InvalidGPRReg)
+ {
+ ASSERT(m_jit);
+ if (jit->isFilled(index))
+ gpr();
+ }
+
+ ~JSValueOperand()
+ {
+ ASSERT(m_gprOrInvalid != InvalidGPRReg);
+ m_jit->unlock(m_gprOrInvalid);
+ }
+
+ NodeIndex index() const
+ {
+ return m_index;
+ }
+
+ GPRReg gpr()
+ {
+ if (m_gprOrInvalid == InvalidGPRReg)
+ m_gprOrInvalid = m_jit->fillJSValue(index());
+ return m_gprOrInvalid;
+ }
+
+private:
+ JITCodeGenerator* m_jit;
+ NodeIndex m_index;
+ GPRReg m_gprOrInvalid;
+};
+
+
+// === Temporaries ===
+//
+// These classes are used to allocate temporary registers.
+// A mechanism is provided to attempt to reuse the registers
+// currently allocated to child nodes whose value is consumed
+// by, and not live after, this operation.
+
+class GPRTemporary {
+public:
+ GPRTemporary(JITCodeGenerator*);
+ GPRTemporary(JITCodeGenerator*, SpeculateIntegerOperand&);
+ GPRTemporary(JITCodeGenerator*, SpeculateIntegerOperand&, SpeculateIntegerOperand&);
+ GPRTemporary(JITCodeGenerator*, IntegerOperand&);
+ GPRTemporary(JITCodeGenerator*, IntegerOperand&, IntegerOperand&);
+ GPRTemporary(JITCodeGenerator*, SpeculateCellOperand&);
+ GPRTemporary(JITCodeGenerator*, JSValueOperand&);
+
+ ~GPRTemporary()
+ {
+ m_jit->unlock(gpr());
+ }
+
+ GPRReg gpr()
+ {
+ ASSERT(m_gpr != InvalidGPRReg);
+ return m_gpr;
+ }
+
+protected:
+ GPRTemporary(JITCodeGenerator* jit, GPRReg lockedGPR)
+ : m_jit(jit)
+ , m_gpr(lockedGPR)
+ {
+ }
+
+private:
+ JITCodeGenerator* m_jit;
+ GPRReg m_gpr;
+};
+
+class FPRTemporary {
+public:
+ FPRTemporary(JITCodeGenerator*);
+ FPRTemporary(JITCodeGenerator*, DoubleOperand&);
+ FPRTemporary(JITCodeGenerator*, DoubleOperand&, DoubleOperand&);
+
+ ~FPRTemporary()
+ {
+ m_jit->unlock(fpr());
+ }
+
+ FPRReg fpr() const
+ {
+ ASSERT(m_fpr != InvalidFPRReg);
+ return m_fpr;
+ }
+
+protected:
+ FPRTemporary(JITCodeGenerator* jit, FPRReg lockedFPR)
+ : m_jit(jit)
+ , m_fpr(lockedFPR)
+ {
+ }
+
+private:
+ JITCodeGenerator* m_jit;
+ FPRReg m_fpr;
+};
+
+
+// === Results ===
+//
+// These classes lock the result of a call to a C++ helper function.
+
+class GPRResult : public GPRTemporary {
+public:
+ GPRResult(JITCodeGenerator* jit)
+ : GPRTemporary(jit, lockedResult(jit))
+ {
+ }
+
+private:
+ static GPRReg lockedResult(JITCodeGenerator* jit)
+ {
+ jit->lock(GPRInfo::returnValueGPR);
+ return GPRInfo::returnValueGPR;
+ }
+};
+
+class FPRResult : public FPRTemporary {
+public:
+ FPRResult(JITCodeGenerator* jit)
+ : FPRTemporary(jit, lockedResult(jit))
+ {
+ }
+
+private:
+ static FPRReg lockedResult(JITCodeGenerator* jit)
+ {
+ jit->lock(FPRInfo::returnValueFPR);
+ return FPRInfo::returnValueFPR;
+ }
+};
+
+} } // namespace JSC::DFG
+
+#endif
+#endif
+
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DFGJITCompiler.h"
+
+#if ENABLE(DFG_JIT)
+
+#include "CodeBlock.h"
+#include "DFGJITCodeGenerator.h"
+#include "DFGNonSpeculativeJIT.h"
+#include "DFGOperations.h"
+#include "DFGRegisterBank.h"
+#include "DFGSpeculativeJIT.h"
+#include "JSGlobalData.h"
+#include "LinkBuffer.h"
+
+namespace JSC { namespace DFG {
+
+// This method used to fill a numeric value to a FPR when linking speculative -> non-speculative.
+void JITCompiler::fillNumericToDouble(NodeIndex nodeIndex, FPRReg fpr, GPRReg temporary)
+{
+ Node& node = graph()[nodeIndex];
+
+ if (node.isConstant()) {
+ ASSERT(node.op == DoubleConstant);
+ move(MacroAssembler::ImmPtr(reinterpret_cast<void*>(reinterpretDoubleToIntptr(valueOfDoubleConstant(nodeIndex)))), temporary);
+ movePtrToDouble(temporary, fpr);
+ } else {
+ loadPtr(addressFor(node.virtualRegister()), temporary);
+ Jump isInteger = branchPtr(MacroAssembler::AboveOrEqual, temporary, GPRInfo::tagTypeNumberRegister);
+ jitAssertIsJSDouble(temporary);
+ addPtr(GPRInfo::tagTypeNumberRegister, temporary);
+ movePtrToDouble(temporary, fpr);
+ Jump hasUnboxedDouble = jump();
+ isInteger.link(this);
+ convertInt32ToDouble(temporary, fpr);
+ hasUnboxedDouble.link(this);
+ }
+}
+
+// This method used to fill an integer value to a GPR when linking speculative -> non-speculative.
+void JITCompiler::fillInt32ToInteger(NodeIndex nodeIndex, GPRReg gpr)
+{
+ Node& node = graph()[nodeIndex];
+
+ if (node.isConstant()) {
+ ASSERT(node.op == Int32Constant);
+ move(MacroAssembler::Imm32(valueOfInt32Constant(nodeIndex)), gpr);
+ } else {
+#if DFG_JIT_ASSERT
+ // Redundant load, just so we can check the tag!
+ loadPtr(addressFor(node.virtualRegister()), gpr);
+ jitAssertIsJSInt32(gpr);
+#endif
+ load32(addressFor(node.virtualRegister()), gpr);
+ }
+}
+
+// This method used to fill a JSValue to a GPR when linking speculative -> non-speculative.
+void JITCompiler::fillToJS(NodeIndex nodeIndex, GPRReg gpr)
+{
+ Node& node = graph()[nodeIndex];
+
+ if (node.isConstant()) {
+ if (isInt32Constant(nodeIndex)) {
+ JSValue jsValue = jsNumber(valueOfInt32Constant(nodeIndex));
+ move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), gpr);
+ } else if (isDoubleConstant(nodeIndex)) {
+ JSValue jsValue(JSValue::EncodeAsDouble, valueOfDoubleConstant(nodeIndex));
+ move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), gpr);
+ } else {
+ ASSERT(isJSConstant(nodeIndex));
+ JSValue jsValue = valueOfJSConstant(nodeIndex);
+ move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), gpr);
+ }
+ return;
+ }
+
+ loadPtr(addressFor(node.virtualRegister()), gpr);
+}
+
+void JITCompiler::jumpFromSpeculativeToNonSpeculative(const SpeculationCheck& check, const EntryLocation& entry, SpeculationRecovery* recovery)
+{
+ ASSERT(check.m_nodeIndex == entry.m_nodeIndex);
+
+ // Link the jump from the Speculative path to here.
+ check.m_check.link(this);
+
+ // Does this speculation check require any additional recovery to be performed,
+ // to restore any state that has been overwritten before we enter back in to the
+ // non-speculative path.
+ if (recovery) {
+ // The only additional recovery we currently support is for integer add operation
+ ASSERT(recovery->type() == SpeculativeAdd);
+ // Revert the add.
+ sub32(recovery->src(), recovery->dest());
+ }
+
+ // FIXME: - This is hideously inefficient!
+ // Where a value is live in a register in the speculative path, and is required in a register
+ // on the non-speculative path, we should not need to be spilling it and reloading (we may
+ // need to spill anyway, if the value is marked as spilled on the non-speculative path).
+ // This may also be spilling values that don't need spilling, e.g. are already spilled,
+ // are constants, or are arguments.
+
+ // Spill all GPRs in use by the speculative path.
+ for (unsigned index = 0; index < GPRInfo::numberOfRegisters; ++index) {
+ NodeIndex nodeIndex = check.m_gprInfo[index].nodeIndex;
+ if (nodeIndex == NoNode)
+ continue;
+
+ DataFormat dataFormat = check.m_gprInfo[index].format;
+ VirtualRegister virtualRegister = graph()[nodeIndex].virtualRegister();
+
+ ASSERT(dataFormat == DataFormatInteger || DataFormatCell || dataFormat & DataFormatJS);
+ if (dataFormat == DataFormatInteger)
+ orPtr(GPRInfo::tagTypeNumberRegister, GPRInfo::toRegister(index));
+ storePtr(GPRInfo::toRegister(index), addressFor(virtualRegister));
+ }
+
+ // Spill all FPRs in use by the speculative path.
+ for (unsigned index = 0; index < FPRInfo::numberOfRegisters; ++index) {
+ NodeIndex nodeIndex = check.m_fprInfo[index];
+ if (nodeIndex == NoNode)
+ continue;
+
+ VirtualRegister virtualRegister = graph()[nodeIndex].virtualRegister();
+
+ moveDoubleToPtr(FPRInfo::toRegister(index), GPRInfo::regT0);
+ subPtr(GPRInfo::tagTypeNumberRegister, GPRInfo::regT0);
+ storePtr(GPRInfo::regT0, addressFor(virtualRegister));
+ }
+
+ // Fill all FPRs in use by the non-speculative path.
+ for (unsigned index = 0; index < FPRInfo::numberOfRegisters; ++index) {
+ NodeIndex nodeIndex = entry.m_fprInfo[index];
+ if (nodeIndex == NoNode)
+ continue;
+
+ fillNumericToDouble(nodeIndex, FPRInfo::toRegister(index), GPRInfo::regT0);
+ }
+
+ // Fill all GPRs in use by the non-speculative path.
+ for (unsigned index = 0; index < GPRInfo::numberOfRegisters; ++index) {
+ NodeIndex nodeIndex = entry.m_gprInfo[index].nodeIndex;
+ if (nodeIndex == NoNode)
+ continue;
+
+ DataFormat dataFormat = entry.m_gprInfo[index].format;
+ if (dataFormat == DataFormatInteger)
+ fillInt32ToInteger(nodeIndex, GPRInfo::toRegister(index));
+ else {
+ ASSERT(dataFormat & DataFormatJS || dataFormat == DataFormatCell); // Treat cell as JSValue for now!
+ fillToJS(nodeIndex, GPRInfo::toRegister(index));
+ // FIXME: For subtypes of DataFormatJS, should jitAssert the subtype?
+ }
+ }
+
+ // Jump into the non-speculative path.
+ jump(entry.m_entry);
+}
+
+void JITCompiler::linkSpeculationChecks(SpeculativeJIT& speculative, NonSpeculativeJIT& nonSpeculative)
+{
+ // Iterators to walk over the set of bail outs & corresponding entry points.
+ SpeculationCheckVector::Iterator checksIter = speculative.speculationChecks().begin();
+ SpeculationCheckVector::Iterator checksEnd = speculative.speculationChecks().end();
+ NonSpeculativeJIT::EntryLocationVector::Iterator entriesIter = nonSpeculative.entryLocations().begin();
+ NonSpeculativeJIT::EntryLocationVector::Iterator entriesEnd = nonSpeculative.entryLocations().end();
+
+ // Iterate over the speculation checks.
+ while (checksIter != checksEnd) {
+ // For every bail out from the speculative path, we must have provided an entry point
+ // into the non-speculative one.
+ ASSERT(checksIter->m_nodeIndex == entriesIter->m_nodeIndex);
+
+ // There may be multiple bail outs that map to the same entry point!
+ do {
+ ASSERT(checksIter != checksEnd);
+ ASSERT(entriesIter != entriesEnd);
+
+ // Plant code to link this speculation failure.
+ const SpeculationCheck& check = *checksIter;
+ const EntryLocation& entry = *entriesIter;
+ jumpFromSpeculativeToNonSpeculative(check, entry, speculative.speculationRecovery(check.m_recoveryIndex));
+ ++checksIter;
+ } while (checksIter != checksEnd && checksIter->m_nodeIndex == entriesIter->m_nodeIndex);
+ ++entriesIter;
+ }
+
+ // FIXME: https://bugs.webkit.org/show_bug.cgi?id=56289
+ ASSERT(!(checksIter != checksEnd));
+ ASSERT(!(entriesIter != entriesEnd));
+}
+
+void JITCompiler::compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWithArityCheck)
+{
+ // === Stage 1 - Function header code generation ===
+ //
+ // This code currently matches the old JIT. In the function header we need to
+ // pop the return address (since we do not allow any recursion on the machine
+ // stack), and perform a fast register file check.
+
+ // This is the main entry point, without performing an arity check.
+ // FIXME: https://bugs.webkit.org/show_bug.cgi?id=56292
+ // We'll need to convert the remaining cti_ style calls (specifically the register file
+ // check) which will be dependent on stack layout. (We'd need to account for this in
+ // both normal return code and when jumping to an exception handler).
+ preserveReturnAddressAfterCall(GPRInfo::regT2);
+ emitPutToCallFrameHeader(GPRInfo::regT2, RegisterFile::ReturnPC);
+ // If we needed to perform an arity check we will already have moved the return address,
+ // so enter after this.
+ Label fromArityCheck(this);
+
+ // Setup a pointer to the codeblock in the CallFrameHeader.
+ emitPutImmediateToCallFrameHeader(m_codeBlock, RegisterFile::CodeBlock);
+
+ // Plant a check that sufficient space is available in the RegisterFile.
+ // FIXME: https://bugs.webkit.org/show_bug.cgi?id=56291
+ addPtr(Imm32(m_codeBlock->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister, GPRInfo::regT1);
+ Jump registerFileCheck = branchPtr(Below, AbsoluteAddress(m_globalData->interpreter->registerFile().addressOfEnd()), GPRInfo::regT1);
+ // Return here after register file check.
+ Label fromRegisterFileCheck = label();
+
+
+ // === Stage 2 - Function body code generation ===
+ //
+ // We generate the speculative code path, followed by the non-speculative
+ // code for the function. Next we need to link the two together, making
+ // bail-outs from the speculative path jump to the corresponding point on
+ // the non-speculative one (and generating any code necessary to juggle
+ // register values around, rebox values, and ensure spilled, to match the
+ // non-speculative path's requirements).
+
+#if DFG_JIT_BREAK_ON_EVERY_FUNCTION
+ // Handy debug tool!
+ breakpoint();
+#endif
+
+ // First generate the speculative path.
+ Label speculativePathBegin = label();
+ SpeculativeJIT speculative(*this);
+#if !DFG_DEBUG_LOCAL_DISBALE_SPECULATIVE
+ bool compiledSpeculative = speculative.compile();
+#else
+ bool compiledSpeculative = false;
+#endif
+
+ // Next, generate the non-speculative path. We pass this a SpeculationCheckIndexIterator
+ // to allow it to check which nodes in the graph may bail out, and may need to reenter the
+ // non-speculative path.
+ if (compiledSpeculative) {
+ SpeculationCheckIndexIterator checkIterator(speculative.speculationChecks());
+ NonSpeculativeJIT nonSpeculative(*this);
+ nonSpeculative.compile(checkIterator);
+
+ // Link the bail-outs from the speculative path to the corresponding entry points into the non-speculative one.
+ linkSpeculationChecks(speculative, nonSpeculative);
+ } else {
+ // If compilation through the SpeculativeJIT failed, throw away the code we generated.
+ m_calls.clear();
+ rewindToLabel(speculativePathBegin);
+
+ SpeculationCheckVector noChecks;
+ SpeculationCheckIndexIterator checkIterator(noChecks);
+ NonSpeculativeJIT nonSpeculative(*this);
+ nonSpeculative.compile(checkIterator);
+ }
+
+ // === Stage 3 - Function footer code generation ===
+ //
+ // Generate code to lookup and jump to exception handlers, to perform the slow
+ // register file check (if the fast one in the function header fails), and
+ // generate the entry point with arity check.
+
+ // Iterate over the m_calls vector, checking for exception checks,
+ // and linking them to here.
+ unsigned exceptionCheckCount = 0;
+ for (unsigned i = 0; i < m_calls.size(); ++i) {
+ Jump& exceptionCheck = m_calls[i].m_exceptionCheck;
+ if (exceptionCheck.isSet()) {
+ exceptionCheck.link(this);
+ ++exceptionCheckCount;
+ }
+ }
+ // If any exception checks were linked, generate code to lookup a handler.
+ if (exceptionCheckCount) {
+ // lookupExceptionHandler is passed two arguments, exec (the CallFrame*), and
+ // an identifier for the operation that threw the exception, which we can use
+ // to look up handler information. The identifier we use is the return address
+ // of the call out from JIT code that threw the exception; this is still
+ // available on the stack, just below the stack pointer!
+ move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+ peek(GPRInfo::argumentGPR1, -1);
+ m_calls.append(CallRecord(call(), lookupExceptionHandler));
+ // lookupExceptionHandler leaves the handler CallFrame* in the returnValueGPR,
+ // and the address of the handler in returnValueGPR2.
+ jump(GPRInfo::returnValueGPR2);
+ }
+
+ // Generate the register file check; if the fast check in the function head fails,
+ // we need to call out to a helper function to check whether more space is available.
+ // FIXME: change this from a cti call to a DFG style operation (normal C calling conventions).
+ registerFileCheck.link(this);
+ move(stackPointerRegister, GPRInfo::argumentGPR0);
+ poke(GPRInfo::callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*));
+ Call callRegisterFileCheck = call();
+ jump(fromRegisterFileCheck);
+
+ // The fast entry point into a function does not check the correct number of arguments
+ // have been passed to the call (we only use the fast entry point where we can statically
+ // determine the correct number of arguments have been passed, or have already checked).
+ // In cases where an arity check is necessary, we enter here.
+ // FIXME: change this from a cti call to a DFG style operation (normal C calling conventions).
+ Label arityCheck = label();
+ preserveReturnAddressAfterCall(GPRInfo::regT2);
+ emitPutToCallFrameHeader(GPRInfo::regT2, RegisterFile::ReturnPC);
+ branch32(Equal, GPRInfo::regT1, Imm32(m_codeBlock->m_numParameters)).linkTo(fromArityCheck, this);
+ move(stackPointerRegister, GPRInfo::argumentGPR0);
+ poke(GPRInfo::callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*));
+ Call callArityCheck = call();
+ move(GPRInfo::regT0, GPRInfo::callFrameRegister);
+ jump(fromArityCheck);
+
+
+ // === Stage 4 - Link ===
+ //
+ // Link the code, populate data in CodeBlock data structures.
+
+ LinkBuffer linkBuffer(*m_globalData, this, m_globalData->executableAllocator);
+
+#if DFG_DEBUG_VERBOSE
+ fprintf(stderr, "JIT code start at %p\n", linkBuffer.debugAddress());
+#endif
+
+ // Link all calls out from the JIT code to their respective functions.
+ for (unsigned i = 0; i < m_calls.size(); ++i)
+ linkBuffer.link(m_calls[i].m_call, m_calls[i].m_function);
+
+ if (m_codeBlock->needsCallReturnIndices()) {
+ m_codeBlock->callReturnIndexVector().reserveCapacity(exceptionCheckCount);
+ for (unsigned i = 0; i < m_calls.size(); ++i) {
+ if (m_calls[i].m_exceptionCheck.isSet()) {
+ unsigned returnAddressOffset = linkBuffer.returnAddressOffset(m_calls[i].m_call);
+ unsigned exceptionInfo = m_calls[i].m_exceptionInfo;
+ m_codeBlock->callReturnIndexVector().append(CallReturnOffsetToBytecodeOffset(returnAddressOffset, exceptionInfo));
+ }
+ }
+ }
+
+ // FIXME: switch the register file check & arity check over to DFGOpertaion style calls, not JIT stubs.
+ linkBuffer.link(callRegisterFileCheck, cti_register_file_check);
+ linkBuffer.link(callArityCheck, m_codeBlock->m_isConstructor ? cti_op_construct_arityCheck : cti_op_call_arityCheck);
+
+ entryWithArityCheck = linkBuffer.locationOf(arityCheck);
+ entry = linkBuffer.finalizeCode();
+}
+
+#if DFG_JIT_ASSERT
+void JITCompiler::jitAssertIsInt32(GPRReg gpr)
+{
+#if CPU(X86_64)
+ Jump checkInt32 = branchPtr(BelowOrEqual, gpr, TrustedImmPtr(reinterpret_cast<void*>(static_cast<uintptr_t>(0xFFFFFFFFu))));
+ breakpoint();
+ checkInt32.link(this);
+#else
+ UNUSED_PARAM(gpr);
+#endif
+}
+
+void JITCompiler::jitAssertIsJSInt32(GPRReg gpr)
+{
+ Jump checkJSInt32 = branchPtr(AboveOrEqual, gpr, GPRInfo::tagTypeNumberRegister);
+ breakpoint();
+ checkJSInt32.link(this);
+}
+
+void JITCompiler::jitAssertIsJSNumber(GPRReg gpr)
+{
+ Jump checkJSNumber = branchTestPtr(MacroAssembler::NonZero, gpr, GPRInfo::tagTypeNumberRegister);
+ breakpoint();
+ checkJSNumber.link(this);
+}
+
+void JITCompiler::jitAssertIsJSDouble(GPRReg gpr)
+{
+ Jump checkJSInt32 = branchPtr(AboveOrEqual, gpr, GPRInfo::tagTypeNumberRegister);
+ Jump checkJSNumber = branchTestPtr(MacroAssembler::NonZero, gpr, GPRInfo::tagTypeNumberRegister);
+ checkJSInt32.link(this);
+ breakpoint();
+ checkJSNumber.link(this);
+}
+#endif
+
+#if ENABLE(SAMPLING_COUNTERS) && CPU(X86_64) // Or any other 64-bit platform!
+void JITCompiler::emitCount(AbstractSamplingCounter& counter, uint32_t increment)
+{
+ addPtr(TrustedImm32(increment), AbsoluteAddress(counter.addressOfCounter()));
+}
+#endif
+
+#if ENABLE(SAMPLING_COUNTERS) && CPU(X86) // Or any other little-endian 32-bit platform!
+void JITCompiler::emitCount(AbstractSamplingCounter& counter, uint32_t increment)
+{
+ intptr_t hiWord = reinterpret_cast<intptr_t>(counter.addressOfCounter()) + sizeof(int32_t);
+ add32(TrustedImm32(increment), AbsoluteAddress(counter.addressOfCounter()));
+ addWithCarry32(TrustedImm32(0), AbsoluteAddress(reinterpret_cast<void*>(hiWord)));
+}
+#endif
+
+#if ENABLE(SAMPLING_FLAGS)
+void JITCompiler::setSamplingFlag(int32_t flag)
+{
+ ASSERT(flag >= 1);
+ ASSERT(flag <= 32);
+ or32(TrustedImm32(1u << (flag - 1)), AbsoluteAddress(SamplingFlags::addressOfFlags()));
+}
+
+void JITCompiler::clearSamplingFlag(int32_t flag)
+{
+ ASSERT(flag >= 1);
+ ASSERT(flag <= 32);
+ and32(TrustedImm32(~(1u << (flag - 1))), AbsoluteAddress(SamplingFlags::addressOfFlags()));
+}
+#endif
+
+} } // namespace JSC::DFG
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DFGJITCompiler_h
+#define DFGJITCompiler_h
+
+#if ENABLE(DFG_JIT)
+
+#include <assembler/MacroAssembler.h>
+#include <bytecode/CodeBlock.h>
+#include <dfg/DFGGraph.h>
+#include <dfg/DFGRegisterBank.h>
+#include <jit/JITCode.h>
+
+#include <dfg/DFGFPRInfo.h>
+#include <dfg/DFGGPRInfo.h>
+
+namespace JSC {
+
+class AbstractSamplingCounter;
+class CodeBlock;
+class JSGlobalData;
+
+namespace DFG {
+
+class JITCodeGenerator;
+class NonSpeculativeJIT;
+class SpeculativeJIT;
+class SpeculationRecovery;
+
+struct EntryLocation;
+struct SpeculationCheck;
+
+// === CallRecord ===
+//
+// A record of a call out from JIT code to a helper function.
+// Every CallRecord contains a reference to the call instruction & the function
+// that it needs to be linked to. Calls that might throw an exception also record
+// the Jump taken on exception (unset if not present), and ExceptionInfo (presently
+// an unsigned, bytecode index) used to recover handler/source info.
+struct CallRecord {
+ // Constructor for a call with no exception handler.
+ CallRecord(MacroAssembler::Call call, FunctionPtr function)
+ : m_call(call)
+ , m_function(function)
+ {
+ }
+
+ // Constructor for a call with an exception handler.
+ CallRecord(MacroAssembler::Call call, FunctionPtr function, MacroAssembler::Jump exceptionCheck, ExceptionInfo exceptionInfo)
+ : m_call(call)
+ , m_function(function)
+ , m_exceptionCheck(exceptionCheck)
+ , m_exceptionInfo(exceptionInfo)
+ {
+ }
+
+ MacroAssembler::Call m_call;
+ FunctionPtr m_function;
+ MacroAssembler::Jump m_exceptionCheck;
+ ExceptionInfo m_exceptionInfo;
+};
+
+// === JITCompiler ===
+//
+// DFG::JITCompiler is responsible for generating JIT code from the dataflow graph.
+// It does so by delegating to the speculative & non-speculative JITs, which
+// generate to a MacroAssembler (which the JITCompiler owns through an inheritance
+// relationship). The JITCompiler holds references to information required during
+// compilation, and also records information used in linking (e.g. a list of all
+// call to be linked).
+class JITCompiler : public MacroAssembler {
+public:
+ JITCompiler(JSGlobalData* globalData, Graph& dfg, CodeBlock* codeBlock)
+ : m_globalData(globalData)
+ , m_graph(dfg)
+ , m_codeBlock(codeBlock)
+ {
+ }
+
+ void compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWithArityCheck);
+
+ // Accessors for properties.
+ Graph& graph() { return m_graph; }
+ CodeBlock* codeBlock() { return m_codeBlock; }
+ JSGlobalData* globalData() { return m_globalData; }
+
+#if CPU(X86_64)
+ void preserveReturnAddressAfterCall(GPRReg reg)
+ {
+ pop(reg);
+ }
+
+ void restoreReturnAddressBeforeReturn(GPRReg reg)
+ {
+ push(reg);
+ }
+
+ void restoreReturnAddressBeforeReturn(Address address)
+ {
+ push(address);
+ }
+
+ void emitGetFromCallFrameHeaderPtr(RegisterFile::CallFrameHeaderEntry entry, GPRReg to)
+ {
+ loadPtr(Address(GPRInfo::callFrameRegister, entry * sizeof(Register)), to);
+ }
+ void emitPutToCallFrameHeader(GPRReg from, RegisterFile::CallFrameHeaderEntry entry)
+ {
+ storePtr(from, Address(GPRInfo::callFrameRegister, entry * sizeof(Register)));
+ }
+
+ void emitPutImmediateToCallFrameHeader(void* value, RegisterFile::CallFrameHeaderEntry entry)
+ {
+ storePtr(TrustedImmPtr(value), Address(GPRInfo::callFrameRegister, entry * sizeof(Register)));
+ }
+#endif
+
+ static Address addressForGlobalVar(GPRReg global, int32_t varNumber)
+ {
+ return Address(global, varNumber * sizeof(Register));
+ }
+
+ static Address addressFor(VirtualRegister virtualRegister)
+ {
+ return Address(GPRInfo::callFrameRegister, virtualRegister * sizeof(Register));
+ }
+
+ static Address tagFor(VirtualRegister virtualRegister)
+ {
+ return Address(GPRInfo::callFrameRegister, virtualRegister * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
+ }
+
+ static Address payloadFor(VirtualRegister virtualRegister)
+ {
+ return Address(GPRInfo::callFrameRegister, virtualRegister * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
+ }
+
+ // Add a call out from JIT code, without an exception check.
+ void appendCall(const FunctionPtr& function)
+ {
+ m_calls.append(CallRecord(call(), function));
+ // FIXME: should be able to JIT_ASSERT here that globalData->exception is null on return back to JIT code.
+ }
+
+ // Add a call out from JIT code, with an exception check.
+ void appendCallWithExceptionCheck(const FunctionPtr& function, unsigned exceptionInfo)
+ {
+ Call functionCall = call();
+ Jump exceptionCheck = branchTestPtr(NonZero, AbsoluteAddress(&globalData()->exception));
+ m_calls.append(CallRecord(functionCall, function, exceptionCheck, exceptionInfo));
+ }
+
+ // Helper methods to check nodes for constants.
+ bool isConstant(NodeIndex nodeIndex)
+ {
+ return graph()[nodeIndex].isConstant();
+ }
+ bool isInt32Constant(NodeIndex nodeIndex)
+ {
+ return graph()[nodeIndex].op == Int32Constant;
+ }
+ bool isDoubleConstant(NodeIndex nodeIndex)
+ {
+ return graph()[nodeIndex].op == DoubleConstant;
+ }
+ bool isJSConstant(NodeIndex nodeIndex)
+ {
+ return graph()[nodeIndex].op == JSConstant;
+ }
+
+ // Helper methods get constant values from nodes.
+ int32_t valueOfInt32Constant(NodeIndex nodeIndex)
+ {
+ ASSERT(isInt32Constant(nodeIndex));
+ return graph()[nodeIndex].int32Constant();
+ }
+ double valueOfDoubleConstant(NodeIndex nodeIndex)
+ {
+ ASSERT(isDoubleConstant(nodeIndex));
+ return graph()[nodeIndex].numericConstant();
+ }
+ JSValue valueOfJSConstant(NodeIndex nodeIndex)
+ {
+ ASSERT(isJSConstant(nodeIndex));
+ unsigned constantIndex = graph()[nodeIndex].constantNumber();
+ return codeBlock()->constantRegister(FirstConstantRegisterIndex + constantIndex).get();
+ }
+
+ // These methods JIT generate dynamic, debug-only checks - akin to ASSERTs.
+#if DFG_JIT_ASSERT
+ void jitAssertIsInt32(GPRReg);
+ void jitAssertIsJSInt32(GPRReg);
+ void jitAssertIsJSNumber(GPRReg);
+ void jitAssertIsJSDouble(GPRReg);
+#else
+ void jitAssertIsInt32(GPRReg) {}
+ void jitAssertIsJSInt32(GPRReg) {}
+ void jitAssertIsJSNumber(GPRReg) {}
+ void jitAssertIsJSDouble(GPRReg) {}
+#endif
+
+#if ENABLE(SAMPLING_COUNTERS)
+ // Debug profiling tool.
+ void emitCount(AbstractSamplingCounter&, uint32_t increment = 1);
+#endif
+
+#if ENABLE(SAMPLING_FLAGS)
+ void setSamplingFlag(int32_t flag);
+ void clearSamplingFlag(int32_t flag);
+#endif
+
+private:
+ // These methods used in linking the speculative & non-speculative paths together.
+ void fillNumericToDouble(NodeIndex, FPRReg, GPRReg temporary);
+ void fillInt32ToInteger(NodeIndex, GPRReg);
+ void fillToJS(NodeIndex, GPRReg);
+ void jumpFromSpeculativeToNonSpeculative(const SpeculationCheck&, const EntryLocation&, SpeculationRecovery*);
+ void linkSpeculationChecks(SpeculativeJIT&, NonSpeculativeJIT&);
+
+ // The globalData, used to access constants such as the vPtrs.
+ JSGlobalData* m_globalData;
+
+ // The dataflow graph currently being generated.
+ Graph& m_graph;
+
+ // The codeBlock currently being generated, used to access information such as constant values, immediates.
+ CodeBlock* m_codeBlock;
+
+ // Vector of calls out from JIT code, including exception handler information.
+ Vector<CallRecord> m_calls;
+};
+
+} } // namespace JSC::DFG
+
+#endif
+#endif
+
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DFGNode_h
+#define DFGNode_h
+
+// Emit various logging information for debugging, including dumping the dataflow graphs.
+#define DFG_DEBUG_VERBOSE 0
+// Enable generation of dynamic checks into the instruction stream.
+#define DFG_JIT_ASSERT 0
+// Consistency check contents compiler data structures.
+#define DFG_CONSISTENCY_CHECK 0
+// Emit a breakpoint into the head of every generated function, to aid debugging in GDB.
+#define DFG_JIT_BREAK_ON_EVERY_FUNCTION 0
+// Emit a breakpoint into the head of every generated node, to aid debugging in GDB.
+#define DFG_JIT_BREAK_ON_EVERY_BLOCK 0
+// Emit a breakpoint into the head of every generated node, to aid debugging in GDB.
+#define DFG_JIT_BREAK_ON_EVERY_NODE 0
+// Disable the DFG JIT without having to touch Platform.h!
+#define DFG_DEBUG_LOCAL_DISBALE 0
+// Disable the SpeculativeJIT without having to touch Platform.h!
+#define DFG_DEBUG_LOCAL_DISBALE_SPECULATIVE 0
+// Generate stats on how successful we were in making use of the DFG jit, and remaining on the hot path.
+#define DFG_SUCCESS_STATS 0
+
+
+#if ENABLE(DFG_JIT)
+
+#include <wtf/Vector.h>
+
+namespace JSC { namespace DFG {
+
+// Type for a virtual register number (spill location).
+// Using an enum to make this type-checked at compile time, to avert programmer errors.
+enum VirtualRegister { InvalidVirtualRegister = -1 };
+COMPILE_ASSERT(sizeof(VirtualRegister) == sizeof(int), VirtualRegister_is_32bit);
+
+// Type for a reference to another node in the graph.
+typedef uint32_t NodeIndex;
+static const NodeIndex NoNode = UINT_MAX;
+
+// Information used to map back from an exception to any handler/source information.
+// (Presently implemented as a bytecode index).
+typedef uint32_t ExceptionInfo;
+
+// Entries in the NodeType enum (below) are composed of an id, a result type (possibly none)
+// and some additional informative flags (must generate, is constant, etc).
+#define NodeIdMask 0xFFF
+#define NodeResultMask 0xF000
+#define NodeMustGenerate 0x10000 // set on nodes that have side effects, and may not trivially be removed by DCE.
+#define NodeIsConstant 0x20000
+#define NodeIsJump 0x40000
+#define NodeIsBranch 0x80000
+#define NodeIsTerminal 0x100000
+
+// These values record the result type of the node (as checked by NodeResultMask, above), 0 for no result.
+#define NodeResultJS 0x1000
+#define NodeResultDouble 0x2000
+#define NodeResultInt32 0x3000
+
+// This macro defines a set of information about all known node types, used to populate NodeId, NodeType below.
+#define FOR_EACH_DFG_OP(macro) \
+ /* Nodes for constants. */\
+ macro(JSConstant, NodeResultJS | NodeIsConstant) \
+ macro(Int32Constant, NodeResultJS | NodeIsConstant) \
+ macro(DoubleConstant, NodeResultJS | NodeIsConstant) \
+ macro(ConvertThis, NodeResultJS) \
+ \
+ /* Nodes for local variable access. */\
+ macro(GetLocal, NodeResultJS) \
+ macro(SetLocal, 0) \
+ macro(Phi, 0) \
+ \
+ /* Nodes for bitwise operations. */\
+ macro(BitAnd, NodeResultInt32) \
+ macro(BitOr, NodeResultInt32) \
+ macro(BitXor, NodeResultInt32) \
+ macro(BitLShift, NodeResultInt32) \
+ macro(BitRShift, NodeResultInt32) \
+ macro(BitURShift, NodeResultInt32) \
+ /* Bitwise operators call ToInt32 on their operands. */\
+ macro(NumberToInt32, NodeResultInt32) \
+ macro(ValueToInt32, NodeResultInt32 | NodeMustGenerate) \
+ /* Used to box the result of URShift nodes (result has range 0..2^32-1). */\
+ macro(UInt32ToNumber, NodeResultDouble) \
+ \
+ /* Nodes for arithmetic operations. */\
+ macro(ArithAdd, NodeResultDouble) \
+ macro(ArithSub, NodeResultDouble) \
+ macro(ArithMul, NodeResultDouble) \
+ macro(ArithDiv, NodeResultDouble) \
+ macro(ArithMod, NodeResultDouble) \
+ /* Arithmetic operators call ToNumber on their operands. */\
+ macro(Int32ToNumber, NodeResultDouble) \
+ macro(ValueToNumber, NodeResultDouble | NodeMustGenerate) \
+ \
+ /* Add of values may either be arithmetic, or result in string concatenation. */\
+ macro(ValueAdd, NodeResultJS | NodeMustGenerate) \
+ \
+ /* Property access. */\
+ /* PutByValAlias indicates a 'put' aliases a prior write to the same property. */\
+ /* Since a put to 'length' may invalidate optimizations here, */\
+ /* this must be the directly subsequent property put. */\
+ macro(GetByVal, NodeResultJS | NodeMustGenerate) \
+ macro(PutByVal, NodeMustGenerate) \
+ macro(PutByValAlias, NodeMustGenerate) \
+ macro(GetById, NodeResultJS | NodeMustGenerate) \
+ macro(PutById, NodeMustGenerate) \
+ macro(PutByIdDirect, NodeMustGenerate) \
+ macro(GetGlobalVar, NodeResultJS | NodeMustGenerate) \
+ macro(PutGlobalVar, NodeMustGenerate) \
+ \
+ /* Nodes for comparison operations. */\
+ macro(CompareLess, NodeResultJS | NodeMustGenerate) \
+ macro(CompareLessEq, NodeResultJS | NodeMustGenerate) \
+ macro(CompareEq, NodeResultJS | NodeMustGenerate) \
+ macro(CompareStrictEq, NodeResultJS) \
+ \
+ /* Nodes for misc operations. */\
+ macro(LogicalNot, NodeResultJS) \
+ \
+ /* Block terminals. */\
+ macro(Jump, NodeMustGenerate | NodeIsTerminal | NodeIsJump) \
+ macro(Branch, NodeMustGenerate | NodeIsTerminal | NodeIsBranch) \
+ macro(Return, NodeMustGenerate | NodeIsTerminal)
+
+// This enum generates a monotonically increasing id for all Node types,
+// and is used by the subsequent enum to fill out the id (as accessed via the NodeIdMask).
+enum NodeId {
+#define DFG_OP_ENUM(opcode, flags) opcode##_id,
+ FOR_EACH_DFG_OP(DFG_OP_ENUM)
+#undef DFG_OP_ENUM
+};
+
+// Entries in this enum describe all Node types.
+// The enum value contains a monotonically increasing id, a result type, and additional flags.
+enum NodeType {
+#define DFG_OP_ENUM(opcode, flags) opcode = opcode##_id | (flags),
+ FOR_EACH_DFG_OP(DFG_OP_ENUM)
+#undef DFG_OP_ENUM
+};
+
+// This type used in passing an immediate argument to Node constructor;
+// distinguishes an immediate value (typically an index into a CodeBlock data structure -
+// a constant index, argument, or identifier) from a NodeIndex.
+struct OpInfo {
+ explicit OpInfo(unsigned value) : m_value(value) {}
+ unsigned m_value;
+};
+
+// === Node ===
+//
+// Node represents a single operation in the data flow graph.
+struct Node {
+ // Construct a node with up to 3 children, no immediate value.
+ Node(NodeType op, ExceptionInfo exceptionInfo, NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode)
+ : op(op)
+ , exceptionInfo(exceptionInfo)
+ , child1(child1)
+ , child2(child2)
+ , child3(child3)
+ , m_virtualRegister(InvalidVirtualRegister)
+ , m_refCount(0)
+ {
+ }
+
+ // Construct a node with up to 3 children and an immediate value.
+ Node(NodeType op, ExceptionInfo exceptionInfo, OpInfo imm, NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode)
+ : op(op)
+ , exceptionInfo(exceptionInfo)
+ , child1(child1)
+ , child2(child2)
+ , child3(child3)
+ , m_virtualRegister(InvalidVirtualRegister)
+ , m_refCount(0)
+ , m_opInfo(imm.m_value)
+ {
+ }
+
+ // Construct a node with up to 3 children and two immediate values.
+ Node(NodeType op, ExceptionInfo exceptionInfo, OpInfo imm1, OpInfo imm2, NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode)
+ : op(op)
+ , exceptionInfo(exceptionInfo)
+ , child1(child1)
+ , child2(child2)
+ , child3(child3)
+ , m_virtualRegister(InvalidVirtualRegister)
+ , m_refCount(0)
+ , m_opInfo(imm1.m_value)
+ {
+ m_constantValue.opInfo2 = imm2.m_value;
+ }
+
+ bool mustGenerate()
+ {
+ return op & NodeMustGenerate;
+ }
+
+ bool isConstant()
+ {
+ return op & NodeIsConstant;
+ }
+
+ unsigned constantNumber()
+ {
+ ASSERT(isConstant());
+ return m_opInfo;
+ }
+
+ bool hasLocal()
+ {
+ return op == GetLocal || op == SetLocal;
+ }
+
+ VirtualRegister local()
+ {
+ ASSERT(hasLocal());
+ return (VirtualRegister)m_opInfo;
+ }
+
+ bool hasIdentifier()
+ {
+ return op == GetById || op == PutById || op == PutByIdDirect;
+ }
+
+ unsigned identifierNumber()
+ {
+ ASSERT(hasIdentifier());
+ return m_opInfo;
+ }
+
+ bool hasVarNumber()
+ {
+ return op == GetGlobalVar || op == PutGlobalVar;
+ }
+
+ unsigned varNumber()
+ {
+ ASSERT(hasVarNumber());
+ return m_opInfo;
+ }
+
+ bool hasResult()
+ {
+ return op & NodeResultMask;
+ }
+
+ bool hasInt32Result()
+ {
+ return (op & NodeResultMask) == NodeResultInt32;
+ }
+
+ bool hasDoubleResult()
+ {
+ return (op & NodeResultMask) == NodeResultDouble;
+ }
+
+ bool hasJSResult()
+ {
+ return (op & NodeResultMask) == NodeResultJS;
+ }
+
+ // Check for integers or doubles.
+ bool hasNumericResult()
+ {
+ // This check will need updating if more result types are added.
+ ASSERT((hasInt32Result() || hasDoubleResult()) == !hasJSResult());
+ return !hasJSResult();
+ }
+
+ int32_t int32Constant()
+ {
+ ASSERT(op == Int32Constant);
+ return m_constantValue.asInt32;
+ }
+
+ void setInt32Constant(int32_t value)
+ {
+ ASSERT(op == Int32Constant);
+ m_constantValue.asInt32 = value;
+ }
+
+ double numericConstant()
+ {
+ ASSERT(op == DoubleConstant);
+ return m_constantValue.asDouble;
+ }
+
+ void setDoubleConstant(double value)
+ {
+ ASSERT(op == DoubleConstant);
+ m_constantValue.asDouble = value;
+ }
+
+ bool isJump()
+ {
+ return op & NodeIsJump;
+ }
+
+ bool isBranch()
+ {
+ return op & NodeIsBranch;
+ }
+
+ bool isTerminal()
+ {
+ return op & NodeIsTerminal;
+ }
+
+ unsigned takenBytecodeOffset()
+ {
+ ASSERT(isBranch() || isJump());
+ return m_opInfo;
+ }
+
+ unsigned notTakenBytecodeOffset()
+ {
+ ASSERT(isBranch());
+ return m_constantValue.opInfo2;
+ }
+
+ VirtualRegister virtualRegister()
+ {
+ ASSERT(hasResult());
+ ASSERT(m_virtualRegister != InvalidVirtualRegister);
+ return m_virtualRegister;
+ }
+
+ void setVirtualRegister(VirtualRegister virtualRegister)
+ {
+ ASSERT(hasResult());
+ ASSERT(m_virtualRegister == InvalidVirtualRegister);
+ m_virtualRegister = virtualRegister;
+ }
+
+ bool shouldGenerate()
+ {
+ return m_refCount && op != Phi;
+ }
+
+ unsigned refCount()
+ {
+ return m_refCount;
+ }
+
+ // returns true when ref count passes from 0 to 1.
+ bool ref()
+ {
+ return !m_refCount++;
+ }
+
+ unsigned adjustedRefCount()
+ {
+ return mustGenerate() ? m_refCount - 1 : m_refCount;
+ }
+
+ // This enum value describes the type of the node.
+ NodeType op;
+ // Used to look up exception handling information (currently implemented as a bytecode index).
+ ExceptionInfo exceptionInfo;
+ // References to up to 3 children (0 for no child).
+ NodeIndex child1, child2, child3;
+
+private:
+ // The virtual register number (spill location) associated with this .
+ VirtualRegister m_virtualRegister;
+ // The number of uses of the result of this operation (+1 for 'must generate' nodes, which have side-effects).
+ unsigned m_refCount;
+ // An immediate value, accesses type-checked via accessors above.
+ unsigned m_opInfo;
+ // The value of an int32/double constant.
+ union {
+ int32_t asInt32;
+ double asDouble;
+ unsigned opInfo2;
+ } m_constantValue;
+};
+
+} } // namespace JSC::DFG
+
+#endif
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DFGNonSpeculativeJIT.h"
+
+#include "DFGSpeculativeJIT.h"
+
+#if ENABLE(DFG_JIT)
+
+namespace JSC { namespace DFG {
+
+const double twoToThe32 = (double)0x100000000ull;
+
+EntryLocation::EntryLocation(MacroAssembler::Label entry, NonSpeculativeJIT* jit)
+ : m_entry(entry)
+ , m_nodeIndex(jit->m_compileIndex)
+{
+ for (gpr_iterator iter = jit->m_gprs.begin(); iter != jit->m_gprs.end(); ++iter) {
+ if (iter.name() != InvalidVirtualRegister) {
+ GenerationInfo& info = jit->m_generationInfo[iter.name()];
+ m_gprInfo[iter.index()].nodeIndex = info.nodeIndex();
+ m_gprInfo[iter.index()].format = info.registerFormat();
+ } else
+ m_gprInfo[iter.index()].nodeIndex = NoNode;
+ }
+ for (fpr_iterator iter = jit->m_fprs.begin(); iter != jit->m_fprs.end(); ++iter) {
+ if (iter.name() != InvalidVirtualRegister) {
+ GenerationInfo& info = jit->m_generationInfo[iter.name()];
+ ASSERT(info.registerFormat() == DataFormatDouble);
+ m_fprInfo[iter.index()] = info.nodeIndex();
+ } else
+ m_fprInfo[iter.index()] = NoNode;
+ }
+}
+
+void NonSpeculativeJIT::valueToNumber(JSValueOperand& operand, FPRReg fpr)
+{
+ GPRReg jsValueGpr = operand.gpr();
+ GPRReg tempGpr = allocate(); // FIXME: can we skip this allocation on the last use of the virtual register?
+
+ JITCompiler::Jump isInteger = m_jit.branchPtr(MacroAssembler::AboveOrEqual, jsValueGpr, GPRInfo::tagTypeNumberRegister);
+ JITCompiler::Jump nonNumeric = m_jit.branchTestPtr(MacroAssembler::Zero, jsValueGpr, GPRInfo::tagTypeNumberRegister);
+
+ // First, if we get here we have a double encoded as a JSValue
+ m_jit.move(jsValueGpr, tempGpr);
+ m_jit.addPtr(GPRInfo::tagTypeNumberRegister, tempGpr);
+ m_jit.movePtrToDouble(tempGpr, fpr);
+ JITCompiler::Jump hasUnboxedDouble = m_jit.jump();
+
+ // Next handle cells (& other JS immediates)
+ nonNumeric.link(&m_jit);
+ silentSpillAllRegisters(fpr, jsValueGpr);
+ m_jit.move(jsValueGpr, GPRInfo::argumentGPR1);
+ m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+ appendCallWithExceptionCheck(dfgConvertJSValueToNumber);
+ m_jit.moveDouble(FPRInfo::returnValueFPR, fpr);
+ silentFillAllRegisters(fpr);
+ JITCompiler::Jump hasCalledToNumber = m_jit.jump();
+
+ // Finally, handle integers.
+ isInteger.link(&m_jit);
+ m_jit.convertInt32ToDouble(jsValueGpr, fpr);
+ hasUnboxedDouble.link(&m_jit);
+ hasCalledToNumber.link(&m_jit);
+
+ m_gprs.unlock(tempGpr);
+}
+
+void NonSpeculativeJIT::valueToInt32(JSValueOperand& operand, GPRReg result)
+{
+ GPRReg jsValueGpr = operand.gpr();
+
+ JITCompiler::Jump isInteger = m_jit.branchPtr(MacroAssembler::AboveOrEqual, jsValueGpr, GPRInfo::tagTypeNumberRegister);
+
+ // First handle non-integers
+ silentSpillAllRegisters(result, jsValueGpr);
+ m_jit.move(jsValueGpr, GPRInfo::argumentGPR1);
+ m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+ appendCallWithExceptionCheck(dfgConvertJSValueToInt32);
+ m_jit.zeroExtend32ToPtr(GPRInfo::returnValueGPR, result);
+ silentFillAllRegisters(result);
+ JITCompiler::Jump hasCalledToInt32 = m_jit.jump();
+
+ // Then handle integers.
+ isInteger.link(&m_jit);
+ m_jit.zeroExtend32ToPtr(jsValueGpr, result);
+ hasCalledToInt32.link(&m_jit);
+}
+
+void NonSpeculativeJIT::numberToInt32(FPRReg fpr, GPRReg gpr)
+{
+ JITCompiler::Jump truncatedToInteger = m_jit.branchTruncateDoubleToInt32(fpr, gpr, JITCompiler::BranchIfTruncateSuccessful);
+
+ silentSpillAllRegisters(gpr);
+
+ m_jit.moveDouble(fpr, FPRInfo::argumentFPR0);
+ appendCallWithExceptionCheck(toInt32);
+ m_jit.zeroExtend32ToPtr(GPRInfo::returnValueGPR, gpr);
+
+ silentFillAllRegisters(gpr);
+
+ truncatedToInteger.link(&m_jit);
+}
+
+bool NonSpeculativeJIT::isKnownInteger(NodeIndex nodeIndex)
+{
+ GenerationInfo& info = m_generationInfo[m_jit.graph()[nodeIndex].virtualRegister()];
+
+ DataFormat registerFormat = info.registerFormat();
+ if (registerFormat != DataFormatNone)
+ return (registerFormat | DataFormatJS) == DataFormatJSInteger;
+
+ DataFormat spillFormat = info.spillFormat();
+ if (spillFormat != DataFormatNone)
+ return (spillFormat | DataFormatJS) == DataFormatJSInteger;
+
+ ASSERT(isConstant(nodeIndex));
+ return isInt32Constant(nodeIndex);
+}
+
+bool NonSpeculativeJIT::isKnownNumeric(NodeIndex nodeIndex)
+{
+ GenerationInfo& info = m_generationInfo[m_jit.graph()[nodeIndex].virtualRegister()];
+
+ DataFormat registerFormat = info.registerFormat();
+ if (registerFormat != DataFormatNone)
+ return (registerFormat | DataFormatJS) == DataFormatJSInteger
+ || (registerFormat | DataFormatJS) == DataFormatJSDouble;
+
+ DataFormat spillFormat = info.spillFormat();
+ if (spillFormat != DataFormatNone)
+ return (spillFormat | DataFormatJS) == DataFormatJSInteger
+ || (spillFormat | DataFormatJS) == DataFormatJSDouble;
+
+ ASSERT(isConstant(nodeIndex));
+ return isInt32Constant(nodeIndex) || isDoubleConstant(nodeIndex);
+}
+
+void NonSpeculativeJIT::compile(SpeculationCheckIndexIterator& checkIterator, Node& node)
+{
+ // Check for speculation checks from the corresponding instruction in the
+ // speculative path. Do not check for NodeIndex 0, since this is checked
+ // in the outermost compile layer, at the head of the non-speculative path
+ // (for index 0 we may need to check regardless of whether or not the node
+ // will be generated, since argument type speculation checks will appear
+ // as speculation checks at this index).
+ if (m_compileIndex && checkIterator.hasCheckAtIndex(m_compileIndex))
+ trackEntry(m_jit.label());
+
+ NodeType op = node.op;
+
+ switch (op) {
+ case ConvertThis: {
+ JSValueOperand thisValue(this, node.child1);
+ GPRReg thisGPR = thisValue.gpr();
+ flushRegisters();
+
+ GPRResult result(this);
+ callOperation(operationConvertThis, result.gpr(), thisGPR);
+ cellResult(result.gpr(), m_compileIndex);
+ break;
+ }
+
+ case Int32Constant:
+ case DoubleConstant:
+ case JSConstant:
+ initConstantInfo(m_compileIndex);
+ break;
+
+ case GetLocal: {
+ GPRTemporary result(this);
+ m_jit.loadPtr(JITCompiler::addressFor(node.local()), result.gpr());
+
+ // Like jsValueResult, but don't useChildren - our children are phi nodes,
+ // and don't represent values within this dataflow with virtual registers.
+ VirtualRegister virtualRegister = node.virtualRegister();
+ m_gprs.retain(result.gpr(), virtualRegister, SpillOrderJS);
+ m_generationInfo[virtualRegister].initJSValue(m_compileIndex, node.refCount(), result.gpr(), DataFormatJS);
+ break;
+ }
+
+ case SetLocal: {
+ JSValueOperand value(this, node.child1);
+ m_jit.storePtr(value.gpr(), JITCompiler::addressFor(node.local()));
+ noResult(m_compileIndex);
+ break;
+ }
+
+ case BitAnd:
+ case BitOr:
+ case BitXor:
+ if (isInt32Constant(node.child1)) {
+ IntegerOperand op2(this, node.child2);
+ GPRTemporary result(this, op2);
+
+ bitOp(op, valueOfInt32Constant(node.child1), op2.gpr(), result.gpr());
+
+ integerResult(result.gpr(), m_compileIndex);
+ } else if (isInt32Constant(node.child2)) {
+ IntegerOperand op1(this, node.child1);
+ GPRTemporary result(this, op1);
+
+ bitOp(op, valueOfInt32Constant(node.child2), op1.gpr(), result.gpr());
+
+ integerResult(result.gpr(), m_compileIndex);
+ } else {
+ IntegerOperand op1(this, node.child1);
+ IntegerOperand op2(this, node.child2);
+ GPRTemporary result(this, op1, op2);
+
+ GPRReg reg1 = op1.gpr();
+ GPRReg reg2 = op2.gpr();
+ bitOp(op, reg1, reg2, result.gpr());
+
+ integerResult(result.gpr(), m_compileIndex);
+ }
+ break;
+
+ case BitRShift:
+ case BitLShift:
+ case BitURShift:
+ if (isInt32Constant(node.child2)) {
+ IntegerOperand op1(this, node.child1);
+ GPRTemporary result(this, op1);
+
+ int shiftAmount = valueOfInt32Constant(node.child2) & 0x1f;
+ // Shifts by zero should have been optimized out of the graph!
+ ASSERT(shiftAmount);
+ shiftOp(op, op1.gpr(), shiftAmount, result.gpr());
+
+ integerResult(result.gpr(), m_compileIndex);
+ } else {
+ // Do not allow shift amount to be used as the result, MacroAssembler does not permit this.
+ IntegerOperand op1(this, node.child1);
+ IntegerOperand op2(this, node.child2);
+ GPRTemporary result(this, op1);
+
+ GPRReg reg1 = op1.gpr();
+ GPRReg reg2 = op2.gpr();
+ shiftOp(op, reg1, reg2, result.gpr());
+
+ integerResult(result.gpr(), m_compileIndex);
+ }
+ break;
+
+ case UInt32ToNumber: {
+ IntegerOperand op1(this, node.child1);
+ FPRTemporary result(this);
+ m_jit.convertInt32ToDouble(op1.gpr(), result.fpr());
+
+ MacroAssembler::Jump positive = m_jit.branch32(MacroAssembler::GreaterThanOrEqual, op1.gpr(), TrustedImm32(0));
+ m_jit.addDouble(JITCompiler::AbsoluteAddress(&twoToThe32), result.fpr());
+ positive.link(&m_jit);
+
+ doubleResult(result.fpr(), m_compileIndex);
+ break;
+ }
+
+ case Int32ToNumber: {
+ IntegerOperand op1(this, node.child1);
+ FPRTemporary result(this);
+ m_jit.convertInt32ToDouble(op1.gpr(), result.fpr());
+ doubleResult(result.fpr(), m_compileIndex);
+ break;
+ }
+
+ case NumberToInt32:
+ case ValueToInt32: {
+ ASSERT(!isInt32Constant(node.child1));
+
+ if (isKnownInteger(node.child1)) {
+ IntegerOperand op1(this, node.child1);
+ GPRTemporary result(this, op1);
+ m_jit.move(op1.gpr(), result.gpr());
+ integerResult(result.gpr(), m_compileIndex);
+ break;
+ }
+
+ if (isKnownNumeric(node.child1)) {
+ DoubleOperand op1(this, node.child1);
+ GPRTemporary result(this);
+ numberToInt32(op1.fpr(), result.gpr());
+ integerResult(result.gpr(), m_compileIndex);
+ break;
+ }
+
+ // We should have handled this via isKnownInteger, or isKnownNumeric!
+ ASSERT(op != NumberToInt32);
+
+ JSValueOperand op1(this, node.child1);
+ GPRTemporary result(this, op1);
+ valueToInt32(op1, result.gpr());
+ integerResult(result.gpr(), m_compileIndex);
+ break;
+ }
+
+ case ValueToNumber: {
+ ASSERT(!isInt32Constant(node.child1));
+ ASSERT(!isDoubleConstant(node.child1));
+
+ if (isKnownInteger(node.child1)) {
+ IntegerOperand op1(this, node.child1);
+ FPRTemporary result(this);
+ m_jit.convertInt32ToDouble(op1.gpr(), result.fpr());
+ doubleResult(result.fpr(), m_compileIndex);
+ break;
+ }
+
+ if (isKnownNumeric(node.child1)) {
+ DoubleOperand op1(this, node.child1);
+ FPRTemporary result(this, op1);
+ m_jit.moveDouble(op1.fpr(), result.fpr());
+ doubleResult(result.fpr(), m_compileIndex);
+ break;
+ }
+
+ JSValueOperand op1(this, node.child1);
+ FPRTemporary result(this);
+ valueToNumber(op1, result.fpr());
+ doubleResult(result.fpr(), m_compileIndex);
+ break;
+ }
+
+ case ValueAdd: {
+ JSValueOperand arg1(this, node.child1);
+ JSValueOperand arg2(this, node.child2);
+ GPRReg arg1GPR = arg1.gpr();
+ GPRReg arg2GPR = arg2.gpr();
+ flushRegisters();
+
+ GPRResult result(this);
+ callOperation(operationValueAdd, result.gpr(), arg1GPR, arg2GPR);
+
+ jsValueResult(result.gpr(), m_compileIndex);
+ break;
+ }
+
+ case ArithAdd: {
+ DoubleOperand op1(this, node.child1);
+ DoubleOperand op2(this, node.child2);
+ FPRTemporary result(this, op1, op2);
+
+ FPRReg reg1 = op1.fpr();
+ FPRReg reg2 = op2.fpr();
+ m_jit.addDouble(reg1, reg2, result.fpr());
+
+ doubleResult(result.fpr(), m_compileIndex);
+ break;
+ }
+
+ case ArithSub: {
+ DoubleOperand op1(this, node.child1);
+ DoubleOperand op2(this, node.child2);
+ FPRTemporary result(this, op1);
+
+ FPRReg reg1 = op1.fpr();
+ FPRReg reg2 = op2.fpr();
+ m_jit.subDouble(reg1, reg2, result.fpr());
+
+ doubleResult(result.fpr(), m_compileIndex);
+ break;
+ }
+
+ case ArithMul: {
+ DoubleOperand op1(this, node.child1);
+ DoubleOperand op2(this, node.child2);
+ FPRTemporary result(this, op1, op2);
+
+ FPRReg reg1 = op1.fpr();
+ FPRReg reg2 = op2.fpr();
+ m_jit.mulDouble(reg1, reg2, result.fpr());
+
+ doubleResult(result.fpr(), m_compileIndex);
+ break;
+ }
+
+ case ArithDiv: {
+ DoubleOperand op1(this, node.child1);
+ DoubleOperand op2(this, node.child2);
+ FPRTemporary result(this, op1);
+
+ FPRReg reg1 = op1.fpr();
+ FPRReg reg2 = op2.fpr();
+ m_jit.divDouble(reg1, reg2, result.fpr());
+
+ doubleResult(result.fpr(), m_compileIndex);
+ break;
+ }
+
+ case ArithMod: {
+ DoubleOperand arg1(this, node.child1);
+ DoubleOperand arg2(this, node.child2);
+ FPRReg arg1FPR = arg1.fpr();
+ FPRReg arg2FPR = arg2.fpr();
+ flushRegisters();
+
+ FPRResult result(this);
+ callOperation(fmod, result.fpr(), arg1FPR, arg2FPR);
+
+ doubleResult(result.fpr(), m_compileIndex);
+ break;
+ }
+
+ case LogicalNot: {
+ JSValueOperand arg1(this, node.child1);
+ GPRReg arg1GPR = arg1.gpr();
+ flushRegisters();
+
+ GPRResult result(this);
+ callOperation(dfgConvertJSValueToBoolean, result.gpr(), arg1GPR);
+
+ // If we add a DataFormatBool, we should use it here.
+ m_jit.xor32(TrustedImm32(ValueTrue), result.gpr());
+ jsValueResult(result.gpr(), m_compileIndex);
+ break;
+ }
+
+ case CompareLess: {
+ JSValueOperand arg1(this, node.child1);
+ JSValueOperand arg2(this, node.child2);
+ GPRReg arg1GPR = arg1.gpr();
+ GPRReg arg2GPR = arg2.gpr();
+ flushRegisters();
+
+ GPRResult result(this);
+ callOperation(operationCompareLess, result.gpr(), arg1GPR, arg2GPR);
+ m_jit.or32(TrustedImm32(ValueFalse), result.gpr());
+
+ jsValueResult(result.gpr(), m_compileIndex);
+ break;
+ }
+
+ case CompareLessEq: {
+ JSValueOperand arg1(this, node.child1);
+ JSValueOperand arg2(this, node.child2);
+ GPRReg arg1GPR = arg1.gpr();
+ GPRReg arg2GPR = arg2.gpr();
+ flushRegisters();
+
+ GPRResult result(this);
+ callOperation(operationCompareLessEq, result.gpr(), arg1GPR, arg2GPR);
+ m_jit.or32(TrustedImm32(ValueFalse), result.gpr());
+
+ jsValueResult(result.gpr(), m_compileIndex);
+ break;
+ }
+
+ case CompareEq: {
+ JSValueOperand arg1(this, node.child1);
+ JSValueOperand arg2(this, node.child2);
+ GPRReg arg1GPR = arg1.gpr();
+ GPRReg arg2GPR = arg2.gpr();
+ flushRegisters();
+
+ GPRResult result(this);
+ callOperation(operationCompareEq, result.gpr(), arg1GPR, arg2GPR);
+ m_jit.or32(TrustedImm32(ValueFalse), result.gpr());
+
+ jsValueResult(result.gpr(), m_compileIndex);
+ break;
+ }
+
+ case CompareStrictEq: {
+ JSValueOperand arg1(this, node.child1);
+ JSValueOperand arg2(this, node.child2);
+ GPRReg arg1GPR = arg1.gpr();
+ GPRReg arg2GPR = arg2.gpr();
+ flushRegisters();
+
+ GPRResult result(this);
+ callOperation(operationCompareStrictEq, result.gpr(), arg1GPR, arg2GPR);
+ m_jit.or32(TrustedImm32(ValueFalse), result.gpr());
+
+ jsValueResult(result.gpr(), m_compileIndex);
+ break;
+ }
+
+ case GetByVal: {
+ JSValueOperand arg1(this, node.child1);
+ JSValueOperand arg2(this, node.child2);
+ GPRReg arg1GPR = arg1.gpr();
+ GPRReg arg2GPR = arg2.gpr();
+ flushRegisters();
+
+ GPRResult result(this);
+ callOperation(operationGetByVal, result.gpr(), arg1GPR, arg2GPR);
+
+ jsValueResult(result.gpr(), m_compileIndex);
+ break;
+ }
+
+ case PutByVal:
+ case PutByValAlias: {
+ JSValueOperand arg1(this, node.child1);
+ JSValueOperand arg2(this, node.child2);
+ JSValueOperand arg3(this, node.child3);
+ GPRReg arg1GPR = arg1.gpr();
+ GPRReg arg2GPR = arg2.gpr();
+ GPRReg arg3GPR = arg3.gpr();
+ flushRegisters();
+
+ GPRResult result(this);
+ callOperation(m_jit.codeBlock()->isStrictMode() ? operationPutByValStrict : operationPutByValNonStrict, arg1GPR, arg2GPR, arg3GPR);
+
+ noResult(m_compileIndex);
+ break;
+ }
+
+ case GetById: {
+ JSValueOperand base(this, node.child1);
+ GPRReg baseGPR = base.gpr();
+ flushRegisters();
+
+ GPRResult result(this);
+ callOperation(operationGetById, result.gpr(), baseGPR, identifier(node.identifierNumber()));
+ jsValueResult(result.gpr(), m_compileIndex);
+ break;
+ }
+
+ case PutById: {
+ JSValueOperand base(this, node.child1);
+ JSValueOperand value(this, node.child2);
+ GPRReg valueGPR = value.gpr();
+ GPRReg baseGPR = base.gpr();
+ flushRegisters();
+
+ callOperation(m_jit.codeBlock()->isStrictMode() ? operationPutByIdStrict : operationPutByIdNonStrict, valueGPR, baseGPR, identifier(node.identifierNumber()));
+ noResult(m_compileIndex);
+ break;
+ }
+
+ case PutByIdDirect: {
+ JSValueOperand base(this, node.child1);
+ JSValueOperand value(this, node.child2);
+ GPRReg valueGPR = value.gpr();
+ GPRReg baseGPR = base.gpr();
+ flushRegisters();
+
+ callOperation(m_jit.codeBlock()->isStrictMode() ? operationPutByIdDirectStrict : operationPutByIdDirectNonStrict, valueGPR, baseGPR, identifier(node.identifierNumber()));
+ noResult(m_compileIndex);
+ break;
+ }
+
+ case GetGlobalVar: {
+ GPRTemporary result(this);
+
+ JSVariableObject* globalObject = m_jit.codeBlock()->globalObject();
+ m_jit.loadPtr(globalObject->addressOfRegisters(), result.gpr());
+ m_jit.loadPtr(JITCompiler::addressForGlobalVar(result.gpr(), node.varNumber()), result.gpr());
+
+ jsValueResult(result.gpr(), m_compileIndex);
+ break;
+ }
+
+ case PutGlobalVar: {
+ JSValueOperand value(this, node.child1);
+ GPRTemporary temp(this);
+
+ JSVariableObject* globalObject = m_jit.codeBlock()->globalObject();
+ m_jit.loadPtr(globalObject->addressOfRegisters(), temp.gpr());
+ m_jit.storePtr(value.gpr(), JITCompiler::addressForGlobalVar(temp.gpr(), node.varNumber()));
+
+ noResult(m_compileIndex);
+ break;
+ }
+
+ case DFG::Jump: {
+ BlockIndex taken = m_jit.graph().blockIndexForBytecodeOffset(node.takenBytecodeOffset());
+ if (taken != (m_block + 1))
+ addBranch(m_jit.jump(), taken);
+ noResult(m_compileIndex);
+ break;
+ }
+
+ case Branch: {
+ JSValueOperand value(this, node.child1);
+ GPRReg valueGPR = value.gpr();
+ flushRegisters();
+
+ GPRResult result(this);
+ callOperation(dfgConvertJSValueToBoolean, result.gpr(), valueGPR);
+
+ BlockIndex taken = m_jit.graph().blockIndexForBytecodeOffset(node.takenBytecodeOffset());
+ BlockIndex notTaken = m_jit.graph().blockIndexForBytecodeOffset(node.notTakenBytecodeOffset());
+
+ addBranch(m_jit.branchTest8(MacroAssembler::NonZero, result.gpr()), taken);
+ if (notTaken != (m_block + 1))
+ addBranch(m_jit.jump(), notTaken);
+
+ noResult(m_compileIndex);
+ break;
+ }
+
+ case Return: {
+ ASSERT(GPRInfo::callFrameRegister != GPRInfo::regT1);
+ ASSERT(GPRInfo::regT1 != GPRInfo::returnValueGPR);
+ ASSERT(GPRInfo::returnValueGPR != GPRInfo::callFrameRegister);
+
+#if DFG_SUCCESS_STATS
+ static SamplingCounter counter("NonSpeculativeJIT");
+ m_jit.emitCount(counter);
+#endif
+
+ // Return the result in returnValueGPR.
+ JSValueOperand op1(this, node.child1);
+ m_jit.move(op1.gpr(), GPRInfo::returnValueGPR);
+
+ // Grab the return address.
+ m_jit.emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, GPRInfo::regT1);
+ // Restore our caller's "r".
+ m_jit.emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, GPRInfo::callFrameRegister);
+ // Return.
+ m_jit.restoreReturnAddressBeforeReturn(GPRInfo::regT1);
+ m_jit.ret();
+
+ noResult(m_compileIndex);
+ break;
+ }
+
+ case Phi:
+ ASSERT_NOT_REACHED();
+ }
+
+ if (node.hasResult() && node.mustGenerate())
+ use(m_compileIndex);
+}
+
+void NonSpeculativeJIT::compile(SpeculationCheckIndexIterator& checkIterator, BasicBlock& block)
+{
+ ASSERT(m_compileIndex == block.begin);
+ m_blockHeads[m_block] = m_jit.label();
+
+#if DFG_JIT_BREAK_ON_EVERY_BLOCK
+ m_jit.breakpoint();
+#endif
+
+ for (; m_compileIndex < block.end; ++m_compileIndex) {
+ Node& node = m_jit.graph()[m_compileIndex];
+ if (!node.shouldGenerate())
+ continue;
+
+#if DFG_DEBUG_VERBOSE
+ fprintf(stderr, "NonSpeculativeJIT generating Node @%d at code offset 0x%x\n", (int)m_compileIndex, m_jit.debugOffset());
+#endif
+#if DFG_JIT_BREAK_ON_EVERY_NODE
+ m_jit.breakpoint();
+#endif
+
+ checkConsistency();
+ compile(checkIterator, node);
+ checkConsistency();
+ }
+}
+
+void NonSpeculativeJIT::compile(SpeculationCheckIndexIterator& checkIterator)
+{
+ // Check for speculation checks added at function entry (checking argument types).
+ if (checkIterator.hasCheckAtIndex(m_compileIndex))
+ trackEntry(m_jit.label());
+
+ ASSERT(!m_compileIndex);
+ for (m_block = 0; m_block < m_jit.graph().m_blocks.size(); ++m_block)
+ compile(checkIterator, *m_jit.graph().m_blocks[m_block]);
+ linkBranches();
+}
+
+} } // namespace JSC::DFG
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DFGNonSpeculativeJIT_h
+#define DFGNonSpeculativeJIT_h
+
+#if ENABLE(DFG_JIT)
+
+#include <dfg/DFGJITCodeGenerator.h>
+
+namespace JSC { namespace DFG {
+
+class SpeculationCheckIndexIterator;
+
+// === EntryLocation ===
+//
+// This structure describes an entry point into the non-speculative
+// code path. This is used in linking bail-outs from the speculative path.
+struct EntryLocation {
+ EntryLocation(MacroAssembler::Label, NonSpeculativeJIT*);
+
+ // The node this entry point corresponds to, and the label
+ // marking the start of code for the given node.
+ MacroAssembler::Label m_entry;
+ NodeIndex m_nodeIndex;
+
+ // For every entry point we record a map recording for every
+ // machine register which, if any, values it contains. For
+ // GPR registers we must also record the format of the value.
+ struct RegisterInfo {
+ NodeIndex nodeIndex;
+ DataFormat format;
+ };
+ RegisterInfo m_gprInfo[GPRInfo::numberOfRegisters];
+ NodeIndex m_fprInfo[FPRInfo::numberOfRegisters];
+};
+
+// === NonSpeculativeJIT ===
+//
+// This class is used to generate code for the non-speculative path.
+// Code generation will take advantage of static information available
+// in the dataflow to perform safe optimizations - for example, avoiding
+// boxing numeric values between arithmetic operations, but will not
+// perform any unsafe optimizations that would render the code unable
+// to produce the correct results for any possible input.
+class NonSpeculativeJIT : public JITCodeGenerator {
+ friend struct EntryLocation;
+public:
+ NonSpeculativeJIT(JITCompiler& jit)
+ : JITCodeGenerator(jit, false)
+ {
+ }
+
+ void compile(SpeculationCheckIndexIterator&);
+
+ typedef SegmentedVector<EntryLocation, 16> EntryLocationVector;
+ EntryLocationVector& entryLocations() { return m_entryLocations; }
+
+private:
+ void compile(SpeculationCheckIndexIterator&, Node&);
+ void compile(SpeculationCheckIndexIterator&, BasicBlock&);
+
+ bool isKnownInteger(NodeIndex);
+ bool isKnownNumeric(NodeIndex);
+
+ // These methods are used when generating 'unexpected'
+ // calls out from JIT code to C++ helper routines -
+ // they spill all live values to the appropriate
+ // slots in the RegisterFile without changing any state
+ // in the GenerationInfo.
+ void silentSpillGPR(VirtualRegister spillMe, GPRReg exclude = InvalidGPRReg)
+ {
+ GenerationInfo& info = m_generationInfo[spillMe];
+ ASSERT(info.registerFormat() != DataFormatNone && info.registerFormat() != DataFormatDouble);
+
+ if (!info.needsSpill() || (info.gpr() == exclude))
+ return;
+
+ DataFormat registerFormat = info.registerFormat();
+
+ if (registerFormat == DataFormatInteger) {
+ m_jit.orPtr(GPRInfo::tagTypeNumberRegister, info.gpr());
+ m_jit.storePtr(info.gpr(), JITCompiler::addressFor(spillMe));
+ } else {
+ ASSERT(registerFormat & DataFormatJS || registerFormat == DataFormatCell);
+ m_jit.storePtr(info.gpr(), JITCompiler::addressFor(spillMe));
+ }
+ }
+ void silentSpillFPR(VirtualRegister spillMe, GPRReg canTrample, FPRReg exclude = InvalidFPRReg)
+ {
+ GenerationInfo& info = m_generationInfo[spillMe];
+ ASSERT(info.registerFormat() == DataFormatDouble);
+
+ if (!info.needsSpill() || (info.fpr() == exclude))
+ return;
+
+ boxDouble(info.fpr(), canTrample);
+ m_jit.storePtr(canTrample, JITCompiler::addressFor(spillMe));
+ }
+
+ void silentFillGPR(VirtualRegister spillMe, GPRReg exclude = InvalidGPRReg)
+ {
+ GenerationInfo& info = m_generationInfo[spillMe];
+ if (info.gpr() == exclude)
+ return;
+
+ NodeIndex nodeIndex = info.nodeIndex();
+ Node& node = m_jit.graph()[nodeIndex];
+ ASSERT(info.registerFormat() != DataFormatNone && info.registerFormat() != DataFormatDouble);
+ DataFormat registerFormat = info.registerFormat();
+
+ if (registerFormat == DataFormatInteger) {
+ if (node.isConstant()) {
+ ASSERT(isInt32Constant(nodeIndex));
+ m_jit.move(Imm32(valueOfInt32Constant(nodeIndex)), info.gpr());
+ } else
+ m_jit.load32(JITCompiler::addressFor(spillMe), info.gpr());
+ return;
+ }
+
+ if (node.isConstant())
+ m_jit.move(constantAsJSValueAsImmPtr(nodeIndex), info.gpr());
+ else {
+ ASSERT(registerFormat & DataFormatJS || registerFormat == DataFormatCell);
+ m_jit.loadPtr(JITCompiler::addressFor(spillMe), info.gpr());
+ }
+ }
+ void silentFillFPR(VirtualRegister spillMe, GPRReg canTrample, FPRReg exclude = InvalidFPRReg)
+ {
+ GenerationInfo& info = m_generationInfo[spillMe];
+ if (info.fpr() == exclude)
+ return;
+
+ NodeIndex nodeIndex = info.nodeIndex();
+ Node& node = m_jit.graph()[nodeIndex];
+ ASSERT(info.registerFormat() == DataFormatDouble);
+
+ if (node.isConstant())
+ m_jit.move(constantAsJSValueAsImmPtr(nodeIndex), info.gpr());
+ else {
+ m_jit.loadPtr(JITCompiler::addressFor(spillMe), canTrample);
+ unboxDouble(canTrample, info.fpr());
+ }
+ }
+
+ void silentSpillAllRegisters(GPRReg exclude, GPRReg preserve = InvalidGPRReg)
+ {
+ GPRReg canTrample = GPRInfo::regT0;
+ if (preserve == GPRInfo::regT0)
+ canTrample = GPRInfo::regT1;
+
+ for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
+ if (iter.name() != InvalidVirtualRegister)
+ silentSpillGPR(iter.name(), exclude);
+ }
+ for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
+ if (iter.name() != InvalidVirtualRegister)
+ silentSpillFPR(iter.name(), canTrample);
+ }
+ }
+ void silentSpillAllRegisters(FPRReg exclude, GPRReg preserve = InvalidGPRReg)
+ {
+ GPRReg canTrample = GPRInfo::regT0;
+ if (preserve == GPRInfo::regT0)
+ canTrample = GPRInfo::regT1;
+
+ for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
+ if (iter.name() != InvalidVirtualRegister)
+ silentSpillGPR(iter.name());
+ }
+ for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
+ if (iter.name() != InvalidVirtualRegister)
+ silentSpillFPR(iter.name(), canTrample, exclude);
+ }
+ }
+ void silentFillAllRegisters(GPRReg exclude)
+ {
+ GPRReg canTrample = GPRInfo::regT0;
+ if (exclude == GPRInfo::regT0)
+ canTrample = GPRInfo::regT1;
+
+ for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
+ if (iter.name() != InvalidVirtualRegister)
+ silentFillFPR(iter.name(), canTrample);
+ }
+ for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
+ if (iter.name() != InvalidVirtualRegister)
+ silentFillGPR(iter.name(), exclude);
+ }
+ }
+ void silentFillAllRegisters(FPRReg exclude)
+ {
+ GPRReg canTrample = GPRInfo::regT0;
+
+ for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
+ if (iter.name() != InvalidVirtualRegister) {
+ ASSERT_UNUSED(exclude, iter.regID() != exclude);
+ silentFillFPR(iter.name(), canTrample, exclude);
+ }
+ }
+ for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
+ if (iter.name() != InvalidVirtualRegister)
+ silentFillGPR(iter.name());
+ }
+ }
+
+ // These methods are used to plant calls out to C++
+ // helper routines to convert between types.
+ void valueToNumber(JSValueOperand&, FPRReg result);
+ void valueToInt32(JSValueOperand&, GPRReg result);
+ void numberToInt32(FPRReg, GPRReg result);
+
+ // Record an entry location into the non-speculative code path;
+ // for every bail-out on the speculative path we record information
+ // to be able to re-enter into the non-speculative one.
+ void trackEntry(MacroAssembler::Label entry)
+ {
+ m_entryLocations.append(EntryLocation(entry, this));
+ }
+
+ EntryLocationVector m_entryLocations;
+};
+
+} } // namespace JSC::DFG
+
+#endif
+#endif
+
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DFGOperations.h"
+
+#if ENABLE(DFG_JIT)
+
+#include "CodeBlock.h"
+#include "Interpreter.h"
+#include "JSByteArray.h"
+#include "JSGlobalData.h"
+#include "Operations.h"
+
+namespace JSC { namespace DFG {
+
+EncodedJSValue operationConvertThis(ExecState* exec, EncodedJSValue encodedOp)
+{
+ return JSValue::encode(JSValue::decode(encodedOp).toThisObject(exec));
+}
+
+EncodedJSValue operationValueAdd(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
+{
+ JSValue op1 = JSValue::decode(encodedOp1);
+ JSValue op2 = JSValue::decode(encodedOp2);
+
+ if (op1.isInt32() && op2.isInt32()) {
+ int64_t result64 = static_cast<int64_t>(op1.asInt32()) + static_cast<int64_t>(op2.asInt32());
+ int32_t result32 = static_cast<int32_t>(result64);
+ if (LIKELY(result32 == result64))
+ return JSValue::encode(jsNumber(result32));
+ return JSValue::encode(jsNumber((double)result64));
+ }
+
+ double number1;
+ double number2;
+ if (op1.getNumber(number1) && op2.getNumber(number2))
+ return JSValue::encode(jsNumber(number1 + number2));
+
+ return JSValue::encode(jsAddSlowCase(exec, op1, op2));
+}
+
+EncodedJSValue operationGetByVal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty)
+{
+ JSValue baseValue = JSValue::decode(encodedBase);
+ JSValue property = JSValue::decode(encodedProperty);
+
+ if (LIKELY(baseValue.isCell())) {
+ JSCell* base = baseValue.asCell();
+
+ if (property.isUInt32()) {
+ JSGlobalData* globalData = &exec->globalData();
+ uint32_t i = property.asUInt32();
+
+ // FIXME: the JIT used to handle these in compiled code!
+ if (isJSArray(globalData, base) && asArray(base)->canGetIndex(i))
+ return JSValue::encode(asArray(base)->getIndex(i));
+
+ // FIXME: the JITstub used to relink this to an optimized form!
+ if (isJSString(globalData, base) && asString(base)->canGetIndex(i))
+ return JSValue::encode(asString(base)->getIndex(exec, i));
+
+ // FIXME: the JITstub used to relink this to an optimized form!
+ if (isJSByteArray(globalData, base) && asByteArray(base)->canAccessIndex(i))
+ return JSValue::encode(asByteArray(base)->getIndex(exec, i));
+
+ return JSValue::encode(baseValue.get(exec, i));
+ }
+
+ if (property.isString()) {
+ Identifier propertyName(exec, asString(property)->value(exec));
+ PropertySlot slot(base);
+ if (base->fastGetOwnPropertySlot(exec, propertyName, slot))
+ return JSValue::encode(slot.getValue(exec, propertyName));
+ }
+ }
+
+ Identifier ident(exec, property.toString(exec));
+ return JSValue::encode(baseValue.get(exec, ident));
+}
+
+EncodedJSValue operationGetById(ExecState* exec, EncodedJSValue encodedBase, Identifier* identifier)
+{
+ JSValue baseValue = JSValue::decode(encodedBase);
+ PropertySlot slot(baseValue);
+ return JSValue::encode(baseValue.get(exec, *identifier, slot));
+}
+
+template<bool strict>
+ALWAYS_INLINE static void operationPutByValInternal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
+{
+ JSGlobalData* globalData = &exec->globalData();
+
+ JSValue baseValue = JSValue::decode(encodedBase);
+ JSValue property = JSValue::decode(encodedProperty);
+ JSValue value = JSValue::decode(encodedValue);
+
+ if (LIKELY(property.isUInt32())) {
+ uint32_t i = property.asUInt32();
+
+ if (isJSArray(globalData, baseValue)) {
+ JSArray* jsArray = asArray(baseValue);
+ if (jsArray->canSetIndex(i)) {
+ jsArray->setIndex(*globalData, i, value);
+ return;
+ }
+
+ jsArray->JSArray::put(exec, i, value);
+ return;
+ }
+
+ if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) {
+ JSByteArray* jsByteArray = asByteArray(baseValue);
+ // FIXME: the JITstub used to relink this to an optimized form!
+ if (value.isInt32()) {
+ jsByteArray->setIndex(i, value.asInt32());
+ return;
+ }
+
+ double dValue = 0;
+ if (value.getNumber(dValue)) {
+ jsByteArray->setIndex(i, dValue);
+ return;
+ }
+ }
+
+ baseValue.put(exec, i, value);
+ return;
+ }
+
+ // Don't put to an object if toString throws an exception.
+ Identifier ident(exec, property.toString(exec));
+ if (!globalData->exception) {
+ PutPropertySlot slot(strict);
+ baseValue.put(exec, ident, value, slot);
+ }
+}
+
+void operationPutByValStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
+{
+ operationPutByValInternal<true>(exec, encodedBase, encodedProperty, encodedValue);
+}
+
+void operationPutByValNonStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
+{
+ operationPutByValInternal<false>(exec, encodedBase, encodedProperty, encodedValue);
+}
+
+void operationPutByIdStrict(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* identifier)
+{
+ PutPropertySlot slot(true);
+ JSValue::decode(encodedBase).put(exec, *identifier, JSValue::decode(encodedValue), slot);
+}
+
+void operationPutByIdNonStrict(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* identifier)
+{
+ PutPropertySlot slot(false);
+ JSValue::decode(encodedBase).put(exec, *identifier, JSValue::decode(encodedValue), slot);
+}
+
+void operationPutByIdDirectStrict(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* identifier)
+{
+ PutPropertySlot slot(true);
+ JSValue::decode(encodedBase).putDirect(exec, *identifier, JSValue::decode(encodedValue), slot);
+}
+
+void operationPutByIdDirectNonStrict(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* identifier)
+{
+ PutPropertySlot slot(false);
+ JSValue::decode(encodedBase).putDirect(exec, *identifier, JSValue::decode(encodedValue), slot);
+}
+
+bool operationCompareLess(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
+{
+ return jsLess(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
+}
+
+bool operationCompareLessEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
+{
+ return jsLessEq(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
+}
+
+bool operationCompareEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
+{
+ return JSValue::equal(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
+}
+
+bool operationCompareStrictEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
+{
+ return JSValue::strictEqual(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
+}
+
+DFGHandler lookupExceptionHandler(ExecState* exec, ReturnAddressPtr faultLocation)
+{
+ JSValue exceptionValue = exec->exception();
+ ASSERT(exceptionValue);
+
+ unsigned vPCIndex = exec->codeBlock()->bytecodeOffset(faultLocation);
+ HandlerInfo* handler = exec->globalData().interpreter->throwException(exec, exceptionValue, vPCIndex);
+
+ void* catchRoutine = handler ? handler->nativeCode.executableAddress() : (void*)ctiOpThrowNotCaught;
+ ASSERT(catchRoutine);
+ return DFGHandler(exec, catchRoutine);
+}
+
+double dfgConvertJSValueToNumber(ExecState* exec, EncodedJSValue value)
+{
+ return JSValue::decode(value).toNumber(exec);
+}
+
+int32_t dfgConvertJSValueToInt32(ExecState* exec, EncodedJSValue value)
+{
+ return JSValue::decode(value).toInt32(exec);
+}
+
+bool dfgConvertJSValueToBoolean(ExecState* exec, EncodedJSValue encodedOp)
+{
+ return JSValue::decode(encodedOp).toBoolean(exec);
+}
+
+} } // namespace JSC::DFG
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DFGOperations_h
+#define DFGOperations_h
+
+#if ENABLE(DFG_JIT)
+
+#include <dfg/DFGJITCompiler.h>
+
+namespace JSC {
+
+class Identifier;
+
+namespace DFG {
+
+// These typedefs provide typechecking when generating calls out to helper routines;
+// this helps prevent calling a helper routine with the wrong arguments!
+typedef EncodedJSValue (*J_DFGOperation_EJJ)(ExecState*, EncodedJSValue, EncodedJSValue);
+typedef EncodedJSValue (*J_DFGOperation_EJ)(ExecState*, EncodedJSValue);
+typedef EncodedJSValue (*J_DFGOperation_EJP)(ExecState*, EncodedJSValue, void*);
+typedef EncodedJSValue (*J_DFGOperation_EJI)(ExecState*, EncodedJSValue, Identifier*);
+typedef bool (*Z_DFGOperation_EJ)(ExecState*, EncodedJSValue);
+typedef bool (*Z_DFGOperation_EJJ)(ExecState*, EncodedJSValue, EncodedJSValue);
+typedef void (*V_DFGOperation_EJJJ)(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue);
+typedef void (*V_DFGOperation_EJJP)(ExecState*, EncodedJSValue, EncodedJSValue, void*);
+typedef void (*V_DFGOperation_EJJI)(ExecState*, EncodedJSValue, EncodedJSValue, Identifier*);
+typedef double (*D_DFGOperation_DD)(double, double);
+
+// These routines are provide callbacks out to C++ implementations of operations too complex to JIT.
+EncodedJSValue operationConvertThis(ExecState*, EncodedJSValue encodedOp1);
+EncodedJSValue operationValueAdd(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2);
+EncodedJSValue operationGetByVal(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty);
+EncodedJSValue operationGetById(ExecState*, EncodedJSValue encodedBase, Identifier*);
+void operationPutByValStrict(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue);
+void operationPutByValNonStrict(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue);
+void operationPutByIdStrict(ExecState*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier*);
+void operationPutByIdNonStrict(ExecState*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier*);
+void operationPutByIdDirectStrict(ExecState*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier*);
+void operationPutByIdDirectNonStrict(ExecState*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier*);
+bool operationCompareLess(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2);
+bool operationCompareLessEq(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2);
+bool operationCompareEq(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2);
+bool operationCompareStrictEq(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2);
+
+// This method is used to lookup an exception hander, keyed by faultLocation, which is
+// the return location from one of the calls out to one of the helper operations above.
+struct DFGHandler {
+ DFGHandler(ExecState* exec, void* handler)
+ : exec(exec)
+ , handler(handler)
+ {
+ }
+
+ ExecState* exec;
+ void* handler;
+};
+DFGHandler lookupExceptionHandler(ExecState*, ReturnAddressPtr faultLocation);
+
+// These operations implement the implicitly called ToInt32, ToNumber, and ToBoolean conversions from ES5.
+double dfgConvertJSValueToNumber(ExecState*, EncodedJSValue);
+int32_t dfgConvertJSValueToInt32(ExecState*, EncodedJSValue);
+bool dfgConvertJSValueToBoolean(ExecState*, EncodedJSValue);
+
+} } // namespace JSC::DFG
+
+#endif
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DFGRegisterBank_h
+#define DFGRegisterBank_h
+
+#if ENABLE(DFG_JIT)
+
+#include <dfg/DFGNode.h>
+
+namespace JSC { namespace DFG {
+
+// === RegisterBank ===
+//
+// This class is used to implement the GPR and FPR register banks.
+// All registers have two pieces of state associated with them:
+// a lock count (used to indicate this register is already in use
+// in code generation of the current node, and cannot be spilled or
+// allocated as a temporary), and VirtualRegister 'name', recording
+// which value (if any) a machine register currently holds.
+// Either or both of these pieces of information may be valid for a
+// given register. A register may be:
+//
+// - unlocked, and unnamed: Available for allocation.
+// - locked, but unnamed: Already allocated as a temporary or
+// result for the current node.
+// - unlocked, but named: Contains the result of a prior operation,
+// not yet in use for this node,
+// - locked, but named: Contains the result of a prior operation,
+// already allocated as a operand to the
+// current operation.
+//
+// For every named register we also record a hint value indicating
+// the order in which registers should be selected to be spilled;
+// registers that can be more cheaply spilled and/or filled should
+// be selected first.
+//
+// Locking register is a strong retention mechanism; a locked register
+// will never be reallocated (this is used to ensure the operands to
+// the current node are in registers). Naming, conversely, in a weak
+// retention mechanism - allocating a register may force a named value
+// to be spilled.
+//
+// All named values must be given a hint that is greater than Min and
+// less than Max.
+template<class BankInfo>
+class RegisterBank {
+ typedef typename BankInfo::RegisterType RegID;
+ static const size_t NUM_REGS = BankInfo::numberOfRegisters;
+
+ typedef uint32_t SpillHint;
+ static const SpillHint SpillHintInvalid = 0xffffffff;
+
+public:
+ RegisterBank()
+ : m_lastAllocated(NUM_REGS - 1)
+ {
+ }
+
+ // Allocate a register - this function finds an unlocked register,
+ // locks it, and returns it. If any named registers exist, one
+ // of these should be selected to be allocated. If all unlocked
+ // registers are named, then one of the named registers will need
+ // to be spilled. In this case the register selected to be spilled
+ // will be one of the registers that has the lowest 'spillOrder'
+ // cost associated with it.
+ //
+ // This method select the register to be allocated, and calls the
+ // private 'allocateInternal' method to update internal data
+ // structures accordingly.
+ RegID allocate(VirtualRegister &spillMe)
+ {
+ uint32_t currentLowest = NUM_REGS;
+ SpillHint currentSpillOrder = SpillHintInvalid;
+
+ // Scan through all register, starting at the last allocated & looping around.
+ ASSERT(m_lastAllocated < NUM_REGS);
+
+ // This loop is broken into two halves, looping from the last allocated
+ // register (the register returned last time this method was called) to
+ // the maximum register value, then from 0 to the last allocated.
+ // This implements a simple round-robin like approach to try to reduce
+ // thrash, and minimize time spent scanning locked registers in allocation.
+ // If a unlocked and unnamed register is found return it immediately.
+ // Otherwise, find the first unlocked register with the lowest spillOrder.
+ for (uint32_t i = m_lastAllocated + 1; i < NUM_REGS; ++i) {
+ // (1) If the current register is locked, it is not a candidate.
+ if (m_data[i].lockCount)
+ continue;
+ // (2) If the current register's spill order is 0, pick this! – unassigned registers have spill order 0.
+ SpillHint spillOrder = m_data[i].spillOrder;
+ if (spillOrder == SpillHintInvalid)
+ return allocateInternal(i, spillMe);
+ // If this register is better (has a lower spill order value) than any prior
+ // candidate, then record it.
+ if (spillOrder < currentSpillOrder) {
+ currentSpillOrder = spillOrder;
+ currentLowest = i;
+ }
+ }
+ // Loop over the remaining entries.
+ for (uint32_t i = 0; i <= m_lastAllocated; ++i) {
+ if (m_data[i].lockCount)
+ continue;
+ SpillHint spillOrder = m_data[i].spillOrder;
+ if (spillOrder == SpillHintInvalid)
+ return allocateInternal(i, spillMe);
+ if (spillOrder < currentSpillOrder) {
+ currentSpillOrder = spillOrder;
+ currentLowest = i;
+ }
+ }
+
+ // Deadlock check - this could only occur is all registers are locked!
+ ASSERT(currentLowest != NUM_REGS && currentSpillOrder != SpillHintInvalid);
+ // There were no available registers; currentLowest will need to be spilled.
+ return allocateInternal(currentLowest, spillMe);
+ }
+
+ // retain/release - these methods are used to associate/disassociate names
+ // with values in registers. retain should only be called on locked registers.
+ void retain(RegID reg, VirtualRegister name, SpillHint spillOrder)
+ {
+ unsigned index = BankInfo::toIndex(reg);
+
+ // SpillHint must be valid.
+ ASSERT(spillOrder != SpillHintInvalid);
+ // 'index' must be a valid, locked register.
+ ASSERT(index < NUM_REGS);
+ ASSERT(m_data[index].lockCount);
+ // 'index' should not currently be named, the new name must be valid.
+ ASSERT(m_data[index].name == InvalidVirtualRegister);
+ ASSERT(name != InvalidVirtualRegister);
+ // 'index' should not currently have a spillOrder.
+ ASSERT(m_data[index].spillOrder == SpillHintInvalid);
+
+ m_data[index].name = name;
+ m_data[index].spillOrder = spillOrder;
+ }
+ void release(RegID reg)
+ {
+ releaseAtIndex(BankInfo::toIndex(reg));
+ }
+
+ // lock/unlock register, ensures that they are not spilled.
+ void lock(RegID reg)
+ {
+ unsigned index = BankInfo::toIndex(reg);
+
+ ASSERT(index < NUM_REGS);
+ ++m_data[index].lockCount;
+ ASSERT(m_data[index].lockCount);
+ }
+ void unlock(RegID reg)
+ {
+ unsigned index = BankInfo::toIndex(reg);
+
+ ASSERT(index < NUM_REGS);
+ ASSERT(m_data[index].lockCount);
+ --m_data[index].lockCount;
+ }
+ bool isLocked(RegID reg) const
+ {
+ return isLockedAtIndex(BankInfo::toIndex(reg));
+ }
+
+ // Get the name (VirtualRegister) associated with the
+ // given register (or InvalidVirtualRegister for none).
+ VirtualRegister name(RegID reg) const
+ {
+ return nameAtIndex(BankInfo::toIndex(reg));
+ }
+
+#ifndef NDEBUG
+ void dump()
+ {
+ // For each register, print the VirtualRegister 'name'.
+ for (uint32_t i =0; i < NUM_REGS; ++i) {
+ if (m_data[i].name != InvalidVirtualRegister)
+ fprintf(stderr, "[%02d]", m_data[i].name);
+ else
+ fprintf(stderr, "[--]");
+ }
+ fprintf(stderr, "\n");
+ }
+#endif
+
+ class iterator {
+ friend class RegisterBank<BankInfo>;
+ public:
+ VirtualRegister name() const
+ {
+ return m_bank->nameAtIndex(m_index);
+ }
+
+ bool isLocked() const
+ {
+ return m_bank->isLockedAtIndex(m_index);
+ }
+
+ void release() const
+ {
+ m_bank->releaseAtIndex(m_index);
+ }
+
+ RegID regID() const
+ {
+ return BankInfo::toRegister(m_index);
+ }
+
+#ifndef NDEBUG
+ const char* debugName() const
+ {
+ return BankInfo::debugName(regID());
+ }
+#endif
+
+ iterator& operator++()
+ {
+ ++m_index;
+ return *this;
+ }
+
+ bool operator!=(const iterator& other) const
+ {
+ ASSERT(m_bank == other.m_bank);
+ return m_index != other.m_index;
+ }
+
+ unsigned index() const
+ {
+ return m_index;
+ }
+
+ private:
+ iterator(RegisterBank<BankInfo>* bank, unsigned index)
+ : m_bank(bank)
+ , m_index(index)
+ {
+ }
+
+ RegisterBank<BankInfo>* m_bank;
+ unsigned m_index;
+ };
+
+ iterator begin()
+ {
+ return iterator(this, 0);
+ }
+
+ iterator end()
+ {
+ return iterator(this, NUM_REGS);
+ }
+
+private:
+ bool isLockedAtIndex(unsigned index) const
+ {
+ ASSERT(index < NUM_REGS);
+ return m_data[index].lockCount;
+ }
+
+ VirtualRegister nameAtIndex(unsigned index) const
+ {
+ ASSERT(index < NUM_REGS);
+ return m_data[index].name;
+ }
+
+ void releaseAtIndex(unsigned index)
+ {
+ // 'index' must be a valid register.
+ ASSERT(index < NUM_REGS);
+ // 'index' should currently be named.
+ ASSERT(m_data[index].name != InvalidVirtualRegister);
+ // 'index' should currently have a valid spill order.
+ ASSERT(m_data[index].spillOrder != SpillHintInvalid);
+
+ m_data[index].name = InvalidVirtualRegister;
+ m_data[index].spillOrder = SpillHintInvalid;
+ }
+
+ // Used by 'allocate', above, to update inforamtion in the map.
+ RegID allocateInternal(uint32_t i, VirtualRegister &spillMe)
+ {
+ // 'i' must be a valid, unlocked register.
+ ASSERT(i < NUM_REGS && !m_data[i].lockCount);
+
+ // Return the VirtualRegister of the named value currently stored in
+ // the register being returned - or InvalidVirtualRegister if none.
+ spillMe = m_data[i].name;
+
+ // Clear any name/spillOrder currently associated with the register,
+ m_data[i] = MapEntry();
+ // Mark the register as locked (with a lock count of 1).
+ m_data[i].lockCount = 1;
+
+ m_lastAllocated = i;
+ return BankInfo::toRegister(i);
+ }
+
+ // === MapEntry ===
+ //
+ // This structure provides information for an individual machine register
+ // being managed by the RegisterBank. For each register we track a lock
+ // count, name and spillOrder hint.
+ struct MapEntry {
+ MapEntry()
+ : name(InvalidVirtualRegister)
+ , spillOrder(SpillHintInvalid)
+ , lockCount(0)
+ {
+ }
+
+ VirtualRegister name;
+ SpillHint spillOrder;
+ uint32_t lockCount;
+ };
+
+ // Holds the current status of all registers.
+ MapEntry m_data[NUM_REGS];
+ // Used to to implement a simple round-robin like allocation scheme.
+ uint32_t m_lastAllocated;
+};
+
+} } // namespace JSC::DFG
+
+#endif
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DFGScoreBoard_h
+#define DFGScoreBoard_h
+
+#if ENABLE(DFG_JIT)
+
+#include <dfg/DFGGraph.h>
+#include <wtf/Vector.h>
+
+namespace JSC { namespace DFG {
+
+// === ScoreBoard ===
+//
+// This class is used in performing a virtual register allocation over the graph.
+// VirtualRegisters are allocated to nodes, with a used count for each virtual
+// register tracking the lifespan of the value; after the final use of a node
+// the VirtualRegister associated is freed such that it can be reused for
+// another node.
+class ScoreBoard {
+public:
+ ScoreBoard(Graph& graph, uint32_t firstTemporary)
+ : m_graph(graph)
+ , m_firstTemporary(firstTemporary)
+ {
+ }
+
+#if DFG_CONSISTENCY_CHECK
+ ~ScoreBoard()
+ {
+ // Every VirtualRegister that was allocated should now be free.
+ ASSERT(m_used.size() == m_free.size());
+ // Every entry in the used list should be available in the free list.
+ for (size_t i = 0; i < m_used.size(); ++i)
+ ASSERT(m_free.contains(i));
+ // For every entry in the used list the use count of the virtual register should be zero.
+ for (size_t i = 0; i < m_free.size(); ++i)
+ ASSERT(!m_used[i]);
+ }
+#endif
+
+ VirtualRegister allocate()
+ {
+ // Do we have any VirtualRegsiters in the free list, that were used by
+ // prior nodes, but are now available?
+ if (!m_free.isEmpty()) {
+ uint32_t index = m_free.last();
+ m_free.removeLast();
+ // Use count must have hit zero for it to have been added to the free list!
+ ASSERT(!m_used[index]);
+ return (VirtualRegister)(m_firstTemporary + index);
+ }
+
+ // Allocate a new VirtualRegister, and add a corresponding entry to m_used.
+ size_t next = allocatedCount();
+ m_used.append(0);
+ return (VirtualRegister)(m_firstTemporary + next);
+ }
+
+ // Increment the usecount for the VirtualRegsiter associated with 'child',
+ // if it reaches the node's refcount, free the VirtualRegsiter.
+ void use(NodeIndex child)
+ {
+ if (child == NoNode)
+ return;
+
+ // Find the virtual register number for this child, increment its use count.
+ Node& node = m_graph[child];
+ uint32_t index = node.virtualRegister() - m_firstTemporary;
+ if (node.refCount() == ++m_used[index]) {
+ // If the use count in the scoreboard reaches the use count for the node,
+ // then this was its last use; the virtual register is now free.
+ // Clear the use count & add to the free list.
+ m_used[index] = 0;
+ m_free.append(index);
+ }
+ }
+
+ unsigned allocatedCount()
+ {
+ // m_used contains an entry for every allocated VirtualRegister.
+ return m_used.size();
+ }
+
+#ifndef NDEBUG
+ void dump()
+ {
+ printf(" USED: [ ");
+ for (unsigned i = 0; i < m_used.size(); ++i) {
+ if (!m_free.contains(i))
+ printf("%d:%d ", m_firstTemporary + i, m_used[i]);
+ }
+ printf("]\n");
+
+ printf(" FREE: [ ");
+ for (unsigned i = 0; i < m_used.size(); ++i) {
+ if (m_free.contains(i)) {
+ ASSERT(!m_used[i]);
+ printf("%d ", m_firstTemporary + i);
+ }
+ }
+ printf("]\n");
+ }
+
+#endif
+
+private:
+ // The graph, so we can get refCounts for nodes, to determine when values are dead.
+ Graph& m_graph;
+ // The first VirtualRegsiter to be used as a temporary.
+ uint32_t m_firstTemporary;
+
+ // For every virtual register that has been allocated (either currently alive, or in
+ // the free list), we keep a count of the number of remaining uses until it is dead
+ // (0, in the case of entries in the free list). Since there is an entry for every
+ // allocated VirtualRegister, the length of this array conveniently provides the
+ // next available VirtualRegister number.
+ Vector<uint32_t, 64> m_used;
+ // A free list of VirtualRegsiters no longer alive.
+ Vector<uint32_t, 64> m_free;
+};
+
+} } // namespace JSC::DFG
+
+#endif
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DFGSpeculativeJIT.h"
+
+#if ENABLE(DFG_JIT)
+
+namespace JSC { namespace DFG {
+
+template<bool strict>
+GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat& returnFormat)
+{
+ Node& node = m_jit.graph()[nodeIndex];
+ VirtualRegister virtualRegister = node.virtualRegister();
+ GenerationInfo& info = m_generationInfo[virtualRegister];
+
+ switch (info.registerFormat()) {
+ case DataFormatNone: {
+ GPRReg gpr = allocate();
+
+ if (node.isConstant()) {
+ m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
+ if (isInt32Constant(nodeIndex)) {
+ m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(nodeIndex)), gpr);
+ info.fillInteger(gpr);
+ returnFormat = DataFormatInteger;
+ return gpr;
+ }
+ m_jit.move(constantAsJSValueAsImmPtr(nodeIndex), gpr);
+ } else {
+ DataFormat spillFormat = info.spillFormat();
+ ASSERT(spillFormat & DataFormatJS);
+
+ m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
+
+ if (spillFormat == DataFormatJSInteger) {
+ // If we know this was spilled as an integer we can fill without checking.
+ if (strict) {
+ m_jit.load32(JITCompiler::addressFor(virtualRegister), gpr);
+ info.fillInteger(gpr);
+ returnFormat = DataFormatInteger;
+ return gpr;
+ }
+ m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr);
+ info.fillJSValue(gpr, DataFormatJSInteger);
+ returnFormat = DataFormatJSInteger;
+ return gpr;
+ }
+ m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr);
+ }
+
+ // Fill as JSValue, and fall through.
+ info.fillJSValue(gpr, DataFormatJSInteger);
+ m_gprs.unlock(gpr);
+ }
+
+ case DataFormatJS: {
+ // Check the value is an integer.
+ GPRReg gpr = info.gpr();
+ m_gprs.lock(gpr);
+ speculationCheck(m_jit.branchPtr(MacroAssembler::Below, gpr, GPRInfo::tagTypeNumberRegister));
+ info.fillJSValue(gpr, DataFormatJSInteger);
+ // If !strict we're done, return.
+ if (!strict) {
+ returnFormat = DataFormatJSInteger;
+ return gpr;
+ }
+ // else fall through & handle as DataFormatJSInteger.
+ m_gprs.unlock(gpr);
+ }
+
+ case DataFormatJSInteger: {
+ // In a strict fill we need to strip off the value tag.
+ if (strict) {
+ GPRReg gpr = info.gpr();
+ GPRReg result;
+ // If the register has already been locked we need to take a copy.
+ // If not, we'll zero extend in place, so mark on the info that this is now type DataFormatInteger, not DataFormatJSInteger.
+ if (m_gprs.isLocked(gpr))
+ result = allocate();
+ else {
+ m_gprs.lock(gpr);
+ info.fillInteger(gpr);
+ result = gpr;
+ }
+ m_jit.zeroExtend32ToPtr(gpr, result);
+ returnFormat = DataFormatInteger;
+ return result;
+ }
+
+ GPRReg gpr = info.gpr();
+ m_gprs.lock(gpr);
+ returnFormat = DataFormatJSInteger;
+ return gpr;
+ }
+
+ case DataFormatInteger: {
+ GPRReg gpr = info.gpr();
+ m_gprs.lock(gpr);
+ returnFormat = DataFormatInteger;
+ return gpr;
+ }
+
+ case DataFormatDouble:
+ case DataFormatCell:
+ case DataFormatJSDouble:
+ case DataFormatJSCell: {
+ terminateSpeculativeExecution();
+ returnFormat = DataFormatInteger;
+ return allocate();
+ }
+ }
+
+ ASSERT_NOT_REACHED();
+ return InvalidGPRReg;
+}
+
+SpeculationCheck::SpeculationCheck(MacroAssembler::Jump check, SpeculativeJIT* jit, unsigned recoveryIndex)
+ : m_check(check)
+ , m_nodeIndex(jit->m_compileIndex)
+ , m_recoveryIndex(recoveryIndex)
+{
+ for (gpr_iterator iter = jit->m_gprs.begin(); iter != jit->m_gprs.end(); ++iter) {
+ if (iter.name() != InvalidVirtualRegister) {
+ GenerationInfo& info = jit->m_generationInfo[iter.name()];
+ m_gprInfo[iter.index()].nodeIndex = info.nodeIndex();
+ m_gprInfo[iter.index()].format = info.registerFormat();
+ } else
+ m_gprInfo[iter.index()].nodeIndex = NoNode;
+ }
+ for (fpr_iterator iter = jit->m_fprs.begin(); iter != jit->m_fprs.end(); ++iter) {
+ if (iter.name() != InvalidVirtualRegister) {
+ GenerationInfo& info = jit->m_generationInfo[iter.name()];
+ ASSERT(info.registerFormat() == DataFormatDouble);
+ m_fprInfo[iter.index()] = info.nodeIndex();
+ } else
+ m_fprInfo[iter.index()] = NoNode;
+ }
+}
+
+GPRReg SpeculativeJIT::fillSpeculateInt(NodeIndex nodeIndex, DataFormat& returnFormat)
+{
+ return fillSpeculateIntInternal<false>(nodeIndex, returnFormat);
+}
+
+GPRReg SpeculativeJIT::fillSpeculateIntStrict(NodeIndex nodeIndex)
+{
+ DataFormat mustBeDataFormatInteger;
+ GPRReg result = fillSpeculateIntInternal<true>(nodeIndex, mustBeDataFormatInteger);
+ ASSERT(mustBeDataFormatInteger == DataFormatInteger);
+ return result;
+}
+
+GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex)
+{
+ Node& node = m_jit.graph()[nodeIndex];
+ VirtualRegister virtualRegister = node.virtualRegister();
+ GenerationInfo& info = m_generationInfo[virtualRegister];
+
+ switch (info.registerFormat()) {
+ case DataFormatNone: {
+ GPRReg gpr = allocate();
+
+ if (node.isConstant()) {
+ m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
+ JSValue jsValue = constantAsJSValue(nodeIndex);
+ if (jsValue.isCell()) {
+ m_jit.move(MacroAssembler::TrustedImmPtr(jsValue.asCell()), gpr);
+ info.fillJSValue(gpr, DataFormatJSCell);
+ return gpr;
+ }
+ terminateSpeculativeExecution();
+ return gpr;
+ }
+ ASSERT(info.spillFormat() & DataFormatJS);
+ m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
+ m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr);
+
+ if (info.spillFormat() != DataFormatJSCell)
+ speculationCheck(m_jit.branchTestPtr(MacroAssembler::NonZero, gpr, GPRInfo::tagMaskRegister));
+ info.fillJSValue(gpr, DataFormatJSCell);
+ return gpr;
+ }
+
+ case DataFormatCell:
+ case DataFormatJSCell: {
+ GPRReg gpr = info.gpr();
+ m_gprs.lock(gpr);
+ return gpr;
+ }
+
+ case DataFormatJS: {
+ GPRReg gpr = info.gpr();
+ m_gprs.lock(gpr);
+ speculationCheck(m_jit.branchTestPtr(MacroAssembler::NonZero, gpr, GPRInfo::tagMaskRegister));
+ info.fillJSValue(gpr, DataFormatJSCell);
+ return gpr;
+ }
+
+ case DataFormatJSInteger:
+ case DataFormatInteger:
+ case DataFormatJSDouble:
+ case DataFormatDouble: {
+ terminateSpeculativeExecution();
+ return allocate();
+ }
+ }
+
+ ASSERT_NOT_REACHED();
+ return InvalidGPRReg;
+}
+
+void SpeculativeJIT::compilePeepHoleBranch(Node& node, JITCompiler::RelationalCondition condition)
+{
+ Node& branchNode = m_jit.graph()[m_compileIndex + 1];
+ BlockIndex taken = m_jit.graph().blockIndexForBytecodeOffset(branchNode.takenBytecodeOffset());
+ BlockIndex notTaken = m_jit.graph().blockIndexForBytecodeOffset(branchNode.notTakenBytecodeOffset());
+
+ // The branch instruction will branch to the taken block.
+ // If taken is next, switch taken with notTaken & invert the branch condition so we can fall through.
+ if (taken == (m_block + 1)) {
+ condition = JITCompiler::invert(condition);
+ BlockIndex tmp = taken;
+ taken = notTaken;
+ notTaken = tmp;
+ }
+
+ int32_t imm;
+ if (isJSConstantWithInt32Value(node.child1, imm)) {
+ SpeculateIntegerOperand op2(this, node.child2);
+ addBranch(m_jit.branch32(condition, JITCompiler::Imm32(imm), op2.gpr()), taken);
+ } else if (isJSConstantWithInt32Value(node.child2, imm)) {
+ SpeculateIntegerOperand op1(this, node.child1);
+ addBranch(m_jit.branch32(condition, op1.gpr(), JITCompiler::Imm32(imm)), taken);
+ } else {
+ SpeculateIntegerOperand op1(this, node.child1);
+ SpeculateIntegerOperand op2(this, node.child2);
+ addBranch(m_jit.branch32(condition, op1.gpr(), op2.gpr()), taken);
+ }
+
+ // Check for fall through, otherwise we need to jump.
+ if (notTaken != (m_block + 1))
+ addBranch(m_jit.jump(), notTaken);
+}
+
+void SpeculativeJIT::compile(Node& node)
+{
+ NodeType op = node.op;
+
+ switch (op) {
+ case Int32Constant:
+ case DoubleConstant:
+ case JSConstant:
+ initConstantInfo(m_compileIndex);
+ break;
+
+ case GetLocal: {
+ GPRTemporary result(this);
+ PredictedType prediction = m_jit.graph().getPrediction(node.local());
+ if (prediction == PredictInt32) {
+ m_jit.load32(JITCompiler::payloadFor(node.local()), result.gpr());
+
+ // Like integerResult, but don't useChildren - our children are phi nodes,
+ // and don't represent values within this dataflow with virtual registers.
+ VirtualRegister virtualRegister = node.virtualRegister();
+ m_gprs.retain(result.gpr(), virtualRegister, SpillOrderInteger);
+ m_generationInfo[virtualRegister].initInteger(m_compileIndex, node.refCount(), result.gpr());
+ } else {
+ m_jit.loadPtr(JITCompiler::addressFor(node.local()), result.gpr());
+
+ // Like jsValueResult, but don't useChildren - our children are phi nodes,
+ // and don't represent values within this dataflow with virtual registers.
+ VirtualRegister virtualRegister = node.virtualRegister();
+ m_gprs.retain(result.gpr(), virtualRegister, SpillOrderJS);
+ m_generationInfo[virtualRegister].initJSValue(m_compileIndex, node.refCount(), result.gpr(), (prediction == PredictArray) ? DataFormatJSCell : DataFormatJS);
+ }
+ break;
+ }
+
+ case SetLocal: {
+ switch (m_jit.graph().getPrediction(node.local())) {
+ case PredictInt32: {
+ SpeculateIntegerOperand value(this, node.child1);
+ m_jit.store32(value.gpr(), JITCompiler::payloadFor(node.local()));
+ noResult(m_compileIndex);
+ break;
+ }
+ case PredictArray: {
+ SpeculateCellOperand cell(this, node.child1);
+ m_jit.storePtr(cell.gpr(), JITCompiler::addressFor(node.local()));
+ noResult(m_compileIndex);
+ break;
+ }
+
+ default: {
+ JSValueOperand value(this, node.child1);
+ m_jit.storePtr(value.gpr(), JITCompiler::addressFor(node.local()));
+ noResult(m_compileIndex);
+ break;
+ }
+ }
+ break;
+ }
+
+ case BitAnd:
+ case BitOr:
+ case BitXor:
+ if (isInt32Constant(node.child1)) {
+ SpeculateIntegerOperand op2(this, node.child2);
+ GPRTemporary result(this, op2);
+
+ bitOp(op, valueOfInt32Constant(node.child1), op2.gpr(), result.gpr());
+
+ integerResult(result.gpr(), m_compileIndex);
+ } else if (isInt32Constant(node.child2)) {
+ SpeculateIntegerOperand op1(this, node.child1);
+ GPRTemporary result(this, op1);
+
+ bitOp(op, valueOfInt32Constant(node.child2), op1.gpr(), result.gpr());
+
+ integerResult(result.gpr(), m_compileIndex);
+ } else {
+ SpeculateIntegerOperand op1(this, node.child1);
+ SpeculateIntegerOperand op2(this, node.child2);
+ GPRTemporary result(this, op1, op2);
+
+ GPRReg reg1 = op1.gpr();
+ GPRReg reg2 = op2.gpr();
+ bitOp(op, reg1, reg2, result.gpr());
+
+ integerResult(result.gpr(), m_compileIndex);
+ }
+ break;
+
+ case BitRShift:
+ case BitLShift:
+ case BitURShift:
+ if (isInt32Constant(node.child2)) {
+ SpeculateIntegerOperand op1(this, node.child1);
+ GPRTemporary result(this, op1);
+
+ shiftOp(op, op1.gpr(), valueOfInt32Constant(node.child2) & 0x1f, result.gpr());
+
+ integerResult(result.gpr(), m_compileIndex);
+ } else {
+ // Do not allow shift amount to be used as the result, MacroAssembler does not permit this.
+ SpeculateIntegerOperand op1(this, node.child1);
+ SpeculateIntegerOperand op2(this, node.child2);
+ GPRTemporary result(this, op1);
+
+ GPRReg reg1 = op1.gpr();
+ GPRReg reg2 = op2.gpr();
+ shiftOp(op, reg1, reg2, result.gpr());
+
+ integerResult(result.gpr(), m_compileIndex);
+ }
+ break;
+
+ case UInt32ToNumber: {
+ IntegerOperand op1(this, node.child1);
+ GPRTemporary result(this, op1);
+
+ // Test the operand is positive.
+ speculationCheck(m_jit.branch32(MacroAssembler::LessThan, op1.gpr(), TrustedImm32(0)));
+
+ m_jit.move(op1.gpr(), result.gpr());
+ integerResult(result.gpr(), m_compileIndex, op1.format());
+ break;
+ }
+
+ case NumberToInt32: {
+ SpeculateIntegerOperand op1(this, node.child1);
+ GPRTemporary result(this, op1);
+ m_jit.move(op1.gpr(), result.gpr());
+ integerResult(result.gpr(), m_compileIndex, op1.format());
+ break;
+ }
+
+ case Int32ToNumber: {
+ SpeculateIntegerOperand op1(this, node.child1);
+ GPRTemporary result(this, op1);
+ m_jit.move(op1.gpr(), result.gpr());
+ integerResult(result.gpr(), m_compileIndex, op1.format());
+ break;
+ }
+
+ case ValueToInt32: {
+ SpeculateIntegerOperand op1(this, node.child1);
+ GPRTemporary result(this, op1);
+ m_jit.move(op1.gpr(), result.gpr());
+ integerResult(result.gpr(), m_compileIndex, op1.format());
+ break;
+ }
+
+ case ValueToNumber: {
+ SpeculateIntegerOperand op1(this, node.child1);
+ GPRTemporary result(this, op1);
+ m_jit.move(op1.gpr(), result.gpr());
+ integerResult(result.gpr(), m_compileIndex, op1.format());
+ break;
+ }
+
+ case ValueAdd:
+ case ArithAdd: {
+ int32_t imm1;
+ if (isDoubleConstantWithInt32Value(node.child1, imm1)) {
+ SpeculateIntegerOperand op2(this, node.child2);
+ GPRTemporary result(this);
+
+ speculationCheck(m_jit.branchAdd32(MacroAssembler::Overflow, op2.gpr(), Imm32(imm1), result.gpr()));
+
+ integerResult(result.gpr(), m_compileIndex);
+ break;
+ }
+
+ int32_t imm2;
+ if (isDoubleConstantWithInt32Value(node.child2, imm2)) {
+ SpeculateIntegerOperand op1(this, node.child1);
+ GPRTemporary result(this);
+
+ speculationCheck(m_jit.branchAdd32(MacroAssembler::Overflow, op1.gpr(), Imm32(imm2), result.gpr()));
+
+ integerResult(result.gpr(), m_compileIndex);
+ break;
+ }
+
+ SpeculateIntegerOperand op1(this, node.child1);
+ SpeculateIntegerOperand op2(this, node.child2);
+ GPRTemporary result(this, op1, op2);
+
+ GPRReg gpr1 = op1.gpr();
+ GPRReg gpr2 = op2.gpr();
+ GPRReg gprResult = result.gpr();
+ MacroAssembler::Jump check = m_jit.branchAdd32(MacroAssembler::Overflow, gpr1, gpr2, gprResult);
+
+ if (gpr1 == gprResult)
+ speculationCheck(check, SpeculationRecovery(SpeculativeAdd, gprResult, gpr2));
+ else if (gpr2 == gprResult)
+ speculationCheck(check, SpeculationRecovery(SpeculativeAdd, gprResult, gpr1));
+ else
+ speculationCheck(check);
+
+ integerResult(gprResult, m_compileIndex);
+ break;
+ }
+
+ case ArithSub: {
+ int32_t imm2;
+ if (isDoubleConstantWithInt32Value(node.child2, imm2)) {
+ SpeculateIntegerOperand op1(this, node.child1);
+ GPRTemporary result(this);
+
+ speculationCheck(m_jit.branchSub32(MacroAssembler::Overflow, op1.gpr(), Imm32(imm2), result.gpr()));
+
+ integerResult(result.gpr(), m_compileIndex);
+ break;
+ }
+
+ SpeculateIntegerOperand op1(this, node.child1);
+ SpeculateIntegerOperand op2(this, node.child2);
+ GPRTemporary result(this);
+
+ speculationCheck(m_jit.branchSub32(MacroAssembler::Overflow, op1.gpr(), op2.gpr(), result.gpr()));
+
+ integerResult(result.gpr(), m_compileIndex);
+ break;
+ }
+
+ case ArithMul: {
+ SpeculateIntegerOperand op1(this, node.child1);
+ SpeculateIntegerOperand op2(this, node.child2);
+ GPRTemporary result(this);
+
+ GPRReg reg1 = op1.gpr();
+ GPRReg reg2 = op2.gpr();
+ speculationCheck(m_jit.branchMul32(MacroAssembler::Overflow, reg1, reg2, result.gpr()));
+
+ MacroAssembler::Jump resultNonZero = m_jit.branchTest32(MacroAssembler::NonZero, result.gpr());
+ speculationCheck(m_jit.branch32(MacroAssembler::LessThan, reg1, TrustedImm32(0)));
+ speculationCheck(m_jit.branch32(MacroAssembler::LessThan, reg2, TrustedImm32(0)));
+ resultNonZero.link(&m_jit);
+
+ integerResult(result.gpr(), m_compileIndex);
+ break;
+ }
+
+ case ArithDiv: {
+ SpeculateIntegerOperand op1(this, node.child1);
+ SpeculateIntegerOperand op2(this, node.child2);
+ GPRTemporary result(this, op1, op2);
+
+ op1.gpr();
+ op2.gpr();
+ terminateSpeculativeExecution();
+
+ integerResult(result.gpr(), m_compileIndex);
+ break;
+ }
+
+ case ArithMod: {
+ SpeculateIntegerOperand op1(this, node.child1);
+ SpeculateIntegerOperand op2(this, node.child2);
+ GPRTemporary result(this, op1, op2);
+
+ op1.gpr();
+ op2.gpr();
+ terminateSpeculativeExecution();
+
+ integerResult(result.gpr(), m_compileIndex);
+ break;
+ }
+
+ case LogicalNot: {
+ JSValueOperand value(this, node.child1);
+ GPRTemporary result(this); // FIXME: We could reuse, but on speculation fail would need recovery to restore tag (akin to add).
+
+ m_jit.move(value.gpr(), result.gpr());
+ m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), result.gpr());
+ speculationCheck(m_jit.branchTestPtr(JITCompiler::NonZero, result.gpr(), TrustedImm32(static_cast<int32_t>(~1))));
+ m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueTrue)), result.gpr());
+
+ // If we add a DataFormatBool, we should use it here.
+ jsValueResult(result.gpr(), m_compileIndex);
+ break;
+ }
+
+ case CompareLess: {
+ // Fused compare & branch.
+ if (detectPeepHoleBranch()) {
+ // detectPeepHoleBranch currently only permits the branch to be the very next node,
+ // so can be no intervening nodes to also reference the compare.
+ ASSERT(node.adjustedRefCount() == 1);
+
+ compilePeepHoleBranch(node, JITCompiler::LessThan);
+
+ use(node.child1);
+ use(node.child2);
+ ++m_compileIndex;
+ return;
+ }
+
+ // Normal case, not fused to branch.
+ SpeculateIntegerOperand op1(this, node.child1);
+ SpeculateIntegerOperand op2(this, node.child2);
+ GPRTemporary result(this, op1, op2);
+
+ m_jit.compare32(JITCompiler::LessThan, op1.gpr(), op2.gpr(), result.gpr());
+
+ // If we add a DataFormatBool, we should use it here.
+ m_jit.or32(TrustedImm32(ValueFalse), result.gpr());
+ jsValueResult(result.gpr(), m_compileIndex);
+ break;
+ }
+
+ case CompareLessEq: {
+ // Fused compare & branch.
+ if (detectPeepHoleBranch()) {
+ // detectPeepHoleBranch currently only permits the branch to be the very next node,
+ // so can be no intervening nodes to also reference the compare.
+ ASSERT(node.adjustedRefCount() == 1);
+
+ compilePeepHoleBranch(node, JITCompiler::LessThanOrEqual);
+
+ use(node.child1);
+ use(node.child2);
+ ++m_compileIndex;
+ return;
+ }
+
+ // Normal case, not fused to branch.
+ SpeculateIntegerOperand op1(this, node.child1);
+ SpeculateIntegerOperand op2(this, node.child2);
+ GPRTemporary result(this, op1, op2);
+
+ m_jit.compare32(JITCompiler::LessThanOrEqual, op1.gpr(), op2.gpr(), result.gpr());
+
+ // If we add a DataFormatBool, we should use it here.
+ m_jit.or32(TrustedImm32(ValueFalse), result.gpr());
+ jsValueResult(result.gpr(), m_compileIndex);
+ break;
+ }
+
+ case CompareEq: {
+ SpeculateIntegerOperand op1(this, node.child1);
+ SpeculateIntegerOperand op2(this, node.child2);
+ GPRTemporary result(this, op1, op2);
+
+ m_jit.compare32(JITCompiler::Equal, op1.gpr(), op2.gpr(), result.gpr());
+
+ // If we add a DataFormatBool, we should use it here.
+ m_jit.or32(TrustedImm32(ValueFalse), result.gpr());
+ jsValueResult(result.gpr(), m_compileIndex);
+ break;
+ }
+
+ case CompareStrictEq: {
+ SpeculateIntegerOperand op1(this, node.child1);
+ SpeculateIntegerOperand op2(this, node.child2);
+ GPRTemporary result(this, op1, op2);
+
+ m_jit.compare32(JITCompiler::Equal, op1.gpr(), op2.gpr(), result.gpr());
+
+ // If we add a DataFormatBool, we should use it here.
+ m_jit.or32(TrustedImm32(ValueFalse), result.gpr());
+ jsValueResult(result.gpr(), m_compileIndex);
+ break;
+ }
+
+ case GetByVal: {
+ NodeIndex alias = node.child3;
+ if (alias != NoNode) {
+ // FIXME: result should be able to reuse child1, child2. Should have an 'UnusedOperand' type.
+ JSValueOperand aliasedValue(this, node.child3);
+ GPRTemporary result(this, aliasedValue);
+ m_jit.move(aliasedValue.gpr(), result.gpr());
+ jsValueResult(result.gpr(), m_compileIndex);
+ break;
+ }
+
+ SpeculateCellOperand base(this, node.child1);
+ SpeculateStrictInt32Operand property(this, node.child2);
+ GPRTemporary storage(this);
+
+ GPRReg baseReg = base.gpr();
+ GPRReg propertyReg = property.gpr();
+ GPRReg storageReg = storage.gpr();
+
+ // Get the array storage. We haven't yet checked this is a JSArray, so this is only safe if
+ // an access with offset JSArray::storageOffset() is valid for all JSCells!
+ m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg);
+
+ // Check that base is an array, and that property is contained within m_vector (< m_vectorLength).
+ // If we have predicted the base to be type array, we can skip the check.
+ Node& baseNode = m_jit.graph()[node.child1];
+ if (baseNode.op != GetLocal || m_jit.graph().getPrediction(baseNode.local()) != PredictArray)
+ speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));
+ speculationCheck(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset())));
+
+ // FIXME: In cases where there are subsequent by_val accesses to the same base it might help to cache
+ // the storage pointer - especially if there happens to be another register free right now. If we do so,
+ // then we'll need to allocate a new temporary for result.
+ GPRTemporary& result = storage;
+ m_jit.loadPtr(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), result.gpr());
+ speculationCheck(m_jit.branchTestPtr(MacroAssembler::Zero, result.gpr()));
+
+ jsValueResult(result.gpr(), m_compileIndex);
+ break;
+ }
+
+ case PutByVal: {
+ SpeculateCellOperand base(this, node.child1);
+ SpeculateStrictInt32Operand property(this, node.child2);
+ JSValueOperand value(this, node.child3);
+ GPRTemporary storage(this);
+
+ // Map base, property & value into registers, allocate a register for storage.
+ GPRReg baseReg = base.gpr();
+ GPRReg propertyReg = property.gpr();
+ GPRReg valueReg = value.gpr();
+ GPRReg storageReg = storage.gpr();
+
+ // Check that base is an array, and that property is contained within m_vector (< m_vectorLength).
+ // If we have predicted the base to be type array, we can skip the check.
+ Node& baseNode = m_jit.graph()[node.child1];
+ if (baseNode.op != GetLocal || m_jit.graph().getPrediction(baseNode.local()) != PredictArray)
+ speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));
+ speculationCheck(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset())));
+
+ // Get the array storage.
+ m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg);
+
+ // Check if we're writing to a hole; if so increment m_numValuesInVector.
+ MacroAssembler::Jump notHoleValue = m_jit.branchTestPtr(MacroAssembler::NonZero, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])));
+ m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
+
+ // If we're writing to a hole we might be growing the array;
+ MacroAssembler::Jump lengthDoesNotNeedUpdate = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length)));
+ m_jit.add32(TrustedImm32(1), propertyReg);
+ m_jit.store32(propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length)));
+ m_jit.sub32(TrustedImm32(1), propertyReg);
+
+ lengthDoesNotNeedUpdate.link(&m_jit);
+ notHoleValue.link(&m_jit);
+
+ // Store the value to the array.
+ m_jit.storePtr(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])));
+
+ noResult(m_compileIndex);
+ break;
+ }
+
+ case PutByValAlias: {
+ SpeculateCellOperand base(this, node.child1);
+ SpeculateStrictInt32Operand property(this, node.child2);
+ JSValueOperand value(this, node.child3);
+ GPRTemporary storage(this, base); // storage may overwrite base.
+
+ // Get the array storage.
+ GPRReg storageReg = storage.gpr();
+ m_jit.loadPtr(MacroAssembler::Address(base.gpr(), JSArray::storageOffset()), storageReg);
+
+ // Map property & value into registers.
+ GPRReg propertyReg = property.gpr();
+ GPRReg valueReg = value.gpr();
+
+ // Store the value to the array.
+ m_jit.storePtr(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])));
+
+ noResult(m_compileIndex);
+ break;
+ }
+
+ case DFG::Jump: {
+ BlockIndex taken = m_jit.graph().blockIndexForBytecodeOffset(node.takenBytecodeOffset());
+ if (taken != (m_block + 1))
+ addBranch(m_jit.jump(), taken);
+ noResult(m_compileIndex);
+ break;
+ }
+
+ case Branch: {
+ JSValueOperand value(this, node.child1);
+ GPRReg valueReg = value.gpr();
+
+ BlockIndex taken = m_jit.graph().blockIndexForBytecodeOffset(node.takenBytecodeOffset());
+ BlockIndex notTaken = m_jit.graph().blockIndexForBytecodeOffset(node.notTakenBytecodeOffset());
+
+ // Integers
+ addBranch(m_jit.branchPtr(MacroAssembler::Equal, valueReg, MacroAssembler::ImmPtr(JSValue::encode(jsNumber(0)))), notTaken);
+ MacroAssembler::Jump isNonZeroInteger = m_jit.branchPtr(MacroAssembler::AboveOrEqual, valueReg, GPRInfo::tagTypeNumberRegister);
+
+ // Booleans
+ addBranch(m_jit.branchPtr(MacroAssembler::Equal, valueReg, MacroAssembler::ImmPtr(JSValue::encode(jsBoolean(false)))), notTaken);
+ speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, valueReg, MacroAssembler::ImmPtr(JSValue::encode(jsBoolean(true)))));
+
+ if (taken == (m_block + 1))
+ isNonZeroInteger.link(&m_jit);
+ else {
+ addBranch(isNonZeroInteger, taken);
+ addBranch(m_jit.jump(), taken);
+ }
+
+ noResult(m_compileIndex);
+ break;
+ }
+
+ case Return: {
+ ASSERT(GPRInfo::callFrameRegister != GPRInfo::regT1);
+ ASSERT(GPRInfo::regT1 != GPRInfo::returnValueGPR);
+ ASSERT(GPRInfo::returnValueGPR != GPRInfo::callFrameRegister);
+
+#if DFG_SUCCESS_STATS
+ static SamplingCounter counter("SpeculativeJIT");
+ m_jit.emitCount(counter);
+#endif
+
+ // Return the result in returnValueGPR.
+ JSValueOperand op1(this, node.child1);
+ m_jit.move(op1.gpr(), GPRInfo::returnValueGPR);
+
+ // Grab the return address.
+ m_jit.emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, GPRInfo::regT1);
+ // Restore our caller's "r".
+ m_jit.emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, GPRInfo::callFrameRegister);
+ // Return.
+ m_jit.restoreReturnAddressBeforeReturn(GPRInfo::regT1);
+ m_jit.ret();
+
+ noResult(m_compileIndex);
+ break;
+ }
+
+ case ConvertThis: {
+ SpeculateCellOperand thisValue(this, node.child1);
+ GPRTemporary temp(this);
+
+ m_jit.loadPtr(JITCompiler::Address(thisValue.gpr(), JSCell::structureOffset()), temp.gpr());
+ speculationCheck(m_jit.branchTest8(JITCompiler::NonZero, JITCompiler::Address(temp.gpr(), Structure::typeInfoFlagsOffset()), JITCompiler::TrustedImm32(NeedsThisConversion)));
+
+ cellResult(thisValue.gpr(), m_compileIndex);
+ break;
+ }
+
+ case GetById: {
+ JSValueOperand base(this, node.child1);
+ GPRReg baseGPR = base.gpr();
+ flushRegisters();
+
+ GPRResult result(this);
+ callOperation(operationGetById, result.gpr(), baseGPR, identifier(node.identifierNumber()));
+ jsValueResult(result.gpr(), m_compileIndex);
+ break;
+ }
+
+ case PutById: {
+ JSValueOperand base(this, node.child1);
+ JSValueOperand value(this, node.child2);
+ GPRReg valueGPR = value.gpr();
+ GPRReg baseGPR = base.gpr();
+ flushRegisters();
+
+ callOperation(m_jit.codeBlock()->isStrictMode() ? operationPutByIdStrict : operationPutByIdNonStrict, valueGPR, baseGPR, identifier(node.identifierNumber()));
+ noResult(m_compileIndex);
+ break;
+ }
+
+ case PutByIdDirect: {
+ JSValueOperand base(this, node.child1);
+ JSValueOperand value(this, node.child2);
+ GPRReg valueGPR = value.gpr();
+ GPRReg baseGPR = base.gpr();
+ flushRegisters();
+
+ callOperation(m_jit.codeBlock()->isStrictMode() ? operationPutByIdDirectStrict : operationPutByIdDirectNonStrict, valueGPR, baseGPR, identifier(node.identifierNumber()));
+ noResult(m_compileIndex);
+ break;
+ }
+
+ case GetGlobalVar: {
+ GPRTemporary result(this);
+
+ JSVariableObject* globalObject = m_jit.codeBlock()->globalObject();
+ m_jit.loadPtr(globalObject->addressOfRegisters(), result.gpr());
+ m_jit.loadPtr(JITCompiler::addressForGlobalVar(result.gpr(), node.varNumber()), result.gpr());
+
+ jsValueResult(result.gpr(), m_compileIndex);
+ break;
+ }
+
+ case PutGlobalVar: {
+ JSValueOperand value(this, node.child1);
+ GPRTemporary temp(this);
+
+ JSVariableObject* globalObject = m_jit.codeBlock()->globalObject();
+ m_jit.loadPtr(globalObject->addressOfRegisters(), temp.gpr());
+ m_jit.storePtr(value.gpr(), JITCompiler::addressForGlobalVar(temp.gpr(), node.varNumber()));
+
+ noResult(m_compileIndex);
+ break;
+ }
+
+ case Phi:
+ ASSERT_NOT_REACHED();
+ }
+
+ if (node.hasResult() && node.mustGenerate())
+ use(m_compileIndex);
+}
+
+void SpeculativeJIT::compile(BasicBlock& block)
+{
+ ASSERT(m_compileIndex == block.begin);
+ m_blockHeads[m_block] = m_jit.label();
+#if DFG_JIT_BREAK_ON_EVERY_BLOCK
+ m_jit.breakpoint();
+#endif
+
+ for (; m_compileIndex < block.end; ++m_compileIndex) {
+ Node& node = m_jit.graph()[m_compileIndex];
+ if (!node.shouldGenerate())
+ continue;
+
+#if DFG_DEBUG_VERBOSE
+ fprintf(stderr, "SpeculativeJIT generating Node @%d at JIT offset 0x%x\n", (int)m_compileIndex, m_jit.debugOffset());
+#endif
+#if DFG_JIT_BREAK_ON_EVERY_NODE
+ m_jit.breakpoint();
+#endif
+ checkConsistency();
+ compile(node);
+ if (!m_compileOkay)
+ return;
+ checkConsistency();
+ }
+}
+
+// If we are making type predictions about our arguments then
+// we need to check that they are correct on function entry.
+void SpeculativeJIT::checkArgumentTypes()
+{
+ ASSERT(!m_compileIndex);
+ for (int i = 0; i < m_jit.codeBlock()->m_numParameters; ++i) {
+ VirtualRegister virtualRegister = (VirtualRegister)(m_jit.codeBlock()->thisRegister() + i);
+ switch (m_jit.graph().getPrediction(virtualRegister)) {
+ case PredictInt32:
+ speculationCheck(m_jit.branchPtr(MacroAssembler::Below, JITCompiler::addressFor(virtualRegister), GPRInfo::tagTypeNumberRegister));
+ break;
+
+ case PredictArray: {
+ GPRTemporary temp(this);
+ m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr());
+ speculationCheck(m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister));
+ speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+}
+
+// For any vars that we will be treating as numeric, write 0 to
+// the var on entry. Throughout the block we will only read/write
+// to the payload, by writing the tag now we prevent the GC from
+// misinterpreting values as pointers.
+void SpeculativeJIT::initializeVariableTypes()
+{
+ ASSERT(!m_compileIndex);
+ for (int var = 0; var < m_jit.codeBlock()->m_numVars; ++var) {
+ if (m_jit.graph().getPrediction(var) == PredictInt32)
+ m_jit.storePtr(GPRInfo::tagTypeNumberRegister, JITCompiler::addressFor((VirtualRegister)var));
+ }
+}
+
+bool SpeculativeJIT::compile()
+{
+ checkArgumentTypes();
+ initializeVariableTypes();
+
+ ASSERT(!m_compileIndex);
+ for (m_block = 0; m_block < m_jit.graph().m_blocks.size(); ++m_block) {
+ compile(*m_jit.graph().m_blocks[m_block]);
+ if (!m_compileOkay)
+ return false;
+ }
+ linkBranches();
+ return true;
+}
+
+} } // namespace JSC::DFG
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DFGSpeculativeJIT_h
+#define DFGSpeculativeJIT_h
+
+#if ENABLE(DFG_JIT)
+
+#include <dfg/DFGJITCodeGenerator.h>
+
+namespace JSC { namespace DFG {
+
+class SpeculativeJIT;
+
+// This enum describes the types of additional recovery that
+// may need be performed should a speculation check fail.
+enum SpeculationRecoveryType {
+ SpeculativeAdd
+};
+
+// === SpeculationRecovery ===
+//
+// This class provides additional information that may be associated with a
+// speculation check - for example
+class SpeculationRecovery {
+public:
+ SpeculationRecovery(SpeculationRecoveryType type, GPRReg dest, GPRReg src)
+ : m_type(type)
+ , m_dest(dest)
+ , m_src(src)
+ {
+ }
+
+ SpeculationRecoveryType type() { return m_type; }
+ GPRReg dest() { return m_dest; }
+ GPRReg src() { return m_src; }
+
+private:
+ // Indicates the type of additional recovery to be performed.
+ SpeculationRecoveryType m_type;
+ // different recovery types may required different additional information here.
+ GPRReg m_dest;
+ GPRReg m_src;
+};
+
+// === SpeculationCheck ===
+//
+// This structure records a bail-out from the speculative path,
+// which will need to be linked in to the non-speculative one.
+struct SpeculationCheck {
+ SpeculationCheck(MacroAssembler::Jump, SpeculativeJIT*, unsigned recoveryIndex = 0);
+
+ // The location of the jump out from the speculative path,
+ // and the node we were generating code for.
+ MacroAssembler::Jump m_check;
+ NodeIndex m_nodeIndex;
+ // Used to record any additional recovery to be performed; this
+ // value is an index into the SpeculativeJIT's m_speculationRecoveryList
+ // array, offset by 1. (m_recoveryIndex == 0) means no recovery.
+ unsigned m_recoveryIndex;
+
+ struct RegisterInfo {
+ NodeIndex nodeIndex;
+ DataFormat format;
+ };
+ RegisterInfo m_gprInfo[GPRInfo::numberOfRegisters];
+ NodeIndex m_fprInfo[FPRInfo::numberOfRegisters];
+};
+typedef SegmentedVector<SpeculationCheck, 16> SpeculationCheckVector;
+
+
+// === SpeculativeJIT ===
+//
+// The SpeculativeJIT is used to generate a fast, but potentially
+// incomplete code path for the dataflow. When code generating
+// we may make assumptions about operand types, dynamically check,
+// and bail-out to an alternate code path if these checks fail.
+// Importantly, the speculative code path cannot be reentered once
+// a speculative check has failed. This allows the SpeculativeJIT
+// to propagate type information (including information that has
+// only speculatively been asserted) through the dataflow.
+class SpeculativeJIT : public JITCodeGenerator {
+ friend struct SpeculationCheck;
+public:
+ SpeculativeJIT(JITCompiler& jit)
+ : JITCodeGenerator(jit, true)
+ , m_compileOkay(true)
+ {
+ }
+
+ bool compile();
+
+ // Retrieve the list of bail-outs from the speculative path,
+ // and additional recovery information.
+ SpeculationCheckVector& speculationChecks()
+ {
+ return m_speculationChecks;
+ }
+ SpeculationRecovery* speculationRecovery(size_t index)
+ {
+ // SpeculationCheck::m_recoveryIndex is offset by 1,
+ // 0 means no recovery.
+ return index ? &m_speculationRecoveryList[index - 1] : 0;
+ }
+
+ // Called by the speculative operand types, below, to fill operand to
+ // machine registers, implicitly generating speculation checks as needed.
+ GPRReg fillSpeculateInt(NodeIndex, DataFormat& returnFormat);
+ GPRReg fillSpeculateIntStrict(NodeIndex);
+ GPRReg fillSpeculateCell(NodeIndex);
+
+private:
+ void compile(Node&);
+ void compile(BasicBlock&);
+
+ void checkArgumentTypes();
+ void initializeVariableTypes();
+
+ bool isDoubleConstantWithInt32Value(NodeIndex nodeIndex, int32_t& out)
+ {
+ if (!m_jit.isDoubleConstant(nodeIndex))
+ return false;
+ double value = m_jit.valueOfDoubleConstant(nodeIndex);
+
+ int32_t asInt32 = static_cast<int32_t>(value);
+ if (value != asInt32)
+ return false;
+ if (!asInt32 && signbit(value))
+ return false;
+
+ out = asInt32;
+ return true;
+ }
+
+ bool isJSConstantWithInt32Value(NodeIndex nodeIndex, int32_t& out)
+ {
+ if (!m_jit.isJSConstant(nodeIndex))
+ return false;
+ JSValue value = m_jit.valueOfJSConstant(nodeIndex);
+
+ if (!value.isInt32())
+ return false;
+
+ out = value.asInt32();
+ return true;
+ }
+
+ bool detectPeepHoleBranch()
+ {
+ // Check if the block contains precisely one more node.
+ if (m_compileIndex + 2 != m_jit.graph().m_blocks[m_block]->end)
+ return false;
+
+ // Check if the lastNode is a branch on this node.
+ Node& lastNode = m_jit.graph()[m_compileIndex + 1];
+ return lastNode.op == Branch && lastNode.child1 == m_compileIndex;
+ }
+
+ void compilePeepHoleBranch(Node&, JITCompiler::RelationalCondition);
+
+ // Add a speculation check without additional recovery.
+ void speculationCheck(MacroAssembler::Jump jumpToFail)
+ {
+ m_speculationChecks.append(SpeculationCheck(jumpToFail, this));
+ }
+ // Add a speculation check with additional recovery.
+ void speculationCheck(MacroAssembler::Jump jumpToFail, const SpeculationRecovery& recovery)
+ {
+ m_speculationRecoveryList.append(recovery);
+ m_speculationChecks.append(SpeculationCheck(jumpToFail, this, m_speculationRecoveryList.size()));
+ }
+
+ // Called when we statically determine that a speculation will fail.
+ void terminateSpeculativeExecution()
+ {
+ // FIXME: in cases where we can statically determine we're going to bail out from the speculative
+ // JIT we should probably rewind code generation and only produce the non-speculative path.
+ m_compileOkay = false;
+ speculationCheck(m_jit.jump());
+ }
+
+ template<bool strict>
+ GPRReg fillSpeculateIntInternal(NodeIndex, DataFormat& returnFormat);
+
+ // It is possible, during speculative generation, to reach a situation in which we
+ // can statically determine a speculation will fail (for example, when two nodes
+ // will make conflicting speculations about the same operand). In such cases this
+ // flag is cleared, indicating no further code generation should take place.
+ bool m_compileOkay;
+ // This vector tracks bail-outs from the speculative path to the non-speculative one.
+ SpeculationCheckVector m_speculationChecks;
+ // Some bail-outs need to record additional information recording specific recovery
+ // to be performed (for example, on detected overflow from an add, we may need to
+ // reverse the addition if an operand is being overwritten).
+ Vector<SpeculationRecovery, 16> m_speculationRecoveryList;
+};
+
+
+// === Speculative Operand types ===
+//
+// SpeculateIntegerOperand, SpeculateStrictInt32Operand and SpeculateCellOperand.
+//
+// These are used to lock the operands to a node into machine registers within the
+// SpeculativeJIT. The classes operate like those provided by the JITCodeGenerator,
+// however these will perform a speculative check for a more restrictive type than
+// we can statically determine the operand to have. If the operand does not have
+// the requested type, a bail-out to the non-speculative path will be taken.
+
+class SpeculateIntegerOperand {
+public:
+ explicit SpeculateIntegerOperand(SpeculativeJIT* jit, NodeIndex index)
+ : m_jit(jit)
+ , m_index(index)
+ , m_gprOrInvalid(InvalidGPRReg)
+#ifndef NDEBUG
+ , m_format(DataFormatNone)
+#endif
+ {
+ ASSERT(m_jit);
+ if (jit->isFilled(index))
+ gpr();
+ }
+
+ ~SpeculateIntegerOperand()
+ {
+ ASSERT(m_gprOrInvalid != InvalidGPRReg);
+ m_jit->unlock(m_gprOrInvalid);
+ }
+
+ NodeIndex index() const
+ {
+ return m_index;
+ }
+
+ DataFormat format()
+ {
+ gpr(); // m_format is set when m_gpr is locked.
+ ASSERT(m_format == DataFormatInteger || m_format == DataFormatJSInteger);
+ return m_format;
+ }
+
+ GPRReg gpr()
+ {
+ if (m_gprOrInvalid == InvalidGPRReg)
+ m_gprOrInvalid = m_jit->fillSpeculateInt(index(), m_format);
+ return m_gprOrInvalid;
+ }
+
+private:
+ SpeculativeJIT* m_jit;
+ NodeIndex m_index;
+ GPRReg m_gprOrInvalid;
+ DataFormat m_format;
+};
+
+class SpeculateStrictInt32Operand {
+public:
+ explicit SpeculateStrictInt32Operand(SpeculativeJIT* jit, NodeIndex index)
+ : m_jit(jit)
+ , m_index(index)
+ , m_gprOrInvalid(InvalidGPRReg)
+ {
+ ASSERT(m_jit);
+ if (jit->isFilled(index))
+ gpr();
+ }
+
+ ~SpeculateStrictInt32Operand()
+ {
+ ASSERT(m_gprOrInvalid != InvalidGPRReg);
+ m_jit->unlock(m_gprOrInvalid);
+ }
+
+ NodeIndex index() const
+ {
+ return m_index;
+ }
+
+ GPRReg gpr()
+ {
+ if (m_gprOrInvalid == InvalidGPRReg)
+ m_gprOrInvalid = m_jit->fillSpeculateIntStrict(index());
+ return m_gprOrInvalid;
+ }
+
+private:
+ SpeculativeJIT* m_jit;
+ NodeIndex m_index;
+ GPRReg m_gprOrInvalid;
+};
+
+class SpeculateCellOperand {
+public:
+ explicit SpeculateCellOperand(SpeculativeJIT* jit, NodeIndex index)
+ : m_jit(jit)
+ , m_index(index)
+ , m_gprOrInvalid(InvalidGPRReg)
+ {
+ ASSERT(m_jit);
+ if (jit->isFilled(index))
+ gpr();
+ }
+
+ ~SpeculateCellOperand()
+ {
+ ASSERT(m_gprOrInvalid != InvalidGPRReg);
+ m_jit->unlock(m_gprOrInvalid);
+ }
+
+ NodeIndex index() const
+ {
+ return m_index;
+ }
+
+ GPRReg gpr()
+ {
+ if (m_gprOrInvalid == InvalidGPRReg)
+ m_gprOrInvalid = m_jit->fillSpeculateCell(index());
+ return m_gprOrInvalid;
+ }
+
+private:
+ SpeculativeJIT* m_jit;
+ NodeIndex m_index;
+ GPRReg m_gprOrInvalid;
+};
+
+
+// === SpeculationCheckIndexIterator ===
+//
+// This class is used by the non-speculative JIT to check which
+// nodes require entry points from the speculative path.
+class SpeculationCheckIndexIterator {
+public:
+ SpeculationCheckIndexIterator(SpeculationCheckVector& speculationChecks)
+ : m_speculationChecks(speculationChecks)
+ , m_iter(m_speculationChecks.begin())
+ , m_end(m_speculationChecks.end())
+ {
+ }
+
+ bool hasCheckAtIndex(NodeIndex nodeIndex)
+ {
+ while (m_iter != m_end) {
+ NodeIndex current = m_iter->m_nodeIndex;
+ if (current >= nodeIndex)
+ return current == nodeIndex;
+ ++m_iter;
+ }
+ return false;
+ }
+
+private:
+ SpeculationCheckVector& m_speculationChecks;
+ SpeculationCheckVector::Iterator m_iter;
+ SpeculationCheckVector::Iterator m_end;
+};
+
+
+} } // namespace JSC::DFG
+
+#endif
+#endif
+
my @undocumented = ();
+print OUTPUT "<!-- Generated from Interpreter.cpp by make-bytecode-docs.pl. -->\n";
print OUTPUT "<style>p code \{ font-size: 14px; \}</style>\n";
while (<MACHINE>) {
--- /dev/null
+{
+ 'includes': [
+ '../../gyp/common.gypi',
+ '../JavaScriptCore.gypi',
+ ],
+ 'configurations': {
+ 'Production': {
+ 'xcode_config_file': '<(project_dir)/Configurations/Base.xcconfig',
+ },
+ 'Profiling': {
+ 'xcode_config_file': '<(project_dir)/Configurations/DebugRelease.xcconfig',
+ 'xcode_settings': {
+ 'STRIP_INSTALLED_PRODUCT': 'NO',
+ },
+ },
+ 'Release': {
+ 'xcode_config_file': '<(project_dir)/Configurations/DebugRelease.xcconfig',
+ 'xcode_settings': {
+ 'STRIP_INSTALLED_PRODUCT': 'NO',
+ },
+ },
+ 'Debug': {
+ 'xcode_config_file': '<(project_dir)/Configurations/DebugRelease.xcconfig',
+ 'xcode_settings': {
+ 'DEAD_CODE_STRIPPING': '$(DEAD_CODE_STRIPPING_debug)',
+ 'DEBUG_DEFINES': '$(DEBUG_DEFINES_debug)',
+ 'GCC_OPTIMIZATION_LEVEL': '$(GCC_OPTIMIZATION_LEVEL_debug)',
+ 'STRIP_INSTALLED_PRODUCT': '$(STRIP_INSTALLED_PRODUCT_debug)',
+ },
+ },
+ },
+ 'variables': {
+ 'javascriptcore_include_dirs': [
+ '<(project_dir)',
+ '<(project_dir)/icu',
+ ],
+ },
+ 'target_defaults': {
+ 'configurations': {
+ 'Profiling': {},
+ },
+ },
+ 'targets': [
+ {
+ 'target_name': 'JavaScriptCore',
+ 'type': 'shared_library',
+ 'dependencies': [
+ 'Derived Sources',
+ 'Update Version',
+ ],
+ 'include_dirs': [
+ '<@(javascriptcore_include_dirs)',
+ '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore',
+ ],
+ 'configurations': {
+ 'Production': {
+ 'INSTALL_PATH': '$(BUILT_PRODUCTS_DIR)',
+ },
+ },
+ 'sources': [
+ '<@(javascriptcore_files)',
+ '<@(javascriptcore_publicheader_files)',
+ '<@(javascriptcore_privateheader_files)',
+ '<@(javascriptcore_derived_source_files)',
+ '$(SDKROOT)/System/Library/Frameworks/CoreFoundation.framework',
+ '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+ '/usr/lib/libicucore.dylib',
+ '/usr/lib/libobjc.dylib',
+ ],
+ 'mac_framework_headers': [
+ '<@(javascriptcore_publicheader_files)',
+ ],
+ 'mac_framework_private_headers': [
+ '<@(javascriptcore_privateheader_files)',
+ ],
+ 'xcode_config_file': '<(project_dir)/Configurations/JavaScriptCore.xcconfig',
+ 'sources/': [
+ ['exclude', 'API/tests/'],
+ ['exclude', 'ForwardingHeaders/'],
+ ['exclude', '(?<!unicode)/icu/'],
+ ['exclude', 'os-win32/'],
+ ['exclude', 'qt/'],
+ ['exclude', 'wtf/(android|brew|efl|gtk|haiku|qt|wince|wx)/'],
+ ['exclude', 'wtf/unicode/brew/'],
+ ['exclude', 'wtf/unicode/glib/'],
+ ['exclude', 'wtf/unicode/qt4/'],
+ ['exclude', 'wtf/unicode/wince/'],
+ ['exclude', 'wtf/url/'],
+ ['exclude', '/(gtk|glib|gobject)/.*\\.(cpp|h)$'],
+ ['exclude', '(Default|Gtk|Chromium|None|Qt|Win|Wx|Symbian)\\.(cpp|mm|h)$'],
+ ['exclude', 'GCActivityCallback\.cpp$'],
+ ['exclude', 'BSTR[^/]*$'],
+ ],
+ 'postbuilds': [
+ {
+ 'postbuild_name': 'Check For Global Initializers',
+ 'action': [
+ 'sh', '<(project_dir)/gyp/run-if-exists.sh', '<(DEPTH)/../Tools/Scripts/check-for-global-initializers'
+ ],
+ },
+ {
+ 'postbuild_name': 'Check For Exit Time Destructors',
+ 'action': [
+ 'sh', '<(project_dir)/gyp/run-if-exists.sh', '<(DEPTH)/../Tools/Scripts/check-for-exit-time-destructors'
+ ],
+ },
+ {
+ 'postbuild_name': 'Check For Weak VTables and Externals',
+ 'action': [
+ 'sh', '<(project_dir)/gyp/run-if-exists.sh', '<(DEPTH)/../Tools/Scripts/check-for-weak-vtables-and-externals'
+ ],
+ },
+ ],
+ 'conditions': [
+ ['OS=="mac"', {
+ 'mac_bundle': 1,
+ 'xcode_settings': {
+ # FIXME: Remove these overrides once JavaScriptCore.xcconfig is
+ # used only by this project.
+ 'GCC_PREFIX_HEADER': '<(project_dir)/JavaScriptCorePrefix.h',
+ 'INFOPLIST_FILE': '<(project_dir)/Info.plist',
+ },
+ }],
+ ],
+ },
+ {
+ 'target_name': 'Derived Sources',
+ 'type': 'none',
+ 'actions': [
+ {
+ 'action_name': 'Generate Derived Sources',
+ 'inputs': [],
+ 'outputs': [
+ '<@(javascriptcore_derived_source_files)',
+ ],
+ 'action': [
+ 'sh', 'generate-derived-sources.sh'
+ ],
+ },
+ {
+ 'action_name': 'Generate DTrace Header',
+ 'inputs': [],
+ 'outputs': [],
+ 'action': [
+ 'sh', '<(project_dir)/gyp/generate-dtrace-header.sh', '<(project_dir)'
+ ]
+ }
+ ],
+ },
+ {
+ 'target_name': 'Update Version',
+ 'type': 'none',
+ 'actions': [{
+ 'action_name': 'Update Info.plist with version information',
+ 'inputs': [],
+ 'outputs': [],
+ 'action': [
+ 'sh', '<(project_dir)/gyp/update-info-plist.sh', '<(project_dir)/Info.plist'
+ ]
+ }],
+ },
+ {
+ 'target_name': 'minidom',
+ 'type': 'executable',
+ 'dependencies': [
+ 'JavaScriptCore',
+ ],
+ # FIXME: We should use a header map instead of listing these explicitly.
+ 'include_dirs': [
+ '<@(javascriptcore_include_dirs)',
+ ],
+ 'sources': [
+ '<@(minidom_files)',
+ '$(SDKROOT)/System/Library/Frameworks/CoreFoundation.framework',
+ ],
+ 'copies': [{
+ 'destination': '<(PRODUCT_DIR)',
+ 'files': [
+ '<@(minidom_support_files)',
+ ],
+ }],
+ },
+ {
+ 'target_name': 'testapi',
+ 'type': 'executable',
+ 'dependencies': [
+ 'JavaScriptCore',
+ ],
+ # FIXME: We should use a header map instead of listing these explicitly.
+ 'include_dirs': [
+ '<@(javascriptcore_include_dirs)',
+ ],
+ 'sources': [
+ '<@(testapi_files)',
+ '$(SDKROOT)/System/Library/Frameworks/CoreFoundation.framework',
+ ],
+ 'copies': [{
+ 'destination': '<(PRODUCT_DIR)',
+ 'files': [
+ '<@(testapi_support_files)',
+ ],
+ }],
+ },
+ {
+ 'target_name': 'jsc',
+ 'type': 'executable',
+ 'dependencies': [
+ 'JavaScriptCore',
+ ],
+ # FIXME: We should use a header map instead of listing these explicitly.
+ 'include_dirs': [
+ '<@(javascriptcore_include_dirs)',
+ ],
+ 'configurations': {
+ 'Production': {
+ 'xcode_settings': {
+ 'INSTALL_PATH': '$(JAVASCRIPTCORE_FRAMEWORKS_DIR)/JavaScriptCore.framework/Resources',
+ },
+ },
+ },
+ 'sources': [
+ '<@(jsc_files)',
+ '$(SDKROOT)/System/Library/Frameworks/CoreFoundation.framework',
+ '/usr/lib/libedit.dylib',
+ ],
+ },
+ ], # targets
+}
--- /dev/null
+#!/bin/sh
+
+mkdir -p "${BUILT_PRODUCTS_DIR}/DerivedSources/JavaScriptCore/docs"
+cd "${BUILT_PRODUCTS_DIR}/DerivedSources/JavaScriptCore"
+
+/bin/ln -sfh "${SRCROOT}/.." JavaScriptCore
+export JavaScriptCore="JavaScriptCore"
+
+make --no-builtin-rules -f "JavaScriptCore/DerivedSources.make" -j `/usr/sbin/sysctl -n hw.ncpu`
--- /dev/null
+#!/bin/sh
+
+TRACING_D="$1/runtime/Tracing.d";
+TRACING_H="$BUILT_PRODUCTS_DIR/DerivedSources/JavaScriptCore/TracingDtrace.h";
+
+if [[ "${HAVE_DTRACE}" = "1" && "${TRACING_D}" -nt "${TRACING_H}" ]]; then
+ dtrace -h -o "${TRACING_H}" -s "${TRACING_D}";
+fi;
+
--- /dev/null
+{ # Just a stub file to allow Source/gyp/configure to run successfully for testing.
+ 'includes': [
+ '../../gyp/common.gypi',
+ '../JavaScriptCore.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'JavaScriptCore',
+ 'type': 'static_library',
+ 'sources': [
+ '<@(javascriptcore_files)',
+ '<@(javascriptcore_publicheader_files)',
+ '<@(javascriptcore_privateheader_files)',
+ '<@(javascriptcore_derived_source_files)',
+ ],
+ },
+ ], # targets
+}
--- /dev/null
+#!/bin/sh
+
+if [ -f $1 ]; then
+ $1 || exit $?;
+fi
--- /dev/null
+# Touch Info.plist to let Xcode know it needs to copy it into the built product
+if [[ "${CONFIGURATION}" != "Production" ]]; then
+ touch "$1";
+fi
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ConservativeRoots.h"
+
+namespace JSC {
+
+inline bool isPointerAligned(void* p)
+{
+ return !((intptr_t)(p) & (sizeof(char*) - 1));
+}
+
+void ConservativeRoots::grow()
+{
+ size_t newCapacity = m_capacity == inlineCapacity ? nonInlineCapacity : m_capacity * 2;
+ JSCell** newRoots = static_cast<JSCell**>(OSAllocator::reserveAndCommit(newCapacity * sizeof(JSCell*)));
+ memcpy(newRoots, m_roots, m_size * sizeof(JSCell*));
+ if (m_roots != m_inlineRoots)
+ OSAllocator::decommitAndRelease(m_roots, m_capacity * sizeof(JSCell*));
+ m_capacity = newCapacity;
+ m_roots = newRoots;
+}
+
+void ConservativeRoots::add(void* begin, void* end)
+{
+ ASSERT(begin <= end);
+ ASSERT((static_cast<char*>(end) - static_cast<char*>(begin)) < 0x1000000);
+ ASSERT(isPointerAligned(begin));
+ ASSERT(isPointerAligned(end));
+
+ for (char** it = static_cast<char**>(begin); it != static_cast<char**>(end); ++it)
+ add(*it);
+}
+
+} // namespace JSC
--- /dev/null
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ConservativeRoots_h
+#define ConservativeRoots_h
+
+#include "Heap.h"
+#include <wtf/OSAllocator.h>
+#include <wtf/Vector.h>
+
+namespace JSC {
+
+class JSCell;
+class Heap;
+
+// May contain duplicates.
+
+class ConservativeRoots {
+public:
+ ConservativeRoots(Heap*);
+ ~ConservativeRoots();
+
+ void add(void*);
+ void add(void* begin, void* end);
+
+ size_t size();
+ JSCell** roots();
+
+private:
+ static const size_t inlineCapacity = 128;
+ static const size_t nonInlineCapacity = 8192 / sizeof(JSCell*);
+
+ void grow();
+
+ Heap* m_heap;
+ JSCell** m_roots;
+ size_t m_size;
+ size_t m_capacity;
+ JSCell* m_inlineRoots[inlineCapacity];
+};
+
+inline ConservativeRoots::ConservativeRoots(Heap* heap)
+ : m_heap(heap)
+ , m_roots(m_inlineRoots)
+ , m_size(0)
+ , m_capacity(inlineCapacity)
+{
+}
+
+inline ConservativeRoots::~ConservativeRoots()
+{
+ if (m_roots != m_inlineRoots)
+ OSAllocator::decommitAndRelease(m_roots, m_capacity * sizeof(JSCell*));
+}
+
+inline void ConservativeRoots::add(void* p)
+{
+ if (!m_heap->contains(p))
+ return;
+
+ if (m_size == m_capacity)
+ grow();
+
+ m_roots[m_size++] = reinterpret_cast<JSCell*>(p);
+}
+
+inline size_t ConservativeRoots::size()
+{
+ return m_size;
+}
+
+inline JSCell** ConservativeRoots::roots()
+{
+ return m_roots;
+}
+
+} // namespace JSC
+
+#endif // ConservativeRoots_h
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef Handle_h
+#define Handle_h
+
+#include "HandleTypes.h"
+
+namespace JSC {
+
+/*
+ A Handle is a smart pointer that updates automatically when the garbage
+ collector moves the object to which it points.
+
+ The base Handle class represents a temporary reference to a pointer whose
+ lifetime is guaranteed by something else.
+*/
+
+template <class T> class Handle;
+
+// Creating a JSValue Handle is invalid
+template <> class Handle<JSValue>;
+
+// Forward declare WeakGCMap
+template<typename KeyType, typename MappedType, typename FinalizerCallback, typename HashArg, typename KeyTraitsArg> class WeakGCMap;
+
+class HandleBase {
+ template <typename T> friend class Weak;
+ friend class HandleHeap;
+ friend struct JSCallbackObjectData;
+ template <typename KeyType, typename MappedType, typename FinalizerCallback, typename HashArg, typename KeyTraitsArg> friend class WeakGCMap;
+
+public:
+ bool operator!() const { return !m_slot || !*m_slot; }
+
+ // This conversion operator allows implicit conversion to bool but not to other integer types.
+ typedef JSValue (HandleBase::*UnspecifiedBoolType);
+ operator UnspecifiedBoolType*() const { return (m_slot && *m_slot) ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; }
+
+protected:
+ HandleBase(HandleSlot slot)
+ : m_slot(slot)
+ {
+ }
+
+ void swap(HandleBase& other) { std::swap(m_slot, other.m_slot); }
+
+ HandleSlot slot() const { return m_slot; }
+ void setSlot(HandleSlot slot)
+ {
+ m_slot = slot;
+ }
+
+private:
+ HandleSlot m_slot;
+};
+
+template <typename Base, typename T> struct HandleConverter {
+ T* operator->()
+ {
+#if ENABLE(JSC_ZOMBIES)
+ ASSERT(!static_cast<const Base*>(this)->get() || !static_cast<const Base*>(this)->get()->isZombie());
+#endif
+ return static_cast<Base*>(this)->get();
+ }
+ const T* operator->() const
+ {
+#if ENABLE(JSC_ZOMBIES)
+ ASSERT(!static_cast<const Base*>(this)->get() || !static_cast<const Base*>(this)->get()->isZombie());
+#endif
+ return static_cast<const Base*>(this)->get();
+ }
+
+ T* operator*()
+ {
+#if ENABLE(JSC_ZOMBIES)
+ ASSERT(!static_cast<const Base*>(this)->get() || !static_cast<const Base*>(this)->get()->isZombie());
+#endif
+ return static_cast<Base*>(this)->get();
+ }
+ const T* operator*() const
+ {
+#if ENABLE(JSC_ZOMBIES)
+ ASSERT(!static_cast<const Base*>(this)->get() || !static_cast<const Base*>(this)->get()->isZombie());
+#endif
+ return static_cast<const Base*>(this)->get();
+ }
+};
+
+template <typename Base> struct HandleConverter<Base, Unknown> {
+ Handle<JSObject> asObject() const;
+ bool isObject() const { return jsValue().isObject(); }
+ bool getNumber(double number) const { return jsValue().getNumber(number); }
+ UString getString(ExecState*) const;
+ bool isUndefinedOrNull() const { return jsValue().isUndefinedOrNull(); }
+
+private:
+ JSValue jsValue() const
+ {
+#if ENABLE(JSC_ZOMBIES)
+ ASSERT(!static_cast<const Base*>(this)->get() || !static_cast<const Base*>(this)->get().isZombie());
+#endif
+ return static_cast<const Base*>(this)->get();
+ }
+};
+
+template <typename T> class Handle : public HandleBase, public HandleConverter<Handle<T>, T> {
+public:
+ template <typename A, typename B> friend class HandleConverter;
+ typedef typename HandleTypes<T>::ExternalType ExternalType;
+ template <typename U> Handle(Handle<U> o)
+ {
+ typename HandleTypes<T>::template validateUpcast<U>();
+ setSlot(o.slot());
+ }
+
+ void swap(Handle& other) { HandleBase::swap(other); }
+
+ ExternalType get() const { return HandleTypes<T>::getFromSlot(this->slot()); }
+
+protected:
+ Handle(HandleSlot slot = 0)
+ : HandleBase(slot)
+ {
+ }
+
+private:
+ friend class HandleHeap;
+
+ static Handle<T> wrapSlot(HandleSlot slot)
+ {
+ return Handle<T>(slot);
+ }
+};
+
+template <typename Base> Handle<JSObject> HandleConverter<Base, Unknown>::asObject() const
+{
+ return Handle<JSObject>::wrapSlot(static_cast<const Base*>(this)->slot());
+}
+
+template <typename T, typename U> inline bool operator==(const Handle<T>& a, const Handle<U>& b)
+{
+ return a.get() == b.get();
+}
+
+template <typename T, typename U> inline bool operator==(const Handle<T>& a, U* b)
+{
+ return a.get() == b;
+}
+
+template <typename T, typename U> inline bool operator==(T* a, const Handle<U>& b)
+{
+ return a == b.get();
+}
+
+template <typename T, typename U> inline bool operator!=(const Handle<T>& a, const Handle<U>& b)
+{
+ return a.get() != b.get();
+}
+
+template <typename T, typename U> inline bool operator!=(const Handle<T>& a, U* b)
+{
+ return a.get() != b;
+}
+
+template <typename T, typename U> inline bool operator!=(T* a, const Handle<U>& b)
+{
+ return a != b.get();
+}
+
+template <typename T, typename U> inline bool operator!=(const Handle<T>& a, JSValue b)
+{
+ return a.get() != b;
+}
+
+template <typename T, typename U> inline bool operator!=(JSValue a, const Handle<U>& b)
+{
+ return a != b.get();
+}
+
+}
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "HandleHeap.h"
+
+#include "JSObject.h"
+
+namespace JSC {
+
+WeakHandleOwner::~WeakHandleOwner()
+{
+}
+
+bool WeakHandleOwner::isReachableFromOpaqueRoots(Handle<Unknown>, void*, SlotVisitor&)
+{
+ return false;
+}
+
+void WeakHandleOwner::finalize(Handle<Unknown>, void*)
+{
+}
+
+HandleHeap::HandleHeap(JSGlobalData* globalData)
+ : m_globalData(globalData)
+ , m_nextToFinalize(0)
+{
+ grow();
+}
+
+void HandleHeap::grow()
+{
+ Node* block = m_blockStack.grow();
+ for (int i = m_blockStack.blockLength - 1; i >= 0; --i) {
+ Node* node = &block[i];
+ new (node) Node(this);
+ m_freeList.push(node);
+ }
+}
+
+void HandleHeap::markStrongHandles(HeapRootVisitor& heapRootMarker)
+{
+ Node* end = m_strongList.end();
+ for (Node* node = m_strongList.begin(); node != end; node = node->next())
+ heapRootMarker.mark(node->slot());
+}
+
+void HandleHeap::markWeakHandles(HeapRootVisitor& heapRootVisitor)
+{
+ SlotVisitor& visitor = heapRootVisitor.visitor();
+
+ Node* end = m_weakList.end();
+ for (Node* node = m_weakList.begin(); node != end; node = node->next()) {
+ ASSERT(isValidWeakNode(node));
+ JSCell* cell = node->slot()->asCell();
+ if (Heap::isMarked(cell))
+ continue;
+
+ WeakHandleOwner* weakOwner = node->weakOwner();
+ if (!weakOwner)
+ continue;
+
+ if (!weakOwner->isReachableFromOpaqueRoots(Handle<Unknown>::wrapSlot(node->slot()), node->weakOwnerContext(), visitor))
+ continue;
+
+ heapRootVisitor.mark(node->slot());
+ }
+}
+
+void HandleHeap::finalizeWeakHandles()
+{
+ Node* end = m_weakList.end();
+ for (Node* node = m_weakList.begin(); node != end; node = m_nextToFinalize) {
+ m_nextToFinalize = node->next();
+
+ ASSERT(isValidWeakNode(node));
+ JSCell* cell = node->slot()->asCell();
+ if (Heap::isMarked(cell))
+ continue;
+
+ if (WeakHandleOwner* weakOwner = node->weakOwner()) {
+ weakOwner->finalize(Handle<Unknown>::wrapSlot(node->slot()), node->weakOwnerContext());
+ if (m_nextToFinalize != node->next()) // Owner deallocated node.
+ continue;
+ }
+
+ *node->slot() = JSValue();
+ SentinelLinkedList<Node>::remove(node);
+ m_immediateList.push(node);
+ }
+
+ m_nextToFinalize = 0;
+}
+
+void HandleHeap::writeBarrier(HandleSlot slot, const JSValue& value)
+{
+ ASSERT(!m_nextToFinalize); // Forbid assignment to handles during the finalization phase, since it would violate many GC invariants.
+
+ if (!value == !*slot && slot->isCell() == value.isCell())
+ return;
+
+ Node* node = toNode(slot);
+ SentinelLinkedList<Node>::remove(node);
+ if (!value || !value.isCell()) {
+ m_immediateList.push(node);
+ return;
+ }
+
+ if (node->isWeak()) {
+ m_weakList.push(node);
+ return;
+ }
+
+ m_strongList.push(node);
+}
+
+unsigned HandleHeap::protectedGlobalObjectCount()
+{
+ unsigned count = 0;
+ Node* end = m_strongList.end();
+ for (Node* node = m_strongList.begin(); node != end; node = node->next()) {
+ JSValue value = *node->slot();
+ if (value.isObject() && asObject(value.asCell())->isGlobalObject())
+ count++;
+ }
+ return count;
+}
+
+#if !ASSERT_DISABLED
+bool HandleHeap::isValidWeakNode(Node* node)
+{
+ if (!node->isWeak())
+ return false;
+
+ JSValue value = *node->slot();
+ if (!value || !value.isCell())
+ return false;
+
+ JSCell* cell = value.asCell();
+ if (!cell || !cell->structure())
+ return false;
+
+#if ENABLE(JSC_ZOMBIES)
+ if (cell->isZombie())
+ return false;
+#endif
+
+ return true;
+}
+#endif
+
+} // namespace JSC
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef HandleHeap_h
+#define HandleHeap_h
+
+#include "BlockStack.h"
+#include "Handle.h"
+#include "SentinelLinkedList.h"
+#include "SinglyLinkedList.h"
+
+namespace JSC {
+
+class HandleHeap;
+class HeapRootVisitor;
+class JSGlobalData;
+class JSValue;
+class MarkStack;
+class TypeCounter;
+typedef MarkStack SlotVisitor;
+
+class WeakHandleOwner {
+public:
+ virtual ~WeakHandleOwner();
+ virtual bool isReachableFromOpaqueRoots(Handle<Unknown>, void* context, SlotVisitor&);
+ virtual void finalize(Handle<Unknown>, void* context);
+};
+
+class HandleHeap {
+public:
+ static HandleHeap* heapFor(HandleSlot);
+
+ HandleHeap(JSGlobalData*);
+
+ JSGlobalData* globalData();
+
+ HandleSlot allocate();
+ void deallocate(HandleSlot);
+
+ void makeWeak(HandleSlot, WeakHandleOwner* = 0, void* context = 0);
+ HandleSlot copyWeak(HandleSlot);
+
+ void markStrongHandles(HeapRootVisitor&);
+ void markWeakHandles(HeapRootVisitor&);
+ void finalizeWeakHandles();
+
+ void writeBarrier(HandleSlot, const JSValue&);
+
+#if !ASSERT_DISABLED
+ bool hasWeakOwner(HandleSlot, WeakHandleOwner*);
+ bool hasFinalizer(HandleSlot);
+#endif
+
+ unsigned protectedGlobalObjectCount();
+ void protectedObjectTypeCounts(TypeCounter&);
+
+private:
+ class Node {
+ public:
+ Node(WTF::SentinelTag);
+ Node(HandleHeap*);
+
+ HandleSlot slot();
+ HandleHeap* handleHeap();
+
+ void makeWeak(WeakHandleOwner*, void* context);
+ bool isWeak();
+
+ WeakHandleOwner* weakOwner();
+ void* weakOwnerContext();
+
+ void setPrev(Node*);
+ Node* prev();
+
+ void setNext(Node*);
+ Node* next();
+
+ private:
+ WeakHandleOwner* emptyWeakOwner();
+
+ JSValue m_value;
+ HandleHeap* m_handleHeap;
+ WeakHandleOwner* m_weakOwner;
+ void* m_weakOwnerContext;
+ Node* m_prev;
+ Node* m_next;
+ };
+
+ static HandleSlot toHandle(Node*);
+ static Node* toNode(HandleSlot);
+
+ void grow();
+
+#if !ASSERT_DISABLED
+ bool isValidWeakNode(Node*);
+#endif
+
+ JSGlobalData* m_globalData;
+ BlockStack<Node> m_blockStack;
+
+ SentinelLinkedList<Node> m_strongList;
+ SentinelLinkedList<Node> m_weakList;
+ SentinelLinkedList<Node> m_immediateList;
+ SinglyLinkedList<Node> m_freeList;
+ Node* m_nextToFinalize;
+};
+
+inline HandleHeap* HandleHeap::heapFor(HandleSlot handle)
+{
+ return toNode(handle)->handleHeap();
+}
+
+inline JSGlobalData* HandleHeap::globalData()
+{
+ return m_globalData;
+}
+
+inline HandleSlot HandleHeap::toHandle(Node* node)
+{
+ return reinterpret_cast<HandleSlot>(node);
+}
+
+inline HandleHeap::Node* HandleHeap::toNode(HandleSlot handle)
+{
+ return reinterpret_cast<Node*>(handle);
+}
+
+inline HandleSlot HandleHeap::allocate()
+{
+ if (m_freeList.isEmpty())
+ grow();
+
+ Node* node = m_freeList.pop();
+ new (node) Node(this);
+ m_immediateList.push(node);
+ return toHandle(node);
+}
+
+inline void HandleHeap::deallocate(HandleSlot handle)
+{
+ Node* node = toNode(handle);
+ if (node == m_nextToFinalize) {
+ m_nextToFinalize = node->next();
+ ASSERT(m_nextToFinalize->next());
+ }
+
+ SentinelLinkedList<Node>::remove(node);
+ m_freeList.push(node);
+}
+
+inline HandleSlot HandleHeap::copyWeak(HandleSlot other)
+{
+ Node* node = toNode(allocate());
+ node->makeWeak(toNode(other)->weakOwner(), toNode(other)->weakOwnerContext());
+ writeBarrier(node->slot(), *other);
+ *node->slot() = *other;
+ return toHandle(node);
+}
+
+inline void HandleHeap::makeWeak(HandleSlot handle, WeakHandleOwner* weakOwner, void* context)
+{
+ Node* node = toNode(handle);
+ node->makeWeak(weakOwner, context);
+
+ SentinelLinkedList<Node>::remove(node);
+ if (!*handle || !handle->isCell()) {
+ m_immediateList.push(node);
+ return;
+ }
+
+ m_weakList.push(node);
+}
+
+#if !ASSERT_DISABLED
+inline bool HandleHeap::hasWeakOwner(HandleSlot handle, WeakHandleOwner* weakOwner)
+{
+ return toNode(handle)->weakOwner() == weakOwner;
+}
+
+inline bool HandleHeap::hasFinalizer(HandleSlot handle)
+{
+ return toNode(handle)->weakOwner();
+}
+#endif
+
+inline HandleHeap::Node::Node(HandleHeap* handleHeap)
+ : m_handleHeap(handleHeap)
+ , m_weakOwner(0)
+ , m_weakOwnerContext(0)
+{
+}
+
+inline HandleHeap::Node::Node(WTF::SentinelTag)
+ : m_handleHeap(0)
+ , m_weakOwner(0)
+ , m_weakOwnerContext(0)
+{
+}
+
+inline HandleSlot HandleHeap::Node::slot()
+{
+ return &m_value;
+}
+
+inline HandleHeap* HandleHeap::Node::handleHeap()
+{
+ return m_handleHeap;
+}
+
+inline void HandleHeap::Node::makeWeak(WeakHandleOwner* weakOwner, void* context)
+{
+ m_weakOwner = weakOwner ? weakOwner : emptyWeakOwner();
+ m_weakOwnerContext = context;
+}
+
+inline bool HandleHeap::Node::isWeak()
+{
+ return m_weakOwner; // True for emptyWeakOwner().
+}
+
+inline WeakHandleOwner* HandleHeap::Node::weakOwner()
+{
+ return m_weakOwner == emptyWeakOwner() ? 0 : m_weakOwner; // 0 for emptyWeakOwner().
+}
+
+inline void* HandleHeap::Node::weakOwnerContext()
+{
+ ASSERT(weakOwner());
+ return m_weakOwnerContext;
+}
+
+inline void HandleHeap::Node::setPrev(Node* prev)
+{
+ m_prev = prev;
+}
+
+inline HandleHeap::Node* HandleHeap::Node::prev()
+{
+ return m_prev;
+}
+
+inline void HandleHeap::Node::setNext(Node* next)
+{
+ m_next = next;
+}
+
+inline HandleHeap::Node* HandleHeap::Node::next()
+{
+ return m_next;
+}
+
+// Sentinel to indicate that a node is weak, but its owner has no meaningful
+// callbacks. This allows us to optimize by skipping such nodes.
+inline WeakHandleOwner* HandleHeap::Node::emptyWeakOwner()
+{
+ return reinterpret_cast<WeakHandleOwner*>(-1);
+}
+
+}
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "HandleStack.h"
+
+#include "MarkStack.h"
+
+namespace JSC {
+
+HandleStack::HandleStack()
+#ifndef NDEBUG
+ : m_scopeDepth(0)
+#endif
+{
+ grow();
+}
+
+void HandleStack::mark(HeapRootVisitor& heapRootMarker)
+{
+ const Vector<HandleSlot>& blocks = m_blockStack.blocks();
+ size_t blockLength = m_blockStack.blockLength;
+
+ int end = blocks.size() - 1;
+ for (int i = 0; i < end; ++i) {
+ HandleSlot block = blocks[i];
+ heapRootMarker.mark(block, blockLength);
+ }
+ HandleSlot block = blocks[end];
+ heapRootMarker.mark(block, m_frame.m_next - block);
+}
+
+void HandleStack::grow()
+{
+ HandleSlot block = m_blockStack.grow();
+ m_frame.m_next = block;
+ m_frame.m_end = block + m_blockStack.blockLength;
+}
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef HandleStack_h
+#define HandleStack_h
+
+#include "Assertions.h"
+#include "BlockStack.h"
+#include "Handle.h"
+
+#include <wtf/UnusedParam.h>
+
+namespace JSC {
+
+class LocalScope;
+class HeapRootVisitor;
+
+class HandleStack {
+public:
+ class Frame {
+ public:
+ HandleSlot m_next;
+ HandleSlot m_end;
+ };
+
+ HandleStack();
+
+ void enterScope(Frame&);
+ void leaveScope(Frame&);
+
+ HandleSlot push();
+
+ void mark(HeapRootVisitor&);
+
+private:
+ void grow();
+ void zapTo(Frame&);
+ HandleSlot findFirstAfter(HandleSlot);
+
+#ifndef NDEBUG
+ size_t m_scopeDepth;
+#endif
+ BlockStack<JSValue> m_blockStack;
+ Frame m_frame;
+};
+
+inline void HandleStack::enterScope(Frame& lastFrame)
+{
+#ifndef NDEBUG
+ ++m_scopeDepth;
+#endif
+
+ lastFrame = m_frame;
+}
+
+
+
+inline void HandleStack::zapTo(Frame& lastFrame)
+{
+#ifdef NDEBUG
+ UNUSED_PARAM(lastFrame);
+#else
+ const Vector<HandleSlot>& blocks = m_blockStack.blocks();
+
+ if (lastFrame.m_end != m_frame.m_end) { // Zapping to a frame in a different block.
+ int i = blocks.size() - 1;
+ for ( ; blocks[i] + m_blockStack.blockLength != lastFrame.m_end; --i) {
+ for (int j = m_blockStack.blockLength - 1; j >= 0; --j)
+ blocks[i][j] = JSValue();
+ }
+
+ for (HandleSlot it = blocks[i] + m_blockStack.blockLength - 1; it != lastFrame.m_next - 1; --it)
+ *it = JSValue();
+
+ return;
+ }
+
+ for (HandleSlot it = m_frame.m_next - 1; it != lastFrame.m_next - 1; --it)
+ *it = JSValue();
+#endif
+}
+
+inline void HandleStack::leaveScope(Frame& lastFrame)
+{
+#ifndef NDEBUG
+ --m_scopeDepth;
+#endif
+
+ zapTo(lastFrame);
+
+ if (lastFrame.m_end != m_frame.m_end) // Popping to a frame in a different block.
+ m_blockStack.shrink(lastFrame.m_end);
+
+ m_frame = lastFrame;
+}
+
+inline HandleSlot HandleStack::push()
+{
+ ASSERT(m_scopeDepth); // Creating a Local outside of a LocalScope is a memory leak.
+ if (m_frame.m_next == m_frame.m_end)
+ grow();
+ return m_frame.m_next++;
+}
+
+}
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef HandleTypes_h
+#define HandleTypes_h
+
+#include "JSValue.h"
+
+namespace JSC {
+
+typedef enum { } Unknown;
+typedef JSValue* HandleSlot;
+
+template<typename T> struct HandleTypes {
+ typedef T* ExternalType;
+ static ExternalType getFromSlot(HandleSlot slot) { return (slot && *slot) ? reinterpret_cast<ExternalType>(slot->asCell()) : 0; }
+ static JSValue toJSValue(T* cell) { return reinterpret_cast<JSCell*>(cell); }
+ template<typename U> static void validateUpcast() { T* temp; temp = (U*)0; }
+};
+
+template<> struct HandleTypes<Unknown> {
+ typedef JSValue ExternalType;
+ static ExternalType getFromSlot(HandleSlot slot) { return slot ? *slot : JSValue(); }
+ static JSValue toJSValue(const JSValue& v) { return v; }
+ template<typename U> static void validateUpcast() { }
+};
+
+} // namespace JSC
+
+#endif // HandleTypes_h
--- /dev/null
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "config.h"
+#include "Heap.h"
+
+#include "CodeBlock.h"
+#include "ConservativeRoots.h"
+#include "GCActivityCallback.h"
+#include "Interpreter.h"
+#include "JSGlobalData.h"
+#include "JSGlobalObject.h"
+#include "JSLock.h"
+#include "JSONObject.h"
+#include "Tracing.h"
+#include <algorithm>
+
+#define COLLECT_ON_EVERY_SLOW_ALLOCATION 0
+
+using namespace std;
+
+namespace JSC {
+
+const size_t minBytesPerCycle = 512 * 1024;
+
+Heap::Heap(JSGlobalData* globalData)
+ : m_operationInProgress(NoOperation)
+ , m_markedSpace(globalData)
+ , m_markListSet(0)
+ , m_activityCallback(DefaultGCActivityCallback::create(this))
+ , m_globalData(globalData)
+ , m_machineThreads(this)
+ , m_markStack(globalData->jsArrayVPtr)
+ , m_handleHeap(globalData)
+ , m_extraCost(0)
+{
+ m_markedSpace.setHighWaterMark(minBytesPerCycle);
+ (*m_activityCallback)();
+}
+
+Heap::~Heap()
+{
+ // The destroy function must already have been called, so assert this.
+ ASSERT(!m_globalData);
+}
+
+void Heap::destroy()
+{
+ JSLock lock(SilenceAssertionsOnly);
+
+ if (!m_globalData)
+ return;
+
+ ASSERT(!m_globalData->dynamicGlobalObject);
+ ASSERT(m_operationInProgress == NoOperation);
+
+ // The global object is not GC protected at this point, so sweeping may delete it
+ // (and thus the global data) before other objects that may use the global data.
+ RefPtr<JSGlobalData> protect(m_globalData);
+
+#if ENABLE(JIT)
+ m_globalData->jitStubs->clearHostFunctionStubs();
+#endif
+
+ delete m_markListSet;
+ m_markListSet = 0;
+ m_markedSpace.clearMarks();
+ m_handleHeap.finalizeWeakHandles();
+ m_markedSpace.destroy();
+
+ m_globalData = 0;
+}
+
+void Heap::reportExtraMemoryCostSlowCase(size_t cost)
+{
+ // Our frequency of garbage collection tries to balance memory use against speed
+ // by collecting based on the number of newly created values. However, for values
+ // that hold on to a great deal of memory that's not in the form of other JS values,
+ // that is not good enough - in some cases a lot of those objects can pile up and
+ // use crazy amounts of memory without a GC happening. So we track these extra
+ // memory costs. Only unusually large objects are noted, and we only keep track
+ // of this extra cost until the next GC. In garbage collected languages, most values
+ // are either very short lived temporaries, or have extremely long lifetimes. So
+ // if a large value survives one garbage collection, there is not much point to
+ // collecting more frequently as long as it stays alive.
+
+ if (m_extraCost > maxExtraCost && m_extraCost > m_markedSpace.highWaterMark() / 2)
+ collectAllGarbage();
+ m_extraCost += cost;
+}
+
+void* Heap::allocateSlowCase(size_t bytes)
+{
+ ASSERT(globalData()->identifierTable == wtfThreadData().currentIdentifierTable());
+ ASSERT(JSLock::lockCount() > 0);
+ ASSERT(JSLock::currentThreadIsHoldingLock());
+ ASSERT(bytes <= MarkedSpace::maxCellSize);
+ ASSERT(m_operationInProgress == NoOperation);
+
+#if COLLECT_ON_EVERY_SLOW_ALLOCATION
+ collectAllGarbage();
+ ASSERT(m_operationInProgress == NoOperation);
+#endif
+
+ reset(DoNotSweep);
+
+ m_operationInProgress = Allocation;
+ void* result = m_markedSpace.allocate(bytes);
+ m_operationInProgress = NoOperation;
+
+ ASSERT(result);
+ return result;
+}
+
+void Heap::protect(JSValue k)
+{
+ ASSERT(k);
+ ASSERT(JSLock::currentThreadIsHoldingLock() || !m_globalData->isSharedInstance());
+
+ if (!k.isCell())
+ return;
+
+ m_protectedValues.add(k.asCell());
+}
+
+bool Heap::unprotect(JSValue k)
+{
+ ASSERT(k);
+ ASSERT(JSLock::currentThreadIsHoldingLock() || !m_globalData->isSharedInstance());
+
+ if (!k.isCell())
+ return false;
+
+ return m_protectedValues.remove(k.asCell());
+}
+
+void Heap::markProtectedObjects(HeapRootVisitor& heapRootMarker)
+{
+ ProtectCountSet::iterator end = m_protectedValues.end();
+ for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it)
+ heapRootMarker.mark(&it->first);
+}
+
+void Heap::pushTempSortVector(Vector<ValueStringPair>* tempVector)
+{
+ m_tempSortingVectors.append(tempVector);
+}
+
+void Heap::popTempSortVector(Vector<ValueStringPair>* tempVector)
+{
+ ASSERT_UNUSED(tempVector, tempVector == m_tempSortingVectors.last());
+ m_tempSortingVectors.removeLast();
+}
+
+void Heap::markTempSortVectors(HeapRootVisitor& heapRootMarker)
+{
+ typedef Vector<Vector<ValueStringPair>* > VectorOfValueStringVectors;
+
+ VectorOfValueStringVectors::iterator end = m_tempSortingVectors.end();
+ for (VectorOfValueStringVectors::iterator it = m_tempSortingVectors.begin(); it != end; ++it) {
+ Vector<ValueStringPair>* tempSortingVector = *it;
+
+ Vector<ValueStringPair>::iterator vectorEnd = tempSortingVector->end();
+ for (Vector<ValueStringPair>::iterator vectorIt = tempSortingVector->begin(); vectorIt != vectorEnd; ++vectorIt) {
+ if (vectorIt->first)
+ heapRootMarker.mark(&vectorIt->first);
+ }
+ }
+}
+
+inline RegisterFile& Heap::registerFile()
+{
+ return m_globalData->interpreter->registerFile();
+}
+
+void Heap::getConservativeRegisterRoots(HashSet<JSCell*>& roots)
+{
+#ifndef NDEBUG
+ if (m_globalData->isSharedInstance()) {
+ ASSERT(JSLock::lockCount() > 0);
+ ASSERT(JSLock::currentThreadIsHoldingLock());
+ }
+#endif
+ if (m_operationInProgress != NoOperation)
+ CRASH();
+ m_operationInProgress = Collection;
+ ConservativeRoots registerFileRoots(this);
+ registerFile().gatherConservativeRoots(registerFileRoots);
+ size_t registerFileRootCount = registerFileRoots.size();
+ JSCell** registerRoots = registerFileRoots.roots();
+ for (size_t i = 0; i < registerFileRootCount; i++) {
+ setMarked(registerRoots[i]);
+ roots.add(registerRoots[i]);
+ }
+ m_operationInProgress = NoOperation;
+}
+
+void Heap::markRoots()
+{
+#ifndef NDEBUG
+ if (m_globalData->isSharedInstance()) {
+ ASSERT(JSLock::lockCount() > 0);
+ ASSERT(JSLock::currentThreadIsHoldingLock());
+ }
+#endif
+
+ void* dummy;
+
+ ASSERT(m_operationInProgress == NoOperation);
+ if (m_operationInProgress != NoOperation)
+ CRASH();
+
+ m_operationInProgress = Collection;
+
+ MarkStack& visitor = m_markStack;
+ HeapRootVisitor heapRootMarker(visitor);
+
+ // We gather conservative roots before clearing mark bits because
+ // conservative gathering uses the mark bits from our last mark pass to
+ // determine whether a reference is valid.
+ ConservativeRoots machineThreadRoots(this);
+ m_machineThreads.gatherConservativeRoots(machineThreadRoots, &dummy);
+
+ ConservativeRoots registerFileRoots(this);
+ registerFile().gatherConservativeRoots(registerFileRoots);
+
+ m_markedSpace.clearMarks();
+
+ visitor.append(machineThreadRoots);
+ visitor.drain();
+
+ visitor.append(registerFileRoots);
+ visitor.drain();
+
+ markProtectedObjects(heapRootMarker);
+ visitor.drain();
+
+ markTempSortVectors(heapRootMarker);
+ visitor.drain();
+
+ if (m_markListSet && m_markListSet->size())
+ MarkedArgumentBuffer::markLists(heapRootMarker, *m_markListSet);
+ if (m_globalData->exception)
+ heapRootMarker.mark(&m_globalData->exception);
+ visitor.drain();
+
+ m_handleHeap.markStrongHandles(heapRootMarker);
+ visitor.drain();
+
+ m_handleStack.mark(heapRootMarker);
+ visitor.drain();
+
+ // Mark the small strings cache as late as possible, since it will clear
+ // itself if nothing else has marked it.
+ // FIXME: Change the small strings cache to use Weak<T>.
+ m_globalData->smallStrings.visitChildren(heapRootMarker);
+ visitor.drain();
+
+ // Weak handles must be marked last, because their owners use the set of
+ // opaque roots to determine reachability.
+ int lastOpaqueRootCount;
+ do {
+ lastOpaqueRootCount = visitor.opaqueRootCount();
+ m_handleHeap.markWeakHandles(heapRootMarker);
+ visitor.drain();
+ // If the set of opaque roots has grown, more weak handles may have become reachable.
+ } while (lastOpaqueRootCount != visitor.opaqueRootCount());
+
+ visitor.reset();
+
+ m_operationInProgress = NoOperation;
+}
+
+size_t Heap::objectCount() const
+{
+ return m_markedSpace.objectCount();
+}
+
+size_t Heap::size() const
+{
+ return m_markedSpace.size();
+}
+
+size_t Heap::capacity() const
+{
+ return m_markedSpace.capacity();
+}
+
+size_t Heap::globalObjectCount()
+{
+ return m_globalData->globalObjectCount;
+}
+
+size_t Heap::protectedGlobalObjectCount()
+{
+ size_t count = m_handleHeap.protectedGlobalObjectCount();
+
+ ProtectCountSet::iterator end = m_protectedValues.end();
+ for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it) {
+ if (it->first->isObject() && asObject(it->first)->isGlobalObject())
+ count++;
+ }
+
+ return count;
+}
+
+size_t Heap::protectedObjectCount()
+{
+ return m_protectedValues.size();
+}
+
+class TypeCounter {
+public:
+ TypeCounter();
+ void operator()(JSCell*);
+ PassOwnPtr<TypeCountSet> take();
+
+private:
+ const char* typeName(JSCell*);
+ OwnPtr<TypeCountSet> m_typeCountSet;
+ HashSet<JSCell*> m_cells;
+};
+
+inline TypeCounter::TypeCounter()
+ : m_typeCountSet(adoptPtr(new TypeCountSet))
+{
+}
+
+inline const char* TypeCounter::typeName(JSCell* cell)
+{
+ if (cell->isString())
+ return "string";
+ if (cell->isGetterSetter())
+ return "Getter-Setter";
+ if (cell->isAPIValueWrapper())
+ return "API wrapper";
+ if (cell->isPropertyNameIterator())
+ return "For-in iterator";
+ if (const ClassInfo* info = cell->classInfo())
+ return info->className;
+ if (!cell->isObject())
+ return "[empty cell]";
+ return "Object";
+}
+
+inline void TypeCounter::operator()(JSCell* cell)
+{
+ if (!m_cells.add(cell).second)
+ return;
+ m_typeCountSet->add(typeName(cell));
+}
+
+inline PassOwnPtr<TypeCountSet> TypeCounter::take()
+{
+ return m_typeCountSet.release();
+}
+
+PassOwnPtr<TypeCountSet> Heap::protectedObjectTypeCounts()
+{
+ TypeCounter typeCounter;
+
+ ProtectCountSet::iterator end = m_protectedValues.end();
+ for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it)
+ typeCounter(it->first);
+ m_handleHeap.protectedObjectTypeCounts(typeCounter);
+
+ return typeCounter.take();
+}
+
+void HandleHeap::protectedObjectTypeCounts(TypeCounter& typeCounter)
+{
+ Node* end = m_strongList.end();
+ for (Node* node = m_strongList.begin(); node != end; node = node->next()) {
+ JSValue value = *node->slot();
+ if (value && value.isCell())
+ typeCounter(value.asCell());
+ }
+}
+
+PassOwnPtr<TypeCountSet> Heap::objectTypeCounts()
+{
+ TypeCounter typeCounter;
+ forEach(typeCounter);
+ return typeCounter.take();
+}
+
+void Heap::collectAllGarbage()
+{
+ m_markStack.setShouldUnlinkCalls(true);
+ reset(DoSweep);
+ m_markStack.setShouldUnlinkCalls(false);
+}
+
+void Heap::reset(SweepToggle sweepToggle)
+{
+ ASSERT(globalData()->identifierTable == wtfThreadData().currentIdentifierTable());
+ JAVASCRIPTCORE_GC_BEGIN();
+
+ markRoots();
+ m_handleHeap.finalizeWeakHandles();
+
+ JAVASCRIPTCORE_GC_MARKED();
+
+ m_markedSpace.reset();
+ m_extraCost = 0;
+
+#if ENABLE(JSC_ZOMBIES)
+ sweepToggle = DoSweep;
+#endif
+
+ if (sweepToggle == DoSweep) {
+ m_markedSpace.sweep();
+ m_markedSpace.shrink();
+ }
+
+ // To avoid pathological GC churn in large heaps, we set the allocation high
+ // water mark to be proportional to the current size of the heap. The exact
+ // proportion is a bit arbitrary. A 2X multiplier gives a 1:1 (heap size :
+ // new bytes allocated) proportion, and seems to work well in benchmarks.
+ size_t proportionalBytes = 2 * m_markedSpace.size();
+ m_markedSpace.setHighWaterMark(max(proportionalBytes, minBytesPerCycle));
+
+ JAVASCRIPTCORE_GC_END();
+
+ (*m_activityCallback)();
+}
+
+void Heap::setActivityCallback(PassOwnPtr<GCActivityCallback> activityCallback)
+{
+ m_activityCallback = activityCallback;
+}
+
+GCActivityCallback* Heap::activityCallback()
+{
+ return m_activityCallback.get();
+}
+
+} // namespace JSC
--- /dev/null
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef Heap_h
+#define Heap_h
+
+#include "HandleHeap.h"
+#include "HandleStack.h"
+#include "MarkStack.h"
+#include "MarkedSpace.h"
+#include <wtf/Forward.h>
+#include <wtf/HashCountedSet.h>
+#include <wtf/HashSet.h>
+
+namespace JSC {
+
+ class GCActivityCallback;
+ class GlobalCodeBlock;
+ class HeapRootVisitor;
+ class JSCell;
+ class JSGlobalData;
+ class JSValue;
+ class LiveObjectIterator;
+ class MarkStack;
+ class MarkedArgumentBuffer;
+ class RegisterFile;
+ class UString;
+ class WeakGCHandlePool;
+ typedef MarkStack SlotVisitor;
+
+ typedef std::pair<JSValue, UString> ValueStringPair;
+ typedef HashCountedSet<JSCell*> ProtectCountSet;
+ typedef HashCountedSet<const char*> TypeCountSet;
+
+ enum OperationInProgress { NoOperation, Allocation, Collection };
+
+ class Heap {
+ WTF_MAKE_NONCOPYABLE(Heap);
+ public:
+ static Heap* heap(JSValue); // 0 for immediate values
+ static Heap* heap(JSCell*);
+
+ static bool isMarked(const JSCell*);
+ static bool testAndSetMarked(const JSCell*);
+ static void setMarked(JSCell*);
+
+ static void writeBarrier(const JSCell*, JSValue);
+ static void writeBarrier(const JSCell*, JSCell*);
+
+ Heap(JSGlobalData*);
+ ~Heap();
+ void destroy(); // JSGlobalData must call destroy() before ~Heap().
+
+ JSGlobalData* globalData() const { return m_globalData; }
+ MarkedSpace& markedSpace() { return m_markedSpace; }
+ MachineThreads& machineThreads() { return m_machineThreads; }
+
+ GCActivityCallback* activityCallback();
+ void setActivityCallback(PassOwnPtr<GCActivityCallback>);
+
+ // true if an allocation or collection is in progress
+ inline bool isBusy();
+
+ void* allocate(size_t);
+ void collectAllGarbage();
+
+ void reportExtraMemoryCost(size_t cost);
+
+ void protect(JSValue);
+ bool unprotect(JSValue); // True when the protect count drops to 0.
+
+ bool contains(void*);
+
+ size_t size() const;
+ size_t capacity() const;
+ size_t objectCount() const;
+ size_t globalObjectCount();
+ size_t protectedObjectCount();
+ size_t protectedGlobalObjectCount();
+ PassOwnPtr<TypeCountSet> protectedObjectTypeCounts();
+ PassOwnPtr<TypeCountSet> objectTypeCounts();
+
+ void pushTempSortVector(Vector<ValueStringPair>*);
+ void popTempSortVector(Vector<ValueStringPair>*);
+
+ HashSet<MarkedArgumentBuffer*>& markListSet() { if (!m_markListSet) m_markListSet = new HashSet<MarkedArgumentBuffer*>; return *m_markListSet; }
+
+ template <typename Functor> void forEach(Functor&);
+
+ HandleSlot allocateGlobalHandle() { return m_handleHeap.allocate(); }
+ HandleSlot allocateLocalHandle() { return m_handleStack.push(); }
+
+ HandleStack* handleStack() { return &m_handleStack; }
+ void getConservativeRegisterRoots(HashSet<JSCell*>& roots);
+
+ private:
+ friend class JSGlobalData;
+
+ static const size_t minExtraCost = 256;
+ static const size_t maxExtraCost = 1024 * 1024;
+
+ void* allocateSlowCase(size_t);
+ void reportExtraMemoryCostSlowCase(size_t);
+
+ void markRoots();
+ void markProtectedObjects(HeapRootVisitor&);
+ void markTempSortVectors(HeapRootVisitor&);
+
+ enum SweepToggle { DoNotSweep, DoSweep };
+ void reset(SweepToggle);
+
+ RegisterFile& registerFile();
+
+ OperationInProgress m_operationInProgress;
+ MarkedSpace m_markedSpace;
+
+ ProtectCountSet m_protectedValues;
+ Vector<Vector<ValueStringPair>* > m_tempSortingVectors;
+
+ HashSet<MarkedArgumentBuffer*>* m_markListSet;
+
+ OwnPtr<GCActivityCallback> m_activityCallback;
+
+ JSGlobalData* m_globalData;
+
+ MachineThreads m_machineThreads;
+ MarkStack m_markStack;
+ HandleHeap m_handleHeap;
+ HandleStack m_handleStack;
+
+ size_t m_extraCost;
+ };
+
+ bool Heap::isBusy()
+ {
+ return m_operationInProgress != NoOperation;
+ }
+
+ inline bool Heap::isMarked(const JSCell* cell)
+ {
+ return MarkedSpace::isMarked(cell);
+ }
+
+ inline bool Heap::testAndSetMarked(const JSCell* cell)
+ {
+ return MarkedSpace::testAndSetMarked(cell);
+ }
+
+ inline void Heap::setMarked(JSCell* cell)
+ {
+ MarkedSpace::setMarked(cell);
+ }
+
+ inline void Heap::writeBarrier(const JSCell*, JSValue)
+ {
+ }
+
+ inline void Heap::writeBarrier(const JSCell*, JSCell*)
+ {
+ }
+
+ inline bool Heap::contains(void* p)
+ {
+ return m_markedSpace.contains(p);
+ }
+
+ inline void Heap::reportExtraMemoryCost(size_t cost)
+ {
+ if (cost > minExtraCost)
+ reportExtraMemoryCostSlowCase(cost);
+ }
+
+ template <typename Functor> inline void Heap::forEach(Functor& functor)
+ {
+ m_markedSpace.forEach(functor);
+ }
+
+} // namespace JSC
+
+#endif // Heap_h
--- /dev/null
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef Local_h
+#define Local_h
+
+#include "Handle.h"
+#include "JSGlobalData.h"
+
+/*
+ A strongly referenced handle whose lifetime is temporary, limited to a given
+ LocalScope. Use Locals for local values on the stack. It is an error to
+ create a Local outside of any LocalScope.
+*/
+
+namespace JSC {
+
+template <typename T> class Local : public Handle<T> {
+ friend class LocalScope;
+ using Handle<T>::slot;
+
+public:
+ typedef typename Handle<T>::ExternalType ExternalType;
+
+ Local(JSGlobalData&, ExternalType = ExternalType());
+ Local(JSGlobalData&, Handle<T>);
+ Local(const Local<T>&); // Adopting constructor. Used to return a Local to a calling function.
+
+ Local& operator=(ExternalType);
+ Local& operator=(Handle<T>);
+
+private:
+ Local(HandleSlot, ExternalType); // Used by LocalScope::release() to move a Local to a containing scope.
+ void set(ExternalType);
+};
+
+template <typename T> inline Local<T>::Local(JSGlobalData& globalData, ExternalType value)
+ : Handle<T>(globalData.allocateLocalHandle())
+{
+ set(value);
+}
+
+template <typename T> inline Local<T>::Local(JSGlobalData& globalData, Handle<T> other)
+ : Handle<T>(globalData.allocateLocalHandle())
+{
+ set(other.get());
+}
+
+template <typename T> inline Local<T>::Local(const Local<T>& other)
+ : Handle<T>(other.slot())
+{
+ const_cast<Local<T>&>(other).setSlot(0); // Prevent accidental sharing.
+}
+
+template <typename T> inline Local<T>::Local(HandleSlot slot, ExternalType value)
+ : Handle<T>(slot, value)
+{
+}
+
+template <typename T> inline Local<T>& Local<T>::operator=(ExternalType value)
+{
+ set(value);
+ return *this;
+}
+
+template <typename T> inline Local<T>& Local<T>::operator=(Handle<T> other)
+{
+ set(other.get());
+ return *this;
+}
+
+template <typename T> inline void Local<T>::set(ExternalType externalType)
+{
+ ASSERT(slot());
+ ASSERT(!HandleTypes<T>::toJSValue(externalType) || !HandleTypes<T>::toJSValue(externalType).isCell() || Heap::isMarked(HandleTypes<T>::toJSValue(externalType).asCell()));
+ *slot() = externalType;
+}
+
+
+template <typename T, unsigned inlineCapacity = 0> class LocalStack {
+ typedef typename Handle<T>::ExternalType ExternalType;
+public:
+ LocalStack(JSGlobalData& globalData)
+ : m_globalData(&globalData)
+ , m_count(0)
+ {
+ }
+
+ ExternalType peek() const
+ {
+ ASSERT(m_count > 0);
+ return m_stack[m_count - 1].get();
+ }
+
+ ExternalType pop()
+ {
+ ASSERT(m_count > 0);
+ return m_stack[--m_count].get();
+ }
+
+ void push(ExternalType value)
+ {
+ if (m_count == m_stack.size())
+ m_stack.append(Local<T>(*m_globalData, value));
+ else
+ m_stack[m_count] = value;
+ m_count++;
+ }
+
+ bool isEmpty() const { return !m_count; }
+ unsigned size() const { return m_count; }
+
+private:
+ RefPtr<JSGlobalData> m_globalData;
+ Vector<Local<T>, inlineCapacity> m_stack;
+ unsigned m_count;
+};
+
+}
+
+namespace WTF {
+
+template<typename T> struct VectorTraits<JSC::Local<T> > : SimpleClassVectorTraits {
+ static const bool needsDestruction = false;
+ static const bool canInitializeWithMemset = false;
+ static const bool canCompareWithMemcmp = false;
+};
+
+}
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LocalScope_h
+#define LocalScope_h
+
+#include "HandleStack.h"
+#include "Local.h"
+
+namespace JSC {
+/*
+ A LocalScope is a temporary scope in which Locals are allocated. When a
+ LocalScope goes out of scope, all the Locals created in it are destroyed.
+
+ LocalScope is similar in concept to NSAutoreleasePool.
+*/
+
+class JSGlobalData;
+
+class LocalScope {
+public:
+ explicit LocalScope(JSGlobalData&);
+ ~LocalScope();
+
+ template <typename T> Local<T> release(Local<T>); // Destroys all other locals in the scope.
+
+private:
+ HandleStack* m_handleStack;
+ HandleStack::Frame m_lastFrame;
+};
+
+inline LocalScope::LocalScope(JSGlobalData& globalData)
+ : m_handleStack(globalData.heap.handleStack())
+{
+ m_handleStack->enterScope(m_lastFrame);
+}
+
+inline LocalScope::~LocalScope()
+{
+ m_handleStack->leaveScope(m_lastFrame);
+}
+
+template <typename T> Local<T> LocalScope::release(Local<T> local)
+{
+ typename Local<T>::ExternalType ptr = local.get();
+
+ m_handleStack->leaveScope(m_lastFrame);
+ HandleSlot slot = m_handleStack->push();
+ m_handleStack->enterScope(m_lastFrame);
+
+ return Local<T>(slot, ptr);
+}
+
+}
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2009 Acision BV. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "config.h"
+#include "MachineStackMarker.h"
+
+#include "ConservativeRoots.h"
+#include "Heap.h"
+#include "JSArray.h"
+#include "JSGlobalData.h"
+#include <setjmp.h>
+#include <stdlib.h>
+#include <wtf/StdLibExtras.h>
+
+#if USE(PTHREAD_BASED_QT) && !defined(WTF_USE_PTHREADS)
+#define WTF_USE_PTHREADS 1
+#endif
+
+#if OS(DARWIN)
+
+#include <mach/mach_init.h>
+#include <mach/mach_port.h>
+#include <mach/task.h>
+#include <mach/thread_act.h>
+#include <mach/vm_map.h>
+
+#elif OS(WINDOWS)
+
+#include <windows.h>
+#include <malloc.h>
+
+#elif OS(HAIKU)
+
+#include <OS.h>
+
+#elif OS(UNIX)
+
+#include <stdlib.h>
+#if !OS(HAIKU)
+#include <sys/mman.h>
+#endif
+#include <unistd.h>
+
+#if OS(SOLARIS)
+#include <thread.h>
+#else
+#include <pthread.h>
+#endif
+
+#if HAVE(PTHREAD_NP_H)
+#include <pthread_np.h>
+#endif
+
+#if OS(QNX)
+#include <fcntl.h>
+#include <sys/procfs.h>
+#include <stdio.h>
+#include <errno.h>
+#endif
+
+#if USE(PTHREADS) && !OS(WINDOWS) && !OS(DARWIN)
+#include <signal.h>
+#ifndef SA_RESTART
+#error MachineThreads requires SA_RESTART
+#endif
+#endif
+
+#endif
+
+using namespace WTF;
+
+namespace JSC {
+
+static inline void swapIfBackwards(void*& begin, void*& end)
+{
+#if OS(WINCE)
+ if (begin <= end)
+ return;
+ std::swap(begin, end);
+#else
+UNUSED_PARAM(begin);
+UNUSED_PARAM(end);
+#endif
+}
+
+#if ENABLE(JSC_MULTIPLE_THREADS)
+
+#if OS(DARWIN)
+typedef mach_port_t PlatformThread;
+#elif OS(WINDOWS)
+typedef HANDLE PlatformThread;
+#elif USE(PTHREADS)
+typedef pthread_t PlatformThread;
+static const int SigThreadSuspendResume = SIGUSR2;
+
+static void pthreadSignalHandlerSuspendResume(int signo)
+{
+ sigset_t signalSet;
+ sigemptyset(&signalSet);
+ sigaddset(&signalSet, SigThreadSuspendResume);
+ sigsuspend(&signalSet);
+}
+#endif
+
+class MachineThreads::Thread {
+public:
+ Thread(pthread_t pthread, const PlatformThread& platThread, void* base)
+ : posixThread(pthread)
+ , platformThread(platThread)
+ , stackBase(base)
+ {
+#if USE(PTHREADS) && !OS(WINDOWS) && !OS(DARWIN)
+ struct sigaction action;
+ action.sa_handler = pthreadSignalHandlerSuspendResume;
+ sigemptyset(&action.sa_mask);
+ action.sa_flags = SA_RESTART;
+ sigaction(SigThreadSuspendResume, &action, 0);
+
+ sigset_t mask;
+ sigemptyset(&mask);
+ sigaddset(&mask, SigThreadSuspendResume);
+ pthread_sigmask(SIG_UNBLOCK, &mask, 0);
+#endif
+ }
+
+ Thread* next;
+ pthread_t posixThread;
+ PlatformThread platformThread;
+ void* stackBase;
+};
+
+#endif
+
+MachineThreads::MachineThreads(Heap* heap)
+ : m_heap(heap)
+#if ENABLE(JSC_MULTIPLE_THREADS)
+ , m_registeredThreads(0)
+ , m_threadSpecific(0)
+#endif
+{
+}
+
+MachineThreads::~MachineThreads()
+{
+#if ENABLE(JSC_MULTIPLE_THREADS)
+ if (m_threadSpecific) {
+ int error = pthread_key_delete(m_threadSpecific);
+ ASSERT_UNUSED(error, !error);
+ }
+
+ MutexLocker registeredThreadsLock(m_registeredThreadsMutex);
+ for (Thread* t = m_registeredThreads; t;) {
+ Thread* next = t->next;
+ delete t;
+ t = next;
+ }
+#endif
+}
+
+#if ENABLE(JSC_MULTIPLE_THREADS)
+
+static inline PlatformThread getCurrentPlatformThread()
+{
+#if OS(DARWIN)
+ return pthread_mach_thread_np(pthread_self());
+#elif OS(WINDOWS)
+ return pthread_getw32threadhandle_np(pthread_self());
+#elif USE(PTHREADS)
+ return pthread_self();
+#endif
+}
+
+void MachineThreads::makeUsableFromMultipleThreads()
+{
+ if (m_threadSpecific)
+ return;
+
+ int error = pthread_key_create(&m_threadSpecific, removeThread);
+ if (error)
+ CRASH();
+}
+
+void MachineThreads::addCurrentThread()
+{
+ ASSERT(!m_heap->globalData()->exclusiveThread || m_heap->globalData()->exclusiveThread == currentThread());
+
+ if (!m_threadSpecific || pthread_getspecific(m_threadSpecific))
+ return;
+
+ pthread_setspecific(m_threadSpecific, this);
+ Thread* thread = new Thread(pthread_self(), getCurrentPlatformThread(), m_heap->globalData()->stack().origin());
+
+ MutexLocker lock(m_registeredThreadsMutex);
+
+ thread->next = m_registeredThreads;
+ m_registeredThreads = thread;
+}
+
+void MachineThreads::removeThread(void* p)
+{
+ if (p)
+ static_cast<MachineThreads*>(p)->removeCurrentThread();
+}
+
+void MachineThreads::removeCurrentThread()
+{
+ pthread_t currentPosixThread = pthread_self();
+
+ MutexLocker lock(m_registeredThreadsMutex);
+
+ if (pthread_equal(currentPosixThread, m_registeredThreads->posixThread)) {
+ Thread* t = m_registeredThreads;
+ m_registeredThreads = m_registeredThreads->next;
+ delete t;
+ } else {
+ Thread* last = m_registeredThreads;
+ Thread* t;
+ for (t = m_registeredThreads->next; t; t = t->next) {
+ if (pthread_equal(t->posixThread, currentPosixThread)) {
+ last->next = t->next;
+ break;
+ }
+ last = t;
+ }
+ ASSERT(t); // If t is NULL, we never found ourselves in the list.
+ delete t;
+ }
+}
+
+#endif
+
+#if COMPILER(GCC)
+#define REGISTER_BUFFER_ALIGNMENT __attribute__ ((aligned (sizeof(void*))))
+#else
+#define REGISTER_BUFFER_ALIGNMENT
+#endif
+
+void MachineThreads::gatherFromCurrentThread(ConservativeRoots& conservativeRoots, void* stackCurrent)
+{
+ // setjmp forces volatile registers onto the stack
+ jmp_buf registers REGISTER_BUFFER_ALIGNMENT;
+#if COMPILER(MSVC)
+#pragma warning(push)
+#pragma warning(disable: 4611)
+#endif
+ setjmp(registers);
+#if COMPILER(MSVC)
+#pragma warning(pop)
+#endif
+
+ void* registersBegin = ®isters;
+ void* registersEnd = reinterpret_cast<void*>(roundUpToMultipleOf<sizeof(void*)>(reinterpret_cast<uintptr_t>(®isters + 1)));
+ swapIfBackwards(registersBegin, registersEnd);
+ conservativeRoots.add(registersBegin, registersEnd);
+
+ void* stackBegin = stackCurrent;
+ void* stackEnd = m_heap->globalData()->stack().origin();
+ swapIfBackwards(stackBegin, stackEnd);
+ conservativeRoots.add(stackBegin, stackEnd);
+}
+
+#if ENABLE(JSC_MULTIPLE_THREADS)
+
+static inline void suspendThread(const PlatformThread& platformThread)
+{
+#if OS(DARWIN)
+ thread_suspend(platformThread);
+#elif OS(WINDOWS)
+ SuspendThread(platformThread);
+#elif USE(PTHREADS)
+ pthread_kill(platformThread, SigThreadSuspendResume);
+#else
+#error Need a way to suspend threads on this platform
+#endif
+}
+
+static inline void resumeThread(const PlatformThread& platformThread)
+{
+#if OS(DARWIN)
+ thread_resume(platformThread);
+#elif OS(WINDOWS)
+ ResumeThread(platformThread);
+#elif USE(PTHREADS)
+ pthread_kill(platformThread, SigThreadSuspendResume);
+#else
+#error Need a way to resume threads on this platform
+#endif
+}
+
+typedef unsigned long usword_t; // word size, assumed to be either 32 or 64 bit
+
+#if OS(DARWIN)
+
+#if CPU(X86)
+typedef i386_thread_state_t PlatformThreadRegisters;
+#elif CPU(X86_64)
+typedef x86_thread_state64_t PlatformThreadRegisters;
+#elif CPU(PPC)
+typedef ppc_thread_state_t PlatformThreadRegisters;
+#elif CPU(PPC64)
+typedef ppc_thread_state64_t PlatformThreadRegisters;
+#elif CPU(ARM)
+typedef arm_thread_state_t PlatformThreadRegisters;
+#else
+#error Unknown Architecture
+#endif
+
+#elif OS(WINDOWS)
+typedef CONTEXT PlatformThreadRegisters;
+#elif USE(PTHREADS)
+typedef pthread_attr_t PlatformThreadRegisters;
+#else
+#error Need a thread register struct for this platform
+#endif
+
+static size_t getPlatformThreadRegisters(const PlatformThread& platformThread, PlatformThreadRegisters& regs)
+{
+#if OS(DARWIN)
+
+#if CPU(X86)
+ unsigned user_count = sizeof(regs)/sizeof(int);
+ thread_state_flavor_t flavor = i386_THREAD_STATE;
+#elif CPU(X86_64)
+ unsigned user_count = x86_THREAD_STATE64_COUNT;
+ thread_state_flavor_t flavor = x86_THREAD_STATE64;
+#elif CPU(PPC)
+ unsigned user_count = PPC_THREAD_STATE_COUNT;
+ thread_state_flavor_t flavor = PPC_THREAD_STATE;
+#elif CPU(PPC64)
+ unsigned user_count = PPC_THREAD_STATE64_COUNT;
+ thread_state_flavor_t flavor = PPC_THREAD_STATE64;
+#elif CPU(ARM)
+ unsigned user_count = ARM_THREAD_STATE_COUNT;
+ thread_state_flavor_t flavor = ARM_THREAD_STATE;
+#else
+#error Unknown Architecture
+#endif
+
+ kern_return_t result = thread_get_state(platformThread, flavor, (thread_state_t)®s, &user_count);
+ if (result != KERN_SUCCESS) {
+ WTFReportFatalError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION,
+ "JavaScript garbage collection failed because thread_get_state returned an error (%d). This is probably the result of running inside Rosetta, which is not supported.", result);
+ CRASH();
+ }
+ return user_count * sizeof(usword_t);
+// end OS(DARWIN)
+
+#elif OS(WINDOWS)
+ regs.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL | CONTEXT_SEGMENTS;
+ GetThreadContext(platformThread, ®s);
+ return sizeof(CONTEXT);
+#elif USE(PTHREADS)
+ pthread_attr_init(®s);
+#if HAVE(PTHREAD_NP_H) || OS(NETBSD)
+ // e.g. on FreeBSD 5.4, neundorf@kde.org
+ pthread_attr_get_np(platformThread, ®s);
+#else
+ // FIXME: this function is non-portable; other POSIX systems may have different np alternatives
+ pthread_getattr_np(platformThread, ®s);
+#endif
+ return 0;
+#else
+#error Need a way to get thread registers on this platform
+#endif
+}
+
+static inline void* otherThreadStackPointer(const PlatformThreadRegisters& regs)
+{
+#if OS(DARWIN)
+
+#if __DARWIN_UNIX03
+
+#if CPU(X86)
+ return reinterpret_cast<void*>(regs.__esp);
+#elif CPU(X86_64)
+ return reinterpret_cast<void*>(regs.__rsp);
+#elif CPU(PPC) || CPU(PPC64)
+ return reinterpret_cast<void*>(regs.__r1);
+#elif CPU(ARM)
+ return reinterpret_cast<void*>(regs.__sp);
+#else
+#error Unknown Architecture
+#endif
+
+#else // !__DARWIN_UNIX03
+
+#if CPU(X86)
+ return reinterpret_cast<void*>(regs.esp);
+#elif CPU(X86_64)
+ return reinterpret_cast<void*>(regs.rsp);
+#elif CPU(PPC) || CPU(PPC64)
+ return reinterpret_cast<void*>(regs.r1);
+#else
+#error Unknown Architecture
+#endif
+
+#endif // __DARWIN_UNIX03
+
+// end OS(DARWIN)
+#elif CPU(X86) && OS(WINDOWS)
+ return reinterpret_cast<void*>((uintptr_t) regs.Esp);
+#elif CPU(X86_64) && OS(WINDOWS)
+ return reinterpret_cast<void*>((uintptr_t) regs.Rsp);
+#elif USE(PTHREADS)
+ void* stackBase = 0;
+ size_t stackSize = 0;
+ int rc = pthread_attr_getstack(®s, &stackBase, &stackSize);
+ (void)rc; // FIXME: Deal with error code somehow? Seems fatal.
+ ASSERT(stackBase);
+ return static_cast<char*>(stackBase) + stackSize;
+#else
+#error Need a way to get the stack pointer for another thread on this platform
+#endif
+}
+
+static void freePlatformThreadRegisters(PlatformThreadRegisters& regs)
+{
+#if USE(PTHREADS) && !OS(WINDOWS) && !OS(DARWIN)
+ pthread_attr_destroy(®s);
+#else
+ UNUSED_PARAM(regs);
+#endif
+}
+
+void MachineThreads::gatherFromOtherThread(ConservativeRoots& conservativeRoots, Thread* thread)
+{
+ suspendThread(thread->platformThread);
+
+ PlatformThreadRegisters regs;
+ size_t regSize = getPlatformThreadRegisters(thread->platformThread, regs);
+
+ conservativeRoots.add(static_cast<void*>(®s), static_cast<void*>(reinterpret_cast<char*>(®s) + regSize));
+
+ void* stackPointer = otherThreadStackPointer(regs);
+ void* stackBase = thread->stackBase;
+ swapIfBackwards(stackPointer, stackBase);
+ conservativeRoots.add(stackPointer, stackBase);
+
+ resumeThread(thread->platformThread);
+
+ freePlatformThreadRegisters(regs);
+}
+
+#endif
+
+void MachineThreads::gatherConservativeRoots(ConservativeRoots& conservativeRoots, void* stackCurrent)
+{
+ gatherFromCurrentThread(conservativeRoots, stackCurrent);
+
+#if ENABLE(JSC_MULTIPLE_THREADS)
+
+ if (m_threadSpecific) {
+
+ MutexLocker lock(m_registeredThreadsMutex);
+
+#ifndef NDEBUG
+ // Forbid malloc during the gather phase. The gather phase suspends
+ // threads, so a malloc during gather would risk a deadlock with a
+ // thread that had been suspended while holding the malloc lock.
+ fastMallocForbid();
+#endif
+ // It is safe to access the registeredThreads list, because we earlier asserted that locks are being held,
+ // and since this is a shared heap, they are real locks.
+ for (Thread* thread = m_registeredThreads; thread; thread = thread->next) {
+ if (!pthread_equal(thread->posixThread, pthread_self()))
+ gatherFromOtherThread(conservativeRoots, thread);
+ }
+#ifndef NDEBUG
+ fastMallocAllow();
+#endif
+ }
+#endif
+}
+
+} // namespace JSC
--- /dev/null
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef MachineThreads_h
+#define MachineThreads_h
+
+#include <wtf/Noncopyable.h>
+#include <wtf/ThreadingPrimitives.h>
+
+#if ENABLE(JSC_MULTIPLE_THREADS)
+#include <pthread.h>
+#endif
+
+namespace JSC {
+
+ class Heap;
+ class ConservativeRoots;
+
+ class MachineThreads {
+ WTF_MAKE_NONCOPYABLE(MachineThreads);
+ public:
+ MachineThreads(Heap*);
+ ~MachineThreads();
+
+ void gatherConservativeRoots(ConservativeRoots&, void* stackCurrent);
+
+#if ENABLE(JSC_MULTIPLE_THREADS)
+ void makeUsableFromMultipleThreads();
+ void addCurrentThread(); // Only needs to be called by clients that can use the same heap from multiple threads.
+#endif
+
+ private:
+ void gatherFromCurrentThread(ConservativeRoots&, void* stackCurrent);
+
+#if ENABLE(JSC_MULTIPLE_THREADS)
+ class Thread;
+
+ static void removeThread(void*);
+ void removeCurrentThread();
+
+ void gatherFromOtherThread(ConservativeRoots&, Thread*);
+#endif
+
+ Heap* m_heap;
+
+#if ENABLE(JSC_MULTIPLE_THREADS)
+ Mutex m_registeredThreadsMutex;
+ Thread* m_registeredThreads;
+ pthread_key_t m_threadSpecific;
+#endif
+ };
+
+} // namespace JSC
+
+#endif // MachineThreads_h
--- /dev/null
+/*
+ * Copyright (C) 2009, 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "MarkStack.h"
+
+#include "ConservativeRoots.h"
+#include "Heap.h"
+#include "JSArray.h"
+#include "JSCell.h"
+#include "JSObject.h"
+#include "ScopeChain.h"
+#include "Structure.h"
+
+namespace JSC {
+
+size_t MarkStack::s_pageSize = 0;
+
+void MarkStack::reset()
+{
+ ASSERT(s_pageSize);
+ m_values.shrinkAllocation(s_pageSize);
+ m_markSets.shrinkAllocation(s_pageSize);
+ m_opaqueRoots.clear();
+}
+
+void MarkStack::append(ConservativeRoots& conservativeRoots)
+{
+ JSCell** roots = conservativeRoots.roots();
+ size_t size = conservativeRoots.size();
+ for (size_t i = 0; i < size; ++i)
+ internalAppend(roots[i]);
+}
+
+inline void MarkStack::visitChildren(JSCell* cell)
+{
+ ASSERT(Heap::isMarked(cell));
+ if (cell->structure()->typeInfo().type() < CompoundType) {
+ cell->JSCell::visitChildren(*this);
+ return;
+ }
+
+ if (!cell->structure()->typeInfo().overridesVisitChildren()) {
+ ASSERT(cell->isObject());
+#ifdef NDEBUG
+ asObject(cell)->visitChildrenDirect(*this);
+#else
+ ASSERT(!m_isCheckingForDefaultMarkViolation);
+ m_isCheckingForDefaultMarkViolation = true;
+ cell->visitChildren(*this);
+ ASSERT(m_isCheckingForDefaultMarkViolation);
+ m_isCheckingForDefaultMarkViolation = false;
+#endif
+ return;
+ }
+ if (cell->vptr() == m_jsArrayVPtr) {
+ asArray(cell)->visitChildrenDirect(*this);
+ return;
+ }
+ cell->visitChildren(*this);
+}
+
+void MarkStack::drain()
+{
+#if !ASSERT_DISABLED
+ ASSERT(!m_isDraining);
+ m_isDraining = true;
+#endif
+ while (!m_markSets.isEmpty() || !m_values.isEmpty()) {
+ while (!m_markSets.isEmpty() && m_values.size() < 50) {
+ ASSERT(!m_markSets.isEmpty());
+ MarkSet& current = m_markSets.last();
+ ASSERT(current.m_values);
+ JSValue* end = current.m_end;
+ ASSERT(current.m_values);
+ ASSERT(current.m_values != end);
+ findNextUnmarkedNullValue:
+ ASSERT(current.m_values != end);
+ JSValue value = *current.m_values;
+ current.m_values++;
+
+ JSCell* cell;
+ if (!value || !value.isCell() || Heap::testAndSetMarked(cell = value.asCell())) {
+ if (current.m_values == end) {
+ m_markSets.removeLast();
+ continue;
+ }
+ goto findNextUnmarkedNullValue;
+ }
+
+ if (cell->structure()->typeInfo().type() < CompoundType) {
+ cell->JSCell::visitChildren(*this);
+ if (current.m_values == end) {
+ m_markSets.removeLast();
+ continue;
+ }
+ goto findNextUnmarkedNullValue;
+ }
+
+ if (current.m_values == end)
+ m_markSets.removeLast();
+
+ visitChildren(cell);
+ }
+ while (!m_values.isEmpty())
+ visitChildren(m_values.removeLast());
+ }
+#if !ASSERT_DISABLED
+ m_isDraining = false;
+#endif
+}
+
+#if ENABLE(GC_VALIDATION)
+void MarkStack::validateSet(JSValue* values, size_t count)
+{
+ for (size_t i = 0; i < count; i++) {
+ if (values[i])
+ validateValue(values[i]);
+ }
+}
+
+void MarkStack::validateValue(JSValue value)
+{
+ if (!value)
+ CRASH();
+ if (!value.isCell())
+ return;
+ JSCell* cell = value.asCell();
+ if (!cell)
+ CRASH();
+
+ if (!cell->structure())
+ CRASH();
+
+ // Both the cell's structure, and the cell's structure's structure should be the Structure Structure.
+ // I hate this sentence.
+ if (cell->structure()->structure()->JSCell::classInfo() != cell->structure()->JSCell::classInfo())
+ CRASH();
+}
+#endif
+
+} // namespace JSC
--- /dev/null
+/*
+ * Copyright (C) 2009, 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MarkStack_h
+#define MarkStack_h
+
+#include "HandleTypes.h"
+#include "JSValue.h"
+#include "Register.h"
+#include <wtf/HashSet.h>
+#include <wtf/Vector.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/OSAllocator.h>
+
+namespace JSC {
+
+ class ConservativeRoots;
+ class JSGlobalData;
+ class Register;
+ template<typename T> class WriteBarrierBase;
+ template<typename T> class JITWriteBarrier;
+
+ enum MarkSetProperties { MayContainNullValues, NoNullValues };
+
+ class MarkStack {
+ WTF_MAKE_NONCOPYABLE(MarkStack);
+ public:
+ MarkStack(void* jsArrayVPtr)
+ : m_jsArrayVPtr(jsArrayVPtr)
+ , m_shouldUnlinkCalls(false)
+#if !ASSERT_DISABLED
+ , m_isCheckingForDefaultMarkViolation(false)
+ , m_isDraining(false)
+#endif
+ {
+ }
+
+ ~MarkStack()
+ {
+ ASSERT(m_markSets.isEmpty());
+ ASSERT(m_values.isEmpty());
+ }
+
+ template<typename T> inline void append(JITWriteBarrier<T>*);
+ template<typename T> inline void append(WriteBarrierBase<T>*);
+ inline void appendValues(WriteBarrierBase<Unknown>*, size_t count, MarkSetProperties = NoNullValues);
+
+ void append(ConservativeRoots&);
+
+ bool addOpaqueRoot(void* root) { return m_opaqueRoots.add(root).second; }
+ bool containsOpaqueRoot(void* root) { return m_opaqueRoots.contains(root); }
+ int opaqueRootCount() { return m_opaqueRoots.size(); }
+
+ void drain();
+ void reset();
+
+ bool shouldUnlinkCalls() const { return m_shouldUnlinkCalls; }
+ void setShouldUnlinkCalls(bool shouldUnlinkCalls) { m_shouldUnlinkCalls = shouldUnlinkCalls; }
+
+ private:
+ friend class HeapRootVisitor; // Allowed to mark a JSValue* or JSCell** directly.
+
+#if ENABLE(GC_VALIDATION)
+ static void validateSet(JSValue*, size_t);
+ static void validateValue(JSValue);
+#endif
+
+ void append(JSValue*);
+ void append(JSValue*, size_t count);
+ void append(JSCell**);
+
+ void internalAppend(JSCell*);
+ void internalAppend(JSValue);
+ void visitChildren(JSCell*);
+
+ struct MarkSet {
+ MarkSet(JSValue* values, JSValue* end, MarkSetProperties properties)
+ : m_values(values)
+ , m_end(end)
+ , m_properties(properties)
+ {
+ ASSERT(values);
+ }
+ JSValue* m_values;
+ JSValue* m_end;
+ MarkSetProperties m_properties;
+ };
+
+ static void* allocateStack(size_t size) { return OSAllocator::reserveAndCommit(size); }
+ static void releaseStack(void* addr, size_t size) { OSAllocator::decommitAndRelease(addr, size); }
+
+ static void initializePagesize();
+ static size_t pageSize()
+ {
+ if (!s_pageSize)
+ initializePagesize();
+ return s_pageSize;
+ }
+
+ template<typename T> struct MarkStackArray {
+ MarkStackArray()
+ : m_top(0)
+ , m_allocated(MarkStack::pageSize())
+ , m_capacity(m_allocated / sizeof(T))
+ {
+ m_data = reinterpret_cast<T*>(allocateStack(m_allocated));
+ }
+
+ ~MarkStackArray()
+ {
+ releaseStack(m_data, m_allocated);
+ }
+
+ void expand()
+ {
+ size_t oldAllocation = m_allocated;
+ m_allocated *= 2;
+ m_capacity = m_allocated / sizeof(T);
+ void* newData = allocateStack(m_allocated);
+ memcpy(newData, m_data, oldAllocation);
+ releaseStack(m_data, oldAllocation);
+ m_data = reinterpret_cast<T*>(newData);
+ }
+
+ inline void append(const T& v)
+ {
+ if (m_top == m_capacity)
+ expand();
+ m_data[m_top++] = v;
+ }
+
+ inline T removeLast()
+ {
+ ASSERT(m_top);
+ return m_data[--m_top];
+ }
+
+ inline T& last()
+ {
+ ASSERT(m_top);
+ return m_data[m_top - 1];
+ }
+
+ inline bool isEmpty()
+ {
+ return m_top == 0;
+ }
+
+ inline size_t size() { return m_top; }
+
+ inline void shrinkAllocation(size_t size)
+ {
+ ASSERT(size <= m_allocated);
+ ASSERT(0 == (size % MarkStack::pageSize()));
+ if (size == m_allocated)
+ return;
+#if OS(WINDOWS) || OS(SYMBIAN) || PLATFORM(BREWMP)
+ // We cannot release a part of a region with VirtualFree. To get around this,
+ // we'll release the entire region and reallocate the size that we want.
+ releaseStack(m_data, m_allocated);
+ m_data = reinterpret_cast<T*>(allocateStack(size));
+#else
+ releaseStack(reinterpret_cast<char*>(m_data) + size, m_allocated - size);
+#endif
+ m_allocated = size;
+ m_capacity = m_allocated / sizeof(T);
+ }
+
+ private:
+ size_t m_top;
+ size_t m_allocated;
+ size_t m_capacity;
+ T* m_data;
+ };
+
+ void* m_jsArrayVPtr;
+ MarkStackArray<MarkSet> m_markSets;
+ MarkStackArray<JSCell*> m_values;
+ static size_t s_pageSize;
+ HashSet<void*> m_opaqueRoots; // Handle-owning data structures not visible to the garbage collector.
+ bool m_shouldUnlinkCalls;
+
+#if !ASSERT_DISABLED
+ public:
+ bool m_isCheckingForDefaultMarkViolation;
+ bool m_isDraining;
+#endif
+ };
+
+ typedef MarkStack SlotVisitor;
+
+ inline void MarkStack::append(JSValue* slot, size_t count)
+ {
+ if (!count)
+ return;
+#if ENABLE(GC_VALIDATION)
+ validateSet(slot, count);
+#endif
+ m_markSets.append(MarkSet(slot, slot + count, NoNullValues));
+ }
+
+ ALWAYS_INLINE void MarkStack::append(JSValue* value)
+ {
+ ASSERT(value);
+ internalAppend(*value);
+ }
+
+ ALWAYS_INLINE void MarkStack::append(JSCell** value)
+ {
+ ASSERT(value);
+ internalAppend(*value);
+ }
+
+ ALWAYS_INLINE void MarkStack::internalAppend(JSValue value)
+ {
+ ASSERT(value);
+#if ENABLE(GC_VALIDATION)
+ validateValue(value);
+#endif
+ if (value.isCell())
+ internalAppend(value.asCell());
+ }
+
+ // Privileged class for marking JSValues directly. It is only safe to use
+ // this class to mark direct heap roots that are marked during every GC pass.
+ // All other references should be wrapped in WriteBarriers and marked through
+ // the MarkStack.
+ class HeapRootVisitor {
+ private:
+ friend class Heap;
+ HeapRootVisitor(SlotVisitor&);
+
+ public:
+ void mark(JSValue*);
+ void mark(JSValue*, size_t);
+ void mark(JSString**);
+ void mark(JSCell**);
+
+ SlotVisitor& visitor();
+
+ private:
+ SlotVisitor& m_visitor;
+ };
+
+ inline HeapRootVisitor::HeapRootVisitor(SlotVisitor& visitor)
+ : m_visitor(visitor)
+ {
+ }
+
+ inline void HeapRootVisitor::mark(JSValue* slot)
+ {
+ m_visitor.append(slot);
+ }
+
+ inline void HeapRootVisitor::mark(JSValue* slot, size_t count)
+ {
+ m_visitor.append(slot, count);
+ }
+
+ inline void HeapRootVisitor::mark(JSString** slot)
+ {
+ m_visitor.append(reinterpret_cast<JSCell**>(slot));
+ }
+
+ inline void HeapRootVisitor::mark(JSCell** slot)
+ {
+ m_visitor.append(slot);
+ }
+
+ inline SlotVisitor& HeapRootVisitor::visitor()
+ {
+ return m_visitor;
+ }
+
+} // namespace JSC
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "MarkStack.h"
+
+#if OS(UNIX) && !OS(SYMBIAN)
+
+#include <unistd.h>
+#include <sys/mman.h>
+
+namespace JSC {
+
+void MarkStack::initializePagesize()
+{
+ MarkStack::s_pageSize = getpagesize();
+}
+
+}
+
+#endif
--- /dev/null
+/*
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
+
+ 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 "MarkStack.h"
+
+#if OS(SYMBIAN)
+
+#include <e32hal.h>
+
+namespace JSC {
+
+void MarkStack::initializePagesize()
+{
+ TInt page_size;
+ UserHal::PageSizeInBytes(page_size);
+ MarkStack::s_pageSize = page_size;
+}
+
+}
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "MarkStack.h"
+
+#if OS(WINDOWS)
+
+#include "windows.h"
+
+namespace JSC {
+
+void MarkStack::initializePagesize()
+{
+ SYSTEM_INFO system_info;
+ GetSystemInfo(&system_info);
+ MarkStack::s_pageSize = system_info.dwPageSize;
+}
+
+}
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "MarkedBlock.h"
+
+#include "JSCell.h"
+#include "JSObject.h"
+#include "JSZombie.h"
+#include "ScopeChain.h"
+
+namespace JSC {
+
+MarkedBlock* MarkedBlock::create(JSGlobalData* globalData, size_t cellSize)
+{
+ PageAllocationAligned allocation = PageAllocationAligned::allocate(blockSize, blockSize, OSAllocator::JSGCHeapPages);
+ if (!static_cast<bool>(allocation))
+ CRASH();
+ return new (allocation.base()) MarkedBlock(allocation, globalData, cellSize);
+}
+
+void MarkedBlock::destroy(MarkedBlock* block)
+{
+ for (size_t i = block->firstAtom(); i < block->m_endAtom; i += block->m_atomsPerCell)
+ reinterpret_cast<JSCell*>(&block->atoms()[i])->~JSCell();
+ block->m_allocation.deallocate();
+}
+
+MarkedBlock::MarkedBlock(const PageAllocationAligned& allocation, JSGlobalData* globalData, size_t cellSize)
+ : m_nextAtom(firstAtom())
+ , m_allocation(allocation)
+ , m_heap(&globalData->heap)
+ , m_prev(0)
+ , m_next(0)
+{
+ m_atomsPerCell = (cellSize + atomSize - 1) / atomSize;
+ m_endAtom = atomsPerBlock - m_atomsPerCell + 1;
+
+ Structure* dummyMarkableCellStructure = globalData->dummyMarkableCellStructure.get();
+ for (size_t i = firstAtom(); i < m_endAtom; i += m_atomsPerCell)
+ new (&atoms()[i]) JSCell(*globalData, dummyMarkableCellStructure, JSCell::CreatingEarlyCell);
+}
+
+void MarkedBlock::sweep()
+{
+ Structure* dummyMarkableCellStructure = m_heap->globalData()->dummyMarkableCellStructure.get();
+
+ for (size_t i = firstAtom(); i < m_endAtom; i += m_atomsPerCell) {
+ if (m_marks.get(i))
+ continue;
+
+ JSCell* cell = reinterpret_cast<JSCell*>(&atoms()[i]);
+#if ENABLE(JSC_ZOMBIES)
+ if (cell->structure() && cell->structure() != dummyMarkableCellStructure && !cell->isZombie()) {
+ const ClassInfo* info = cell->classInfo();
+ cell->~JSCell();
+ new (cell) JSZombie(*m_heap->globalData(), info, m_heap->globalData()->zombieStructure.get());
+ m_marks.set(i);
+ }
+#else
+ cell->~JSCell();
+ new (cell) JSCell(*m_heap->globalData(), dummyMarkableCellStructure);
+#endif
+ }
+}
+
+} // namespace JSC
--- /dev/null
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef MarkedBlock_h
+#define MarkedBlock_h
+
+#include <wtf/Bitmap.h>
+#include <wtf/PageAllocationAligned.h>
+#include <wtf/StdLibExtras.h>
+
+namespace JSC {
+
+ class Heap;
+ class JSCell;
+ class JSGlobalData;
+
+ typedef uintptr_t Bits;
+
+ static const size_t KB = 1024;
+
+ class MarkedBlock {
+ public:
+ static const size_t atomSize = sizeof(double); // Ensures natural alignment for all built-in types.
+
+ static MarkedBlock* create(JSGlobalData*, size_t cellSize);
+ static void destroy(MarkedBlock*);
+
+ static bool isAtomAligned(const void*);
+ static MarkedBlock* blockFor(const void*);
+ static size_t firstAtom();
+
+ Heap* heap() const;
+
+ void setPrev(MarkedBlock*);
+ void setNext(MarkedBlock*);
+ MarkedBlock* prev() const;
+ MarkedBlock* next() const;
+
+ void* allocate();
+ void reset();
+ void sweep();
+
+ bool isEmpty();
+
+ void clearMarks();
+ size_t markCount();
+
+ size_t cellSize();
+
+ size_t size();
+ size_t capacity();
+
+ bool contains(const void*);
+ size_t atomNumber(const void*);
+ bool isMarked(const void*);
+ bool testAndSetMarked(const void*);
+ void setMarked(const void*);
+
+ template <typename Functor> void forEach(Functor&);
+
+ private:
+ static const size_t blockSize = 16 * KB;
+ static const size_t blockMask = ~(blockSize - 1); // blockSize must be a power of two.
+
+ static const size_t atomMask = ~(atomSize - 1); // atomSize must be a power of two.
+
+ static const size_t atomsPerBlock = blockSize / atomSize;
+
+ typedef char Atom[atomSize];
+
+ MarkedBlock(const PageAllocationAligned&, JSGlobalData*, size_t cellSize);
+ Atom* atoms();
+
+ size_t m_nextAtom;
+ size_t m_endAtom; // This is a fuzzy end. Always test for < m_endAtom.
+ size_t m_atomsPerCell;
+ WTF::Bitmap<blockSize / atomSize> m_marks;
+ PageAllocationAligned m_allocation;
+ Heap* m_heap;
+ MarkedBlock* m_prev;
+ MarkedBlock* m_next;
+ };
+
+ inline size_t MarkedBlock::firstAtom()
+ {
+ return WTF::roundUpToMultipleOf<atomSize>(sizeof(MarkedBlock)) / atomSize;
+ }
+
+ inline MarkedBlock::Atom* MarkedBlock::atoms()
+ {
+ return reinterpret_cast<Atom*>(this);
+ }
+
+ inline bool MarkedBlock::isAtomAligned(const void* p)
+ {
+ return !((intptr_t)(p) & ~atomMask);
+ }
+
+ inline MarkedBlock* MarkedBlock::blockFor(const void* p)
+ {
+ return reinterpret_cast<MarkedBlock*>(reinterpret_cast<uintptr_t>(p) & blockMask);
+ }
+
+ inline Heap* MarkedBlock::heap() const
+ {
+ return m_heap;
+ }
+
+ inline void MarkedBlock::setPrev(MarkedBlock* prev)
+ {
+ m_prev = prev;
+ }
+
+ inline void MarkedBlock::setNext(MarkedBlock* next)
+ {
+ m_next = next;
+ }
+
+ inline MarkedBlock* MarkedBlock::prev() const
+ {
+ return m_prev;
+ }
+
+ inline MarkedBlock* MarkedBlock::next() const
+ {
+ return m_next;
+ }
+
+ inline void MarkedBlock::reset()
+ {
+ m_nextAtom = firstAtom();
+ }
+
+ inline bool MarkedBlock::isEmpty()
+ {
+ return m_marks.isEmpty();
+ }
+
+ inline void MarkedBlock::clearMarks()
+ {
+ m_marks.clearAll();
+ }
+
+ inline size_t MarkedBlock::markCount()
+ {
+ return m_marks.count();
+ }
+
+ inline size_t MarkedBlock::cellSize()
+ {
+ return m_atomsPerCell * atomSize;
+ }
+
+ inline size_t MarkedBlock::size()
+ {
+ return markCount() * cellSize();
+ }
+
+ inline size_t MarkedBlock::capacity()
+ {
+ return m_allocation.size();
+ }
+
+ inline bool MarkedBlock::contains(const void* p)
+ {
+ ASSERT(p && isAtomAligned(p) && atomNumber(p) < atomsPerBlock);
+
+ // Even though we physically contain p, we only logically contain p if p
+ // points to a live cell. (Claiming to contain a dead cell would trick the
+ // conservative garbage collector into resurrecting the cell in a zombie state.)
+ return isMarked(p);
+ }
+
+ inline size_t MarkedBlock::atomNumber(const void* p)
+ {
+ return (reinterpret_cast<uintptr_t>(p) - reinterpret_cast<uintptr_t>(this)) / atomSize;
+ }
+
+ inline bool MarkedBlock::isMarked(const void* p)
+ {
+ return m_marks.get(atomNumber(p));
+ }
+
+ inline bool MarkedBlock::testAndSetMarked(const void* p)
+ {
+ return m_marks.testAndSet(atomNumber(p));
+ }
+
+ inline void MarkedBlock::setMarked(const void* p)
+ {
+ m_marks.set(atomNumber(p));
+ }
+
+ template <typename Functor> inline void MarkedBlock::forEach(Functor& functor)
+ {
+ for (size_t i = firstAtom(); i < m_endAtom; i += m_atomsPerCell) {
+ if (!m_marks.get(i))
+ continue;
+ functor(reinterpret_cast<JSCell*>(&atoms()[i]));
+ }
+ }
+
+} // namespace JSC
+
+#endif // MarkedSpace_h
--- /dev/null
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "config.h"
+#include "MarkedSpace.h"
+
+#include "JSGlobalObject.h"
+#include "JSCell.h"
+#include "JSGlobalData.h"
+#include "JSLock.h"
+#include "JSObject.h"
+#include "ScopeChain.h"
+
+namespace JSC {
+
+class Structure;
+
+MarkedSpace::MarkedSpace(JSGlobalData* globalData)
+ : m_waterMark(0)
+ , m_highWaterMark(0)
+ , m_globalData(globalData)
+{
+ for (size_t cellSize = preciseStep; cellSize < preciseCutoff; cellSize += preciseStep)
+ sizeClassFor(cellSize).cellSize = cellSize;
+
+ for (size_t cellSize = impreciseStep; cellSize < impreciseCutoff; cellSize += impreciseStep)
+ sizeClassFor(cellSize).cellSize = cellSize;
+}
+
+void MarkedSpace::destroy()
+{
+ clearMarks();
+ shrink();
+ ASSERT(!size());
+}
+
+MarkedBlock* MarkedSpace::allocateBlock(SizeClass& sizeClass)
+{
+ MarkedBlock* block = MarkedBlock::create(globalData(), sizeClass.cellSize);
+ sizeClass.blockList.append(block);
+ sizeClass.nextBlock = block;
+ m_blocks.add(block);
+
+ return block;
+}
+
+void MarkedSpace::freeBlocks(DoublyLinkedList<MarkedBlock>& blocks)
+{
+ MarkedBlock* next;
+ for (MarkedBlock* block = blocks.head(); block; block = next) {
+ next = block->next();
+
+ blocks.remove(block);
+ m_blocks.remove(block);
+ MarkedBlock::destroy(block);
+ }
+}
+
+void* MarkedSpace::allocateFromSizeClass(SizeClass& sizeClass)
+{
+ for (MarkedBlock*& block = sizeClass.nextBlock ; block; block = block->next()) {
+ if (void* result = block->allocate())
+ return result;
+
+ m_waterMark += block->capacity();
+ }
+
+ if (m_waterMark < m_highWaterMark)
+ return allocateBlock(sizeClass)->allocate();
+
+ return 0;
+}
+
+void MarkedSpace::shrink()
+{
+ // We record a temporary list of empties to avoid modifying m_blocks while iterating it.
+ DoublyLinkedList<MarkedBlock> empties;
+
+ BlockIterator end = m_blocks.end();
+ for (BlockIterator it = m_blocks.begin(); it != end; ++it) {
+ MarkedBlock* block = *it;
+ if (block->isEmpty()) {
+ SizeClass& sizeClass = sizeClassFor(block->cellSize());
+ sizeClass.blockList.remove(block);
+ sizeClass.nextBlock = sizeClass.blockList.head();
+ empties.append(block);
+ }
+ }
+
+ freeBlocks(empties);
+ ASSERT(empties.isEmpty());
+}
+
+void MarkedSpace::clearMarks()
+{
+ BlockIterator end = m_blocks.end();
+ for (BlockIterator it = m_blocks.begin(); it != end; ++it)
+ (*it)->clearMarks();
+}
+
+void MarkedSpace::sweep()
+{
+ BlockIterator end = m_blocks.end();
+ for (BlockIterator it = m_blocks.begin(); it != end; ++it)
+ (*it)->sweep();
+}
+
+size_t MarkedSpace::objectCount() const
+{
+ size_t result = 0;
+ BlockIterator end = m_blocks.end();
+ for (BlockIterator it = m_blocks.begin(); it != end; ++it)
+ result += (*it)->markCount();
+ return result;
+}
+
+size_t MarkedSpace::size() const
+{
+ size_t result = 0;
+ BlockIterator end = m_blocks.end();
+ for (BlockIterator it = m_blocks.begin(); it != end; ++it)
+ result += (*it)->size();
+ return result;
+}
+
+size_t MarkedSpace::capacity() const
+{
+ size_t result = 0;
+ BlockIterator end = m_blocks.end();
+ for (BlockIterator it = m_blocks.begin(); it != end; ++it)
+ result += (*it)->capacity();
+ return result;
+}
+
+void MarkedSpace::reset()
+{
+ m_waterMark = 0;
+
+ for (size_t cellSize = preciseStep; cellSize < preciseCutoff; cellSize += preciseStep)
+ sizeClassFor(cellSize).reset();
+
+ for (size_t cellSize = impreciseStep; cellSize < impreciseCutoff; cellSize += impreciseStep)
+ sizeClassFor(cellSize).reset();
+
+ BlockIterator end = m_blocks.end();
+ for (BlockIterator it = m_blocks.begin(); it != end; ++it)
+ (*it)->reset();
+}
+
+} // namespace JSC
--- /dev/null
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef MarkedSpace_h
+#define MarkedSpace_h
+
+#include "MachineStackMarker.h"
+#include "MarkedBlock.h"
+#include "PageAllocationAligned.h"
+#include <wtf/Bitmap.h>
+#include <wtf/DoublyLinkedList.h>
+#include <wtf/FixedArray.h>
+#include <wtf/HashSet.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/Vector.h>
+
+#define ASSERT_CLASS_FITS_IN_CELL(class) COMPILE_ASSERT(sizeof(class) < MarkedSpace::maxCellSize, class_fits_in_cell)
+
+namespace JSC {
+
+ class Heap;
+ class JSCell;
+ class JSGlobalData;
+ class LiveObjectIterator;
+ class MarkStack;
+ class WeakGCHandle;
+ typedef MarkStack SlotVisitor;
+
+ class MarkedSpace {
+ WTF_MAKE_NONCOPYABLE(MarkedSpace);
+ public:
+ // Currently public for use in assertions.
+ static const size_t maxCellSize = 1024;
+
+ static Heap* heap(JSCell*);
+
+ static bool isMarked(const JSCell*);
+ static bool testAndSetMarked(const JSCell*);
+ static void setMarked(const JSCell*);
+
+ MarkedSpace(JSGlobalData*);
+ void destroy();
+
+ JSGlobalData* globalData();
+
+ size_t highWaterMark();
+ void setHighWaterMark(size_t);
+
+ void* allocate(size_t);
+
+ void clearMarks();
+ void markRoots();
+ void reset();
+ void sweep();
+ void shrink();
+
+ size_t size() const;
+ size_t capacity() const;
+ size_t objectCount() const;
+
+ bool contains(const void*);
+
+ template<typename Functor> void forEach(Functor&);
+
+ private:
+ // [ 8, 16... 128 )
+ static const size_t preciseStep = MarkedBlock::atomSize;
+ static const size_t preciseCutoff = 128;
+ static const size_t preciseCount = preciseCutoff / preciseStep - 1;
+
+ // [ 128, 256... 1024 )
+ static const size_t impreciseStep = preciseCutoff;
+ static const size_t impreciseCutoff = maxCellSize;
+ static const size_t impreciseCount = impreciseCutoff / impreciseStep - 1;
+
+ typedef HashSet<MarkedBlock*>::iterator BlockIterator;
+
+ struct SizeClass {
+ SizeClass();
+ void reset();
+
+ MarkedBlock* nextBlock;
+ DoublyLinkedList<MarkedBlock> blockList;
+ size_t cellSize;
+ };
+
+ MarkedBlock* allocateBlock(SizeClass&);
+ void freeBlocks(DoublyLinkedList<MarkedBlock>&);
+
+ SizeClass& sizeClassFor(size_t);
+ void* allocateFromSizeClass(SizeClass&);
+
+ void clearMarks(MarkedBlock*);
+
+ SizeClass m_preciseSizeClasses[preciseCount];
+ SizeClass m_impreciseSizeClasses[impreciseCount];
+ HashSet<MarkedBlock*> m_blocks;
+ size_t m_waterMark;
+ size_t m_highWaterMark;
+ JSGlobalData* m_globalData;
+ };
+
+ inline Heap* MarkedSpace::heap(JSCell* cell)
+ {
+ return MarkedBlock::blockFor(cell)->heap();
+ }
+
+ inline bool MarkedSpace::isMarked(const JSCell* cell)
+ {
+ return MarkedBlock::blockFor(cell)->isMarked(cell);
+ }
+
+ inline bool MarkedSpace::testAndSetMarked(const JSCell* cell)
+ {
+ return MarkedBlock::blockFor(cell)->testAndSetMarked(cell);
+ }
+
+ inline void MarkedSpace::setMarked(const JSCell* cell)
+ {
+ MarkedBlock::blockFor(cell)->setMarked(cell);
+ }
+
+ inline bool MarkedSpace::contains(const void* x)
+ {
+ if (!MarkedBlock::isAtomAligned(x))
+ return false;
+
+ MarkedBlock* block = MarkedBlock::blockFor(x);
+ if (!block || !m_blocks.contains(block))
+ return false;
+
+ return block->contains(x);
+ }
+
+ template <typename Functor> inline void MarkedSpace::forEach(Functor& functor)
+ {
+ BlockIterator end = m_blocks.end();
+ for (BlockIterator it = m_blocks.begin(); it != end; ++it)
+ (*it)->forEach(functor);
+ }
+
+ inline JSGlobalData* MarkedSpace::globalData()
+ {
+ return m_globalData;
+ }
+
+ inline size_t MarkedSpace::highWaterMark()
+ {
+ return m_highWaterMark;
+ }
+
+ inline void MarkedSpace::setHighWaterMark(size_t highWaterMark)
+ {
+ m_highWaterMark = highWaterMark;
+ }
+
+ inline MarkedSpace::SizeClass::SizeClass()
+ : nextBlock(0)
+ , cellSize(0)
+ {
+ }
+
+ inline void MarkedSpace::SizeClass::reset()
+ {
+ nextBlock = blockList.head();
+ }
+
+} // namespace JSC
+
+#endif // MarkedSpace_h
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef Strong_h
+#define Strong_h
+
+#include "Assertions.h"
+#include "Handle.h"
+#include "HandleHeap.h"
+
+namespace JSC {
+
+class JSGlobalData;
+HandleSlot allocateGlobalHandle(JSGlobalData&);
+
+// A strongly referenced handle that prevents the object it points to from being garbage collected.
+template <typename T> class Strong : public Handle<T> {
+ using Handle<T>::slot;
+ using Handle<T>::setSlot;
+
+public:
+ typedef typename Handle<T>::ExternalType ExternalType;
+
+ Strong()
+ : Handle<T>()
+ {
+ }
+
+ Strong(JSGlobalData& globalData, ExternalType value = ExternalType())
+ : Handle<T>(allocateGlobalHandle(globalData))
+ {
+ set(value);
+ }
+
+ Strong(JSGlobalData& globalData, Handle<T> handle)
+ : Handle<T>(allocateGlobalHandle(globalData))
+ {
+ set(handle.get());
+ }
+
+ Strong(const Strong& other)
+ : Handle<T>()
+ {
+ if (!other.slot())
+ return;
+ setSlot(HandleHeap::heapFor(other.slot())->allocate());
+ set(other.get());
+ }
+
+ template <typename U> Strong(const Strong<U>& other)
+ : Handle<T>()
+ {
+ if (!other.slot())
+ return;
+ setSlot(HandleHeap::heapFor(other.slot())->allocate());
+ set(other.get());
+ }
+
+ enum HashTableDeletedValueTag { HashTableDeletedValue };
+ bool isHashTableDeletedValue() const { return slot() == hashTableDeletedValue(); }
+ Strong(HashTableDeletedValueTag)
+ : Handle<T>(hashTableDeletedValue())
+ {
+ }
+
+ ~Strong()
+ {
+ clear();
+ }
+
+ void swap(Strong& other)
+ {
+ Handle<T>::swap(other);
+ }
+
+ void set(JSGlobalData& globalData, ExternalType value)
+ {
+ if (!slot())
+ setSlot(allocateGlobalHandle(globalData));
+ set(value);
+ }
+
+ template <typename U> Strong& operator=(const Strong<U>& other)
+ {
+ if (!other.slot()) {
+ clear();
+ return *this;
+ }
+
+ set(*HandleHeap::heapFor(other.slot())->globalData(), other.get());
+ return *this;
+ }
+
+ Strong& operator=(const Strong& other)
+ {
+ if (!other.slot()) {
+ clear();
+ return *this;
+ }
+
+ set(*HandleHeap::heapFor(other.slot())->globalData(), other.get());
+ return *this;
+ }
+
+ void clear()
+ {
+ if (!slot())
+ return;
+ HandleHeap::heapFor(slot())->deallocate(slot());
+ setSlot(0);
+ }
+
+private:
+ static HandleSlot hashTableDeletedValue() { return reinterpret_cast<HandleSlot>(-1); }
+
+ void set(ExternalType externalType)
+ {
+ ASSERT(slot());
+ JSValue value = HandleTypes<T>::toJSValue(externalType);
+ HandleHeap::heapFor(slot())->writeBarrier(slot(), value);
+ *slot() = value;
+ }
+};
+
+template<class T> inline void swap(Strong<T>& a, Strong<T>& b)
+{
+ a.swap(b);
+}
+
+} // namespace JSC
+
+namespace WTF {
+
+template<typename T> struct VectorTraits<JSC::Strong<T> > : SimpleClassVectorTraits {
+ static const bool canCompareWithMemcmp = false;
+};
+
+template<typename P> struct HashTraits<JSC::Strong<P> > : SimpleClassHashTraits<JSC::Strong<P> > { };
+
+}
+
+#endif // Strong_h
--- /dev/null
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef Weak_h
+#define Weak_h
+
+#include "Assertions.h"
+#include "Handle.h"
+#include "HandleHeap.h"
+#include "JSGlobalData.h"
+
+namespace JSC {
+
+// A weakly referenced handle that becomes 0 when the value it points to is garbage collected.
+template <typename T> class Weak : public Handle<T> {
+ using Handle<T>::slot;
+ using Handle<T>::setSlot;
+
+public:
+ typedef typename Handle<T>::ExternalType ExternalType;
+
+ Weak()
+ : Handle<T>()
+ {
+ }
+
+ Weak(JSGlobalData& globalData, ExternalType value = ExternalType(), WeakHandleOwner* weakOwner = 0, void* context = 0)
+ : Handle<T>(globalData.allocateGlobalHandle())
+ {
+ HandleHeap::heapFor(slot())->makeWeak(slot(), weakOwner, context);
+ set(value);
+ }
+
+ enum AdoptTag { Adopt };
+ template<typename U> Weak(AdoptTag, Handle<U> handle)
+ : Handle<T>(handle.slot())
+ {
+ validateCell(get());
+ }
+
+ Weak(const Weak& other)
+ : Handle<T>()
+ {
+ if (!other.slot())
+ return;
+ setSlot(HandleHeap::heapFor(other.slot())->copyWeak(other.slot()));
+ }
+
+ template <typename U> Weak(const Weak<U>& other)
+ : Handle<T>()
+ {
+ if (!other.slot())
+ return;
+ setSlot(HandleHeap::heapFor(other.slot())->copyWeak(other.slot()));
+ }
+
+ enum HashTableDeletedValueTag { HashTableDeletedValue };
+ bool isHashTableDeletedValue() const { return slot() == hashTableDeletedValue(); }
+ Weak(HashTableDeletedValueTag)
+ : Handle<T>(hashTableDeletedValue())
+ {
+ }
+
+ ~Weak()
+ {
+ clear();
+ }
+
+ void swap(Weak& other)
+ {
+ Handle<T>::swap(other);
+ }
+
+ ExternalType get() const { return HandleTypes<T>::getFromSlot(slot()); }
+
+ void clear()
+ {
+ if (!slot())
+ return;
+ HandleHeap::heapFor(slot())->deallocate(slot());
+ setSlot(0);
+ }
+
+ void set(JSGlobalData& globalData, ExternalType value, WeakHandleOwner* weakOwner = 0, void* context = 0)
+ {
+ if (!slot()) {
+ setSlot(globalData.allocateGlobalHandle());
+ HandleHeap::heapFor(slot())->makeWeak(slot(), weakOwner, context);
+ }
+ ASSERT(HandleHeap::heapFor(slot())->hasWeakOwner(slot(), weakOwner));
+ set(value);
+ }
+
+ template <typename U> Weak& operator=(const Weak<U>& other)
+ {
+ clear();
+ if (other.slot())
+ setSlot(HandleHeap::heapFor(other.slot())->copyWeak(other.slot()));
+ return *this;
+ }
+
+ Weak& operator=(const Weak& other)
+ {
+ clear();
+ if (other.slot())
+ setSlot(HandleHeap::heapFor(other.slot())->copyWeak(other.slot()));
+ return *this;
+ }
+
+ HandleSlot leakHandle()
+ {
+ ASSERT(HandleHeap::heapFor(slot())->hasFinalizer(slot()));
+ HandleSlot result = slot();
+ setSlot(0);
+ return result;
+ }
+
+private:
+ static HandleSlot hashTableDeletedValue() { return reinterpret_cast<HandleSlot>(-1); }
+
+ void set(ExternalType externalType)
+ {
+ ASSERT(slot());
+ JSValue value = HandleTypes<T>::toJSValue(externalType);
+ ASSERT(!value || !value.isCell() || Heap::isMarked(value.asCell()));
+ HandleHeap::heapFor(slot())->writeBarrier(slot(), value);
+ *slot() = value;
+ }
+};
+
+template<class T> inline void swap(Weak<T>& a, Weak<T>& b)
+{
+ a.swap(b);
+}
+
+} // namespace JSC
+
+namespace WTF {
+
+template<typename T> struct VectorTraits<JSC::Weak<T> > : SimpleClassVectorTraits {
+ static const bool canCompareWithMemcmp = false;
+};
+
+template<typename P> struct HashTraits<JSC::Weak<P> > : SimpleClassHashTraits<JSC::Weak<P> > { };
+
+}
+
+#endif // Weak_h
#include "Interpreter.h"
namespace JSC {
- class CachedCall : public Noncopyable {
+ class CachedCall {
+ WTF_MAKE_NONCOPYABLE(CachedCall); WTF_MAKE_FAST_ALLOCATED;
public:
- CachedCall(CallFrame* callFrame, JSFunction* function, int argCount, JSValue* exception)
+ CachedCall(CallFrame* callFrame, JSFunction* function, int argCount)
: m_valid(false)
, m_interpreter(callFrame->interpreter())
- , m_exception(exception)
- , m_globalObjectScope(callFrame, function->scope().globalObject())
+ , m_globalObjectScope(callFrame->globalData(), function->scope()->globalObject.get())
{
ASSERT(!function->isHostFunction());
- m_closure = m_interpreter->prepareForRepeatCall(function->jsExecutable(), callFrame, function, argCount, function->scope().node(), exception);
- m_valid = !*exception;
+ m_closure = m_interpreter->prepareForRepeatCall(function->jsExecutable(), callFrame, function, argCount, function->scope());
+ m_valid = !callFrame->hadException();
}
JSValue call()
{
ASSERT(m_valid);
- return m_interpreter->execute(m_closure, m_exception);
+ return m_interpreter->execute(m_closure);
}
void setThis(JSValue v) { m_closure.setArgument(0, v); }
void setArgument(int n, JSValue v) { m_closure.setArgument(n + 1, v); }
private:
bool m_valid;
Interpreter* m_interpreter;
- JSValue* m_exception;
DynamicGlobalObjectScope m_globalObjectScope;
CallFrameClosure m_closure;
};
namespace JSC {
-JSValue CallFrame::thisValue()
-{
- return this[codeBlock()->thisRegister()].jsValue();
-}
-
#ifndef NDEBUG
void CallFrame::dumpCaller()
{
JSValue function;
interpreter()->retrieveLastCaller(this, signedLineNumber, sourceID, urlString, function);
- printf("Callpoint => %s:%d\n", urlString.ascii(), signedLineNumber);
+ printf("Callpoint => %s:%d\n", urlString.utf8().data(), signedLineNumber);
}
+
+RegisterFile* CallFrame::registerFile()
+{
+ return &interpreter()->registerFile();
+}
+
#endif
}
/*
* Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
- * Copyright (C) 2003, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2007, 2008, 2011 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
#define CallFrame_h
#include "JSGlobalData.h"
+#include "MacroAssemblerCodeRef.h"
#include "RegisterFile.h"
-#include "ScopeChain.h"
namespace JSC {
class Arguments;
class JSActivation;
class Interpreter;
+ class ScopeChainNode;
// Represents the current state of script execution.
// Passed as the first argument to most functions.
class ExecState : private Register {
public:
- JSFunction* callee() const { return this[RegisterFile::Callee].function(); }
+ JSObject* callee() const { return this[RegisterFile::Callee].function(); }
CodeBlock* codeBlock() const { return this[RegisterFile::CodeBlock].Register::codeBlock(); }
ScopeChainNode* scopeChain() const
{
ASSERT(this[RegisterFile::ScopeChain].Register::scopeChain());
return this[RegisterFile::ScopeChain].Register::scopeChain();
}
- int argumentCount() const { return this[RegisterFile::ArgumentCount].i(); }
-
- JSValue thisValue();
// Global object in which execution began.
JSGlobalObject* dynamicGlobalObject();
// Global object in which the currently executing code was defined.
// Differs from dynamicGlobalObject() during function calls across web browser frames.
- JSGlobalObject* lexicalGlobalObject() const
- {
- return scopeChain()->globalObject;
- }
+ inline JSGlobalObject* lexicalGlobalObject() const;
// Differs from lexicalGlobalObject because this will have DOM window shell rather than
// the actual DOM window, which can't be "this" for security reasons.
- JSObject* globalThisValue() const
- {
- return scopeChain()->globalThis;
- }
+ inline JSObject* globalThisValue() const;
- // FIXME: Elsewhere, we use JSGlobalData* rather than JSGlobalData&.
- // We should make this more uniform and either use a reference everywhere
- // or a pointer everywhere.
- JSGlobalData& globalData() const
- {
- ASSERT(scopeChain()->globalData);
- return *scopeChain()->globalData;
- }
+ inline JSGlobalData& globalData() const;
// Convenience functions for access to global data.
// It takes a few memory references to get from a call frame to the global data
// pointer, so these are inefficient, and should be used sparingly in new code.
// But they're used in many places in legacy code, so they're not going away any time soon.
- void setException(JSValue exception) { globalData().exception = exception; }
void clearException() { globalData().exception = JSValue(); }
JSValue exception() const { return globalData().exception; }
- JSValue* exceptionSlot() { return &globalData().exception; }
bool hadException() const { return globalData().exception; }
const CommonIdentifiers& propertyNames() const { return *globalData().propertyNames; }
#ifndef NDEBUG
void dumpCaller();
#endif
- static const HashTable* arrayTable(CallFrame* callFrame) { return callFrame->globalData().arrayTable; }
+ static const HashTable* arrayConstructorTable(CallFrame* callFrame) { return callFrame->globalData().arrayConstructorTable; }
+ static const HashTable* arrayPrototypeTable(CallFrame* callFrame) { return callFrame->globalData().arrayPrototypeTable; }
+ static const HashTable* booleanPrototypeTable(CallFrame* callFrame) { return callFrame->globalData().booleanPrototypeTable; }
static const HashTable* dateTable(CallFrame* callFrame) { return callFrame->globalData().dateTable; }
+ static const HashTable* dateConstructorTable(CallFrame* callFrame) { return callFrame->globalData().dateConstructorTable; }
+ static const HashTable* errorPrototypeTable(CallFrame* callFrame) { return callFrame->globalData().errorPrototypeTable; }
+ static const HashTable* globalObjectTable(CallFrame* callFrame) { return callFrame->globalData().globalObjectTable; }
static const HashTable* jsonTable(CallFrame* callFrame) { return callFrame->globalData().jsonTable; }
static const HashTable* mathTable(CallFrame* callFrame) { return callFrame->globalData().mathTable; }
- static const HashTable* numberTable(CallFrame* callFrame) { return callFrame->globalData().numberTable; }
+ static const HashTable* numberConstructorTable(CallFrame* callFrame) { return callFrame->globalData().numberConstructorTable; }
+ static const HashTable* numberPrototypeTable(CallFrame* callFrame) { return callFrame->globalData().numberPrototypeTable; }
+ static const HashTable* objectConstructorTable(CallFrame* callFrame) { return callFrame->globalData().objectConstructorTable; }
+ static const HashTable* objectPrototypeTable(CallFrame* callFrame) { return callFrame->globalData().objectPrototypeTable; }
static const HashTable* regExpTable(CallFrame* callFrame) { return callFrame->globalData().regExpTable; }
static const HashTable* regExpConstructorTable(CallFrame* callFrame) { return callFrame->globalData().regExpConstructorTable; }
+ static const HashTable* regExpPrototypeTable(CallFrame* callFrame) { return callFrame->globalData().regExpPrototypeTable; }
static const HashTable* stringTable(CallFrame* callFrame) { return callFrame->globalData().stringTable; }
+ static const HashTable* stringConstructorTable(CallFrame* callFrame) { return callFrame->globalData().stringConstructorTable; }
static CallFrame* create(Register* callFrameBase) { return static_cast<CallFrame*>(callFrameBase); }
Register* registers() { return this; }
CallFrame& operator=(const Register& r) { *static_cast<Register*>(this) = r; return *this; }
CallFrame* callerFrame() const { return this[RegisterFile::CallerFrame].callFrame(); }
- Arguments* optionalCalleeArguments() const { return this[RegisterFile::OptionalCalleeArguments].arguments(); }
#if ENABLE(JIT)
ReturnAddressPtr returnPC() const { return ReturnAddressPtr(this[RegisterFile::ReturnPC].vPC()); }
#endif
Instruction* returnVPC() const { return this[RegisterFile::ReturnPC].vPC(); }
#endif
- void setCalleeArguments(JSValue arguments) { static_cast<Register*>(this)[RegisterFile::OptionalCalleeArguments] = arguments; }
void setCallerFrame(CallFrame* callerFrame) { static_cast<Register*>(this)[RegisterFile::CallerFrame] = callerFrame; }
void setScopeChain(ScopeChainNode* scopeChain) { static_cast<Register*>(this)[RegisterFile::ScopeChain] = scopeChain; }
ALWAYS_INLINE void init(CodeBlock* codeBlock, Instruction* vPC, ScopeChainNode* scopeChain,
- CallFrame* callerFrame, int returnValueRegister, int argc, JSFunction* function)
+ CallFrame* callerFrame, int argc, JSObject* callee)
{
ASSERT(callerFrame); // Use noCaller() rather than 0 for the outer host call frame caller.
+ ASSERT(callerFrame == noCaller() || callerFrame->removeHostCallFrameFlag()->registerFile()->end() >= this);
setCodeBlock(codeBlock);
setScopeChain(scopeChain);
setCallerFrame(callerFrame);
- static_cast<Register*>(this)[RegisterFile::ReturnPC] = vPC; // This is either an Instruction* or a pointer into JIT generated code stored as an Instruction*.
- static_cast<Register*>(this)[RegisterFile::ReturnValueRegister] = Register::withInt(returnValueRegister);
- setArgumentCount(argc); // original argument count (for the sake of the "arguments" object)
- setCallee(function);
- setCalleeArguments(JSValue());
+ setReturnPC(vPC); // This is either an Instruction* or a pointer into JIT generated code stored as an Instruction*.
+ setArgumentCountIncludingThis(argc); // original argument count (for the sake of the "arguments" object)
+ setCallee(callee);
}
// Read a register from the codeframe (or constant from the CodeBlock).
inline Register& r(int);
+ // Read a register for a non-constant
+ inline Register& uncheckedR(int);
+
+ // Access to arguments.
+ int hostThisRegister() { return -RegisterFile::CallFrameHeaderSize - argumentCountIncludingThis(); }
+ JSValue hostThisValue() { return this[hostThisRegister()].jsValue(); }
+ size_t argumentCount() const { return argumentCountIncludingThis() - 1; }
+ size_t argumentCountIncludingThis() const { return this[RegisterFile::ArgumentCount].i(); }
+ JSValue argument(int argumentNumber)
+ {
+ int argumentIndex = -RegisterFile::CallFrameHeaderSize - this[RegisterFile::ArgumentCount].i() + argumentNumber + 1;
+ if (argumentIndex >= -RegisterFile::CallFrameHeaderSize)
+ return jsUndefined();
+ return this[argumentIndex].jsValue();
+ }
static CallFrame* noCaller() { return reinterpret_cast<CallFrame*>(HostCallFrameFlag); }
- int returnValueRegister() const { return this[RegisterFile::ReturnValueRegister].i(); }
bool hasHostCallFrameFlag() const { return reinterpret_cast<intptr_t>(this) & HostCallFrameFlag; }
CallFrame* addHostCallFrameFlag() const { return reinterpret_cast<CallFrame*>(reinterpret_cast<intptr_t>(this) | HostCallFrameFlag); }
CallFrame* removeHostCallFrameFlag() { return reinterpret_cast<CallFrame*>(reinterpret_cast<intptr_t>(this) & ~HostCallFrameFlag); }
- private:
- void setArgumentCount(int count) { static_cast<Register*>(this)[RegisterFile::ArgumentCount] = Register::withInt(count); }
- void setCallee(JSFunction* callee) { static_cast<Register*>(this)[RegisterFile::Callee] = callee; }
+ void setArgumentCountIncludingThis(int count) { static_cast<Register*>(this)[RegisterFile::ArgumentCount] = Register::withInt(count); }
+ void setCallee(JSObject* callee) { static_cast<Register*>(this)[RegisterFile::Callee] = Register::withCallee(callee); }
void setCodeBlock(CodeBlock* codeBlock) { static_cast<Register*>(this)[RegisterFile::CodeBlock] = codeBlock; }
+ void setReturnPC(void* value) { static_cast<Register*>(this)[RegisterFile::ReturnPC] = (Instruction*)value; }
+ private:
static const intptr_t HostCallFrameFlag = 1;
-
+#ifndef NDEBUG
+ RegisterFile* registerFile();
+#endif
ExecState();
~ExecState();
};
else
newCallFrame[arg - RegisterFile::CallFrameHeaderSize - expectedParams - providedParams] = value;
}
+
void resetCallFrame()
{
newCallFrame->setScopeChain(scopeChain);
- newCallFrame->setCalleeArguments(JSValue());
for (int i = providedParams; i < expectedParams; ++i)
newCallFrame[i - RegisterFile::CallFrameHeaderSize - expectedParams] = jsUndefined();
}
#include "CallFrame.h"
#include "CallFrameClosure.h"
#include "CodeBlock.h"
-#include "Collector.h"
+#include "Heap.h"
#include "Debugger.h"
#include "DebuggerCallFrame.h"
+#include "ErrorInstance.h"
#include "EvalCodeCache.h"
#include "ExceptionHelpers.h"
#include "GetterSetter.h"
-#include "GlobalEvalFunction.h"
#include "JSActivation.h"
#include "JSArray.h"
#include "JSByteArray.h"
#include "RegExpPrototype.h"
#include "Register.h"
#include "SamplingTool.h"
+#include "StrictEvalActivation.h"
+#include "UStringConcatenate.h"
#include <limits.h>
#include <stdio.h>
#include <wtf/Threading.h>
using namespace std;
namespace JSC {
-
-#if ENABLE(JIT)
- static ALWAYS_INLINE unsigned bytecodeOffsetForPC(CallFrame* callFrame, CodeBlock* codeBlock, ReturnAddressPtr pc)
- {
- return codeBlock->getBytecodeIndex(callFrame, ReturnAddressPtr(pc));
- }
-#endif
-#if ENABLE(INTERPRETER)
- static ALWAYS_INLINE unsigned bytecodeOffsetForPC(CallFrame* callFrame, CodeBlock* codeBlock, Instruction* pc)
- {
- UNUSED_PARAM(callFrame);
- return pc - codeBlock->instructions().begin();
- }
-#endif
// Returns the depth of the scope chain within a given call frame.
-static int depth(CodeBlock* codeBlock, ScopeChain& sc)
+static int depth(CodeBlock* codeBlock, ScopeChainNode* sc)
{
if (!codeBlock->needsFullScopeChain())
return 0;
- return sc.localDepth();
+ return sc->localDepth();
}
#if ENABLE(INTERPRETER)
CodeBlock* codeBlock = callFrame->codeBlock();
Identifier& ident = codeBlock->identifier(property);
do {
- JSObject* o = *iter;
+ JSObject* o = iter->get();
PropertySlot slot(o);
if (o->getPropertySlot(callFrame, ident, slot)) {
JSValue result = slot.getValue(callFrame, ident);
exceptionValue = callFrame->globalData().exception;
if (exceptionValue)
return false;
- callFrame->r(dst) = JSValue(result);
+ callFrame->uncheckedR(dst) = JSValue(result);
return true;
}
} while (++iter != end);
- exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock);
+ exceptionValue = createUndefinedVariableError(callFrame, ident);
return false;
}
int dst = vPC[1].u.operand;
int property = vPC[2].u.operand;
- int skip = vPC[3].u.operand + codeBlock->needsFullScopeChain();
+ int skip = vPC[3].u.operand;
ScopeChainNode* scopeChain = callFrame->scopeChain();
ScopeChainIterator iter = scopeChain->begin();
ScopeChainIterator end = scopeChain->end();
ASSERT(iter != end);
+ bool checkTopLevel = codeBlock->codeType() == FunctionCode && codeBlock->needsFullScopeChain();
+ ASSERT(skip || !checkTopLevel);
+ if (checkTopLevel && skip--) {
+ if (callFrame->uncheckedR(codeBlock->activationRegister()).jsValue())
+ ++iter;
+ }
while (skip--) {
++iter;
ASSERT(iter != end);
}
Identifier& ident = codeBlock->identifier(property);
do {
- JSObject* o = *iter;
+ JSObject* o = iter->get();
PropertySlot slot(o);
if (o->getPropertySlot(callFrame, ident, slot)) {
JSValue result = slot.getValue(callFrame, ident);
exceptionValue = callFrame->globalData().exception;
if (exceptionValue)
return false;
- callFrame->r(dst) = JSValue(result);
+ ASSERT(result);
+ callFrame->uncheckedR(dst) = JSValue(result);
return true;
}
} while (++iter != end);
- exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock);
+ exceptionValue = createUndefinedVariableError(callFrame, ident);
return false;
}
NEVER_INLINE bool Interpreter::resolveGlobal(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
{
int dst = vPC[1].u.operand;
- JSGlobalObject* globalObject = static_cast<JSGlobalObject*>(vPC[2].u.jsCell);
+ CodeBlock* codeBlock = callFrame->codeBlock();
+ JSGlobalObject* globalObject = codeBlock->globalObject();
ASSERT(globalObject->isGlobalObject());
- int property = vPC[3].u.operand;
- Structure* structure = vPC[4].u.structure;
- int offset = vPC[5].u.operand;
+ int property = vPC[2].u.operand;
+ Structure* structure = vPC[3].u.structure.get();
+ int offset = vPC[4].u.operand;
if (structure == globalObject->structure()) {
- callFrame->r(dst) = JSValue(globalObject->getDirectOffset(offset));
+ callFrame->uncheckedR(dst) = JSValue(globalObject->getDirectOffset(offset));
return true;
}
- CodeBlock* codeBlock = callFrame->codeBlock();
Identifier& ident = codeBlock->identifier(property);
PropertySlot slot(globalObject);
if (globalObject->getPropertySlot(callFrame, ident, slot)) {
JSValue result = slot.getValue(callFrame, ident);
if (slot.isCacheableValue() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) {
- if (vPC[4].u.structure)
- vPC[4].u.structure->deref();
- globalObject->structure()->ref();
- vPC[4] = globalObject->structure();
- vPC[5] = slot.cachedOffset();
- callFrame->r(dst) = JSValue(result);
+ vPC[3].u.structure.set(callFrame->globalData(), codeBlock->ownerExecutable(), globalObject->structure());
+ vPC[4] = slot.cachedOffset();
+ callFrame->uncheckedR(dst) = JSValue(result);
return true;
}
exceptionValue = callFrame->globalData().exception;
if (exceptionValue)
return false;
- callFrame->r(dst) = JSValue(result);
+ callFrame->uncheckedR(dst) = JSValue(result);
return true;
}
- exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock);
+ exceptionValue = createUndefinedVariableError(callFrame, ident);
return false;
}
NEVER_INLINE bool Interpreter::resolveGlobalDynamic(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
{
int dst = vPC[1].u.operand;
- JSGlobalObject* globalObject = static_cast<JSGlobalObject*>(vPC[2].u.jsCell);
- ASSERT(globalObject->isGlobalObject());
- int property = vPC[3].u.operand;
- Structure* structure = vPC[4].u.structure;
- int offset = vPC[5].u.operand;
CodeBlock* codeBlock = callFrame->codeBlock();
- int skip = vPC[6].u.operand + codeBlock->needsFullScopeChain();
+ JSGlobalObject* globalObject = codeBlock->globalObject();
+ ASSERT(globalObject->isGlobalObject());
+ int property = vPC[2].u.operand;
+ Structure* structure = vPC[3].u.structure.get();
+ int offset = vPC[4].u.operand;
+ int skip = vPC[5].u.operand;
ScopeChainNode* scopeChain = callFrame->scopeChain();
ScopeChainIterator iter = scopeChain->begin();
ScopeChainIterator end = scopeChain->end();
ASSERT(iter != end);
+ bool checkTopLevel = codeBlock->codeType() == FunctionCode && codeBlock->needsFullScopeChain();
+ ASSERT(skip || !checkTopLevel);
+ if (checkTopLevel && skip--) {
+ if (callFrame->uncheckedR(codeBlock->activationRegister()).jsValue())
+ ++iter;
+ }
while (skip--) {
- JSObject* o = *iter;
+ JSObject* o = iter->get();
if (o->hasCustomProperties()) {
Identifier& ident = codeBlock->identifier(property);
do {
exceptionValue = callFrame->globalData().exception;
if (exceptionValue)
return false;
- callFrame->r(dst) = JSValue(result);
+ ASSERT(result);
+ callFrame->uncheckedR(dst) = JSValue(result);
return true;
}
if (iter == end)
break;
- o = *iter;
+ o = iter->get();
++iter;
} while (true);
- exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock);
+ exceptionValue = createUndefinedVariableError(callFrame, ident);
return false;
}
++iter;
}
if (structure == globalObject->structure()) {
- callFrame->r(dst) = JSValue(globalObject->getDirectOffset(offset));
+ callFrame->uncheckedR(dst) = JSValue(globalObject->getDirectOffset(offset));
+ ASSERT(callFrame->uncheckedR(dst).jsValue());
return true;
}
if (globalObject->getPropertySlot(callFrame, ident, slot)) {
JSValue result = slot.getValue(callFrame, ident);
if (slot.isCacheableValue() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) {
- if (vPC[4].u.structure)
- vPC[4].u.structure->deref();
- globalObject->structure()->ref();
- vPC[4] = globalObject->structure();
- vPC[5] = slot.cachedOffset();
- callFrame->r(dst) = JSValue(result);
+ vPC[3].u.structure.set(callFrame->globalData(), codeBlock->ownerExecutable(), globalObject->structure());
+ vPC[4] = slot.cachedOffset();
+ ASSERT(result);
+ callFrame->uncheckedR(dst) = JSValue(result);
return true;
}
exceptionValue = callFrame->globalData().exception;
if (exceptionValue)
return false;
- callFrame->r(dst) = JSValue(result);
+ ASSERT(result);
+ callFrame->uncheckedR(dst) = JSValue(result);
return true;
}
- exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock);
+ exceptionValue = createUndefinedVariableError(callFrame, ident);
return false;
}
{
int dst = vPC[1].u.operand;
int property = vPC[2].u.operand;
- callFrame->r(dst) = JSValue(JSC::resolveBase(callFrame, callFrame->codeBlock()->identifier(property), callFrame->scopeChain()));
+ bool isStrictPut = vPC[3].u.operand;
+ Identifier ident = callFrame->codeBlock()->identifier(property);
+ JSValue result = JSC::resolveBase(callFrame, ident, callFrame->scopeChain(), isStrictPut);
+ if (result) {
+ callFrame->uncheckedR(dst) = result;
+ ASSERT(callFrame->uncheckedR(dst).jsValue());
+ } else
+ callFrame->globalData().exception = createErrorForInvalidGlobalAssignment(callFrame, ident.ustring());
}
NEVER_INLINE bool Interpreter::resolveBaseAndProperty(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
Identifier& ident = codeBlock->identifier(property);
JSObject* base;
do {
- base = *iter;
+ base = iter->get();
PropertySlot slot(base);
if (base->getPropertySlot(callFrame, ident, slot)) {
JSValue result = slot.getValue(callFrame, ident);
exceptionValue = callFrame->globalData().exception;
if (exceptionValue)
return false;
- callFrame->r(propDst) = JSValue(result);
- callFrame->r(baseDst) = JSValue(base);
+ callFrame->uncheckedR(propDst) = JSValue(result);
+ callFrame->uncheckedR(baseDst) = JSValue(base);
return true;
}
++iter;
} while (iter != end);
- exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock);
+ exceptionValue = createUndefinedVariableError(callFrame, ident);
return false;
}
}
#if ENABLE(INTERPRETER)
-static NEVER_INLINE bool isInvalidParamForIn(CallFrame* callFrame, CodeBlock* codeBlock, const Instruction* vPC, JSValue value, JSValue& exceptionData)
+static NEVER_INLINE bool isInvalidParamForIn(CallFrame* callFrame, JSValue value, JSValue& exceptionData)
{
if (value.isObject())
return false;
- exceptionData = createInvalidParamError(callFrame, "in" , value, vPC - codeBlock->instructions().begin(), codeBlock);
+ exceptionData = createInvalidParamError(callFrame, "in" , value);
return true;
}
-static NEVER_INLINE bool isInvalidParamForInstanceOf(CallFrame* callFrame, CodeBlock* codeBlock, const Instruction* vPC, JSValue value, JSValue& exceptionData)
+static NEVER_INLINE bool isInvalidParamForInstanceOf(CallFrame* callFrame, JSValue value, JSValue& exceptionData)
{
if (value.isObject() && asObject(value)->structure()->typeInfo().implementsHasInstance())
return false;
- exceptionData = createInvalidParamError(callFrame, "instanceof" , value, vPC - codeBlock->instructions().begin(), codeBlock);
+ exceptionData = createInvalidParamError(callFrame, "instanceof" , value);
return true;
}
#endif
-NEVER_INLINE JSValue Interpreter::callEval(CallFrame* callFrame, RegisterFile* registerFile, Register* argv, int argc, int registerOffset, JSValue& exceptionValue)
+NEVER_INLINE JSValue Interpreter::callEval(CallFrame* callFrame, RegisterFile* registerFile, Register* argv, int argc, int registerOffset)
{
if (argc < 2)
return jsUndefined();
UString programSource = asString(program)->value(callFrame);
if (callFrame->hadException())
return JSValue();
-
- LiteralParser preparser(callFrame, programSource, LiteralParser::NonStrictJSON);
- if (JSValue parsedObject = preparser.tryLiteralParse())
- return parsedObject;
+
+ CodeBlock* codeBlock = callFrame->codeBlock();
+ if (!codeBlock->isStrictMode()) {
+ // FIXME: We can use the preparser in strict mode, we just need additional logic
+ // to prevent duplicates.
+ LiteralParser preparser(callFrame, programSource.characters(), programSource.length(), LiteralParser::NonStrictJSON);
+ if (JSValue parsedObject = preparser.tryLiteralParse())
+ return parsedObject;
+ }
ScopeChainNode* scopeChain = callFrame->scopeChain();
- CodeBlock* codeBlock = callFrame->codeBlock();
- RefPtr<EvalExecutable> eval = codeBlock->evalCodeCache().get(callFrame, programSource, scopeChain, exceptionValue);
+ JSValue exceptionValue;
+ EvalExecutable* eval = codeBlock->evalCodeCache().get(callFrame, codeBlock->ownerExecutable(), codeBlock->isStrictMode(), programSource, scopeChain, exceptionValue);
- JSValue result = jsUndefined();
- if (eval)
- result = callFrame->globalData().interpreter->execute(eval.get(), callFrame, callFrame->thisValue().toThisObject(callFrame), callFrame->registers() - registerFile->start() + registerOffset, scopeChain, &exceptionValue);
+ ASSERT(!eval == exceptionValue);
+ if (UNLIKELY(!eval))
+ return throwError(callFrame, exceptionValue);
- return result;
+ return callFrame->globalData().interpreter->execute(eval, callFrame, callFrame->uncheckedR(codeBlock->thisRegister()).jsValue().toThisObject(callFrame), callFrame->registers() - registerFile->start() + registerOffset, scopeChain);
}
-Interpreter::Interpreter()
+Interpreter::Interpreter(JSGlobalData& globalData)
: m_sampleEntryDepth(0)
, m_reentryDepth(0)
+ , m_registerFile(globalData)
{
#if ENABLE(COMPUTED_GOTO_INTERPRETER)
- privateExecute(InitializeAndReturn, 0, 0, 0);
+ privateExecute(InitializeAndReturn, 0, 0);
for (int i = 0; i < numOpcodeIDs; ++i)
m_opcodeIDTable.add(m_opcodeTable[i], static_cast<OpcodeID>(i));
printf("-----------------------------------------------------------------------------\n");
CodeBlock* codeBlock = callFrame->codeBlock();
- RegisterFile* registerFile = &callFrame->scopeChain()->globalObject->globalData()->interpreter->registerFile();
+ RegisterFile* registerFile = &callFrame->scopeChain()->globalObject->globalData().interpreter->registerFile();
const Register* it;
const Register* end;
JSValue v;
printf("[ScopeChain] | %10p | %p \n", it, (*it).scopeChain()); ++it;
printf("[CallerRegisters] | %10p | %d \n", it, (*it).i()); ++it;
printf("[ReturnPC] | %10p | %p \n", it, (*it).vPC()); ++it;
- printf("[ReturnValueRegister] | %10p | %d \n", it, (*it).i()); ++it;
printf("[ArgumentCount] | %10p | %d \n", it, (*it).i()); ++it;
printf("[Callee] | %10p | %p \n", it, (*it).function()); ++it;
- printf("[OptionalCalleeArguments] | %10p | %p \n", it, (*it).arguments()); ++it;
printf("-----------------------------------------------------------------------------\n");
int registerCount = 0;
debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->lastLine());
}
- if (Profiler* profiler = *Profiler::enabledProfilerReference()) {
- if (callFrame->callee())
- profiler->didExecute(callFrame, callFrame->callee());
- else
- profiler->didExecute(callFrame, codeBlock->ownerExecutable()->sourceURL(), codeBlock->ownerExecutable()->lineNo());
- }
-
// If this call frame created an activation or an 'arguments' object, tear it off.
if (oldCodeBlock->codeType() == FunctionCode && oldCodeBlock->needsFullScopeChain()) {
- while (!scopeChain->object->inherits(&JSActivation::info))
+ if (!callFrame->uncheckedR(oldCodeBlock->activationRegister()).jsValue()) {
+ oldCodeBlock->createActivation(callFrame);
+ scopeChain = callFrame->scopeChain();
+ }
+ while (!scopeChain->object->inherits(&JSActivation::s_info))
scopeChain = scopeChain->pop();
- static_cast<JSActivation*>(scopeChain->object)->copyRegisters(callFrame->optionalCalleeArguments());
- } else if (Arguments* arguments = callFrame->optionalCalleeArguments()) {
- if (!arguments->isTornOff())
- arguments->copyRegisters();
- }
- if (oldCodeBlock->needsFullScopeChain())
- scopeChain->deref();
+ callFrame->setScopeChain(scopeChain);
+ JSActivation* activation = asActivation(scopeChain->object.get());
+ activation->copyRegisters(*scopeChain->globalData);
+ if (JSValue arguments = callFrame->uncheckedR(unmodifiedArgumentsRegister(oldCodeBlock->argumentsRegister())).jsValue()) {
+ if (!oldCodeBlock->isStrictMode())
+ asArguments(arguments)->setActivation(callFrame->globalData(), activation);
+ }
+ } else if (oldCodeBlock->usesArguments() && !oldCodeBlock->isStrictMode()) {
+ if (JSValue arguments = callFrame->uncheckedR(unmodifiedArgumentsRegister(oldCodeBlock->argumentsRegister())).jsValue())
+ asArguments(arguments)->copyRegisters(callFrame->globalData());
+ }
- ExecState* callerFrame = callFrame->callerFrame();
+ CallFrame* callerFrame = callFrame->callerFrame();
if (callerFrame->hasHostCallFrameFlag())
return false;
codeBlock = callerFrame->codeBlock();
-#if ENABLE(JIT)
-#if ENABLE(INTERPRETER)
+
+ // Because of how the JIT records call site->bytecode offset
+ // information the JIT reports the bytecodeOffset for the returnPC
+ // to be at the beginning of the opcode that has caused the call.
+ // In the interpreter we have an actual return address, which is
+ // the beginning of next instruction to execute. To get an offset
+ // inside the call instruction that triggered the exception we
+ // have to subtract 1.
+#if ENABLE(JIT) && ENABLE(INTERPRETER)
if (callerFrame->globalData().canUseJIT())
-#endif
- bytecodeOffset = bytecodeOffsetForPC(callerFrame, codeBlock, callFrame->returnPC());
-#if ENABLE(INTERPRETER)
+ bytecodeOffset = codeBlock->bytecodeOffset(callFrame->returnPC());
else
- bytecodeOffset = bytecodeOffsetForPC(callerFrame, codeBlock, callFrame->returnVPC());
-#endif
+ bytecodeOffset = codeBlock->bytecodeOffset(callFrame->returnVPC()) - 1;
+#elif ENABLE(JIT)
+ bytecodeOffset = codeBlock->bytecodeOffset(callFrame->returnPC());
#else
- bytecodeOffset = codeBlock->bytecodeOffset(callerFrame, callFrame->returnVPC());
+ bytecodeOffset = codeBlock->bytecodeOffset(callFrame->returnVPC()) - 1;
#endif
+
callFrame = callerFrame;
return true;
}
-NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSValue& exceptionValue, unsigned bytecodeOffset, bool explicitThrow)
+static void appendSourceToError(CallFrame* callFrame, ErrorInstance* exception, unsigned bytecodeOffset)
{
- // Set up the exception object
+ exception->clearAppendSourceToMessage();
+
+ if (!callFrame->codeBlock()->hasExpressionInfo())
+ return;
+
+ int startOffset = 0;
+ int endOffset = 0;
+ int divotPoint = 0;
+
+ CodeBlock* codeBlock = callFrame->codeBlock();
+ codeBlock->expressionRangeForBytecodeOffset(bytecodeOffset, divotPoint, startOffset, endOffset);
+
+ int expressionStart = divotPoint - startOffset;
+ int expressionStop = divotPoint + endOffset;
+
+ if (!expressionStop || expressionStart > codeBlock->source()->length())
+ return;
+
+ JSGlobalData* globalData = &callFrame->globalData();
+ JSValue jsMessage = exception->getDirect(*globalData, globalData->propertyNames->message);
+ if (!jsMessage || !jsMessage.isString())
+ return;
+
+ UString message = asString(jsMessage)->value(callFrame);
+
+ if (expressionStart < expressionStop)
+ message = makeUString(message, " (evaluating '", codeBlock->source()->getRange(expressionStart, expressionStop), "')");
+ else {
+ // No range information, so give a few characters of context
+ const UChar* data = codeBlock->source()->data();
+ int dataLength = codeBlock->source()->length();
+ int start = expressionStart;
+ int stop = expressionStart;
+ // Get up to 20 characters of context to the left and right of the divot, clamping to the line.
+ // then strip whitespace.
+ while (start > 0 && (expressionStart - start < 20) && data[start - 1] != '\n')
+ start--;
+ while (start < (expressionStart - 1) && isStrWhiteSpace(data[start]))
+ start++;
+ while (stop < dataLength && (stop - expressionStart < 20) && data[stop] != '\n')
+ stop++;
+ while (stop > expressionStart && isStrWhiteSpace(data[stop - 1]))
+ stop--;
+ message = makeUString(message, " (near '...", codeBlock->source()->getRange(start, stop), "...')");
+ }
+
+ exception->putDirect(*globalData, globalData->propertyNames->message, jsString(globalData, message));
+}
+NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSValue& exceptionValue, unsigned bytecodeOffset)
+{
CodeBlock* codeBlock = callFrame->codeBlock();
+ bool isInterrupt = false;
+
+ // Set up the exception object
if (exceptionValue.isObject()) {
JSObject* exception = asObject(exceptionValue);
- if (exception->isNotAnObjectErrorStub()) {
- exception = createNotAnObjectError(callFrame, static_cast<JSNotAnObjectErrorStub*>(exception), bytecodeOffset, codeBlock);
- exceptionValue = exception;
- } else {
- if (!exception->hasProperty(callFrame, Identifier(callFrame, "line")) &&
- !exception->hasProperty(callFrame, Identifier(callFrame, "sourceId")) &&
- !exception->hasProperty(callFrame, Identifier(callFrame, "sourceURL")) &&
- !exception->hasProperty(callFrame, Identifier(callFrame, expressionBeginOffsetPropertyName)) &&
- !exception->hasProperty(callFrame, Identifier(callFrame, expressionCaretOffsetPropertyName)) &&
- !exception->hasProperty(callFrame, Identifier(callFrame, expressionEndOffsetPropertyName))) {
- if (explicitThrow) {
- int startOffset = 0;
- int endOffset = 0;
- int divotPoint = 0;
- int line = codeBlock->expressionRangeForBytecodeOffset(callFrame, bytecodeOffset, divotPoint, startOffset, endOffset);
- exception->putWithAttributes(callFrame, Identifier(callFrame, "line"), jsNumber(callFrame, line), ReadOnly | DontDelete);
-
- // We only hit this path for error messages and throw statements, which don't have a specific failure position
- // So we just give the full range of the error/throw statement.
- exception->putWithAttributes(callFrame, Identifier(callFrame, expressionBeginOffsetPropertyName), jsNumber(callFrame, divotPoint - startOffset), ReadOnly | DontDelete);
- exception->putWithAttributes(callFrame, Identifier(callFrame, expressionEndOffsetPropertyName), jsNumber(callFrame, divotPoint + endOffset), ReadOnly | DontDelete);
- } else
- exception->putWithAttributes(callFrame, Identifier(callFrame, "line"), jsNumber(callFrame, codeBlock->lineNumberForBytecodeOffset(callFrame, bytecodeOffset)), ReadOnly | DontDelete);
- exception->putWithAttributes(callFrame, Identifier(callFrame, "sourceId"), jsNumber(callFrame, codeBlock->ownerExecutable()->sourceID()), ReadOnly | DontDelete);
- exception->putWithAttributes(callFrame, Identifier(callFrame, "sourceURL"), jsOwnedString(callFrame, codeBlock->ownerExecutable()->sourceURL()), ReadOnly | DontDelete);
- }
- ComplType exceptionType = exception->exceptionType();
- if (exceptionType == Interrupted || exceptionType == Terminated) {
- while (unwindCallFrame(callFrame, exceptionValue, bytecodeOffset, codeBlock)) {
- // Don't need handler checks or anything, we just want to unroll all the JS callframes possible.
- }
- return 0;
- }
+ if (exception->isErrorInstance() && static_cast<ErrorInstance*>(exception)->appendSourceToMessage())
+ appendSourceToError(callFrame, static_cast<ErrorInstance*>(exception), bytecodeOffset);
+
+ // Using hasExpressionInfo to imply we are interested in rich exception info.
+ if (codeBlock->hasExpressionInfo() && !hasErrorInfo(callFrame, exception)) {
+ ASSERT(codeBlock->hasLineInfo());
+
+ // FIXME: should only really be adding these properties to VM generated exceptions,
+ // but the inspector currently requires these for all thrown objects.
+ addErrorInfo(callFrame, exception, codeBlock->lineNumberForBytecodeOffset(bytecodeOffset), codeBlock->ownerExecutable()->source());
}
+
+ ComplType exceptionType = exception->exceptionType();
+ isInterrupt = exceptionType == Interrupted || exceptionType == Terminated;
}
if (Debugger* debugger = callFrame->dynamicGlobalObject()->debugger()) {
DebuggerCallFrame debuggerCallFrame(callFrame, exceptionValue);
bool hasHandler = codeBlock->handlerForBytecodeOffset(bytecodeOffset);
- debugger->exception(debuggerCallFrame, codeBlock->ownerExecutable()->sourceID(), codeBlock->lineNumberForBytecodeOffset(callFrame, bytecodeOffset), hasHandler);
- }
-
- // If we throw in the middle of a call instruction, we need to notify
- // the profiler manually that the call instruction has returned, since
- // we'll never reach the relevant op_profile_did_call.
- if (Profiler* profiler = *Profiler::enabledProfilerReference()) {
-#if ENABLE(INTERPRETER)
- if (!callFrame->globalData().canUseJIT()) {
- // FIXME: Why 8? - work out what this magic value is, replace the constant with something more helpful.
- if (isCallBytecode(codeBlock->instructions()[bytecodeOffset].u.opcode))
- profiler->didExecute(callFrame, callFrame->r(codeBlock->instructions()[bytecodeOffset + 1].u.operand).jsValue());
- else if (codeBlock->instructions().size() > (bytecodeOffset + 8) && codeBlock->instructions()[bytecodeOffset + 8].u.opcode == getOpcode(op_construct))
- profiler->didExecute(callFrame, callFrame->r(codeBlock->instructions()[bytecodeOffset + 9].u.operand).jsValue());
- }
-#if ENABLE(JIT)
- else
-#endif
-#endif
-#if ENABLE(JIT)
- {
- int functionRegisterIndex;
- if (codeBlock->functionRegisterForBytecodeOffset(bytecodeOffset, functionRegisterIndex))
- profiler->didExecute(callFrame, callFrame->r(functionRegisterIndex).jsValue());
- }
-#endif
+ debugger->exception(debuggerCallFrame, codeBlock->ownerExecutable()->sourceID(), codeBlock->lineNumberForBytecodeOffset(bytecodeOffset), hasHandler);
}
// Calculate an exception handler vPC, unwinding call frames as necessary.
-
HandlerInfo* handler = 0;
- while (!(handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset))) {
- if (!unwindCallFrame(callFrame, exceptionValue, bytecodeOffset, codeBlock))
+ while (isInterrupt || !(handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset))) {
+ if (!unwindCallFrame(callFrame, exceptionValue, bytecodeOffset, codeBlock)) {
+ if (Profiler* profiler = *Profiler::enabledProfilerReference())
+ profiler->exceptionUnwind(callFrame);
return 0;
+ }
}
- // Now unwind the scope chain within the exception handler's call frame.
+ if (Profiler* profiler = *Profiler::enabledProfilerReference())
+ profiler->exceptionUnwind(callFrame);
+ // Shrink the JS stack, in case stack overflow made it huge.
+ Register* highWaterMark = 0;
+ for (CallFrame* callerFrame = callFrame; callerFrame; callerFrame = callerFrame->callerFrame()->removeHostCallFrameFlag()) {
+ CodeBlock* codeBlock = callerFrame->codeBlock();
+ if (!codeBlock)
+ continue;
+ Register* callerHighWaterMark = callerFrame->registers() + codeBlock->m_numCalleeRegisters;
+ highWaterMark = max(highWaterMark, callerHighWaterMark);
+ }
+ m_registerFile.shrink(highWaterMark);
+
+ // Unwind the scope chain within the exception handler's call frame.
ScopeChainNode* scopeChain = callFrame->scopeChain();
- ScopeChain sc(scopeChain);
- int scopeDelta = depth(codeBlock, sc) - handler->scopeDepth;
+ int scopeDelta = 0;
+ if (!codeBlock->needsFullScopeChain() || codeBlock->codeType() != FunctionCode
+ || callFrame->uncheckedR(codeBlock->activationRegister()).jsValue())
+ scopeDelta = depth(codeBlock, scopeChain) - handler->scopeDepth;
ASSERT(scopeDelta >= 0);
while (scopeDelta--)
scopeChain = scopeChain->pop();
return handler;
}
-JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, ScopeChainNode* scopeChain, JSObject* thisObj, JSValue* exception)
+static inline JSValue checkedReturn(JSValue returnValue)
+{
+ ASSERT(returnValue);
+ return returnValue;
+}
+
+static inline JSObject* checkedReturn(JSObject* returnValue)
+{
+ ASSERT(returnValue);
+ return returnValue;
+}
+
+JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, ScopeChainNode* scopeChain, JSObject* thisObj)
{
ASSERT(!scopeChain->globalData->exception);
+ ASSERT(!callFrame->globalData().isCollectorBusy());
+ if (callFrame->globalData().isCollectorBusy())
+ return jsNull();
- if (m_reentryDepth >= MaxSmallThreadReentryDepth) {
- if (m_reentryDepth >= callFrame->globalData().maxReentryDepth) {
- *exception = createStackOverflowError(callFrame);
- return jsNull();
+ if (m_reentryDepth >= MaxSmallThreadReentryDepth && m_reentryDepth >= callFrame->globalData().maxReentryDepth)
+ return checkedReturn(throwStackOverflowError(callFrame));
+
+ DynamicGlobalObjectScope globalObjectScope(*scopeChain->globalData, scopeChain->globalObject.get());
+ LiteralParser literalParser(callFrame, program->source().data(), program->source().length(), LiteralParser::JSONP);
+ Vector<LiteralParser::JSONPData> JSONPData;
+ if (literalParser.tryJSONPParse(JSONPData, scopeChain->globalObject->supportsRichSourceInfo())) {
+ JSGlobalObject* globalObject = scopeChain->globalObject.get();
+ JSValue result;
+ for (unsigned entry = 0; entry < JSONPData.size(); entry++) {
+ Vector<LiteralParser::JSONPPathEntry> JSONPPath;
+ JSONPPath.swap(JSONPData[entry].m_path);
+ JSValue JSONPValue = JSONPData[entry].m_value.get();
+ if (JSONPPath.size() == 1 && JSONPPath[0].m_type == LiteralParser::JSONPPathEntryTypeDeclare) {
+ if (globalObject->hasProperty(callFrame, JSONPPath[0].m_pathEntryName)) {
+ PutPropertySlot slot;
+ globalObject->put(callFrame, JSONPPath[0].m_pathEntryName, JSONPValue, slot);
+ } else
+ globalObject->putWithAttributes(callFrame, JSONPPath[0].m_pathEntryName, JSONPValue, DontEnum | DontDelete);
+ // var declarations return undefined
+ result = jsUndefined();
+ continue;
+ }
+ JSValue baseObject(globalObject);
+ for (unsigned i = 0; i < JSONPPath.size() - 1; i++) {
+ ASSERT(JSONPPath[i].m_type != LiteralParser::JSONPPathEntryTypeDeclare);
+ switch (JSONPPath[i].m_type) {
+ case LiteralParser::JSONPPathEntryTypeDot: {
+ if (i == 0) {
+ PropertySlot slot(globalObject);
+ if (!globalObject->getPropertySlot(callFrame, JSONPPath[i].m_pathEntryName, slot)) {
+ if (entry)
+ return throwError(callFrame, createUndefinedVariableError(globalObject->globalExec(), JSONPPath[i].m_pathEntryName));
+ goto failedJSONP;
+ }
+ baseObject = slot.getValue(callFrame, JSONPPath[i].m_pathEntryName);
+ } else
+ baseObject = baseObject.get(callFrame, JSONPPath[i].m_pathEntryName);
+ if (callFrame->hadException())
+ return jsUndefined();
+ continue;
+ }
+ case LiteralParser::JSONPPathEntryTypeLookup: {
+ baseObject = baseObject.get(callFrame, JSONPPath[i].m_pathIndex);
+ if (callFrame->hadException())
+ return jsUndefined();
+ continue;
+ }
+ default:
+ ASSERT_NOT_REACHED();
+ return jsUndefined();
+ }
+ }
+ PutPropertySlot slot;
+ switch (JSONPPath.last().m_type) {
+ case LiteralParser::JSONPPathEntryTypeCall: {
+ JSValue function = baseObject.get(callFrame, JSONPPath.last().m_pathEntryName);
+ if (callFrame->hadException())
+ return jsUndefined();
+ CallData callData;
+ CallType callType = getCallData(function, callData);
+ if (callType == CallTypeNone)
+ return throwError(callFrame, createNotAFunctionError(callFrame, function));
+ MarkedArgumentBuffer jsonArg;
+ jsonArg.append(JSONPValue);
+ JSValue thisValue = JSONPPath.size() == 1 ? jsUndefined(): baseObject;
+ JSONPValue = JSC::call(callFrame, function, callType, callData, thisValue, jsonArg);
+ if (callFrame->hadException())
+ return jsUndefined();
+ break;
+ }
+ case LiteralParser::JSONPPathEntryTypeDot: {
+ baseObject.put(callFrame, JSONPPath.last().m_pathEntryName, JSONPValue, slot);
+ if (callFrame->hadException())
+ return jsUndefined();
+ break;
+ }
+ case LiteralParser::JSONPPathEntryTypeLookup: {
+ baseObject.put(callFrame, JSONPPath.last().m_pathIndex, JSONPValue);
+ if (callFrame->hadException())
+ return jsUndefined();
+ break;
+ }
+ default:
+ ASSERT_NOT_REACHED();
+ return jsUndefined();
+ }
+ result = JSONPValue;
}
+ return result;
}
-
- CodeBlock* codeBlock = &program->bytecode(callFrame, scopeChain);
+failedJSONP:
+ JSObject* error = program->compile(callFrame, scopeChain);
+ if (error)
+ return checkedReturn(throwError(callFrame, error));
+ CodeBlock* codeBlock = &program->generatedBytecode();
Register* oldEnd = m_registerFile.end();
Register* newEnd = oldEnd + codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize + codeBlock->m_numCalleeRegisters;
- if (!m_registerFile.grow(newEnd)) {
- *exception = createStackOverflowError(callFrame);
- return jsNull();
- }
-
- DynamicGlobalObjectScope globalObjectScope(callFrame, scopeChain->globalObject);
+ if (!m_registerFile.grow(newEnd))
+ return checkedReturn(throwStackOverflowError(callFrame));
JSGlobalObject* lastGlobalObject = m_registerFile.globalObject();
JSGlobalObject* globalObject = callFrame->dynamicGlobalObject();
globalObject->copyGlobalsTo(m_registerFile);
CallFrame* newCallFrame = CallFrame::create(oldEnd + codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize);
- newCallFrame->r(codeBlock->thisRegister()) = JSValue(thisObj);
- newCallFrame->init(codeBlock, 0, scopeChain, CallFrame::noCaller(), 0, 0, 0);
-
- if (codeBlock->needsFullScopeChain())
- scopeChain->ref();
+ ASSERT(codeBlock->m_numParameters == 1); // 1 parameter for 'this'.
+ newCallFrame->init(codeBlock, 0, scopeChain, CallFrame::noCaller(), codeBlock->m_numParameters, 0);
+ newCallFrame->uncheckedR(newCallFrame->hostThisRegister()) = JSValue(thisObj);
Profiler** profiler = Profiler::enabledProfilerReference();
if (*profiler)
- (*profiler)->willExecute(newCallFrame, program->sourceURL(), program->lineNo());
+ (*profiler)->willExecute(callFrame, program->sourceURL(), program->lineNo());
JSValue result;
{
m_reentryDepth++;
#if ENABLE(JIT)
-#if ENABLE(INTERPRETER)
if (callFrame->globalData().canUseJIT())
-#endif
- result = program->jitCode(newCallFrame, scopeChain).execute(&m_registerFile, newCallFrame, scopeChain->globalData, exception);
-#if ENABLE(INTERPRETER)
+ result = program->generatedJITCode().execute(&m_registerFile, newCallFrame, scopeChain->globalData);
else
#endif
-#endif
-#if ENABLE(INTERPRETER)
- result = privateExecute(Normal, &m_registerFile, newCallFrame, exception);
-#endif
+ result = privateExecute(Normal, &m_registerFile, newCallFrame);
m_reentryDepth--;
}
m_registerFile.shrink(oldEnd);
- return result;
+ return checkedReturn(result);
}
-JSValue Interpreter::execute(FunctionExecutable* functionExecutable, CallFrame* callFrame, JSFunction* function, JSObject* thisObj, const ArgList& args, ScopeChainNode* scopeChain, JSValue* exception)
+JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallType callType, const CallData& callData, JSValue thisValue, const ArgList& args)
{
- ASSERT(!scopeChain->globalData->exception);
+ ASSERT(!callFrame->hadException());
+ ASSERT(!callFrame->globalData().isCollectorBusy());
+ if (callFrame->globalData().isCollectorBusy())
+ return jsNull();
- if (m_reentryDepth >= MaxSmallThreadReentryDepth) {
- if (m_reentryDepth >= callFrame->globalData().maxReentryDepth) {
- *exception = createStackOverflowError(callFrame);
- return jsNull();
- }
- }
+ if (m_reentryDepth >= MaxSmallThreadReentryDepth && m_reentryDepth >= callFrame->globalData().maxReentryDepth)
+ return checkedReturn(throwStackOverflowError(callFrame));
Register* oldEnd = m_registerFile.end();
- int argc = 1 + args.size(); // implicit "this" parameter
+ int argCount = 1 + args.size(); // implicit "this" parameter
+ size_t registerOffset = argCount + RegisterFile::CallFrameHeaderSize;
- if (!m_registerFile.grow(oldEnd + argc)) {
- *exception = createStackOverflowError(callFrame);
- return jsNull();
- }
-
- DynamicGlobalObjectScope globalObjectScope(callFrame, scopeChain->globalObject);
+ if (!m_registerFile.grow(oldEnd + registerOffset))
+ return checkedReturn(throwStackOverflowError(callFrame));
CallFrame* newCallFrame = CallFrame::create(oldEnd);
size_t dst = 0;
- newCallFrame->r(0) = JSValue(thisObj);
+ newCallFrame->uncheckedR(0) = thisValue;
ArgList::const_iterator end = args.end();
for (ArgList::const_iterator it = args.begin(); it != end; ++it)
- newCallFrame->r(++dst) = *it;
+ newCallFrame->uncheckedR(++dst) = *it;
+
+ if (callType == CallTypeJS) {
+ ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
+
+ DynamicGlobalObjectScope globalObjectScope(*callDataScopeChain->globalData, callDataScopeChain->globalObject.get());
+
+ JSObject* compileError = callData.js.functionExecutable->compileForCall(callFrame, callDataScopeChain);
+ if (UNLIKELY(!!compileError)) {
+ m_registerFile.shrink(oldEnd);
+ return checkedReturn(throwError(callFrame, compileError));
+ }
+
+ CodeBlock* newCodeBlock = &callData.js.functionExecutable->generatedBytecodeForCall();
+ newCallFrame = slideRegisterWindowForCall(newCodeBlock, &m_registerFile, newCallFrame, registerOffset, argCount);
+ if (UNLIKELY(!newCallFrame)) {
+ m_registerFile.shrink(oldEnd);
+ return checkedReturn(throwStackOverflowError(callFrame));
+ }
+
+ newCallFrame->init(newCodeBlock, 0, callDataScopeChain, callFrame->addHostCallFrameFlag(), argCount, function);
+
+ Profiler** profiler = Profiler::enabledProfilerReference();
+ if (*profiler)
+ (*profiler)->willExecute(callFrame, function);
+
+ JSValue result;
+ {
+ SamplingTool::CallRecord callRecord(m_sampler.get());
+
+ m_reentryDepth++;
+#if ENABLE(JIT)
+ if (callFrame->globalData().canUseJIT())
+ result = callData.js.functionExecutable->generatedJITCodeForCall().execute(&m_registerFile, newCallFrame, callDataScopeChain->globalData);
+ else
+#endif
+ result = privateExecute(Normal, &m_registerFile, newCallFrame);
+ m_reentryDepth--;
+ }
+
+ if (*profiler)
+ (*profiler)->didExecute(callFrame, function);
- CodeBlock* codeBlock = &functionExecutable->bytecode(callFrame, scopeChain);
- newCallFrame = slideRegisterWindowForCall(codeBlock, &m_registerFile, newCallFrame, argc + RegisterFile::CallFrameHeaderSize, argc);
- if (UNLIKELY(!newCallFrame)) {
- *exception = createStackOverflowError(callFrame);
m_registerFile.shrink(oldEnd);
- return jsNull();
+ return checkedReturn(result);
}
- // a 0 codeBlock indicates a built-in caller
- newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), 0, argc, function);
+
+ ASSERT(callType == CallTypeHost);
+ ScopeChainNode* scopeChain = callFrame->scopeChain();
+ newCallFrame = CallFrame::create(newCallFrame->registers() + registerOffset);
+ newCallFrame->init(0, 0, scopeChain, callFrame->addHostCallFrameFlag(), argCount, function);
+
+ DynamicGlobalObjectScope globalObjectScope(*scopeChain->globalData, scopeChain->globalObject.get());
Profiler** profiler = Profiler::enabledProfilerReference();
if (*profiler)
JSValue result;
{
- SamplingTool::CallRecord callRecord(m_sampler.get());
+ SamplingTool::HostCallRecord callRecord(m_sampler.get());
+ result = JSValue::decode(callData.native.function(newCallFrame));
+ }
- m_reentryDepth++;
+ if (*profiler)
+ (*profiler)->didExecute(callFrame, function);
+
+ m_registerFile.shrink(oldEnd);
+ return checkedReturn(result);
+}
+
+JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* constructor, ConstructType constructType, const ConstructData& constructData, const ArgList& args)
+{
+ ASSERT(!callFrame->hadException());
+ ASSERT(!callFrame->globalData().isCollectorBusy());
+ // We throw in this case because we have to return something "valid" but we're
+ // already in an invalid state.
+ if (callFrame->globalData().isCollectorBusy())
+ return checkedReturn(throwStackOverflowError(callFrame));
+
+ if (m_reentryDepth >= MaxSmallThreadReentryDepth && m_reentryDepth >= callFrame->globalData().maxReentryDepth)
+ return checkedReturn(throwStackOverflowError(callFrame));
+
+ Register* oldEnd = m_registerFile.end();
+ int argCount = 1 + args.size(); // implicit "this" parameter
+ size_t registerOffset = argCount + RegisterFile::CallFrameHeaderSize;
+
+ if (!m_registerFile.grow(oldEnd + registerOffset))
+ return checkedReturn(throwStackOverflowError(callFrame));
+
+ CallFrame* newCallFrame = CallFrame::create(oldEnd);
+ size_t dst = 0;
+ ArgList::const_iterator end = args.end();
+ for (ArgList::const_iterator it = args.begin(); it != end; ++it)
+ newCallFrame->uncheckedR(++dst) = *it;
+
+ if (constructType == ConstructTypeJS) {
+ ScopeChainNode* constructDataScopeChain = constructData.js.scopeChain;
+
+ DynamicGlobalObjectScope globalObjectScope(*constructDataScopeChain->globalData, constructDataScopeChain->globalObject.get());
+
+ JSObject* compileError = constructData.js.functionExecutable->compileForConstruct(callFrame, constructDataScopeChain);
+ if (UNLIKELY(!!compileError)) {
+ m_registerFile.shrink(oldEnd);
+ return checkedReturn(throwError(callFrame, compileError));
+ }
+
+ CodeBlock* newCodeBlock = &constructData.js.functionExecutable->generatedBytecodeForConstruct();
+ newCallFrame = slideRegisterWindowForCall(newCodeBlock, &m_registerFile, newCallFrame, registerOffset, argCount);
+ if (UNLIKELY(!newCallFrame)) {
+ m_registerFile.shrink(oldEnd);
+ return checkedReturn(throwStackOverflowError(callFrame));
+ }
+
+ newCallFrame->init(newCodeBlock, 0, constructDataScopeChain, callFrame->addHostCallFrameFlag(), argCount, constructor);
+
+ Profiler** profiler = Profiler::enabledProfilerReference();
+ if (*profiler)
+ (*profiler)->willExecute(callFrame, constructor);
+
+ JSValue result;
+ {
+ SamplingTool::CallRecord callRecord(m_sampler.get());
+
+ m_reentryDepth++;
#if ENABLE(JIT)
-#if ENABLE(INTERPRETER)
- if (scopeChain->globalData->canUseJIT())
-#endif
- result = functionExecutable->jitCode(newCallFrame, scopeChain).execute(&m_registerFile, newCallFrame, scopeChain->globalData, exception);
-#if ENABLE(INTERPRETER)
- else
-#endif
-#endif
-#if ENABLE(INTERPRETER)
- result = privateExecute(Normal, &m_registerFile, newCallFrame, exception);
+ if (callFrame->globalData().canUseJIT())
+ result = constructData.js.functionExecutable->generatedJITCodeForConstruct().execute(&m_registerFile, newCallFrame, constructDataScopeChain->globalData);
+ else
#endif
- m_reentryDepth--;
+ result = privateExecute(Normal, &m_registerFile, newCallFrame);
+ m_reentryDepth--;
+ }
+
+ if (*profiler)
+ (*profiler)->didExecute(callFrame, constructor);
+
+ m_registerFile.shrink(oldEnd);
+ if (callFrame->hadException())
+ return 0;
+ ASSERT(result.isObject());
+ return checkedReturn(asObject(result));
}
+ ASSERT(constructType == ConstructTypeHost);
+ ScopeChainNode* scopeChain = callFrame->scopeChain();
+ newCallFrame = CallFrame::create(newCallFrame->registers() + registerOffset);
+ newCallFrame->init(0, 0, scopeChain, callFrame->addHostCallFrameFlag(), argCount, constructor);
+
+ DynamicGlobalObjectScope globalObjectScope(*scopeChain->globalData, scopeChain->globalObject.get());
+
+ Profiler** profiler = Profiler::enabledProfilerReference();
if (*profiler)
- (*profiler)->didExecute(callFrame, function);
+ (*profiler)->willExecute(callFrame, constructor);
+
+ JSValue result;
+ {
+ SamplingTool::HostCallRecord callRecord(m_sampler.get());
+ result = JSValue::decode(constructData.native.function(newCallFrame));
+ }
+
+ if (*profiler)
+ (*profiler)->didExecute(callFrame, constructor);
m_registerFile.shrink(oldEnd);
- return result;
+ if (callFrame->hadException())
+ return 0;
+ ASSERT(result.isObject());
+ return checkedReturn(asObject(result));
}
-CallFrameClosure Interpreter::prepareForRepeatCall(FunctionExecutable* FunctionExecutable, CallFrame* callFrame, JSFunction* function, int argCount, ScopeChainNode* scopeChain, JSValue* exception)
+CallFrameClosure Interpreter::prepareForRepeatCall(FunctionExecutable* FunctionExecutable, CallFrame* callFrame, JSFunction* function, int argCount, ScopeChainNode* scopeChain)
{
ASSERT(!scopeChain->globalData->exception);
if (m_reentryDepth >= MaxSmallThreadReentryDepth) {
if (m_reentryDepth >= callFrame->globalData().maxReentryDepth) {
- *exception = createStackOverflowError(callFrame);
+ throwStackOverflowError(callFrame);
return CallFrameClosure();
}
}
int argc = 1 + argCount; // implicit "this" parameter
if (!m_registerFile.grow(oldEnd + argc)) {
- *exception = createStackOverflowError(callFrame);
+ throwStackOverflowError(callFrame);
return CallFrameClosure();
}
CallFrame* newCallFrame = CallFrame::create(oldEnd);
+ // We initialise |this| unnecessarily here for the sake of code clarity
size_t dst = 0;
for (int i = 0; i < argc; ++i)
- newCallFrame->r(++dst) = jsUndefined();
+ newCallFrame->uncheckedR(dst++) = jsUndefined();
- CodeBlock* codeBlock = &FunctionExecutable->bytecode(callFrame, scopeChain);
+ JSObject* error = FunctionExecutable->compileForCall(callFrame, scopeChain);
+ if (error) {
+ throwError(callFrame, error);
+ m_registerFile.shrink(oldEnd);
+ return CallFrameClosure();
+ }
+ CodeBlock* codeBlock = &FunctionExecutable->generatedBytecodeForCall();
+
newCallFrame = slideRegisterWindowForCall(codeBlock, &m_registerFile, newCallFrame, argc + RegisterFile::CallFrameHeaderSize, argc);
if (UNLIKELY(!newCallFrame)) {
- *exception = createStackOverflowError(callFrame);
+ throwStackOverflowError(callFrame);
m_registerFile.shrink(oldEnd);
return CallFrameClosure();
}
- // a 0 codeBlock indicates a built-in caller
- newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), 0, argc, function);
-#if ENABLE(JIT)
-#if ENABLE(INTERPRETER)
- if (callFrame->globalData().canUseJIT())
-#endif
- FunctionExecutable->jitCode(newCallFrame, scopeChain);
-#endif
+ newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), argc, function);
CallFrameClosure result = { callFrame, newCallFrame, function, FunctionExecutable, scopeChain->globalData, oldEnd, scopeChain, codeBlock->m_numParameters, argc };
return result;
}
-JSValue Interpreter::execute(CallFrameClosure& closure, JSValue* exception)
+JSValue Interpreter::execute(CallFrameClosure& closure)
{
+ ASSERT(!closure.oldCallFrame->globalData().isCollectorBusy());
+ if (closure.oldCallFrame->globalData().isCollectorBusy())
+ return jsNull();
closure.resetCallFrame();
Profiler** profiler = Profiler::enabledProfilerReference();
if (*profiler)
#if ENABLE(INTERPRETER)
if (closure.newCallFrame->globalData().canUseJIT())
#endif
- result = closure.functionExecutable->generatedJITCode().execute(&m_registerFile, closure.newCallFrame, closure.globalData, exception);
+ result = closure.functionExecutable->generatedJITCodeForCall().execute(&m_registerFile, closure.newCallFrame, closure.globalData);
#if ENABLE(INTERPRETER)
else
#endif
#endif
#if ENABLE(INTERPRETER)
- result = privateExecute(Normal, &m_registerFile, closure.newCallFrame, exception);
+ result = privateExecute(Normal, &m_registerFile, closure.newCallFrame);
#endif
m_reentryDepth--;
}
if (*profiler)
(*profiler)->didExecute(closure.oldCallFrame, closure.function);
- return result;
+ return checkedReturn(result);
}
void Interpreter::endRepeatCall(CallFrameClosure& closure)
m_registerFile.shrink(closure.oldEnd);
}
-JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSObject* thisObj, ScopeChainNode* scopeChain, JSValue* exception)
+JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSObject* thisObj, ScopeChainNode* scopeChain)
{
- return execute(eval, callFrame, thisObj, m_registerFile.size() + eval->bytecode(callFrame, scopeChain).m_numParameters + RegisterFile::CallFrameHeaderSize, scopeChain, exception);
+ JSObject* compileError = eval->compile(callFrame, scopeChain);
+ if (UNLIKELY(!!compileError))
+ return checkedReturn(throwError(callFrame, compileError));
+ return execute(eval, callFrame, thisObj, m_registerFile.size() + eval->generatedBytecode().m_numParameters + RegisterFile::CallFrameHeaderSize, scopeChain);
}
-JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSObject* thisObj, int globalRegisterOffset, ScopeChainNode* scopeChain, JSValue* exception)
+JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSObject* thisObj, int globalRegisterOffset, ScopeChainNode* scopeChain)
{
ASSERT(!scopeChain->globalData->exception);
+ ASSERT(!callFrame->globalData().isCollectorBusy());
+ if (callFrame->globalData().isCollectorBusy())
+ return jsNull();
- if (m_reentryDepth >= MaxSmallThreadReentryDepth) {
- if (m_reentryDepth >= callFrame->globalData().maxReentryDepth) {
- *exception = createStackOverflowError(callFrame);
- return jsNull();
- }
- }
+ DynamicGlobalObjectScope globalObjectScope(*scopeChain->globalData, scopeChain->globalObject.get());
- DynamicGlobalObjectScope globalObjectScope(callFrame, scopeChain->globalObject);
+ if (m_reentryDepth >= MaxSmallThreadReentryDepth && m_reentryDepth >= callFrame->globalData().maxReentryDepth)
+ return checkedReturn(throwStackOverflowError(callFrame));
- EvalCodeBlock* codeBlock = &eval->bytecode(callFrame, scopeChain);
+ JSObject* compileError = eval->compile(callFrame, scopeChain);
+ if (UNLIKELY(!!compileError))
+ return checkedReturn(throwError(callFrame, compileError));
+ EvalCodeBlock* codeBlock = &eval->generatedBytecode();
- JSVariableObject* variableObject;
- for (ScopeChainNode* node = scopeChain; ; node = node->next) {
+ JSObject* variableObject;
+ for (ScopeChainNode* node = scopeChain; ; node = node->next.get()) {
ASSERT(node);
if (node->object->isVariableObject()) {
- variableObject = static_cast<JSVariableObject*>(node->object);
+ variableObject = static_cast<JSVariableObject*>(node->object.get());
break;
}
}
unsigned numVariables = codeBlock->numVariables();
int numFunctions = codeBlock->numberOfFunctionDecls();
+ bool pushedScope = false;
if (numVariables || numFunctions) {
+ if (codeBlock->isStrictMode()) {
+ variableObject = new (callFrame) StrictEvalActivation(callFrame);
+ scopeChain = scopeChain->push(variableObject);
+ pushedScope = true;
+ }
// Scope for BatchedTransitionOptimizer
- BatchedTransitionOptimizer optimizer(variableObject);
+ BatchedTransitionOptimizer optimizer(callFrame->globalData(), variableObject);
for (unsigned i = 0; i < numVariables; ++i) {
const Identifier& ident = codeBlock->variable(i);
Register* oldEnd = m_registerFile.end();
Register* newEnd = m_registerFile.start() + globalRegisterOffset + codeBlock->m_numCalleeRegisters;
if (!m_registerFile.grow(newEnd)) {
- *exception = createStackOverflowError(callFrame);
- return jsNull();
+ if (pushedScope)
+ scopeChain->pop();
+ return checkedReturn(throwStackOverflowError(callFrame));
}
CallFrame* newCallFrame = CallFrame::create(m_registerFile.start() + globalRegisterOffset);
- // a 0 codeBlock indicates a built-in caller
- newCallFrame->r(codeBlock->thisRegister()) = JSValue(thisObj);
- newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), 0, 0, 0);
-
- if (codeBlock->needsFullScopeChain())
- scopeChain->ref();
+ ASSERT(codeBlock->m_numParameters == 1); // 1 parameter for 'this'.
+ newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), codeBlock->m_numParameters, 0);
+ newCallFrame->uncheckedR(newCallFrame->hostThisRegister()) = JSValue(thisObj);
Profiler** profiler = Profiler::enabledProfilerReference();
if (*profiler)
- (*profiler)->willExecute(newCallFrame, eval->sourceURL(), eval->lineNo());
+ (*profiler)->willExecute(callFrame, eval->sourceURL(), eval->lineNo());
JSValue result;
{
#if ENABLE(INTERPRETER)
if (callFrame->globalData().canUseJIT())
#endif
- result = eval->jitCode(newCallFrame, scopeChain).execute(&m_registerFile, newCallFrame, scopeChain->globalData, exception);
+ result = eval->generatedJITCode().execute(&m_registerFile, newCallFrame, scopeChain->globalData);
#if ENABLE(INTERPRETER)
else
#endif
#endif
#if ENABLE(INTERPRETER)
- result = privateExecute(Normal, &m_registerFile, newCallFrame, exception);
+ result = privateExecute(Normal, &m_registerFile, newCallFrame);
#endif
m_reentryDepth--;
}
(*profiler)->didExecute(callFrame, eval->sourceURL(), eval->lineNo());
m_registerFile.shrink(oldEnd);
- return result;
+ if (pushedScope)
+ scopeChain->pop();
+ return checkedReturn(result);
}
NEVER_INLINE void Interpreter::debug(CallFrame* callFrame, DebugHookID debugHookID, int firstLine, int lastLine)
Identifier& property = codeBlock->identifier(vPC[2].u.operand);
JSValue value = callFrame->r(vPC[3].u.operand).jsValue();
JSObject* scope = new (callFrame) JSStaticScopeObject(callFrame, property, value, DontDelete);
- callFrame->r(dst) = JSValue(scope);
+ callFrame->uncheckedR(dst) = JSValue(scope);
return callFrame->scopeChain()->push(scope);
}
return;
}
- JSCell* baseCell = asCell(baseValue);
+ JSCell* baseCell = baseValue.asCell();
Structure* structure = baseCell->structure();
- if (structure->isUncacheableDictionary()) {
+ if (structure->isUncacheableDictionary() || structure->typeInfo().prohibitsPropertyCaching()) {
vPC[0] = getOpcode(op_put_by_id_generic);
return;
}
// Cache miss: record Structure to compare against next time.
- Structure* lastStructure = vPC[4].u.structure;
+ Structure* lastStructure = vPC[4].u.structure.get();
if (structure != lastStructure) {
// First miss: record Structure to compare against next time.
if (!lastStructure) {
- vPC[4] = structure;
+ vPC[4].u.structure.set(callFrame->globalData(), codeBlock->ownerExecutable(), structure);
return;
}
// put_by_id_transition checks the prototype chain for setters.
normalizePrototypeChain(callFrame, baseCell);
-
+ JSCell* owner = codeBlock->ownerExecutable();
+ JSGlobalData& globalData = callFrame->globalData();
+ // Get the prototype here because the call to prototypeChain could cause a
+ // GC allocation, which we don't want to happen while we're in the middle of
+ // initializing the union.
+ StructureChain* prototypeChain = structure->prototypeChain(callFrame);
vPC[0] = getOpcode(op_put_by_id_transition);
- vPC[4] = structure->previousID();
- vPC[5] = structure;
- vPC[6] = structure->prototypeChain(callFrame);
+ vPC[4].u.structure.set(globalData, owner, structure->previousID());
+ vPC[5].u.structure.set(globalData, owner, structure);
+ vPC[6].u.structureChain.set(callFrame->globalData(), codeBlock->ownerExecutable(), prototypeChain);
+ ASSERT(vPC[6].u.structureChain);
vPC[7] = slot.cachedOffset();
- codeBlock->refStructures(vPC);
return;
}
vPC[0] = getOpcode(op_put_by_id_replace);
vPC[5] = slot.cachedOffset();
- codeBlock->refStructures(vPC);
}
-NEVER_INLINE void Interpreter::uncachePutByID(CodeBlock* codeBlock, Instruction* vPC)
+NEVER_INLINE void Interpreter::uncachePutByID(CodeBlock*, Instruction* vPC)
{
- codeBlock->derefStructures(vPC);
vPC[0] = getOpcode(op_put_by_id);
vPC[4] = 0;
}
return;
}
- Structure* structure = asCell(baseValue)->structure();
+ Structure* structure = baseValue.asCell()->structure();
- if (structure->isUncacheableDictionary()) {
+ if (structure->isUncacheableDictionary() || structure->typeInfo().prohibitsPropertyCaching()) {
vPC[0] = getOpcode(op_get_by_id_generic);
return;
}
// Cache miss
- Structure* lastStructure = vPC[4].u.structure;
+ Structure* lastStructure = vPC[4].u.structure.get();
if (structure != lastStructure) {
// First miss: record Structure to compare against next time.
if (!lastStructure) {
- vPC[4] = structure;
+ vPC[4].u.structure.set(callFrame->globalData(), codeBlock->ownerExecutable(), structure);
return;
}
vPC[5] = slot.cachedOffset();
break;
}
-
- codeBlock->refStructures(vPC);
return;
}
// Since we're accessing a prototype in a loop, it's a good bet that it
// should not be treated as a dictionary.
if (baseObject->structure()->isDictionary()) {
- baseObject->flattenDictionaryObject();
- offset = baseObject->structure()->get(propertyName);
+ baseObject->flattenDictionaryObject(callFrame->globalData());
+ offset = baseObject->structure()->get(callFrame->globalData(), propertyName);
}
ASSERT(!baseObject->structure()->isUncacheableDictionary());
vPC[6] = offset;
break;
}
- vPC[5] = baseObject->structure();
-
- codeBlock->refStructures(vPC);
+ vPC[5].u.structure.set(callFrame->globalData(), codeBlock->ownerExecutable(), baseObject->structure());
return;
}
vPC[7] = offset;
break;
}
- vPC[4] = structure;
- vPC[5] = structure->prototypeChain(callFrame);
+ vPC[4].u.structure.set(callFrame->globalData(), codeBlock->ownerExecutable(), structure);
+ vPC[5].u.structureChain.set(callFrame->globalData(), codeBlock->ownerExecutable(), structure->prototypeChain(callFrame));
vPC[6] = count;
- codeBlock->refStructures(vPC);
}
-NEVER_INLINE void Interpreter::uncacheGetByID(CodeBlock* codeBlock, Instruction* vPC)
+NEVER_INLINE void Interpreter::uncacheGetByID(CodeBlock*, Instruction* vPC)
{
- codeBlock->derefStructures(vPC);
vPC[0] = getOpcode(op_get_by_id);
vPC[4] = 0;
}
#endif // ENABLE(INTERPRETER)
-JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFile, CallFrame* callFrame, JSValue* exception)
+JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFile, CallFrame* callFrame)
{
// One-time initialization of our address tables. We have to put this code
// here because our labels are only in scope inside this function.
#if ENABLE(COMPUTED_GOTO_INTERPRETER)
#define LIST_OPCODE_LABEL(id, length) &&id,
static Opcode labels[] = { FOR_EACH_OPCODE_ID(LIST_OPCODE_LABEL) };
- for (size_t i = 0; i < sizeof(labels) / sizeof(Opcode); ++i)
+ for (size_t i = 0; i < WTF_ARRAY_LENGTH(labels); ++i)
m_opcodeTable[i] = labels[i];
#undef LIST_OPCODE_LABEL
#endif // ENABLE(COMPUTED_GOTO_INTERPRETER)
#if !ENABLE(INTERPRETER)
UNUSED_PARAM(registerFile);
UNUSED_PARAM(callFrame);
- UNUSED_PARAM(exception);
return JSValue();
#else
JSValue exceptionValue;
HandlerInfo* handler = 0;
- Instruction* vPC = callFrame->codeBlock()->instructions().begin();
+ CodeBlock* codeBlock = callFrame->codeBlock();
+ Instruction* vPC = codeBlock->instructions().begin();
Profiler** enabledProfilerReference = Profiler::enabledProfilerReference();
unsigned tickCount = globalData->timeoutChecker.ticksUntilNextCheck();
+ JSValue functionReturnValue;
#define CHECK_FOR_EXCEPTION() \
do { \
#endif
#if ENABLE(COMPUTED_GOTO_INTERPRETER)
- #define NEXT_INSTRUCTION() SAMPLE(callFrame->codeBlock(), vPC); goto *vPC->u.opcode
+ #define NEXT_INSTRUCTION() SAMPLE(codeBlock, vPC); goto *vPC->u.opcode
#if ENABLE(OPCODE_STATS)
#define DEFINE_OPCODE(opcode) opcode: OpcodeStats::recordInstruction(opcode);
#else
#endif
NEXT_INSTRUCTION();
#else
- #define NEXT_INSTRUCTION() SAMPLE(callFrame->codeBlock(), vPC); goto interpreterLoopStart
+ #define NEXT_INSTRUCTION() SAMPLE(codeBlock, vPC); goto interpreterLoopStart
#if ENABLE(OPCODE_STATS)
#define DEFINE_OPCODE(opcode) case opcode: OpcodeStats::recordInstruction(opcode);
#else
constructor, and puts the result in register dst.
*/
int dst = vPC[1].u.operand;
- callFrame->r(dst) = JSValue(constructEmptyObject(callFrame));
+ callFrame->uncheckedR(dst) = JSValue(constructEmptyObject(callFrame));
vPC += OPCODE_LENGTH(op_new_object);
NEXT_INSTRUCTION();
int firstArg = vPC[2].u.operand;
int argCount = vPC[3].u.operand;
ArgList args(callFrame->registers() + firstArg, argCount);
- callFrame->r(dst) = JSValue(constructArray(callFrame, args));
+ callFrame->uncheckedR(dst) = JSValue(constructArray(callFrame, args));
vPC += OPCODE_LENGTH(op_new_array);
NEXT_INSTRUCTION();
}
+ DEFINE_OPCODE(op_new_array_buffer) {
+ /* new_array_buffer dst(r) index(n) argCount(n)
+
+ Constructs a new Array instance using the original
+ constructor, and puts the result in register dst.
+ The array be initialized with the values from constantBuffer[index]
+ */
+ int dst = vPC[1].u.operand;
+ int firstArg = vPC[2].u.operand;
+ int argCount = vPC[3].u.operand;
+ ArgList args(codeBlock->constantBuffer(firstArg), argCount);
+ callFrame->uncheckedR(dst) = JSValue(constructArray(callFrame, args));
+
+ vPC += OPCODE_LENGTH(op_new_array);
+ NEXT_INSTRUCTION();
+ }
DEFINE_OPCODE(op_new_regexp) {
/* new_regexp dst(r) regExp(re)
register dst.
*/
int dst = vPC[1].u.operand;
- int regExp = vPC[2].u.operand;
- callFrame->r(dst) = JSValue(new (globalData) RegExpObject(callFrame->scopeChain()->globalObject->regExpStructure(), callFrame->codeBlock()->regexp(regExp)));
+ RegExp* regExp = codeBlock->regexp(vPC[2].u.operand);
+ if (!regExp->isValid()) {
+ exceptionValue = createSyntaxError(callFrame, "Invalid flags supplied to RegExp constructor.");
+ goto vm_throw;
+ }
+ callFrame->uncheckedR(dst) = JSValue(new (globalData) RegExpObject(callFrame->lexicalGlobalObject(), callFrame->scopeChain()->globalObject->regExpStructure(), regExp));
vPC += OPCODE_LENGTH(op_new_regexp);
NEXT_INSTRUCTION();
*/
int dst = vPC[1].u.operand;
int src = vPC[2].u.operand;
- callFrame->r(dst) = callFrame->r(src);
+
+ callFrame->uncheckedR(dst) = callFrame->r(src);
vPC += OPCODE_LENGTH(op_mov);
NEXT_INSTRUCTION();
JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
if (src1.isInt32() && src2.isInt32())
- callFrame->r(dst) = jsBoolean(src1.asInt32() == src2.asInt32());
+ callFrame->uncheckedR(dst) = jsBoolean(src1.asInt32() == src2.asInt32());
else {
JSValue result = jsBoolean(JSValue::equalSlowCase(callFrame, src1, src2));
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
}
vPC += OPCODE_LENGTH(op_eq);
JSValue src = callFrame->r(vPC[2].u.operand).jsValue();
if (src.isUndefinedOrNull()) {
- callFrame->r(dst) = jsBoolean(true);
+ callFrame->uncheckedR(dst) = jsBoolean(true);
vPC += OPCODE_LENGTH(op_eq_null);
NEXT_INSTRUCTION();
}
- callFrame->r(dst) = jsBoolean(src.isCell() && src.asCell()->structure()->typeInfo().masqueradesAsUndefined());
+ callFrame->uncheckedR(dst) = jsBoolean(src.isCell() && src.asCell()->structure()->typeInfo().masqueradesAsUndefined());
vPC += OPCODE_LENGTH(op_eq_null);
NEXT_INSTRUCTION();
}
JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
if (src1.isInt32() && src2.isInt32())
- callFrame->r(dst) = jsBoolean(src1.asInt32() != src2.asInt32());
+ callFrame->uncheckedR(dst) = jsBoolean(src1.asInt32() != src2.asInt32());
else {
JSValue result = jsBoolean(!JSValue::equalSlowCase(callFrame, src1, src2));
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
}
vPC += OPCODE_LENGTH(op_neq);
JSValue src = callFrame->r(vPC[2].u.operand).jsValue();
if (src.isUndefinedOrNull()) {
- callFrame->r(dst) = jsBoolean(false);
+ callFrame->uncheckedR(dst) = jsBoolean(false);
vPC += OPCODE_LENGTH(op_neq_null);
NEXT_INSTRUCTION();
}
- callFrame->r(dst) = jsBoolean(!src.isCell() || !asCell(src)->structure()->typeInfo().masqueradesAsUndefined());
+ callFrame->uncheckedR(dst) = jsBoolean(!src.isCell() || !src.asCell()->structure()->typeInfo().masqueradesAsUndefined());
vPC += OPCODE_LENGTH(op_neq_null);
NEXT_INSTRUCTION();
}
JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
bool result = JSValue::strictEqual(callFrame, src1, src2);
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = jsBoolean(result);
+ callFrame->uncheckedR(dst) = jsBoolean(result);
vPC += OPCODE_LENGTH(op_stricteq);
NEXT_INSTRUCTION();
JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
bool result = !JSValue::strictEqual(callFrame, src1, src2);
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = jsBoolean(result);
+ callFrame->uncheckedR(dst) = jsBoolean(result);
vPC += OPCODE_LENGTH(op_nstricteq);
NEXT_INSTRUCTION();
JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
JSValue result = jsBoolean(jsLess(callFrame, src1, src2));
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
vPC += OPCODE_LENGTH(op_less);
NEXT_INSTRUCTION();
JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
JSValue result = jsBoolean(jsLessEq(callFrame, src1, src2));
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
vPC += OPCODE_LENGTH(op_lesseq);
NEXT_INSTRUCTION();
int srcDst = vPC[1].u.operand;
JSValue v = callFrame->r(srcDst).jsValue();
if (v.isInt32() && v.asInt32() < INT_MAX)
- callFrame->r(srcDst) = jsNumber(callFrame, v.asInt32() + 1);
+ callFrame->uncheckedR(srcDst) = jsNumber(v.asInt32() + 1);
else {
- JSValue result = jsNumber(callFrame, v.toNumber(callFrame) + 1);
+ JSValue result = jsNumber(v.toNumber(callFrame) + 1);
CHECK_FOR_EXCEPTION();
- callFrame->r(srcDst) = result;
+ callFrame->uncheckedR(srcDst) = result;
}
vPC += OPCODE_LENGTH(op_pre_inc);
int srcDst = vPC[1].u.operand;
JSValue v = callFrame->r(srcDst).jsValue();
if (v.isInt32() && v.asInt32() > INT_MIN)
- callFrame->r(srcDst) = jsNumber(callFrame, v.asInt32() - 1);
+ callFrame->uncheckedR(srcDst) = jsNumber(v.asInt32() - 1);
else {
- JSValue result = jsNumber(callFrame, v.toNumber(callFrame) - 1);
+ JSValue result = jsNumber(v.toNumber(callFrame) - 1);
CHECK_FOR_EXCEPTION();
- callFrame->r(srcDst) = result;
+ callFrame->uncheckedR(srcDst) = result;
}
vPC += OPCODE_LENGTH(op_pre_dec);
int srcDst = vPC[2].u.operand;
JSValue v = callFrame->r(srcDst).jsValue();
if (v.isInt32() && v.asInt32() < INT_MAX) {
- callFrame->r(srcDst) = jsNumber(callFrame, v.asInt32() + 1);
- callFrame->r(dst) = v;
+ callFrame->uncheckedR(srcDst) = jsNumber(v.asInt32() + 1);
+ callFrame->uncheckedR(dst) = v;
} else {
JSValue number = callFrame->r(srcDst).jsValue().toJSNumber(callFrame);
CHECK_FOR_EXCEPTION();
- callFrame->r(srcDst) = jsNumber(callFrame, number.uncheckedGetNumber() + 1);
- callFrame->r(dst) = number;
+ callFrame->uncheckedR(srcDst) = jsNumber(number.uncheckedGetNumber() + 1);
+ callFrame->uncheckedR(dst) = number;
}
vPC += OPCODE_LENGTH(op_post_inc);
int srcDst = vPC[2].u.operand;
JSValue v = callFrame->r(srcDst).jsValue();
if (v.isInt32() && v.asInt32() > INT_MIN) {
- callFrame->r(srcDst) = jsNumber(callFrame, v.asInt32() - 1);
- callFrame->r(dst) = v;
+ callFrame->uncheckedR(srcDst) = jsNumber(v.asInt32() - 1);
+ callFrame->uncheckedR(dst) = v;
} else {
JSValue number = callFrame->r(srcDst).jsValue().toJSNumber(callFrame);
CHECK_FOR_EXCEPTION();
- callFrame->r(srcDst) = jsNumber(callFrame, number.uncheckedGetNumber() - 1);
- callFrame->r(dst) = number;
+ callFrame->uncheckedR(srcDst) = jsNumber(number.uncheckedGetNumber() - 1);
+ callFrame->uncheckedR(dst) = number;
}
vPC += OPCODE_LENGTH(op_post_dec);
JSValue srcVal = callFrame->r(src).jsValue();
if (LIKELY(srcVal.isNumber()))
- callFrame->r(dst) = callFrame->r(src);
+ callFrame->uncheckedR(dst) = callFrame->r(src);
else {
JSValue result = srcVal.toJSNumber(callFrame);
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
}
vPC += OPCODE_LENGTH(op_to_jsnumber);
int dst = vPC[1].u.operand;
JSValue src = callFrame->r(vPC[2].u.operand).jsValue();
if (src.isInt32() && (src.asInt32() & 0x7fffffff)) // non-zero and no overflow
- callFrame->r(dst) = jsNumber(callFrame, -src.asInt32());
+ callFrame->uncheckedR(dst) = jsNumber(-src.asInt32());
else {
- JSValue result = jsNumber(callFrame, -src.toNumber(callFrame));
+ JSValue result = jsNumber(-src.toNumber(callFrame));
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
}
vPC += OPCODE_LENGTH(op_negate);
JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | (src2.asInt32() & 0xc0000000))) // no overflow
- callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() + src2.asInt32());
+ callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() + src2.asInt32());
else {
JSValue result = jsAdd(callFrame, src1, src2);
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
}
vPC += OPCODE_LENGTH(op_add);
NEXT_INSTRUCTION();
JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | src2.asInt32() >> 15)) // no overflow
- callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() * src2.asInt32());
+ callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() * src2.asInt32());
else {
- JSValue result = jsNumber(callFrame, src1.toNumber(callFrame) * src2.toNumber(callFrame));
+ JSValue result = jsNumber(src1.toNumber(callFrame) * src2.toNumber(callFrame));
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
}
vPC += OPCODE_LENGTH(op_mul);
JSValue dividend = callFrame->r(vPC[2].u.operand).jsValue();
JSValue divisor = callFrame->r(vPC[3].u.operand).jsValue();
- JSValue result = jsNumber(callFrame, dividend.toNumber(callFrame) / divisor.toNumber(callFrame));
+ JSValue result = jsNumber(dividend.toNumber(callFrame) / divisor.toNumber(callFrame));
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
vPC += OPCODE_LENGTH(op_div);
NEXT_INSTRUCTION();
JSValue divisor = callFrame->r(vPC[3].u.operand).jsValue();
if (dividend.isInt32() && divisor.isInt32() && divisor.asInt32() != 0) {
- JSValue result = jsNumber(callFrame, dividend.asInt32() % divisor.asInt32());
+ JSValue result = jsNumber(dividend.asInt32() % divisor.asInt32());
ASSERT(result);
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
vPC += OPCODE_LENGTH(op_mod);
NEXT_INSTRUCTION();
}
// order of argument evaluation is not guaranteed.
double d1 = dividend.toNumber(callFrame);
double d2 = divisor.toNumber(callFrame);
- JSValue result = jsNumber(callFrame, fmod(d1, d2));
+ JSValue result = jsNumber(fmod(d1, d2));
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
vPC += OPCODE_LENGTH(op_mod);
NEXT_INSTRUCTION();
}
JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | (src2.asInt32() & 0xc0000000))) // no overflow
- callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() - src2.asInt32());
+ callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() - src2.asInt32());
else {
- JSValue result = jsNumber(callFrame, src1.toNumber(callFrame) - src2.toNumber(callFrame));
+ JSValue result = jsNumber(src1.toNumber(callFrame) - src2.toNumber(callFrame));
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
}
vPC += OPCODE_LENGTH(op_sub);
NEXT_INSTRUCTION();
JSValue shift = callFrame->r(vPC[3].u.operand).jsValue();
if (val.isInt32() && shift.isInt32())
- callFrame->r(dst) = jsNumber(callFrame, val.asInt32() << (shift.asInt32() & 0x1f));
+ callFrame->uncheckedR(dst) = jsNumber(val.asInt32() << (shift.asInt32() & 0x1f));
else {
- JSValue result = jsNumber(callFrame, (val.toInt32(callFrame)) << (shift.toUInt32(callFrame) & 0x1f));
+ JSValue result = jsNumber((val.toInt32(callFrame)) << (shift.toUInt32(callFrame) & 0x1f));
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
}
vPC += OPCODE_LENGTH(op_lshift);
JSValue shift = callFrame->r(vPC[3].u.operand).jsValue();
if (val.isInt32() && shift.isInt32())
- callFrame->r(dst) = jsNumber(callFrame, val.asInt32() >> (shift.asInt32() & 0x1f));
+ callFrame->uncheckedR(dst) = jsNumber(val.asInt32() >> (shift.asInt32() & 0x1f));
else {
- JSValue result = jsNumber(callFrame, (val.toInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f));
+ JSValue result = jsNumber((val.toInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f));
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
}
vPC += OPCODE_LENGTH(op_rshift);
JSValue val = callFrame->r(vPC[2].u.operand).jsValue();
JSValue shift = callFrame->r(vPC[3].u.operand).jsValue();
if (val.isUInt32() && shift.isInt32())
- callFrame->r(dst) = jsNumber(callFrame, val.asInt32() >> (shift.asInt32() & 0x1f));
+ callFrame->uncheckedR(dst) = jsNumber(val.asInt32() >> (shift.asInt32() & 0x1f));
else {
- JSValue result = jsNumber(callFrame, (val.toUInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f));
+ JSValue result = jsNumber((val.toUInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f));
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
}
vPC += OPCODE_LENGTH(op_urshift);
JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
if (src1.isInt32() && src2.isInt32())
- callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() & src2.asInt32());
+ callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() & src2.asInt32());
else {
- JSValue result = jsNumber(callFrame, src1.toInt32(callFrame) & src2.toInt32(callFrame));
+ JSValue result = jsNumber(src1.toInt32(callFrame) & src2.toInt32(callFrame));
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
}
vPC += OPCODE_LENGTH(op_bitand);
JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
if (src1.isInt32() && src2.isInt32())
- callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() ^ src2.asInt32());
+ callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() ^ src2.asInt32());
else {
- JSValue result = jsNumber(callFrame, src1.toInt32(callFrame) ^ src2.toInt32(callFrame));
+ JSValue result = jsNumber(src1.toInt32(callFrame) ^ src2.toInt32(callFrame));
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
}
vPC += OPCODE_LENGTH(op_bitxor);
JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
if (src1.isInt32() && src2.isInt32())
- callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() | src2.asInt32());
+ callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() | src2.asInt32());
else {
- JSValue result = jsNumber(callFrame, src1.toInt32(callFrame) | src2.toInt32(callFrame));
+ JSValue result = jsNumber(src1.toInt32(callFrame) | src2.toInt32(callFrame));
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
}
vPC += OPCODE_LENGTH(op_bitor);
int dst = vPC[1].u.operand;
JSValue src = callFrame->r(vPC[2].u.operand).jsValue();
if (src.isInt32())
- callFrame->r(dst) = jsNumber(callFrame, ~src.asInt32());
+ callFrame->uncheckedR(dst) = jsNumber(~src.asInt32());
else {
- JSValue result = jsNumber(callFrame, ~src.toInt32(callFrame));
+ JSValue result = jsNumber(~src.toInt32(callFrame));
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
}
vPC += OPCODE_LENGTH(op_bitnot);
NEXT_INSTRUCTION();
int src = vPC[2].u.operand;
JSValue result = jsBoolean(!callFrame->r(src).jsValue().toBoolean(callFrame));
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
vPC += OPCODE_LENGTH(op_not);
NEXT_INSTRUCTION();
}
+ DEFINE_OPCODE(op_check_has_instance) {
+ /* check_has_instance constructor(r)
+
+ Check 'constructor' is an object with the internal property
+ [HasInstance] (i.e. is a function ... *shakes head sadly at
+ JSC API*). Raises an exception if register constructor is not
+ an valid parameter for instanceof.
+ */
+ int base = vPC[1].u.operand;
+ JSValue baseVal = callFrame->r(base).jsValue();
+
+ if (isInvalidParamForInstanceOf(callFrame, baseVal, exceptionValue))
+ goto vm_throw;
+
+ vPC += OPCODE_LENGTH(op_check_has_instance);
+ NEXT_INSTRUCTION();
+ }
DEFINE_OPCODE(op_instanceof) {
/* instanceof dst(r) value(r) constructor(r) constructorProto(r)
JSValue baseVal = callFrame->r(base).jsValue();
- if (isInvalidParamForInstanceOf(callFrame, callFrame->codeBlock(), vPC, baseVal, exceptionValue))
- goto vm_throw;
+ ASSERT(!isInvalidParamForInstanceOf(callFrame, baseVal, exceptionValue));
bool result = asObject(baseVal)->hasInstance(callFrame, callFrame->r(value).jsValue(), callFrame->r(baseProto).jsValue());
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = jsBoolean(result);
+ callFrame->uncheckedR(dst) = jsBoolean(result);
vPC += OPCODE_LENGTH(op_instanceof);
NEXT_INSTRUCTION();
*/
int dst = vPC[1].u.operand;
int src = vPC[2].u.operand;
- callFrame->r(dst) = JSValue(jsTypeStringForValue(callFrame, callFrame->r(src).jsValue()));
+ callFrame->uncheckedR(dst) = JSValue(jsTypeStringForValue(callFrame, callFrame->r(src).jsValue()));
vPC += OPCODE_LENGTH(op_typeof);
NEXT_INSTRUCTION();
int dst = vPC[1].u.operand;
int src = vPC[2].u.operand;
JSValue v = callFrame->r(src).jsValue();
- callFrame->r(dst) = jsBoolean(v.isCell() ? v.asCell()->structure()->typeInfo().masqueradesAsUndefined() : v.isUndefined());
+ callFrame->uncheckedR(dst) = jsBoolean(v.isCell() ? v.asCell()->structure()->typeInfo().masqueradesAsUndefined() : v.isUndefined());
vPC += OPCODE_LENGTH(op_is_undefined);
NEXT_INSTRUCTION();
*/
int dst = vPC[1].u.operand;
int src = vPC[2].u.operand;
- callFrame->r(dst) = jsBoolean(callFrame->r(src).jsValue().isBoolean());
+ callFrame->uncheckedR(dst) = jsBoolean(callFrame->r(src).jsValue().isBoolean());
vPC += OPCODE_LENGTH(op_is_boolean);
NEXT_INSTRUCTION();
*/
int dst = vPC[1].u.operand;
int src = vPC[2].u.operand;
- callFrame->r(dst) = jsBoolean(callFrame->r(src).jsValue().isNumber());
+ callFrame->uncheckedR(dst) = jsBoolean(callFrame->r(src).jsValue().isNumber());
vPC += OPCODE_LENGTH(op_is_number);
NEXT_INSTRUCTION();
*/
int dst = vPC[1].u.operand;
int src = vPC[2].u.operand;
- callFrame->r(dst) = jsBoolean(callFrame->r(src).jsValue().isString());
+ callFrame->uncheckedR(dst) = jsBoolean(callFrame->r(src).jsValue().isString());
vPC += OPCODE_LENGTH(op_is_string);
NEXT_INSTRUCTION();
*/
int dst = vPC[1].u.operand;
int src = vPC[2].u.operand;
- callFrame->r(dst) = jsBoolean(jsIsObjectType(callFrame->r(src).jsValue()));
+ callFrame->uncheckedR(dst) = jsBoolean(jsIsObjectType(callFrame->r(src).jsValue()));
vPC += OPCODE_LENGTH(op_is_object);
NEXT_INSTRUCTION();
*/
int dst = vPC[1].u.operand;
int src = vPC[2].u.operand;
- callFrame->r(dst) = jsBoolean(jsIsFunctionType(callFrame->r(src).jsValue()));
+ callFrame->uncheckedR(dst) = jsBoolean(jsIsFunctionType(callFrame->r(src).jsValue()));
vPC += OPCODE_LENGTH(op_is_function);
NEXT_INSTRUCTION();
int base = vPC[3].u.operand;
JSValue baseVal = callFrame->r(base).jsValue();
- if (isInvalidParamForIn(callFrame, callFrame->codeBlock(), vPC, baseVal, exceptionValue))
+ if (isInvalidParamForIn(callFrame, baseVal, exceptionValue))
goto vm_throw;
JSObject* baseObj = asObject(baseVal);
uint32_t i;
if (propName.getUInt32(i))
- callFrame->r(dst) = jsBoolean(baseObj->hasProperty(callFrame, i));
+ callFrame->uncheckedR(dst) = jsBoolean(baseObj->hasProperty(callFrame, i));
else {
Identifier property(callFrame, propName.toString(callFrame));
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = jsBoolean(baseObj->hasProperty(callFrame, property));
+ callFrame->uncheckedR(dst) = jsBoolean(baseObj->hasProperty(callFrame, property));
}
vPC += OPCODE_LENGTH(op_in);
Gets the global var at global slot index and places it in register dst.
*/
int dst = vPC[1].u.operand;
- JSGlobalObject* scope = static_cast<JSGlobalObject*>(vPC[2].u.jsCell);
+ JSGlobalObject* scope = codeBlock->globalObject();
ASSERT(scope->isGlobalObject());
- int index = vPC[3].u.operand;
+ int index = vPC[2].u.operand;
- callFrame->r(dst) = scope->registerAt(index);
+ callFrame->uncheckedR(dst) = scope->registerAt(index).get();
vPC += OPCODE_LENGTH(op_get_global_var);
NEXT_INSTRUCTION();
}
Puts value into global slot index.
*/
- JSGlobalObject* scope = static_cast<JSGlobalObject*>(vPC[1].u.jsCell);
+ JSGlobalObject* scope = codeBlock->globalObject();
ASSERT(scope->isGlobalObject());
- int index = vPC[2].u.operand;
- int value = vPC[3].u.operand;
+ int index = vPC[1].u.operand;
+ int value = vPC[2].u.operand;
- scope->registerAt(index) = JSValue(callFrame->r(value).jsValue());
+ scope->registerAt(index).set(*globalData, scope, callFrame->r(value).jsValue());
vPC += OPCODE_LENGTH(op_put_global_var);
NEXT_INSTRUCTION();
}
/* get_scoped_var dst(r) index(n) skip(n)
Loads the contents of the index-th local from the scope skip nodes from
- the top of the scope chain, and places it in register dst
+ the top of the scope chain, and places it in register dst.
*/
int dst = vPC[1].u.operand;
int index = vPC[2].u.operand;
- int skip = vPC[3].u.operand + callFrame->codeBlock()->needsFullScopeChain();
+ int skip = vPC[3].u.operand;
ScopeChainNode* scopeChain = callFrame->scopeChain();
ScopeChainIterator iter = scopeChain->begin();
ScopeChainIterator end = scopeChain->end();
ASSERT(iter != end);
+ ASSERT(codeBlock == callFrame->codeBlock());
+ bool checkTopLevel = codeBlock->codeType() == FunctionCode && codeBlock->needsFullScopeChain();
+ ASSERT(skip || !checkTopLevel);
+ if (checkTopLevel && skip--) {
+ if (callFrame->r(codeBlock->activationRegister()).jsValue())
+ ++iter;
+ }
while (skip--) {
++iter;
ASSERT(iter != end);
}
ASSERT((*iter)->isVariableObject());
- JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
- callFrame->r(dst) = scope->registerAt(index);
+ JSVariableObject* scope = static_cast<JSVariableObject*>(iter->get());
+ callFrame->uncheckedR(dst) = scope->registerAt(index).get();
+ ASSERT(callFrame->r(dst).jsValue());
vPC += OPCODE_LENGTH(op_get_scoped_var);
NEXT_INSTRUCTION();
}
*/
int index = vPC[1].u.operand;
- int skip = vPC[2].u.operand + callFrame->codeBlock()->needsFullScopeChain();
+ int skip = vPC[2].u.operand;
int value = vPC[3].u.operand;
ScopeChainNode* scopeChain = callFrame->scopeChain();
ScopeChainIterator iter = scopeChain->begin();
ScopeChainIterator end = scopeChain->end();
+ ASSERT(codeBlock == callFrame->codeBlock());
ASSERT(iter != end);
+ bool checkTopLevel = codeBlock->codeType() == FunctionCode && codeBlock->needsFullScopeChain();
+ ASSERT(skip || !checkTopLevel);
+ if (checkTopLevel && skip--) {
+ if (callFrame->r(codeBlock->activationRegister()).jsValue())
+ ++iter;
+ }
while (skip--) {
++iter;
ASSERT(iter != end);
}
ASSERT((*iter)->isVariableObject());
- JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
- scope->registerAt(index) = JSValue(callFrame->r(value).jsValue());
+ JSVariableObject* scope = static_cast<JSVariableObject*>(iter->get());
+ ASSERT(callFrame->r(value).jsValue());
+ scope->registerAt(index).set(*globalData, scope, callFrame->r(value).jsValue());
vPC += OPCODE_LENGTH(op_put_scoped_var);
NEXT_INSTRUCTION();
}
DEFINE_OPCODE(op_resolve_base) {
- /* resolve_base dst(r) property(id)
+ /* resolve_base dst(r) property(id) isStrict(bool)
Searches the scope chain for an object containing
identifier property, and if one is found, writes it to
- register dst. If none is found, the outermost scope (which
- will be the global object) is stored in register dst.
+ register dst. If none is found and isStrict is false, the
+ outermost scope (which will be the global object) is
+ stored in register dst.
*/
resolveBase(callFrame, vPC);
+ CHECK_FOR_EXCEPTION();
vPC += OPCODE_LENGTH(op_resolve_base);
NEXT_INSTRUCTION();
}
+ DEFINE_OPCODE(op_ensure_property_exists) {
+ /* ensure_property_exists base(r) property(id)
+
+ Throws an exception if property does not exist on base
+ */
+ int base = vPC[1].u.operand;
+ int property = vPC[2].u.operand;
+ Identifier& ident = codeBlock->identifier(property);
+
+ JSValue baseVal = callFrame->r(base).jsValue();
+ JSObject* baseObject = asObject(baseVal);
+ PropertySlot slot(baseVal);
+ if (!baseObject->getPropertySlot(callFrame, ident, slot)) {
+ exceptionValue = createErrorForInvalidGlobalAssignment(callFrame, ident.ustring());
+ goto vm_throw;
+ }
+
+ vPC += OPCODE_LENGTH(op_ensure_property_exists);
+ NEXT_INSTRUCTION();
+ }
DEFINE_OPCODE(op_resolve_with_base) {
/* resolve_with_base baseDst(r) propDst(r) property(id)
int base = vPC[2].u.operand;
int property = vPC[3].u.operand;
- CodeBlock* codeBlock = callFrame->codeBlock();
Identifier& ident = codeBlock->identifier(property);
JSValue baseValue = callFrame->r(base).jsValue();
PropertySlot slot(baseValue);
tryCacheGetByID(callFrame, codeBlock, vPC, baseValue, ident, slot);
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
vPC += OPCODE_LENGTH(op_get_by_id);
NEXT_INSTRUCTION();
}
JSValue baseValue = callFrame->r(base).jsValue();
if (LIKELY(baseValue.isCell())) {
- JSCell* baseCell = asCell(baseValue);
- Structure* structure = vPC[4].u.structure;
+ JSCell* baseCell = baseValue.asCell();
+ Structure* structure = vPC[4].u.structure.get();
if (LIKELY(baseCell->structure() == structure)) {
ASSERT(baseCell->isObject());
int dst = vPC[1].u.operand;
int offset = vPC[5].u.operand;
- ASSERT(baseObject->get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));
- callFrame->r(dst) = JSValue(baseObject->getDirectOffset(offset));
+ ASSERT(baseObject->get(callFrame, codeBlock->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));
+ callFrame->uncheckedR(dst) = JSValue(baseObject->getDirectOffset(offset));
vPC += OPCODE_LENGTH(op_get_by_id_self);
NEXT_INSTRUCTION();
}
}
- uncacheGetByID(callFrame->codeBlock(), vPC);
+ uncacheGetByID(codeBlock, vPC);
NEXT_INSTRUCTION();
}
DEFINE_OPCODE(op_get_by_id_proto) {
JSValue baseValue = callFrame->r(base).jsValue();
if (LIKELY(baseValue.isCell())) {
- JSCell* baseCell = asCell(baseValue);
- Structure* structure = vPC[4].u.structure;
+ JSCell* baseCell = baseValue.asCell();
+ Structure* structure = vPC[4].u.structure.get();
if (LIKELY(baseCell->structure() == structure)) {
ASSERT(structure->prototypeForLookup(callFrame).isObject());
JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));
- Structure* prototypeStructure = vPC[5].u.structure;
+ Structure* prototypeStructure = vPC[5].u.structure.get();
if (LIKELY(protoObject->structure() == prototypeStructure)) {
int dst = vPC[1].u.operand;
int offset = vPC[6].u.operand;
- ASSERT(protoObject->get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == protoObject->getDirectOffset(offset));
- ASSERT(baseValue.get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == protoObject->getDirectOffset(offset));
- callFrame->r(dst) = JSValue(protoObject->getDirectOffset(offset));
+ ASSERT(protoObject->get(callFrame, codeBlock->identifier(vPC[3].u.operand)) == protoObject->getDirectOffset(offset));
+ ASSERT(baseValue.get(callFrame, codeBlock->identifier(vPC[3].u.operand)) == protoObject->getDirectOffset(offset));
+ callFrame->uncheckedR(dst) = JSValue(protoObject->getDirectOffset(offset));
vPC += OPCODE_LENGTH(op_get_by_id_proto);
NEXT_INSTRUCTION();
}
}
- uncacheGetByID(callFrame->codeBlock(), vPC);
+ uncacheGetByID(codeBlock, vPC);
NEXT_INSTRUCTION();
}
#if USE(GCC_COMPUTED_GOTO_WORKAROUND)
JSValue baseValue = callFrame->r(base).jsValue();
if (LIKELY(baseValue.isCell())) {
- JSCell* baseCell = asCell(baseValue);
- Structure* structure = vPC[4].u.structure;
+ JSCell* baseCell = baseValue.asCell();
+ Structure* structure = vPC[4].u.structure.get();
if (LIKELY(baseCell->structure() == structure)) {
ASSERT(structure->prototypeForLookup(callFrame).isObject());
JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));
- Structure* prototypeStructure = vPC[5].u.structure;
+ Structure* prototypeStructure = vPC[5].u.structure.get();
if (LIKELY(protoObject->structure() == prototypeStructure)) {
int dst = vPC[1].u.operand;
CallType callType = getter->getCallData(callData);
JSValue result = call(callFrame, getter, callType, callData, asObject(baseCell), ArgList());
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
} else
- callFrame->r(dst) = jsUndefined();
+ callFrame->uncheckedR(dst) = jsUndefined();
vPC += OPCODE_LENGTH(op_get_by_id_getter_proto);
NEXT_INSTRUCTION();
}
}
}
- uncacheGetByID(callFrame->codeBlock(), vPC);
+ uncacheGetByID(codeBlock, vPC);
NEXT_INSTRUCTION();
}
#if USE(GCC_COMPUTED_GOTO_WORKAROUND)
JSValue baseValue = callFrame->r(base).jsValue();
if (LIKELY(baseValue.isCell())) {
- JSCell* baseCell = asCell(baseValue);
- Structure* structure = vPC[4].u.structure;
+ JSCell* baseCell = baseValue.asCell();
+ Structure* structure = vPC[4].u.structure.get();
if (LIKELY(baseCell->structure() == structure)) {
ASSERT(structure->prototypeForLookup(callFrame).isObject());
JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));
- Structure* prototypeStructure = vPC[5].u.structure;
+ Structure* prototypeStructure = vPC[5].u.structure.get();
if (LIKELY(protoObject->structure() == prototypeStructure)) {
int dst = vPC[1].u.operand;
int property = vPC[3].u.operand;
- Identifier& ident = callFrame->codeBlock()->identifier(property);
+ Identifier& ident = codeBlock->identifier(property);
PropertySlot::GetValueFunc getter = vPC[6].u.getterFunc;
JSValue result = getter(callFrame, protoObject, ident);
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
vPC += OPCODE_LENGTH(op_get_by_id_custom_proto);
NEXT_INSTRUCTION();
}
}
}
- uncacheGetByID(callFrame->codeBlock(), vPC);
+ uncacheGetByID(codeBlock, vPC);
NEXT_INSTRUCTION();
}
#if USE(GCC_COMPUTED_GOTO_WORKAROUND)
vPC += OPCODE_LENGTH(op_get_by_id_proto_list);
NEXT_INSTRUCTION();
}
+#if USE(GCC_COMPUTED_GOTO_WORKAROUND)
+ goto *(&&skip_get_by_id_chain);
+#endif
DEFINE_OPCODE(op_get_by_id_chain) {
/* op_get_by_id_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n)
JSValue baseValue = callFrame->r(base).jsValue();
if (LIKELY(baseValue.isCell())) {
- JSCell* baseCell = asCell(baseValue);
- Structure* structure = vPC[4].u.structure;
+ JSCell* baseCell = baseValue.asCell();
+ Structure* structure = vPC[4].u.structure.get();
if (LIKELY(baseCell->structure() == structure)) {
- RefPtr<Structure>* it = vPC[5].u.structureChain->head();
+ WriteBarrier<Structure>* it = vPC[5].u.structureChain->head();
size_t count = vPC[6].u.operand;
- RefPtr<Structure>* end = it + count;
+ WriteBarrier<Structure>* end = it + count;
while (true) {
JSObject* baseObject = asObject(baseCell->structure()->prototypeForLookup(callFrame));
int dst = vPC[1].u.operand;
int offset = vPC[7].u.operand;
- ASSERT(baseObject->get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));
- ASSERT(baseValue.get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));
- callFrame->r(dst) = JSValue(baseObject->getDirectOffset(offset));
+ ASSERT(baseObject->get(callFrame, codeBlock->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));
+ ASSERT(baseValue.get(callFrame, codeBlock->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));
+ callFrame->uncheckedR(dst) = JSValue(baseObject->getDirectOffset(offset));
vPC += OPCODE_LENGTH(op_get_by_id_chain);
NEXT_INSTRUCTION();
}
}
- uncacheGetByID(callFrame->codeBlock(), vPC);
+ uncacheGetByID(codeBlock, vPC);
NEXT_INSTRUCTION();
}
#if USE(GCC_COMPUTED_GOTO_WORKAROUND)
+ skip_get_by_id_chain:
goto *(&&skip_id_getter_self);
#endif
DEFINE_OPCODE(op_get_by_id_getter_self) {
JSValue baseValue = callFrame->r(base).jsValue();
if (LIKELY(baseValue.isCell())) {
- JSCell* baseCell = asCell(baseValue);
- Structure* structure = vPC[4].u.structure;
+ JSCell* baseCell = baseValue.asCell();
+ Structure* structure = vPC[4].u.structure.get();
if (LIKELY(baseCell->structure() == structure)) {
ASSERT(baseCell->isObject());
CallType callType = getter->getCallData(callData);
JSValue result = call(callFrame, getter, callType, callData, baseObject, ArgList());
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
} else
- callFrame->r(dst) = jsUndefined();
+ callFrame->uncheckedR(dst) = jsUndefined();
vPC += OPCODE_LENGTH(op_get_by_id_getter_self);
NEXT_INSTRUCTION();
}
}
- uncacheGetByID(callFrame->codeBlock(), vPC);
+ uncacheGetByID(codeBlock, vPC);
NEXT_INSTRUCTION();
}
#if USE(GCC_COMPUTED_GOTO_WORKAROUND)
JSValue baseValue = callFrame->r(base).jsValue();
if (LIKELY(baseValue.isCell())) {
- JSCell* baseCell = asCell(baseValue);
- Structure* structure = vPC[4].u.structure;
+ JSCell* baseCell = baseValue.asCell();
+ Structure* structure = vPC[4].u.structure.get();
if (LIKELY(baseCell->structure() == structure)) {
ASSERT(baseCell->isObject());
int dst = vPC[1].u.operand;
int property = vPC[3].u.operand;
- Identifier& ident = callFrame->codeBlock()->identifier(property);
+ Identifier& ident = codeBlock->identifier(property);
PropertySlot::GetValueFunc getter = vPC[5].u.getterFunc;
JSValue result = getter(callFrame, baseValue, ident);
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
vPC += OPCODE_LENGTH(op_get_by_id_custom_self);
NEXT_INSTRUCTION();
}
}
- uncacheGetByID(callFrame->codeBlock(), vPC);
+ uncacheGetByID(codeBlock, vPC);
NEXT_INSTRUCTION();
}
#if USE(GCC_COMPUTED_GOTO_WORKAROUND)
int base = vPC[2].u.operand;
int property = vPC[3].u.operand;
- Identifier& ident = callFrame->codeBlock()->identifier(property);
+ Identifier& ident = codeBlock->identifier(property);
JSValue baseValue = callFrame->r(base).jsValue();
PropertySlot slot(baseValue);
JSValue result = baseValue.get(callFrame, ident, slot);
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
vPC += OPCODE_LENGTH(op_get_by_id_generic);
NEXT_INSTRUCTION();
}
JSValue baseValue = callFrame->r(base).jsValue();
if (LIKELY(baseValue.isCell())) {
- JSCell* baseCell = asCell(baseValue);
- Structure* structure = vPC[4].u.structure;
+ JSCell* baseCell = baseValue.asCell();
+ Structure* structure = vPC[4].u.structure.get();
if (LIKELY(baseCell->structure() == structure)) {
- RefPtr<Structure>* it = vPC[5].u.structureChain->head();
+ WriteBarrier<Structure>* it = vPC[5].u.structureChain->head();
size_t count = vPC[6].u.operand;
- RefPtr<Structure>* end = it + count;
+ WriteBarrier<Structure>* end = it + count;
while (true) {
JSObject* baseObject = asObject(baseCell->structure()->prototypeForLookup(callFrame));
CallType callType = getter->getCallData(callData);
JSValue result = call(callFrame, getter, callType, callData, baseValue, ArgList());
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
} else
- callFrame->r(dst) = jsUndefined();
+ callFrame->uncheckedR(dst) = jsUndefined();
vPC += OPCODE_LENGTH(op_get_by_id_getter_chain);
NEXT_INSTRUCTION();
}
}
}
}
- uncacheGetByID(callFrame->codeBlock(), vPC);
+ uncacheGetByID(codeBlock, vPC);
NEXT_INSTRUCTION();
}
#if USE(GCC_COMPUTED_GOTO_WORKAROUND)
JSValue baseValue = callFrame->r(base).jsValue();
if (LIKELY(baseValue.isCell())) {
- JSCell* baseCell = asCell(baseValue);
- Structure* structure = vPC[4].u.structure;
+ JSCell* baseCell = baseValue.asCell();
+ Structure* structure = vPC[4].u.structure.get();
if (LIKELY(baseCell->structure() == structure)) {
- RefPtr<Structure>* it = vPC[5].u.structureChain->head();
+ WriteBarrier<Structure>* it = vPC[5].u.structureChain->head();
size_t count = vPC[6].u.operand;
- RefPtr<Structure>* end = it + count;
+ WriteBarrier<Structure>* end = it + count;
while (true) {
JSObject* baseObject = asObject(baseCell->structure()->prototypeForLookup(callFrame));
if (++it == end) {
int dst = vPC[1].u.operand;
int property = vPC[3].u.operand;
- Identifier& ident = callFrame->codeBlock()->identifier(property);
+ Identifier& ident = codeBlock->identifier(property);
PropertySlot::GetValueFunc getter = vPC[7].u.getterFunc;
JSValue result = getter(callFrame, baseObject, ident);
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
vPC += OPCODE_LENGTH(op_get_by_id_custom_chain);
NEXT_INSTRUCTION();
}
}
}
}
- uncacheGetByID(callFrame->codeBlock(), vPC);
+ uncacheGetByID(codeBlock, vPC);
NEXT_INSTRUCTION();
}
#if USE(GCC_COMPUTED_GOTO_WORKAROUND)
skip_id_custom_chain:
+ goto *(&&skip_get_array_length);
#endif
DEFINE_OPCODE(op_get_array_length) {
/* op_get_array_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
JSValue baseValue = callFrame->r(base).jsValue();
if (LIKELY(isJSArray(globalData, baseValue))) {
int dst = vPC[1].u.operand;
- callFrame->r(dst) = jsNumber(callFrame, asArray(baseValue)->length());
+ callFrame->uncheckedR(dst) = jsNumber(asArray(baseValue)->length());
vPC += OPCODE_LENGTH(op_get_array_length);
NEXT_INSTRUCTION();
}
- uncacheGetByID(callFrame->codeBlock(), vPC);
+ uncacheGetByID(codeBlock, vPC);
NEXT_INSTRUCTION();
}
+#if USE(GCC_COMPUTED_GOTO_WORKAROUND)
+ skip_get_array_length:
+ goto *(&&skip_get_string_length);
+#endif
DEFINE_OPCODE(op_get_string_length) {
/* op_get_string_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
JSValue baseValue = callFrame->r(base).jsValue();
if (LIKELY(isJSString(globalData, baseValue))) {
int dst = vPC[1].u.operand;
- callFrame->r(dst) = jsNumber(callFrame, asString(baseValue)->length());
+ callFrame->uncheckedR(dst) = jsNumber(asString(baseValue)->length());
vPC += OPCODE_LENGTH(op_get_string_length);
NEXT_INSTRUCTION();
}
- uncacheGetByID(callFrame->codeBlock(), vPC);
+ uncacheGetByID(codeBlock, vPC);
NEXT_INSTRUCTION();
}
+#if USE(GCC_COMPUTED_GOTO_WORKAROUND)
+ skip_get_string_length:
+ goto *(&&skip_put_by_id);
+#endif
DEFINE_OPCODE(op_put_by_id) {
/* put_by_id base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n) direct(b)
Unlike many opcodes, this one does not write any output to
the register file.
-
+
The "direct" flag should only be set this put_by_id is to initialize
an object literal.
*/
int value = vPC[3].u.operand;
int direct = vPC[8].u.operand;
- CodeBlock* codeBlock = callFrame->codeBlock();
JSValue baseValue = callFrame->r(base).jsValue();
Identifier& ident = codeBlock->identifier(property);
- PutPropertySlot slot;
+ PutPropertySlot slot(codeBlock->isStrictMode());
if (direct) {
baseValue.putDirect(callFrame, ident, callFrame->r(value).jsValue(), slot);
ASSERT(slot.base() == baseValue);
vPC += OPCODE_LENGTH(op_put_by_id);
NEXT_INSTRUCTION();
}
+#if USE(GCC_COMPUTED_GOTO_WORKAROUND)
+ skip_put_by_id:
+#endif
DEFINE_OPCODE(op_put_by_id_transition) {
/* op_put_by_id_transition base(r) property(id) value(r) oldStructure(sID) newStructure(sID) structureChain(chain) offset(n) direct(b)
JSValue baseValue = callFrame->r(base).jsValue();
if (LIKELY(baseValue.isCell())) {
- JSCell* baseCell = asCell(baseValue);
- Structure* oldStructure = vPC[4].u.structure;
- Structure* newStructure = vPC[5].u.structure;
+ JSCell* baseCell = baseValue.asCell();
+ Structure* oldStructure = vPC[4].u.structure.get();
+ Structure* newStructure = vPC[5].u.structure.get();
if (LIKELY(baseCell->structure() == oldStructure)) {
ASSERT(baseCell->isObject());
JSObject* baseObject = asObject(baseCell);
int direct = vPC[8].u.operand;
-
+
if (!direct) {
- RefPtr<Structure>* it = vPC[6].u.structureChain->head();
+ WriteBarrier<Structure>* it = vPC[6].u.structureChain->head();
JSValue proto = baseObject->structure()->prototypeForLookup(callFrame);
while (!proto.isNull()) {
if (UNLIKELY(asObject(proto)->structure() != (*it).get())) {
- uncachePutByID(callFrame->codeBlock(), vPC);
+ uncachePutByID(codeBlock, vPC);
NEXT_INSTRUCTION();
}
++it;
proto = asObject(proto)->structure()->prototypeForLookup(callFrame);
}
}
- baseObject->transitionTo(newStructure);
+ baseObject->transitionTo(*globalData, newStructure);
int value = vPC[3].u.operand;
unsigned offset = vPC[7].u.operand;
- ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(callFrame->codeBlock()->identifier(vPC[2].u.operand))) == offset);
- baseObject->putDirectOffset(offset, callFrame->r(value).jsValue());
+ ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(*globalData, codeBlock->identifier(vPC[2].u.operand))) == offset);
+ baseObject->putDirectOffset(callFrame->globalData(), offset, callFrame->r(value).jsValue());
vPC += OPCODE_LENGTH(op_put_by_id_transition);
NEXT_INSTRUCTION();
}
}
- uncachePutByID(callFrame->codeBlock(), vPC);
+ uncachePutByID(codeBlock, vPC);
NEXT_INSTRUCTION();
}
DEFINE_OPCODE(op_put_by_id_replace) {
JSValue baseValue = callFrame->r(base).jsValue();
if (LIKELY(baseValue.isCell())) {
- JSCell* baseCell = asCell(baseValue);
- Structure* structure = vPC[4].u.structure;
+ JSCell* baseCell = baseValue.asCell();
+ Structure* structure = vPC[4].u.structure.get();
if (LIKELY(baseCell->structure() == structure)) {
ASSERT(baseCell->isObject());
int value = vPC[3].u.operand;
unsigned offset = vPC[5].u.operand;
- ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(callFrame->codeBlock()->identifier(vPC[2].u.operand))) == offset);
- baseObject->putDirectOffset(offset, callFrame->r(value).jsValue());
+ ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(*globalData, codeBlock->identifier(vPC[2].u.operand))) == offset);
+ baseObject->putDirectOffset(callFrame->globalData(), offset, callFrame->r(value).jsValue());
vPC += OPCODE_LENGTH(op_put_by_id_replace);
NEXT_INSTRUCTION();
}
}
- uncachePutByID(callFrame->codeBlock(), vPC);
+ uncachePutByID(codeBlock, vPC);
NEXT_INSTRUCTION();
}
DEFINE_OPCODE(op_put_by_id_generic) {
int direct = vPC[8].u.operand;
JSValue baseValue = callFrame->r(base).jsValue();
- Identifier& ident = callFrame->codeBlock()->identifier(property);
- PutPropertySlot slot;
+ Identifier& ident = codeBlock->identifier(property);
+ PutPropertySlot slot(codeBlock->isStrictMode());
if (direct) {
baseValue.putDirect(callFrame, ident, callFrame->r(value).jsValue(), slot);
ASSERT(slot.base() == baseValue);
int property = vPC[3].u.operand;
JSObject* baseObj = callFrame->r(base).jsValue().toObject(callFrame);
- Identifier& ident = callFrame->codeBlock()->identifier(property);
- JSValue result = jsBoolean(baseObj->deleteProperty(callFrame, ident));
+ Identifier& ident = codeBlock->identifier(property);
+ bool result = baseObj->deleteProperty(callFrame, ident);
+ if (!result && codeBlock->isStrictMode()) {
+ exceptionValue = createTypeError(callFrame, "Unable to delete property.");
+ goto vm_throw;
+ }
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = jsBoolean(result);
vPC += OPCODE_LENGTH(op_del_by_id);
NEXT_INSTRUCTION();
}
JSValue result;
int offset = 0;
if (subscript == expectedSubscript && baseValue.isCell() && (baseValue.asCell()->structure() == it->cachedStructure()) && it->getOffset(index, offset)) {
- callFrame->r(dst) = asObject(baseValue)->getDirectOffset(offset);
+ callFrame->uncheckedR(dst) = JSValue(asObject(baseValue)->getDirectOffset(offset));
vPC += OPCODE_LENGTH(op_get_by_pname);
NEXT_INSTRUCTION();
}
- Identifier propertyName(callFrame, subscript.toString(callFrame));
- result = baseValue.get(callFrame, propertyName);
+ {
+ Identifier propertyName(callFrame, subscript.toString(callFrame));
+ result = baseValue.get(callFrame, propertyName);
+ }
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
vPC += OPCODE_LENGTH(op_get_by_pname);
NEXT_INSTRUCTION();
}
+ DEFINE_OPCODE(op_get_arguments_length) {
+ int dst = vPC[1].u.operand;
+ int argumentsRegister = vPC[2].u.operand;
+ int property = vPC[3].u.operand;
+ JSValue arguments = callFrame->r(argumentsRegister).jsValue();
+ if (arguments) {
+ Identifier& ident = codeBlock->identifier(property);
+ PropertySlot slot(arguments);
+ JSValue result = arguments.get(callFrame, ident, slot);
+ CHECK_FOR_EXCEPTION();
+ callFrame->uncheckedR(dst) = result;
+ } else
+ callFrame->uncheckedR(dst) = jsNumber(callFrame->argumentCount());
+
+ vPC += OPCODE_LENGTH(op_get_arguments_length);
+ NEXT_INSTRUCTION();
+ }
+ DEFINE_OPCODE(op_get_argument_by_val) {
+ int dst = vPC[1].u.operand;
+ int argumentsRegister = vPC[2].u.operand;
+ int property = vPC[3].u.operand;
+ JSValue arguments = callFrame->r(argumentsRegister).jsValue();
+ JSValue subscript = callFrame->r(property).jsValue();
+ if (!arguments && subscript.isUInt32() && subscript.asUInt32() < callFrame->argumentCount()) {
+ unsigned arg = subscript.asUInt32() + 1;
+ unsigned numParameters = callFrame->codeBlock()->m_numParameters;
+ if (arg < numParameters)
+ callFrame->uncheckedR(dst) = callFrame->r(arg - RegisterFile::CallFrameHeaderSize - numParameters);
+ else
+ callFrame->uncheckedR(dst) = callFrame->r(arg - RegisterFile::CallFrameHeaderSize - numParameters - callFrame->argumentCount() - 1);
+ vPC += OPCODE_LENGTH(op_get_argument_by_val);
+ NEXT_INSTRUCTION();
+ }
+ if (!arguments) {
+ Arguments* arguments = new (globalData) Arguments(callFrame);
+ callFrame->uncheckedR(argumentsRegister) = JSValue(arguments);
+ callFrame->uncheckedR(unmodifiedArgumentsRegister(argumentsRegister)) = JSValue(arguments);
+ }
+ // fallthrough
+ }
DEFINE_OPCODE(op_get_by_val) {
/* get_by_val dst(r) base(r) property(r)
}
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = result;
vPC += OPCODE_LENGTH(op_get_by_val);
NEXT_INSTRUCTION();
}
if (isJSArray(globalData, baseValue)) {
JSArray* jsArray = asArray(baseValue);
if (jsArray->canSetIndex(i))
- jsArray->setIndex(i, callFrame->r(value).jsValue());
+ jsArray->setIndex(*globalData, i, callFrame->r(value).jsValue());
else
jsArray->JSArray::put(callFrame, i, callFrame->r(value).jsValue());
} else if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) {
} else {
Identifier property(callFrame, subscript.toString(callFrame));
if (!globalData->exception) { // Don't put to an object if toString threw an exception.
- PutPropertySlot slot;
+ PutPropertySlot slot(codeBlock->isStrictMode());
baseValue.put(callFrame, property, callFrame->r(value).jsValue(), slot);
}
}
JSObject* baseObj = callFrame->r(base).jsValue().toObject(callFrame); // may throw
JSValue subscript = callFrame->r(property).jsValue();
- JSValue result;
+ bool result;
uint32_t i;
if (subscript.getUInt32(i))
- result = jsBoolean(baseObj->deleteProperty(callFrame, i));
+ result = baseObj->deleteProperty(callFrame, i);
else {
CHECK_FOR_EXCEPTION();
Identifier property(callFrame, subscript.toString(callFrame));
CHECK_FOR_EXCEPTION();
- result = jsBoolean(baseObj->deleteProperty(callFrame, property));
+ result = baseObj->deleteProperty(callFrame, property);
+ }
+ if (!result && codeBlock->isStrictMode()) {
+ exceptionValue = createTypeError(callFrame, "Unable to delete property.");
+ goto vm_throw;
}
-
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = result;
+ callFrame->uncheckedR(dst) = jsBoolean(result);
vPC += OPCODE_LENGTH(op_del_by_val);
NEXT_INSTRUCTION();
}
to ptr, using pointer equality.
*/
int src = vPC[1].u.operand;
- JSValue ptr = JSValue(vPC[2].u.jsCell);
int target = vPC[3].u.operand;
JSValue srcValue = callFrame->r(src).jsValue();
- if (srcValue != ptr) {
+ if (srcValue != vPC[2].u.jsCell.get()) {
vPC += target;
NEXT_INSTRUCTION();
}
int defaultOffset = vPC[2].u.operand;
JSValue scrutinee = callFrame->r(vPC[3].u.operand).jsValue();
if (scrutinee.isInt32())
- vPC += callFrame->codeBlock()->immediateSwitchJumpTable(tableIndex).offsetForValue(scrutinee.asInt32(), defaultOffset);
+ vPC += codeBlock->immediateSwitchJumpTable(tableIndex).offsetForValue(scrutinee.asInt32(), defaultOffset);
else {
double value;
int32_t intValue;
if (scrutinee.getNumber(value) && ((intValue = static_cast<int32_t>(value)) == value))
- vPC += callFrame->codeBlock()->immediateSwitchJumpTable(tableIndex).offsetForValue(intValue, defaultOffset);
+ vPC += codeBlock->immediateSwitchJumpTable(tableIndex).offsetForValue(intValue, defaultOffset);
else
vPC += defaultOffset;
}
if (!scrutinee.isString())
vPC += defaultOffset;
else {
- UString::Rep* value = asString(scrutinee)->value(callFrame).rep();
+ StringImpl* value = asString(scrutinee)->value(callFrame).impl();
if (value->length() != 1)
vPC += defaultOffset;
else
- vPC += callFrame->codeBlock()->characterSwitchJumpTable(tableIndex).offsetForValue(value->characters()[0], defaultOffset);
+ vPC += codeBlock->characterSwitchJumpTable(tableIndex).offsetForValue(value->characters()[0], defaultOffset);
}
NEXT_INSTRUCTION();
}
if (!scrutinee.isString())
vPC += defaultOffset;
else
- vPC += callFrame->codeBlock()->stringSwitchJumpTable(tableIndex).offsetForValue(asString(scrutinee)->value(callFrame).rep(), defaultOffset);
+ vPC += codeBlock->stringSwitchJumpTable(tableIndex).offsetForValue(asString(scrutinee)->value(callFrame).impl(), defaultOffset);
NEXT_INSTRUCTION();
}
DEFINE_OPCODE(op_new_func) {
*/
int dst = vPC[1].u.operand;
int func = vPC[2].u.operand;
-
- callFrame->r(dst) = JSValue(callFrame->codeBlock()->functionDecl(func)->make(callFrame, callFrame->scopeChain()));
+ int shouldCheck = vPC[3].u.operand;
+ ASSERT(codeBlock->codeType() != FunctionCode || !codeBlock->needsFullScopeChain() || callFrame->r(codeBlock->activationRegister()).jsValue());
+ if (!shouldCheck || !callFrame->r(dst).jsValue())
+ callFrame->uncheckedR(dst) = JSValue(codeBlock->functionDecl(func)->make(callFrame, callFrame->scopeChain()));
vPC += OPCODE_LENGTH(op_new_func);
NEXT_INSTRUCTION();
*/
int dst = vPC[1].u.operand;
int funcIndex = vPC[2].u.operand;
-
- FunctionExecutable* function = callFrame->codeBlock()->functionExpr(funcIndex);
+
+ ASSERT(codeBlock->codeType() != FunctionCode || !codeBlock->needsFullScopeChain() || callFrame->r(codeBlock->activationRegister()).jsValue());
+ FunctionExecutable* function = codeBlock->functionExpr(funcIndex);
JSFunction* func = function->make(callFrame, callFrame->scopeChain());
/*
*/
if (!function->name().isNull()) {
JSStaticScopeObject* functionScopeObject = new (callFrame) JSStaticScopeObject(callFrame, function->name(), func, ReadOnly | DontDelete);
- func->scope().push(functionScopeObject);
+ func->setScope(*globalData, func->scope()->push(functionScopeObject));
}
- callFrame->r(dst) = JSValue(func);
+ callFrame->uncheckedR(dst) = JSValue(func);
vPC += OPCODE_LENGTH(op_new_func_exp);
NEXT_INSTRUCTION();
}
DEFINE_OPCODE(op_call_eval) {
- /* call_eval dst(r) func(r) argCount(n) registerOffset(n)
+ /* call_eval func(r) argCount(n) registerOffset(n)
Call a function named "eval" with no explicit "this" value
(which may therefore be the eval operator). If register
opcode). Otherwise, act exactly as the "call" opcode would.
*/
- int dst = vPC[1].u.operand;
- int func = vPC[2].u.operand;
- int argCount = vPC[3].u.operand;
- int registerOffset = vPC[4].u.operand;
-
+ int func = vPC[1].u.operand;
+ int argCount = vPC[2].u.operand;
+ int registerOffset = vPC[3].u.operand;
+
+ ASSERT(codeBlock->codeType() != FunctionCode || !codeBlock->needsFullScopeChain() || callFrame->r(codeBlock->activationRegister()).jsValue());
JSValue funcVal = callFrame->r(func).jsValue();
Register* newCallFrame = callFrame->registers() + registerOffset;
Register* argv = newCallFrame - RegisterFile::CallFrameHeaderSize - argCount;
JSValue thisValue = argv[0].jsValue();
- JSGlobalObject* globalObject = callFrame->scopeChain()->globalObject;
+ JSGlobalObject* globalObject = callFrame->scopeChain()->globalObject.get();
if (thisValue == globalObject && funcVal == globalObject->evalFunction()) {
- JSValue result = callEval(callFrame, registerFile, argv, argCount, registerOffset, exceptionValue);
- if (exceptionValue)
+ JSValue result = callEval(callFrame, registerFile, argv, argCount, registerOffset);
+ if ((exceptionValue = globalData->exception))
goto vm_throw;
- callFrame->r(dst) = result;
+ functionReturnValue = result;
vPC += OPCODE_LENGTH(op_call_eval);
NEXT_INSTRUCTION();
// fall through to op_call
}
DEFINE_OPCODE(op_call) {
- /* call dst(r) func(r) argCount(n) registerOffset(n)
+ /* call func(r) argCount(n) registerOffset(n)
Perform a function call.
dst is where op_ret should store its result.
*/
- int dst = vPC[1].u.operand;
- int func = vPC[2].u.operand;
- int argCount = vPC[3].u.operand;
- int registerOffset = vPC[4].u.operand;
+ int func = vPC[1].u.operand;
+ int argCount = vPC[2].u.operand;
+ int registerOffset = vPC[3].u.operand;
JSValue v = callFrame->r(func).jsValue();
CallData callData;
- CallType callType = v.getCallData(callData);
+ CallType callType = getCallData(v, callData);
if (callType == CallTypeJS) {
ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
- CodeBlock* newCodeBlock = &callData.js.functionExecutable->bytecode(callFrame, callDataScopeChain);
- CallFrame* previousCallFrame = callFrame;
+ JSObject* error = callData.js.functionExecutable->compileForCall(callFrame, callDataScopeChain);
+ if (UNLIKELY(!!error)) {
+ exceptionValue = error;
+ goto vm_throw;
+ }
+ CallFrame* previousCallFrame = callFrame;
+ CodeBlock* newCodeBlock = &callData.js.functionExecutable->generatedBytecodeForCall();
callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount);
if (UNLIKELY(!callFrame)) {
callFrame = previousCallFrame;
goto vm_throw;
}
- callFrame->init(newCodeBlock, vPC + 5, callDataScopeChain, previousCallFrame, dst, argCount, asFunction(v));
+ callFrame->init(newCodeBlock, vPC + OPCODE_LENGTH(op_call), callDataScopeChain, previousCallFrame, argCount, asFunction(v));
+ codeBlock = newCodeBlock;
+ ASSERT(codeBlock == callFrame->codeBlock());
vPC = newCodeBlock->instructions().begin();
#if ENABLE(OPCODE_STATS)
if (callType == CallTypeHost) {
ScopeChainNode* scopeChain = callFrame->scopeChain();
CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset);
- newCallFrame->init(0, vPC + 5, scopeChain, callFrame, dst, argCount, 0);
-
- Register* thisRegister = newCallFrame->registers() - RegisterFile::CallFrameHeaderSize - argCount;
- ArgList args(thisRegister + 1, argCount - 1);
+ if (!registerFile->grow(newCallFrame->registers())) {
+ exceptionValue = createStackOverflowError(callFrame);
+ goto vm_throw;
+ }
- // FIXME: All host methods should be calling toThisObject, but this is not presently the case.
- JSValue thisValue = thisRegister->jsValue();
- if (thisValue == jsNull())
- thisValue = callFrame->globalThisValue();
+ newCallFrame->init(0, vPC + OPCODE_LENGTH(op_call), scopeChain, callFrame, argCount, asObject(v));
JSValue returnValue;
{
SamplingTool::HostCallRecord callRecord(m_sampler.get());
- returnValue = callData.native.function(newCallFrame, asObject(v), thisValue, args);
+ returnValue = JSValue::decode(callData.native.function(newCallFrame));
}
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = returnValue;
+ functionReturnValue = returnValue;
vPC += OPCODE_LENGTH(op_call);
NEXT_INSTRUCTION();
ASSERT(callType == CallTypeNone);
- exceptionValue = createNotAFunctionError(callFrame, v, vPC - callFrame->codeBlock()->instructions().begin(), callFrame->codeBlock());
+ exceptionValue = createNotAFunctionError(callFrame, v);
goto vm_throw;
}
DEFINE_OPCODE(op_load_varargs) {
JSValue arguments = callFrame->r(argsOffset).jsValue();
uint32_t argCount = 0;
if (!arguments) {
- argCount = (uint32_t)(callFrame->argumentCount()) - 1;
+ argCount = (uint32_t)(callFrame->argumentCount());
argCount = min<uint32_t>(argCount, Arguments::MaxArguments);
int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
Register* newEnd = callFrame->registers() + sizeDelta;
exceptionValue = createStackOverflowError(callFrame);
goto vm_throw;
}
- ASSERT(!callFrame->callee()->isHostFunction());
- uint32_t expectedParams = callFrame->callee()->jsExecutable()->parameterCount();
- uint32_t inplaceArgs = min(argCount, expectedParams);
- uint32_t i = 0;
+ ASSERT(!asFunction(callFrame->callee())->isHostFunction());
+ int32_t expectedParams = asFunction(callFrame->callee())->jsExecutable()->parameterCount();
+ int32_t inplaceArgs = min(static_cast<int32_t>(argCount), expectedParams);
+ int32_t i = 0;
Register* argStore = callFrame->registers() + argsOffset;
// First step is to copy the "expected" parameters from their normal location relative to the callframe
for (; i < inplaceArgs; i++)
argStore[i] = callFrame->registers()[i - RegisterFile::CallFrameHeaderSize - expectedParams];
// Then we copy any additional arguments that may be further up the stack ('-1' to account for 'this')
- for (; i < argCount; i++)
- argStore[i] = callFrame->registers()[i - RegisterFile::CallFrameHeaderSize - expectedParams - argCount - 1];
+ for (; i < static_cast<int32_t>(argCount); i++)
+ argStore[i] = callFrame->registers()[i - RegisterFile::CallFrameHeaderSize - expectedParams - static_cast<int32_t>(argCount) - 1];
} else if (!arguments.isUndefinedOrNull()) {
if (!arguments.isObject()) {
- exceptionValue = createInvalidParamError(callFrame, "Function.prototype.apply", arguments, vPC - callFrame->codeBlock()->instructions().begin(), callFrame->codeBlock());
+ exceptionValue = createInvalidParamError(callFrame, "Function.prototype.apply", arguments);
goto vm_throw;
}
- if (asObject(arguments)->classInfo() == &Arguments::info) {
+ if (asObject(arguments)->classInfo() == &Arguments::s_info) {
Arguments* args = asArguments(arguments);
argCount = args->numProvidedArguments(callFrame);
argCount = min<uint32_t>(argCount, Arguments::MaxArguments);
goto vm_throw;
}
array->copyToRegisters(callFrame, callFrame->registers() + argsOffset, argCount);
- } else if (asObject(arguments)->inherits(&JSArray::info)) {
+ } else if (asObject(arguments)->inherits(&JSArray::s_info)) {
JSObject* argObject = asObject(arguments);
argCount = argObject->get(callFrame, callFrame->propertyNames().length).toUInt32(callFrame);
argCount = min<uint32_t>(argCount, Arguments::MaxArguments);
CHECK_FOR_EXCEPTION();
}
} else {
- exceptionValue = createInvalidParamError(callFrame, "Function.prototype.apply", arguments, vPC - callFrame->codeBlock()->instructions().begin(), callFrame->codeBlock());
+ exceptionValue = createInvalidParamError(callFrame, "Function.prototype.apply", arguments);
goto vm_throw;
}
}
CHECK_FOR_EXCEPTION();
- callFrame->r(argCountDst) = Register::withInt(argCount + 1);
+ callFrame->uncheckedR(argCountDst) = Register::withInt(argCount + 1);
vPC += OPCODE_LENGTH(op_load_varargs);
NEXT_INSTRUCTION();
}
DEFINE_OPCODE(op_call_varargs) {
- /* call_varargs dst(r) func(r) argCountReg(r) baseRegisterOffset(n)
+ /* call_varargs func(r) argCountReg(r) baseRegisterOffset(n)
Perform a function call with a dynamic set of arguments.
dst is where op_ret should store its result.
*/
- int dst = vPC[1].u.operand;
- int func = vPC[2].u.operand;
- int argCountReg = vPC[3].u.operand;
- int registerOffset = vPC[4].u.operand;
+ int func = vPC[1].u.operand;
+ int argCountReg = vPC[2].u.operand;
+ int registerOffset = vPC[3].u.operand;
JSValue v = callFrame->r(func).jsValue();
int argCount = callFrame->r(argCountReg).i();
registerOffset += argCount;
CallData callData;
- CallType callType = v.getCallData(callData);
+ CallType callType = getCallData(v, callData);
if (callType == CallTypeJS) {
ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
- CodeBlock* newCodeBlock = &callData.js.functionExecutable->bytecode(callFrame, callDataScopeChain);
-
+
+ JSObject* error = callData.js.functionExecutable->compileForCall(callFrame, callDataScopeChain);
+ if (UNLIKELY(!!error)) {
+ exceptionValue = error;
+ goto vm_throw;
+ }
+
CallFrame* previousCallFrame = callFrame;
-
+ CodeBlock* newCodeBlock = &callData.js.functionExecutable->generatedBytecodeForCall();
callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount);
if (UNLIKELY(!callFrame)) {
callFrame = previousCallFrame;
exceptionValue = createStackOverflowError(callFrame);
goto vm_throw;
}
-
- callFrame->init(newCodeBlock, vPC + 5, callDataScopeChain, previousCallFrame, dst, argCount, asFunction(v));
+
+ callFrame->init(newCodeBlock, vPC + OPCODE_LENGTH(op_call_varargs), callDataScopeChain, previousCallFrame, argCount, asFunction(v));
+ codeBlock = newCodeBlock;
+ ASSERT(codeBlock == callFrame->codeBlock());
vPC = newCodeBlock->instructions().begin();
#if ENABLE(OPCODE_STATS)
if (callType == CallTypeHost) {
ScopeChainNode* scopeChain = callFrame->scopeChain();
CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset);
- newCallFrame->init(0, vPC + 5, scopeChain, callFrame, dst, argCount, 0);
-
- Register* thisRegister = newCallFrame->registers() - RegisterFile::CallFrameHeaderSize - argCount;
- ArgList args(thisRegister + 1, argCount - 1);
-
- // FIXME: All host methods should be calling toThisObject, but this is not presently the case.
- JSValue thisValue = thisRegister->jsValue();
- if (thisValue == jsNull())
- thisValue = callFrame->globalThisValue();
+ if (!registerFile->grow(newCallFrame->registers())) {
+ exceptionValue = createStackOverflowError(callFrame);
+ goto vm_throw;
+ }
+ newCallFrame->init(0, vPC + OPCODE_LENGTH(op_call_varargs), scopeChain, callFrame, argCount, asObject(v));
JSValue returnValue;
{
SamplingTool::HostCallRecord callRecord(m_sampler.get());
- returnValue = callData.native.function(newCallFrame, asObject(v), thisValue, args);
+ returnValue = JSValue::decode(callData.native.function(newCallFrame));
}
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = returnValue;
+ functionReturnValue = returnValue;
vPC += OPCODE_LENGTH(op_call_varargs);
NEXT_INSTRUCTION();
ASSERT(callType == CallTypeNone);
- exceptionValue = createNotAFunctionError(callFrame, v, vPC - callFrame->codeBlock()->instructions().begin(), callFrame->codeBlock());
+ exceptionValue = createNotAFunctionError(callFrame, v);
goto vm_throw;
}
DEFINE_OPCODE(op_tear_off_activation) {
- /* tear_off_activation activation(r)
+ /* tear_off_activation activation(r) arguments(r)
- Copy all locals and parameters to new memory allocated on
- the heap, and make the passed activation use this memory
- in the future when looking up entries in the symbol table.
- If there is an 'arguments' object, then it will also use
- this memory for storing the named parameters, but not any
- extra arguments.
+ Copy locals and named parameters from the register file to the heap.
+ Point the bindings in 'activation' and 'arguments' to this new backing
+ store. (Note that 'arguments' may not have been created. If created,
+ 'arguments' already holds a copy of any extra / unnamed parameters.)
- This opcode should only be used immediately before op_ret.
+ This opcode appears before op_ret in functions that require full scope chains.
*/
- int src = vPC[1].u.operand;
- ASSERT(callFrame->codeBlock()->needsFullScopeChain());
+ int activation = vPC[1].u.operand;
+ int arguments = vPC[2].u.operand;
+ ASSERT(codeBlock->needsFullScopeChain());
+ JSValue activationValue = callFrame->r(activation).jsValue();
+ if (activationValue) {
+ asActivation(activationValue)->copyRegisters(*globalData);
- asActivation(callFrame->r(src).jsValue())->copyRegisters(callFrame->optionalCalleeArguments());
+ if (JSValue argumentsValue = callFrame->r(unmodifiedArgumentsRegister(arguments)).jsValue()) {
+ if (!codeBlock->isStrictMode())
+ asArguments(argumentsValue)->setActivation(*globalData, asActivation(activationValue));
+ }
+ } else if (JSValue argumentsValue = callFrame->r(unmodifiedArgumentsRegister(arguments)).jsValue()) {
+ if (!codeBlock->isStrictMode())
+ asArguments(argumentsValue)->copyRegisters(*globalData);
+ }
vPC += OPCODE_LENGTH(op_tear_off_activation);
NEXT_INSTRUCTION();
}
DEFINE_OPCODE(op_tear_off_arguments) {
- /* tear_off_arguments
+ /* tear_off_arguments arguments(r)
- Copy all arguments to new memory allocated on the heap,
- and make the 'arguments' object use this memory in the
- future when looking up named parameters, but not any
- extra arguments. If an activation object exists for the
- current function context, then the tear_off_activation
- opcode should be used instead.
+ Copy named parameters from the register file to the heap. Point the
+ bindings in 'arguments' to this new backing store. (Note that
+ 'arguments' may not have been created. If created, 'arguments' already
+ holds a copy of any extra / unnamed parameters.)
- This opcode should only be used immediately before op_ret.
+ This opcode appears before op_ret in functions that don't require full
+ scope chains, but do use 'arguments'.
*/
- ASSERT(callFrame->codeBlock()->usesArguments() && !callFrame->codeBlock()->needsFullScopeChain());
+ int src1 = vPC[1].u.operand;
+ ASSERT(!codeBlock->needsFullScopeChain() && codeBlock->ownerExecutable()->usesArguments());
- if (callFrame->optionalCalleeArguments())
- callFrame->optionalCalleeArguments()->copyRegisters();
+ if (JSValue arguments = callFrame->r(unmodifiedArgumentsRegister(src1)).jsValue())
+ asArguments(arguments)->copyRegisters(*globalData);
vPC += OPCODE_LENGTH(op_tear_off_arguments);
NEXT_INSTRUCTION();
}
DEFINE_OPCODE(op_ret) {
+ /* ret result(r)
+
+ Return register result as the return value of the current
+ function call, writing it into functionReturnValue.
+ In addition, unwind one call frame and restore the scope
+ chain, code block instruction pointer and register base
+ to those of the calling function.
+ */
+
+ int result = vPC[1].u.operand;
+
+ JSValue returnValue = callFrame->r(result).jsValue();
+
+ vPC = callFrame->returnVPC();
+ callFrame = callFrame->callerFrame();
+
+ if (callFrame->hasHostCallFrameFlag())
+ return returnValue;
+
+ functionReturnValue = returnValue;
+ codeBlock = callFrame->codeBlock();
+ ASSERT(codeBlock == callFrame->codeBlock());
+
+ NEXT_INSTRUCTION();
+ }
+ DEFINE_OPCODE(op_call_put_result) {
+ /* op_call_put_result result(r)
+
+ Move call result from functionReturnValue to caller's
+ expected return value register.
+ */
+
+ callFrame->uncheckedR(vPC[1].u.operand) = functionReturnValue;
+
+ vPC += OPCODE_LENGTH(op_call_put_result);
+ NEXT_INSTRUCTION();
+ }
+ DEFINE_OPCODE(op_ret_object_or_this) {
/* ret result(r)
Return register result as the return value of the current
int result = vPC[1].u.operand;
- if (callFrame->codeBlock()->needsFullScopeChain())
- callFrame->scopeChain()->deref();
-
JSValue returnValue = callFrame->r(result).jsValue();
+ if (UNLIKELY(!returnValue.isObject()))
+ returnValue = callFrame->r(vPC[2].u.operand).jsValue();
+
vPC = callFrame->returnVPC();
- int dst = callFrame->returnValueRegister();
callFrame = callFrame->callerFrame();
-
+
if (callFrame->hasHostCallFrameFlag())
return returnValue;
- callFrame->r(dst) = returnValue;
+ functionReturnValue = returnValue;
+ codeBlock = callFrame->codeBlock();
+ ASSERT(codeBlock == callFrame->codeBlock());
NEXT_INSTRUCTION();
}
DEFINE_OPCODE(op_enter) {
/* enter
- Initializes local variables to undefined and fills constant
- registers with their values. If the code block requires an
- activation, enter_with_activation should be used instead.
+ Initializes local variables to undefined. If the code block requires
+ an activation, enter_with_activation is used instead.
- This opcode should only be used at the beginning of a code
- block.
+ This opcode appears only at the beginning of a code block.
*/
size_t i = 0;
- CodeBlock* codeBlock = callFrame->codeBlock();
-
for (size_t count = codeBlock->m_numVars; i < count; ++i)
- callFrame->r(i) = jsUndefined();
+ callFrame->uncheckedR(i) = jsUndefined();
vPC += OPCODE_LENGTH(op_enter);
NEXT_INSTRUCTION();
}
- DEFINE_OPCODE(op_enter_with_activation) {
- /* enter_with_activation dst(r)
+ DEFINE_OPCODE(op_create_activation) {
+ /* create_activation dst(r)
- Initializes local variables to undefined, fills constant
- registers with their values, creates an activation object,
- and places the new activation both in dst and at the top
- of the scope chain. If the code block does not require an
- activation, enter should be used instead.
+ If the activation object for this callframe has not yet been created,
+ this creates it and writes it back to dst.
+ */
+
+ int activationReg = vPC[1].u.operand;
+ if (!callFrame->r(activationReg).jsValue()) {
+ JSActivation* activation = new (globalData) JSActivation(callFrame, static_cast<FunctionExecutable*>(codeBlock->ownerExecutable()));
+ callFrame->r(activationReg) = JSValue(activation);
+ callFrame->setScopeChain(callFrame->scopeChain()->push(activation));
+ }
+ vPC += OPCODE_LENGTH(op_create_activation);
+ NEXT_INSTRUCTION();
+ }
+ DEFINE_OPCODE(op_get_callee) {
+ /* op_get_callee callee(r)
+
+ Move callee into a register.
+ */
+
+ callFrame->uncheckedR(vPC[1].u.operand) = JSValue(callFrame->callee());
+
+ vPC += OPCODE_LENGTH(op_get_callee);
+ NEXT_INSTRUCTION();
+ }
+ DEFINE_OPCODE(op_create_this) {
+ /* op_create_this this(r) proto(r)
+
+ Allocate an object as 'this', fr use in construction.
This opcode should only be used at the beginning of a code
block.
*/
- size_t i = 0;
- CodeBlock* codeBlock = callFrame->codeBlock();
+ int thisRegister = vPC[1].u.operand;
+ int protoRegister = vPC[2].u.operand;
- for (size_t count = codeBlock->m_numVars; i < count; ++i)
- callFrame->r(i) = jsUndefined();
+ JSFunction* constructor = asFunction(callFrame->callee());
+#if !ASSERT_DISABLED
+ ConstructData constructData;
+ ASSERT(constructor->getConstructData(constructData) == ConstructTypeJS);
+#endif
- int dst = vPC[1].u.operand;
- JSActivation* activation = new (globalData) JSActivation(callFrame, static_cast<FunctionExecutable*>(codeBlock->ownerExecutable()));
- callFrame->r(dst) = JSValue(activation);
- callFrame->setScopeChain(callFrame->scopeChain()->copy()->push(activation));
+ Structure* structure;
+ JSValue proto = callFrame->r(protoRegister).jsValue();
+ if (proto.isObject())
+ structure = asObject(proto)->inheritorID(callFrame->globalData());
+ else
+ structure = constructor->scope()->globalObject->emptyObjectStructure();
+ callFrame->uncheckedR(thisRegister) = constructEmptyObject(callFrame, structure);
- vPC += OPCODE_LENGTH(op_enter_with_activation);
+ vPC += OPCODE_LENGTH(op_create_this);
NEXT_INSTRUCTION();
}
DEFINE_OPCODE(op_convert_this) {
int thisRegister = vPC[1].u.operand;
JSValue thisVal = callFrame->r(thisRegister).jsValue();
if (thisVal.needsThisConversion())
- callFrame->r(thisRegister) = JSValue(thisVal.toThisObject(callFrame));
+ callFrame->uncheckedR(thisRegister) = JSValue(thisVal.toThisObject(callFrame));
vPC += OPCODE_LENGTH(op_convert_this);
NEXT_INSTRUCTION();
}
- DEFINE_OPCODE(op_init_arguments) {
- /* create_arguments
+ DEFINE_OPCODE(op_convert_this_strict) {
+ /* convert_this_strict this(r)
+
+ Takes the value in the 'this' register, and converts it to
+ its "this" form if (and only if) "this" is an object with a
+ custom this conversion
+
+ This opcode should only be used at the beginning of a code
+ block.
+ */
+
+ int thisRegister = vPC[1].u.operand;
+ JSValue thisVal = callFrame->r(thisRegister).jsValue();
+ if (thisVal.isObject() && thisVal.needsThisConversion())
+ callFrame->uncheckedR(thisRegister) = JSValue(thisVal.toStrictThisObject(callFrame));
+
+ vPC += OPCODE_LENGTH(op_convert_this_strict);
+ NEXT_INSTRUCTION();
+ }
+ DEFINE_OPCODE(op_init_lazy_reg) {
+ /* init_lazy_reg dst(r)
- Initialises the arguments object reference to null to ensure
- we can correctly detect that we need to create it later (or
- avoid creating it altogether).
+ Initialises dst(r) to JSValue().
- This opcode should only be used at the beginning of a code
- block.
+ This opcode appears only at the beginning of a code block.
*/
- callFrame->r(RegisterFile::ArgumentsRegister) = JSValue();
- vPC += OPCODE_LENGTH(op_init_arguments);
+ int dst = vPC[1].u.operand;
+
+ callFrame->uncheckedR(dst) = JSValue();
+ vPC += OPCODE_LENGTH(op_init_lazy_reg);
NEXT_INSTRUCTION();
}
DEFINE_OPCODE(op_create_arguments) {
- /* create_arguments
+ /* create_arguments dst(r)
Creates the 'arguments' object and places it in both the
'arguments' call frame slot and the local 'arguments'
register, if it has not already been initialised.
*/
- if (!callFrame->r(RegisterFile::ArgumentsRegister).jsValue()) {
- Arguments* arguments = new (globalData) Arguments(callFrame);
- callFrame->setCalleeArguments(arguments);
- callFrame->r(RegisterFile::ArgumentsRegister) = JSValue(arguments);
- }
+ int dst = vPC[1].u.operand;
+
+ if (!callFrame->r(dst).jsValue()) {
+ Arguments* arguments = new (globalData) Arguments(callFrame);
+ callFrame->uncheckedR(dst) = JSValue(arguments);
+ callFrame->uncheckedR(unmodifiedArgumentsRegister(dst)) = JSValue(arguments);
+ }
vPC += OPCODE_LENGTH(op_create_arguments);
NEXT_INSTRUCTION();
}
DEFINE_OPCODE(op_construct) {
- /* construct dst(r) func(r) argCount(n) registerOffset(n) proto(r) thisRegister(r)
+ /* construct func(r) argCount(n) registerOffset(n) proto(r) thisRegister(r)
Invoke register "func" as a constructor. For JS
functions, the calling convention is exactly as for the
caching of this lookup.
*/
- int dst = vPC[1].u.operand;
- int func = vPC[2].u.operand;
- int argCount = vPC[3].u.operand;
- int registerOffset = vPC[4].u.operand;
- int proto = vPC[5].u.operand;
- int thisRegister = vPC[6].u.operand;
+ int func = vPC[1].u.operand;
+ int argCount = vPC[2].u.operand;
+ int registerOffset = vPC[3].u.operand;
JSValue v = callFrame->r(func).jsValue();
ConstructData constructData;
- ConstructType constructType = v.getConstructData(constructData);
+ ConstructType constructType = getConstructData(v, constructData);
if (constructType == ConstructTypeJS) {
ScopeChainNode* callDataScopeChain = constructData.js.scopeChain;
- CodeBlock* newCodeBlock = &constructData.js.functionExecutable->bytecode(callFrame, callDataScopeChain);
-
- Structure* structure;
- JSValue prototype = callFrame->r(proto).jsValue();
- if (prototype.isObject())
- structure = asObject(prototype)->inheritorID();
- else
- structure = callDataScopeChain->globalObject->emptyObjectStructure();
- JSObject* newObject = new (globalData) JSObject(structure);
- callFrame->r(thisRegister) = JSValue(newObject); // "this" value
+ JSObject* error = constructData.js.functionExecutable->compileForConstruct(callFrame, callDataScopeChain);
+ if (UNLIKELY(!!error)) {
+ exceptionValue = error;
+ goto vm_throw;
+ }
CallFrame* previousCallFrame = callFrame;
-
+ CodeBlock* newCodeBlock = &constructData.js.functionExecutable->generatedBytecodeForConstruct();
callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount);
if (UNLIKELY(!callFrame)) {
callFrame = previousCallFrame;
goto vm_throw;
}
- callFrame->init(newCodeBlock, vPC + 7, callDataScopeChain, previousCallFrame, dst, argCount, asFunction(v));
+ callFrame->init(newCodeBlock, vPC + OPCODE_LENGTH(op_construct), callDataScopeChain, previousCallFrame, argCount, asFunction(v));
+ codeBlock = newCodeBlock;
vPC = newCodeBlock->instructions().begin();
#if ENABLE(OPCODE_STATS)
OpcodeStats::resetLastInstruction();
}
if (constructType == ConstructTypeHost) {
- ArgList args(callFrame->registers() + thisRegister + 1, argCount - 1);
-
ScopeChainNode* scopeChain = callFrame->scopeChain();
CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset);
- newCallFrame->init(0, vPC + 7, scopeChain, callFrame, dst, argCount, 0);
+ if (!registerFile->grow(newCallFrame->registers())) {
+ exceptionValue = createStackOverflowError(callFrame);
+ goto vm_throw;
+ }
+ newCallFrame->init(0, vPC + OPCODE_LENGTH(op_construct), scopeChain, callFrame, argCount, asObject(v));
JSValue returnValue;
{
SamplingTool::HostCallRecord callRecord(m_sampler.get());
- returnValue = constructData.native.function(newCallFrame, asObject(v), args);
+ returnValue = JSValue::decode(constructData.native.function(newCallFrame));
}
CHECK_FOR_EXCEPTION();
- callFrame->r(dst) = JSValue(returnValue);
+ functionReturnValue = returnValue;
vPC += OPCODE_LENGTH(op_construct);
NEXT_INSTRUCTION();
ASSERT(constructType == ConstructTypeNone);
- exceptionValue = createNotAConstructorError(callFrame, v, vPC - callFrame->codeBlock()->instructions().begin(), callFrame->codeBlock());
+ exceptionValue = createNotAConstructorError(callFrame, v);
goto vm_throw;
}
- DEFINE_OPCODE(op_construct_verify) {
- /* construct_verify dst(r) override(r)
+ DEFINE_OPCODE(op_strcat) {
+ /* strcat dst(r) src(r) count(n)
- Verifies that register dst holds an object. If not, moves
- the object in register override to register dst.
+ Construct a new String instance using the original
+ constructor, and puts the result in register dst.
+ The string will be the result of concatenating count
+ strings with values taken from registers starting at
+ register src.
*/
-
- int dst = vPC[1].u.operand;
- if (LIKELY(callFrame->r(dst).jsValue().isObject())) {
- vPC += OPCODE_LENGTH(op_construct_verify);
- NEXT_INSTRUCTION();
- }
-
- int override = vPC[2].u.operand;
- callFrame->r(dst) = callFrame->r(override);
-
- vPC += OPCODE_LENGTH(op_construct_verify);
- NEXT_INSTRUCTION();
- }
- DEFINE_OPCODE(op_strcat) {
int dst = vPC[1].u.operand;
int src = vPC[2].u.operand;
int count = vPC[3].u.operand;
- callFrame->r(dst) = concatenateStrings(callFrame, &callFrame->registers()[src], count);
+ callFrame->uncheckedR(dst) = concatenateStrings(callFrame, &callFrame->registers()[src], count);
CHECK_FOR_EXCEPTION();
vPC += OPCODE_LENGTH(op_strcat);
int dst = vPC[1].u.operand;
int src = vPC[2].u.operand;
- callFrame->r(dst) = callFrame->r(src).jsValue().toPrimitive(callFrame);
+ callFrame->uncheckedR(dst) = callFrame->r(src).jsValue().toPrimitive(callFrame);
vPC += OPCODE_LENGTH(op_to_primitive);
NEXT_INSTRUCTION();
JSObject* o = v.toObject(callFrame);
CHECK_FOR_EXCEPTION();
- callFrame->r(scope) = JSValue(o);
+ callFrame->uncheckedR(scope) = JSValue(o);
callFrame->setScopeChain(callFrame->scopeChain()->push(o));
vPC += OPCODE_LENGTH(op_push_scope);
if (!jsPropertyNameIterator || jsPropertyNameIterator->cachedPrototypeChain() != structure->prototypeChain(callFrame))
jsPropertyNameIterator = JSPropertyNameIterator::create(callFrame, o);
- callFrame->r(dst) = jsPropertyNameIterator;
- callFrame->r(base) = JSValue(o);
- callFrame->r(i) = Register::withInt(0);
- callFrame->r(size) = Register::withInt(jsPropertyNameIterator->size());
+ callFrame->uncheckedR(dst) = jsPropertyNameIterator;
+ callFrame->uncheckedR(base) = JSValue(o);
+ callFrame->uncheckedR(i) = Register::withInt(0);
+ callFrame->uncheckedR(size) = Register::withInt(jsPropertyNameIterator->size());
vPC += OPCODE_LENGTH(op_get_pnames);
NEXT_INSTRUCTION();
}
JSPropertyNameIterator* it = callFrame->r(iter).propertyNameIterator();
while (callFrame->r(i).i() != callFrame->r(size).i()) {
JSValue key = it->get(callFrame, asObject(callFrame->r(base).jsValue()), callFrame->r(i).i());
- callFrame->r(i) = Register::withInt(callFrame->r(i).i() + 1);
+ CHECK_FOR_EXCEPTION();
+ callFrame->uncheckedR(i) = Register::withInt(callFrame->r(i).i() + 1);
if (key) {
CHECK_FOR_TIMEOUT();
- callFrame->r(dst) = key;
+ callFrame->uncheckedR(dst) = key;
vPC += target;
NEXT_INSTRUCTION();
}
ASSERT(exceptionValue);
ASSERT(!globalData->exception);
int ex = vPC[1].u.operand;
- callFrame->r(ex) = exceptionValue;
+ callFrame->uncheckedR(ex) = exceptionValue;
exceptionValue = JSValue();
vPC += OPCODE_LENGTH(op_catch);
int ex = vPC[1].u.operand;
exceptionValue = callFrame->r(ex).jsValue();
- handler = throwException(callFrame, exceptionValue, vPC - callFrame->codeBlock()->instructions().begin(), true);
- if (!handler) {
- *exception = exceptionValue;
- return jsNull();
- }
+ handler = throwException(callFrame, exceptionValue, vPC - codeBlock->instructions().begin());
+ if (!handler)
+ return throwError(callFrame, exceptionValue);
- vPC = callFrame->codeBlock()->instructions().begin() + handler->target;
+ codeBlock = callFrame->codeBlock();
+ vPC = codeBlock->instructions().begin() + handler->target;
NEXT_INSTRUCTION();
}
- DEFINE_OPCODE(op_new_error) {
- /* new_error dst(r) type(n) message(k)
+ DEFINE_OPCODE(op_throw_reference_error) {
+ /* op_throw_reference_error message(k)
- Constructs a new Error instance using the original
- constructor, using immediate number n as the type and
- constant message as the message string. The result is
- written to register dst.
+ Constructs a new reference Error instance using the
+ original constructor, using constant message as the
+ message string. The result is thrown.
*/
- int dst = vPC[1].u.operand;
- int type = vPC[2].u.operand;
- int message = vPC[3].u.operand;
-
- CodeBlock* codeBlock = callFrame->codeBlock();
- callFrame->r(dst) = JSValue(Error::create(callFrame, (ErrorType)type, callFrame->r(message).jsValue().toString(callFrame), codeBlock->lineNumberForBytecodeOffset(callFrame, vPC - codeBlock->instructions().begin()), codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->sourceURL()));
-
- vPC += OPCODE_LENGTH(op_new_error);
- NEXT_INSTRUCTION();
+ UString message = callFrame->r(vPC[1].u.operand).jsValue().toString(callFrame);
+ exceptionValue = JSValue(createReferenceError(callFrame, message));
+ goto vm_throw;
}
DEFINE_OPCODE(op_end) {
/* end result(r)
program. Return control to the calling native code.
*/
- if (callFrame->codeBlock()->needsFullScopeChain()) {
- ScopeChainNode* scopeChain = callFrame->scopeChain();
- ASSERT(scopeChain->refCount > 1);
- scopeChain->deref();
- }
int result = vPC[1].u.operand;
return callFrame->r(result).jsValue();
}
ASSERT(callFrame->r(base).jsValue().isObject());
JSObject* baseObj = asObject(callFrame->r(base).jsValue());
- Identifier& ident = callFrame->codeBlock()->identifier(property);
+ Identifier& ident = codeBlock->identifier(property);
ASSERT(callFrame->r(function).jsValue().isObject());
baseObj->defineGetter(callFrame, ident, asObject(callFrame->r(function).jsValue()));
ASSERT(callFrame->r(base).jsValue().isObject());
JSObject* baseObj = asObject(callFrame->r(base).jsValue());
- Identifier& ident = callFrame->codeBlock()->identifier(property);
+ Identifier& ident = codeBlock->identifier(property);
ASSERT(callFrame->r(function).jsValue().isObject());
baseObj->defineSetter(callFrame, ident, asObject(callFrame->r(function).jsValue()), 0);
// cannot fathom if we don't assign to the exceptionValue before branching)
exceptionValue = createInterruptedExecutionException(globalData);
}
- handler = throwException(callFrame, exceptionValue, vPC - callFrame->codeBlock()->instructions().begin(), false);
+ JSGlobalObject* globalObject = callFrame->lexicalGlobalObject();
+ handler = throwException(callFrame, exceptionValue, vPC - codeBlock->instructions().begin());
if (!handler) {
- *exception = exceptionValue;
- return jsNull();
+ // Can't use the callframe at this point as the scopechain, etc have
+ // been released.
+ return throwError(globalObject->globalExec(), exceptionValue);
}
- vPC = callFrame->codeBlock()->instructions().begin() + handler->target;
+ codeBlock = callFrame->codeBlock();
+ vPC = codeBlock->instructions().begin() + handler->target;
NEXT_INSTRUCTION();
}
}
CodeBlock* codeBlock = functionCallFrame->codeBlock();
if (codeBlock->usesArguments()) {
ASSERT(codeBlock->codeType() == FunctionCode);
- SymbolTable& symbolTable = *codeBlock->symbolTable();
- int argumentsIndex = symbolTable.get(functionCallFrame->propertyNames().arguments.ustring().rep()).getIndex();
- if (!functionCallFrame->r(argumentsIndex).jsValue()) {
- Arguments* arguments = new (callFrame) Arguments(functionCallFrame);
- functionCallFrame->setCalleeArguments(arguments);
- functionCallFrame->r(RegisterFile::ArgumentsRegister) = JSValue(arguments);
- }
- return functionCallFrame->r(argumentsIndex).jsValue();
- }
-
- Arguments* arguments = functionCallFrame->optionalCalleeArguments();
- if (!arguments) {
- arguments = new (functionCallFrame) Arguments(functionCallFrame);
- arguments->copyRegisters();
- callFrame->setCalleeArguments(arguments);
- }
-
+ int argumentsRegister = codeBlock->argumentsRegister();
+ int realArgumentsRegister = unmodifiedArgumentsRegister(argumentsRegister);
+ if (JSValue arguments = functionCallFrame->uncheckedR(argumentsRegister).jsValue())
+ return arguments;
+ JSValue arguments = JSValue(new (callFrame) Arguments(functionCallFrame));
+ functionCallFrame->r(argumentsRegister) = arguments;
+ functionCallFrame->r(realArgumentsRegister) = arguments;
+ return arguments;
+ }
+
+ Arguments* arguments = new (functionCallFrame) Arguments(functionCallFrame);
+ arguments->copyRegisters(functionCallFrame->globalData());
return arguments;
}
-JSValue Interpreter::retrieveCaller(CallFrame* callFrame, InternalFunction* function) const
+JSValue Interpreter::retrieveCaller(CallFrame* callFrame, JSFunction* function) const
{
CallFrame* functionCallFrame = findFunctionCallFrame(callFrame, function);
if (!functionCallFrame)
unsigned bytecodeOffset = 0;
#if ENABLE(INTERPRETER)
if (!callerFrame->globalData().canUseJIT())
- bytecodeOffset = bytecodeOffsetForPC(callerFrame, callerCodeBlock, callFrame->returnVPC());
+ bytecodeOffset = callerCodeBlock->bytecodeOffset(callFrame->returnVPC());
#if ENABLE(JIT)
else
- bytecodeOffset = bytecodeOffsetForPC(callerFrame, callerCodeBlock, callFrame->returnPC());
+ bytecodeOffset = callerCodeBlock->bytecodeOffset(callFrame->returnPC());
#endif
#else
- bytecodeOffset = bytecodeOffsetForPC(callerFrame, callerCodeBlock, callFrame->returnPC());
+ bytecodeOffset = callerCodeBlock->bytecodeOffset(callFrame->returnPC());
#endif
- lineNumber = callerCodeBlock->lineNumberForBytecodeOffset(callerFrame, bytecodeOffset - 1);
+ lineNumber = callerCodeBlock->lineNumberForBytecodeOffset(bytecodeOffset - 1);
sourceID = callerCodeBlock->ownerExecutable()->sourceID();
sourceURL = callerCodeBlock->ownerExecutable()->sourceURL();
function = callerFrame->callee();
}
-CallFrame* Interpreter::findFunctionCallFrame(CallFrame* callFrame, InternalFunction* function)
+CallFrame* Interpreter::findFunctionCallFrame(CallFrame* callFrame, JSFunction* function)
{
for (CallFrame* candidate = callFrame; candidate; candidate = candidate->callerFrame()->removeHostCallFrameFlag()) {
if (candidate->callee() == function)
#define Interpreter_h
#include "ArgList.h"
-#include "FastAllocBase.h"
#include "JSCell.h"
#include "JSValue.h"
#include "JSObject.h"
class CodeBlock;
class EvalExecutable;
class FunctionExecutable;
- class InternalFunction;
class JSFunction;
class JSGlobalObject;
class ProgramExecutable;
// We use a smaller reentrancy limit on iPhone because of the high amount of
// stack space required on the web thread.
- enum { MaxLargeThreadReentryDepth = 100, MaxSmallThreadReentryDepth = 32 };
+ enum { MaxLargeThreadReentryDepth = 93, MaxSmallThreadReentryDepth = 32 };
- class Interpreter : public FastAllocBase {
+ class Interpreter {
+ WTF_MAKE_FAST_ALLOCATED;
friend class JIT;
friend class CachedCall;
public:
- Interpreter();
+ Interpreter(JSGlobalData&);
RegisterFile& registerFile() { return m_registerFile; }
}
bool isOpcode(Opcode);
-
- JSValue execute(ProgramExecutable*, CallFrame*, ScopeChainNode*, JSObject* thisObj, JSValue* exception);
- JSValue execute(FunctionExecutable*, CallFrame*, JSFunction*, JSObject* thisObj, const ArgList& args, ScopeChainNode*, JSValue* exception);
- JSValue execute(EvalExecutable* evalNode, CallFrame* exec, JSObject* thisObj, ScopeChainNode* scopeChain, JSValue* exception);
+
+ JSValue execute(ProgramExecutable*, CallFrame*, ScopeChainNode*, JSObject* thisObj);
+ JSValue executeCall(CallFrame*, JSObject* function, CallType, const CallData&, JSValue thisValue, const ArgList&);
+ JSObject* executeConstruct(CallFrame*, JSObject* function, ConstructType, const ConstructData&, const ArgList&);
+ JSValue execute(EvalExecutable* evalNode, CallFrame* exec, JSObject* thisObj, ScopeChainNode* scopeChain);
JSValue retrieveArguments(CallFrame*, JSFunction*) const;
- JSValue retrieveCaller(CallFrame*, InternalFunction*) const;
+ JSValue retrieveCaller(CallFrame*, JSFunction*) const;
void retrieveLastCaller(CallFrame*, int& lineNumber, intptr_t& sourceID, UString& sourceURL, JSValue& function) const;
void getArgumentsData(CallFrame*, JSFunction*&, ptrdiff_t& firstParameterIndex, Register*& argv, int& argc);
SamplingTool* sampler() { return m_sampler.get(); }
- NEVER_INLINE JSValue callEval(CallFrame*, RegisterFile*, Register* argv, int argc, int registerOffset, JSValue& exceptionValue);
- NEVER_INLINE HandlerInfo* throwException(CallFrame*&, JSValue&, unsigned bytecodeOffset, bool);
+ NEVER_INLINE JSValue callEval(CallFrame*, RegisterFile*, Register* argv, int argc, int registerOffset);
+ NEVER_INLINE HandlerInfo* throwException(CallFrame*&, JSValue&, unsigned bytecodeOffset);
NEVER_INLINE void debug(CallFrame*, DebugHookID, int firstLine, int lastLine);
void dumpSampleData(ExecState* exec);
private:
enum ExecutionFlag { Normal, InitializeAndReturn };
- CallFrameClosure prepareForRepeatCall(FunctionExecutable*, CallFrame*, JSFunction*, int argCount, ScopeChainNode*, JSValue* exception);
+ CallFrameClosure prepareForRepeatCall(FunctionExecutable*, CallFrame*, JSFunction*, int argCount, ScopeChainNode*);
void endRepeatCall(CallFrameClosure&);
- JSValue execute(CallFrameClosure&, JSValue* exception);
+ JSValue execute(CallFrameClosure&);
- JSValue execute(EvalExecutable*, CallFrame*, JSObject* thisObject, int globalRegisterOffset, ScopeChainNode*, JSValue* exception);
+ JSValue execute(EvalExecutable*, CallFrame*, JSObject* thisObject, int globalRegisterOffset, ScopeChainNode*);
#if ENABLE(INTERPRETER)
NEVER_INLINE bool resolve(CallFrame*, Instruction*, JSValue& exceptionValue);
static ALWAYS_INLINE CallFrame* slideRegisterWindowForCall(CodeBlock*, RegisterFile*, CallFrame*, size_t registerOffset, int argc);
- static CallFrame* findFunctionCallFrame(CallFrame*, InternalFunction*);
+ static CallFrame* findFunctionCallFrame(CallFrame*, JSFunction*);
- JSValue privateExecute(ExecutionFlag, RegisterFile*, CallFrame*, JSValue* exception);
+ JSValue privateExecute(ExecutionFlag, RegisterFile*, CallFrame*);
void dumpCallFrame(CallFrame*);
void dumpRegisters(CallFrame*);
#include "JSValue.h"
#include <wtf/Assertions.h>
-#include <wtf/FastAllocBase.h>
#include <wtf/VectorTraits.h>
namespace JSC {
- class Arguments;
class CodeBlock;
class ExecState;
class JSActivation;
- class JSFunction;
+ class JSObject;
class JSPropertyNameIterator;
class ScopeChainNode;
typedef ExecState CallFrame;
- class Register : public WTF::FastAllocBase {
+ class Register {
+ WTF_MAKE_FAST_ALLOCATED;
public:
Register();
Register(const JSValue&);
Register& operator=(const JSValue&);
JSValue jsValue() const;
+ EncodedJSValue encodedJSValue() const;
- Register& operator=(JSActivation*);
Register& operator=(CallFrame*);
Register& operator=(CodeBlock*);
- Register& operator=(JSFunction*);
- Register& operator=(JSPropertyNameIterator*);
Register& operator=(ScopeChainNode*);
Register& operator=(Instruction*);
int32_t i() const;
JSActivation* activation() const;
- Arguments* arguments() const;
CallFrame* callFrame() const;
CodeBlock* codeBlock() const;
- JSFunction* function() const;
+ JSObject* function() const;
JSPropertyNameIterator* propertyNameIterator() const;
ScopeChainNode* scopeChain() const;
Instruction* vPC() const;
static Register withInt(int32_t i)
{
- Register r;
- r.u.i = i;
+ Register r = jsNumber(i);
return r;
}
+ static inline Register withCallee(JSObject* callee);
+
private:
union {
- int32_t i;
EncodedJSValue value;
-
- JSActivation* activation;
CallFrame* callFrame;
CodeBlock* codeBlock;
- JSFunction* function;
- JSPropertyNameIterator* propertyNameIterator;
- ScopeChainNode* scopeChain;
Instruction* vPC;
} u;
};
return JSValue::decode(u.value);
}
- // Interpreter functions
-
- ALWAYS_INLINE Register& Register::operator=(JSActivation* activation)
+ ALWAYS_INLINE EncodedJSValue Register::encodedJSValue() const
{
- u.activation = activation;
- return *this;
+ return u.value;
}
+ // Interpreter functions
+
ALWAYS_INLINE Register& Register::operator=(CallFrame* callFrame)
{
u.callFrame = callFrame;
return *this;
}
- ALWAYS_INLINE Register& Register::operator=(JSFunction* function)
- {
- u.function = function;
- return *this;
- }
-
ALWAYS_INLINE Register& Register::operator=(Instruction* vPC)
{
u.vPC = vPC;
return *this;
}
- ALWAYS_INLINE Register& Register::operator=(ScopeChainNode* scopeChain)
- {
- u.scopeChain = scopeChain;
- return *this;
- }
-
- ALWAYS_INLINE Register& Register::operator=(JSPropertyNameIterator* propertyNameIterator)
- {
- u.propertyNameIterator = propertyNameIterator;
- return *this;
- }
-
ALWAYS_INLINE int32_t Register::i() const
{
- return u.i;
+ return jsValue().asInt32();
}
-
- ALWAYS_INLINE JSActivation* Register::activation() const
- {
- return u.activation;
- }
-
+
ALWAYS_INLINE CallFrame* Register::callFrame() const
{
return u.callFrame;
{
return u.codeBlock;
}
-
- ALWAYS_INLINE JSFunction* Register::function() const
- {
- return u.function;
- }
-
- ALWAYS_INLINE JSPropertyNameIterator* Register::propertyNameIterator() const
- {
- return u.propertyNameIterator;
- }
-
- ALWAYS_INLINE ScopeChainNode* Register::scopeChain() const
- {
- return u.scopeChain;
- }
-
+
ALWAYS_INLINE Instruction* Register::vPC() const
{
return u.vPC;
#include "config.h"
#include "RegisterFile.h"
+#include "ConservativeRoots.h"
+#include "Interpreter.h"
+#include "JSGlobalData.h"
#include "JSGlobalObject.h"
namespace JSC {
+static size_t committedBytesCount = 0;
+
+static Mutex& registerFileStatisticsMutex()
+{
+ DEFINE_STATIC_LOCAL(Mutex, staticMutex, ());
+ return staticMutex;
+}
+
RegisterFile::~RegisterFile()
{
-#if HAVE(MMAP)
- munmap(m_buffer, ((m_max - m_start) + m_maxGlobals) * sizeof(Register));
-#elif HAVE(VIRTUALALLOC)
-#if OS(WINCE)
- VirtualFree(m_buffer, DWORD(m_commitEnd) - DWORD(m_buffer), MEM_DECOMMIT);
-#endif
- VirtualFree(m_buffer, 0, MEM_RELEASE);
-#else
- fastFree(m_buffer);
-#endif
+ void* base = m_reservation.base();
+ m_reservation.decommit(base, reinterpret_cast<intptr_t>(m_commitEnd) - reinterpret_cast<intptr_t>(base));
+ addToCommittedByteCount(-(reinterpret_cast<intptr_t>(m_commitEnd) - reinterpret_cast<intptr_t>(base)));
+ m_reservation.deallocate();
+}
+
+void RegisterFile::gatherConservativeRoots(ConservativeRoots& conservativeRoots)
+{
+ for (Register* it = start(); it != end(); ++it) {
+ JSValue v = it->jsValue();
+ if (!v.isCell())
+ continue;
+ conservativeRoots.add(v.asCell());
+ }
}
void RegisterFile::releaseExcessCapacity()
{
-#if HAVE(MMAP) && HAVE(MADV_FREE) && !HAVE(VIRTUALALLOC)
- while (madvise(m_start, (m_max - m_start) * sizeof(Register), MADV_FREE) == -1 && errno == EAGAIN) { }
-#elif HAVE(VIRTUALALLOC)
- VirtualFree(m_start, (m_max - m_start) * sizeof(Register), MEM_DECOMMIT);
+ m_reservation.decommit(m_start, reinterpret_cast<intptr_t>(m_commitEnd) - reinterpret_cast<intptr_t>(m_start));
+ addToCommittedByteCount(-(reinterpret_cast<intptr_t>(m_commitEnd) - reinterpret_cast<intptr_t>(m_start)));
m_commitEnd = m_start;
-#endif
m_maxUsed = m_start;
}
void RegisterFile::setGlobalObject(JSGlobalObject* globalObject)
{
- m_globalObject = globalObject;
+ m_globalObject.set(globalObject->globalData(), globalObject, &m_globalObjectOwner, this);
}
-bool RegisterFile::clearGlobalObject(JSGlobalObject* globalObject)
+JSGlobalObject* RegisterFile::globalObject()
{
- return m_globalObject.clear(globalObject);
+ return m_globalObject.get();
}
-JSGlobalObject* RegisterFile::globalObject()
+void RegisterFile::initializeThreading()
{
- return m_globalObject.get();
+ registerFileStatisticsMutex();
+}
+
+size_t RegisterFile::committedByteCount()
+{
+ MutexLocker locker(registerFileStatisticsMutex());
+ return committedBytesCount;
+}
+
+void RegisterFile::addToCommittedByteCount(long byteCount)
+{
+ MutexLocker locker(registerFileStatisticsMutex());
+ ASSERT(static_cast<long>(committedBytesCount) + byteCount > -1);
+ committedBytesCount += byteCount;
}
} // namespace JSC
#ifndef RegisterFile_h
#define RegisterFile_h
-#include "Collector.h"
+#include "Heap.h"
#include "ExecutableAllocator.h"
#include "Register.h"
-#include "WeakGCPtr.h"
+#include "Weak.h"
#include <stdio.h>
#include <wtf/Noncopyable.h>
+#include <wtf/PageReservation.h>
#include <wtf/VMTags.h>
-#if HAVE(MMAP)
-#include <errno.h>
-#include <sys/mman.h>
-#endif
-
namespace JSC {
/*
class JSGlobalObject;
- class RegisterFile : public Noncopyable {
- friend class JIT;
+ class RegisterFile {
+ WTF_MAKE_NONCOPYABLE(RegisterFile);
public:
enum CallFrameHeaderEntry {
- CallFrameHeaderSize = 8,
-
- CodeBlock = -8,
- ScopeChain = -7,
- CallerFrame = -6,
- ReturnPC = -5, // This is either an Instruction* or a pointer into JIT generated code stored as an Instruction*.
- ReturnValueRegister = -4,
- ArgumentCount = -3,
- Callee = -2,
- OptionalCalleeArguments = -1,
+ CallFrameHeaderSize = 6,
+
+ ArgumentCount = -6,
+ CallerFrame = -5,
+ Callee = -4,
+ ScopeChain = -3,
+ ReturnPC = -2, // This is either an Instruction* or a pointer into JIT generated code stored as an Instruction*.
+ CodeBlock = -1,
};
enum { ProgramCodeThisRegister = -CallFrameHeaderSize - 1 };
- enum { ArgumentsRegister = 0 };
- static const size_t defaultCapacity = 524288;
- static const size_t defaultMaxGlobals = 8192;
- static const size_t commitSize = 1 << 14;
+ static const size_t defaultCapacity = 512 * 1024;
+ static const size_t defaultMaxGlobals = 8 * 1024;
+ static const size_t commitSize = 16 * 1024;
// Allow 8k of excess registers before we start trying to reap the registerfile
static const ptrdiff_t maxExcessCapacity = 8 * 1024;
- RegisterFile(size_t capacity = defaultCapacity, size_t maxGlobals = defaultMaxGlobals);
+ RegisterFile(JSGlobalData&, size_t capacity = defaultCapacity, size_t maxGlobals = defaultMaxGlobals);
~RegisterFile();
+
+ void gatherConservativeRoots(ConservativeRoots&);
Register* start() const { return m_start; }
Register* end() const { return m_end; }
size_t size() const { return m_end - m_start; }
void setGlobalObject(JSGlobalObject*);
- bool clearGlobalObject(JSGlobalObject*);
JSGlobalObject* globalObject();
bool grow(Register* newEnd);
Register* lastGlobal() const { return m_start - m_numGlobals; }
- void markGlobals(MarkStack& markStack, Heap* heap) { heap->markConservatively(markStack, lastGlobal(), m_start); }
- void markCallFrames(MarkStack& markStack, Heap* heap) { heap->markConservatively(markStack, m_start, m_end); }
+ static size_t committedByteCount();
+ static void initializeThreading();
+
+ Register* const * addressOfEnd() const
+ {
+ return &m_end;
+ }
private:
void releaseExcessCapacity();
+ void addToCommittedByteCount(long);
size_t m_numGlobals;
const size_t m_maxGlobals;
Register* m_start;
Register* m_end;
Register* m_max;
- Register* m_buffer;
Register* m_maxUsed;
-
-#if HAVE(VIRTUALALLOC)
Register* m_commitEnd;
-#endif
+ PageReservation m_reservation;
- WeakGCPtr<JSGlobalObject> m_globalObject; // The global object whose vars are currently stored in the register file.
+ Weak<JSGlobalObject> m_globalObject; // The global object whose vars are currently stored in the register file.
+ class GlobalObjectOwner : public WeakHandleOwner {
+ virtual void finalize(Handle<Unknown>, void* context)
+ {
+ static_cast<RegisterFile*>(context)->setNumGlobals(0);
+ }
+ } m_globalObjectOwner;
};
- // FIXME: Add a generic getpagesize() to WTF, then move this function to WTF as well.
- inline bool isPageAligned(size_t size) { return size != 0 && size % (8 * 1024) == 0; }
-
- inline RegisterFile::RegisterFile(size_t capacity, size_t maxGlobals)
+ inline RegisterFile::RegisterFile(JSGlobalData& globalData, size_t capacity, size_t maxGlobals)
: m_numGlobals(0)
, m_maxGlobals(maxGlobals)
, m_start(0)
, m_end(0)
, m_max(0)
- , m_buffer(0)
+ , m_globalObject(globalData, 0, &m_globalObjectOwner, this)
{
- // Verify that our values will play nice with mmap and VirtualAlloc.
- ASSERT(isPageAligned(maxGlobals));
- ASSERT(isPageAligned(capacity));
-
+ ASSERT(maxGlobals && isPageAligned(maxGlobals));
+ ASSERT(capacity && isPageAligned(capacity));
size_t bufferLength = (capacity + maxGlobals) * sizeof(Register);
- #if HAVE(MMAP)
- m_buffer = static_cast<Register*>(mmap(0, bufferLength, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, VM_TAG_FOR_REGISTERFILE_MEMORY, 0));
- if (m_buffer == MAP_FAILED) {
-#if OS(WINCE)
- fprintf(stderr, "Could not allocate register file: %d\n", GetLastError());
-#else
- fprintf(stderr, "Could not allocate register file: %d\n", errno);
-#endif
- CRASH();
- }
- #elif HAVE(VIRTUALALLOC)
- m_buffer = static_cast<Register*>(VirtualAlloc(0, roundUpAllocationSize(bufferLength, commitSize), MEM_RESERVE, PAGE_READWRITE));
- if (!m_buffer) {
-#if OS(WINCE)
- fprintf(stderr, "Could not allocate register file: %d\n", GetLastError());
-#else
- fprintf(stderr, "Could not allocate register file: %d\n", errno);
-#endif
- CRASH();
- }
+ m_reservation = PageReservation::reserve(roundUpAllocationSize(bufferLength, commitSize), OSAllocator::JSVMStackPages);
+ void* base = m_reservation.base();
size_t committedSize = roundUpAllocationSize(maxGlobals * sizeof(Register), commitSize);
- void* commitCheck = VirtualAlloc(m_buffer, committedSize, MEM_COMMIT, PAGE_READWRITE);
- if (commitCheck != m_buffer) {
-#if OS(WINCE)
- fprintf(stderr, "Could not allocate register file: %d\n", GetLastError());
-#else
- fprintf(stderr, "Could not allocate register file: %d\n", errno);
-#endif
- CRASH();
- }
- m_commitEnd = reinterpret_cast<Register*>(reinterpret_cast<char*>(m_buffer) + committedSize);
- #else
- /*
- * If neither MMAP nor VIRTUALALLOC are available - use fastMalloc instead.
- *
- * Please note that this is the fallback case, which is non-optimal.
- * If any possible, the platform should provide for a better memory
- * allocation mechanism that allows for "lazy commit" or dynamic
- * pre-allocation, similar to mmap or VirtualAlloc, to avoid waste of memory.
- */
- m_buffer = static_cast<Register*>(fastMalloc(bufferLength));
- #endif
- m_start = m_buffer + maxGlobals;
+ m_reservation.commit(base, committedSize);
+ addToCommittedByteCount(static_cast<long>(committedSize));
+ m_commitEnd = reinterpret_cast_ptr<Register*>(reinterpret_cast<char*>(base) + committedSize);
+ m_start = static_cast<Register*>(base) + maxGlobals;
m_end = m_start;
m_maxUsed = m_end;
m_max = m_start + capacity;
if (newEnd > m_max)
return false;
-#if !HAVE(MMAP) && HAVE(VIRTUALALLOC)
if (newEnd > m_commitEnd) {
size_t size = roundUpAllocationSize(reinterpret_cast<char*>(newEnd) - reinterpret_cast<char*>(m_commitEnd), commitSize);
- if (!VirtualAlloc(m_commitEnd, size, MEM_COMMIT, PAGE_READWRITE)) {
-#if OS(WINCE)
- fprintf(stderr, "Could not allocate register file: %d\n", GetLastError());
-#else
- fprintf(stderr, "Could not allocate register file: %d\n", errno);
-#endif
- CRASH();
- }
- m_commitEnd = reinterpret_cast<Register*>(reinterpret_cast<char*>(m_commitEnd) + size);
+ m_reservation.commit(m_commitEnd, size);
+ addToCommittedByteCount(static_cast<long>(size));
+ m_commitEnd = reinterpret_cast_ptr<Register*>(reinterpret_cast<char*>(m_commitEnd) + size);
}
-#endif
if (newEnd > m_maxUsed)
m_maxUsed = newEnd;
size_t ExecutableAllocator::pageSize = 0;
+#if ENABLE(EXECUTABLE_ALLOCATOR_DEMAND)
+
+void ExecutableAllocator::intializePageSize()
+{
+#if OS(SYMBIAN) && CPU(ARMV5_OR_LOWER)
+ // The moving memory model (as used in ARMv5 and earlier platforms)
+ // on Symbian OS limits the number of chunks for each process to 16.
+ // To mitigate this limitation increase the pagesize to allocate
+ // fewer, larger chunks. Set the page size to 256 Kb to compensate
+ // for moving memory model limitation
+ ExecutableAllocator::pageSize = 256 * 1024;
+#else
+ ExecutableAllocator::pageSize = WTF::pageSize();
+#endif
+}
+
+ExecutablePool::Allocation ExecutablePool::systemAlloc(size_t size)
+{
+ PageAllocation allocation = PageAllocation::allocate(size, OSAllocator::JSJITCodePages, EXECUTABLE_POOL_WRITABLE, true);
+ if (!allocation)
+ CRASH();
+ return allocation;
+}
+
+void ExecutablePool::systemRelease(ExecutablePool::Allocation& allocation)
+{
+ allocation.deallocate();
+}
+
+bool ExecutableAllocator::isValid() const
+{
+ return true;
+}
+
+bool ExecutableAllocator::underMemoryPressure()
+{
+ return false;
+}
+
+size_t ExecutableAllocator::committedByteCount()
+{
+ return 0;
+}
+
+#endif
+
#if ENABLE(ASSEMBLER_WX_EXCLUSIVE)
-void ExecutableAllocator::reprotectRegion(void* start, size_t size, ProtectionSeting setting)
+
+#if OS(WINDOWS) || OS(SYMBIAN)
+#error "ASSEMBLER_WX_EXCLUSIVE not yet suported on this platform."
+#endif
+
+void ExecutableAllocator::reprotectRegion(void* start, size_t size, ProtectionSetting setting)
{
if (!pageSize)
intializePageSize();
mprotect(pageStart, size, (setting == Writable) ? PROTECTION_FLAGS_RW : PROTECTION_FLAGS_RX);
}
+
#endif
#if CPU(ARM_TRADITIONAL) && OS(LINUX) && COMPILER(RVCT)
+
__asm void ExecutableAllocator::cacheFlush(void* code, size_t size)
{
ARM
pop {r7}
bx lr
}
+
#endif
}
#ifndef ExecutableAllocator_h
#define ExecutableAllocator_h
-
#include <stddef.h> // for ptrdiff_t
#include <limits>
#include <wtf/Assertions.h>
+#include <wtf/PageAllocation.h>
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
#include <wtf/UnusedParam.h>
#include <wtf/Vector.h>
-#if OS(IPHONE_OS)
+#if OS(IOS)
#include <libkern/OSCacheControl.h>
#include <sys/mman.h>
#endif
#include <sys/cachectl.h>
#endif
+#if CPU(SH4) && OS(LINUX)
+#include <asm/cachectl.h>
+#include <asm/unistd.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+#endif
+
#if OS(WINCE)
// From pkfuncs.h (private header file from the Platform Builder)
#define CACHE_SYNC_ALL 0x07F
extern "C" __declspec(dllimport) void CacheRangeFlush(LPVOID pAddr, DWORD dwLength, DWORD dwFlags);
#endif
+#if PLATFORM(BREWMP)
+#include <AEEIMemCache1.h>
+#include <AEEMemCache1.bid>
+#include <wtf/brew/RefPtrBrew.h>
+#endif
+
#define JIT_ALLOCATOR_PAGE_SIZE (ExecutableAllocator::pageSize)
#define JIT_ALLOCATOR_LARGE_ALLOC_SIZE (ExecutableAllocator::pageSize * 4)
#if ENABLE(ASSEMBLER_WX_EXCLUSIVE)
#define PROTECTION_FLAGS_RW (PROT_READ | PROT_WRITE)
#define PROTECTION_FLAGS_RX (PROT_READ | PROT_EXEC)
-#define INITIAL_PROTECTION_FLAGS PROTECTION_FLAGS_RX
+#define EXECUTABLE_POOL_WRITABLE false
#else
-#define INITIAL_PROTECTION_FLAGS (PROT_READ | PROT_WRITE | PROT_EXEC)
+#define EXECUTABLE_POOL_WRITABLE true
#endif
namespace JSC {
}
-#if ENABLE(ASSEMBLER)
+#if ENABLE(JIT) && ENABLE(ASSEMBLER)
namespace JSC {
+class JSGlobalData;
+void releaseExecutableMemory(JSGlobalData&);
+
class ExecutablePool : public RefCounted<ExecutablePool> {
-private:
- struct Allocation {
- char* pages;
- size_t size;
-#if OS(SYMBIAN)
- RChunk* chunk;
-#endif
+public:
+#if ENABLE(EXECUTABLE_ALLOCATOR_DEMAND)
+ typedef PageAllocation Allocation;
+#else
+ class Allocation {
+ public:
+ Allocation(void* base, size_t size)
+ : m_base(base)
+ , m_size(size)
+ {
+ }
+ void* base() { return m_base; }
+ size_t size() { return m_size; }
+ bool operator!() const { return !m_base; }
+
+ private:
+ void* m_base;
+ size_t m_size;
};
+#endif
typedef Vector<Allocation, 2> AllocationList;
-public:
- static PassRefPtr<ExecutablePool> create(size_t n)
+ static PassRefPtr<ExecutablePool> create(JSGlobalData& globalData, size_t n)
{
- return adoptRef(new ExecutablePool(n));
+ return adoptRef(new ExecutablePool(globalData, n));
}
- void* alloc(size_t n)
+ void* alloc(JSGlobalData& globalData, size_t n)
{
ASSERT(m_freePtr <= m_end);
// Insufficient space to allocate in the existing pool
// so we need allocate into a new pool
- return poolAllocate(n);
+ return poolAllocate(globalData, n);
}
void tryShrink(void* allocation, size_t oldSize, size_t newSize)
~ExecutablePool()
{
- AllocationList::const_iterator end = m_pools.end();
- for (AllocationList::const_iterator ptr = m_pools.begin(); ptr != end; ++ptr)
+ AllocationList::iterator end = m_pools.end();
+ for (AllocationList::iterator ptr = m_pools.begin(); ptr != end; ++ptr)
ExecutablePool::systemRelease(*ptr);
}
size_t available() const { return (m_pools.size() > 1) ? 0 : m_end - m_freePtr; }
- static bool underMemoryPressure();
-
private:
static Allocation systemAlloc(size_t n);
- static void systemRelease(const Allocation& alloc);
+ static void systemRelease(Allocation& alloc);
- ExecutablePool(size_t n);
+ ExecutablePool(JSGlobalData&, size_t n);
- void* poolAllocate(size_t n);
+ void* poolAllocate(JSGlobalData&, size_t n);
char* m_freePtr;
char* m_end;
};
class ExecutableAllocator {
- enum ProtectionSeting { Writable, Executable };
+ enum ProtectionSetting { Writable, Executable };
public:
static size_t pageSize;
- ExecutableAllocator()
+ ExecutableAllocator(JSGlobalData& globalData)
{
if (!pageSize)
intializePageSize();
if (isValid())
- m_smallAllocationPool = ExecutablePool::create(JIT_ALLOCATOR_LARGE_ALLOC_SIZE);
+ m_smallAllocationPool = ExecutablePool::create(globalData, JIT_ALLOCATOR_LARGE_ALLOC_SIZE);
#if !ENABLE(INTERPRETER)
else
CRASH();
}
bool isValid() const;
-
- PassRefPtr<ExecutablePool> poolForSize(size_t n)
+
+ static bool underMemoryPressure();
+
+ PassRefPtr<ExecutablePool> poolForSize(JSGlobalData& globalData, size_t n)
{
// Try to fit in the existing small allocator
ASSERT(m_smallAllocationPool);
// If the request is large, we just provide a unshared allocator
if (n > JIT_ALLOCATOR_LARGE_ALLOC_SIZE)
- return ExecutablePool::create(n);
+ return ExecutablePool::create(globalData, n);
// Create a new allocator
- RefPtr<ExecutablePool> pool = ExecutablePool::create(JIT_ALLOCATOR_LARGE_ALLOC_SIZE);
+ RefPtr<ExecutablePool> pool = ExecutablePool::create(globalData, JIT_ALLOCATOR_LARGE_ALLOC_SIZE);
// If the new allocator will result in more free space than in
// the current small allocator, then we will use it instead
#elif CPU(MIPS)
static void cacheFlush(void* code, size_t size)
{
-#if COMPILER(GCC) && (GCC_VERSION >= 40300)
-#if WTF_MIPS_ISA_REV(2) && (GCC_VERSION < 40403)
+#if GCC_VERSION_AT_LEAST(4, 3, 0)
+#if WTF_MIPS_ISA_REV(2) && !GCC_VERSION_AT_LEAST(4, 4, 3)
int lineSize;
asm("rdhwr %0, $1" : "=r" (lineSize));
//
_flush_cache(reinterpret_cast<char*>(code), size, BCACHE);
#endif
}
-#elif CPU(ARM_THUMB2) && OS(IPHONE_OS)
+#elif CPU(ARM_THUMB2) && OS(IOS)
static void cacheFlush(void* code, size_t size)
{
- sys_dcache_flush(code, size);
- sys_icache_invalidate(code, size);
+ sys_cache_control(kCacheFunctionPrepareForExecution, code, size);
}
#elif CPU(ARM_THUMB2) && OS(LINUX)
static void cacheFlush(void* code, size_t size)
{
CacheRangeFlush(code, size, CACHE_SYNC_ALL);
}
+#elif PLATFORM(BREWMP)
+ static void cacheFlush(void* code, size_t size)
+ {
+ RefPtr<IMemCache1> memCache = createRefPtrInstance<IMemCache1>(AEECLSID_MemCache1);
+ IMemCache1_ClearCache(memCache.get(), reinterpret_cast<uint32>(code), size, MEMSPACE_CACHE_FLUSH, MEMSPACE_DATACACHE);
+ IMemCache1_ClearCache(memCache.get(), reinterpret_cast<uint32>(code), size, MEMSPACE_CACHE_INVALIDATE, MEMSPACE_INSTCACHE);
+ }
+#elif CPU(SH4) && OS(LINUX)
+ static void cacheFlush(void* code, size_t size)
+ {
+#ifdef CACHEFLUSH_D_L2
+ syscall(__NR_cacheflush, reinterpret_cast<unsigned>(code), size, CACHEFLUSH_D_WB | CACHEFLUSH_I | CACHEFLUSH_D_L2);
+#else
+ syscall(__NR_cacheflush, reinterpret_cast<unsigned>(code), size, CACHEFLUSH_D_WB | CACHEFLUSH_I);
+#endif
+ }
#else
#error "The cacheFlush support is missing on this platform."
#endif
+ static size_t committedByteCount();
private:
#if ENABLE(ASSEMBLER_WX_EXCLUSIVE)
- static void reprotectRegion(void*, size_t, ProtectionSeting);
+ static void reprotectRegion(void*, size_t, ProtectionSetting);
#endif
RefPtr<ExecutablePool> m_smallAllocationPool;
static void intializePageSize();
};
-inline ExecutablePool::ExecutablePool(size_t n)
+inline ExecutablePool::ExecutablePool(JSGlobalData& globalData, size_t n)
{
size_t allocSize = roundUpAllocationSize(n, JIT_ALLOCATOR_PAGE_SIZE);
Allocation mem = systemAlloc(allocSize);
+ if (!mem.base()) {
+ releaseExecutableMemory(globalData);
+ mem = systemAlloc(allocSize);
+ }
m_pools.append(mem);
- m_freePtr = mem.pages;
+ m_freePtr = static_cast<char*>(mem.base());
if (!m_freePtr)
CRASH(); // Failed to allocate
m_end = m_freePtr + allocSize;
}
-inline void* ExecutablePool::poolAllocate(size_t n)
+inline void* ExecutablePool::poolAllocate(JSGlobalData& globalData, size_t n)
{
size_t allocSize = roundUpAllocationSize(n, JIT_ALLOCATOR_PAGE_SIZE);
Allocation result = systemAlloc(allocSize);
- if (!result.pages)
- CRASH(); // Failed to allocate
+ if (!result.base()) {
+ releaseExecutableMemory(globalData);
+ result = systemAlloc(allocSize);
+ if (!result.base())
+ CRASH(); // Failed to allocate
+ }
ASSERT(m_end >= m_freePtr);
if ((allocSize - n) > static_cast<size_t>(m_end - m_freePtr)) {
// Replace allocation pool
- m_freePtr = result.pages + n;
- m_end = result.pages + allocSize;
+ m_freePtr = static_cast<char*>(result.base()) + n;
+ m_end = static_cast<char*>(result.base()) + allocSize;
}
m_pools.append(result);
- return result.pages;
+ return result.base();
}
}
-#endif // ENABLE(ASSEMBLER)
+#else
+
+namespace JSC {
+
+class ExecutableAllocator {
+public:
+ static size_t committedByteCount();
+};
+
+} // namespace JSC
+
+#endif // ENABLE(JIT) && ENABLE(ASSEMBLER)
#endif // !defined(ExecutableAllocator)
#include <sys/mman.h>
#include <unistd.h>
#include <wtf/AVLTree.h>
+#include <wtf/PageReservation.h>
#include <wtf/VMTags.h>
+#if OS(LINUX)
+#include <stdio.h>
+#endif
+
#define MMAP_FLAGS (MAP_PRIVATE | MAP_ANON | MAP_JIT)
using namespace WTF;
namespace JSC {
-
+
#define TwoPow(n) (1ull << n)
class AllocationTableSizeClass {
// Mirror the suballocation's full bit.
if (m_suballocations[i].isFull())
m_full |= bit;
- return (i * subregionSize) + location;
+ return (i * subregionSize) | location;
}
}
return notFound;
BitField m_hasSuballocation;
};
+
typedef AllocationTableLeaf<6> PageTables256KB;
typedef AllocationTableDirectory<PageTables256KB, 6> PageTables16MB;
typedef AllocationTableDirectory<LazyAllocationTable<PageTables16MB>, 1> PageTables32MB;
#if CPU(ARM)
typedef PageTables16MB FixedVMPoolPageTables;
-#elif CPU(X86_64) && !OS(LINUX)
+#elif CPU(X86_64)
typedef PageTables1GB FixedVMPoolPageTables;
#else
typedef PageTables32MB FixedVMPoolPageTables;
#endif
+
class FixedVMPoolAllocator
{
public:
FixedVMPoolAllocator()
{
- m_base = mmap(0, FixedVMPoolPageTables::size(), INITIAL_PROTECTION_FLAGS, MMAP_FLAGS, VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY, 0);
+ ASSERT(PageTables256KB::size() == 256 * 1024);
+ ASSERT(PageTables16MB::size() == 16 * 1024 * 1024);
+ ASSERT(PageTables32MB::size() == 32 * 1024 * 1024);
+ ASSERT(PageTables1GB::size() == 1024 * 1024 * 1024);
- if (m_base == MAP_FAILED) {
-#if ENABLE(INTERPRETER)
- m_base = 0;
-#else
+ m_reservation = PageReservation::reserveWithGuardPages(FixedVMPoolPageTables::size(), OSAllocator::JSJITCodePages, EXECUTABLE_POOL_WRITABLE, true);
+#if !ENABLE(INTERPRETER)
+ if (!isValid())
CRASH();
#endif
- } else {
- // For simplicity, we keep all memory in m_freeList in a 'released' state.
- // This means that we can simply reuse all memory when allocating, without
- // worrying about it's previous state, and also makes coalescing m_freeList
- // simpler since we need not worry about the possibility of coalescing released
- // chunks with non-released ones.
- release(m_base, FixedVMPoolPageTables::size());
- }
}
- void* alloc(size_t size)
+ ExecutablePool::Allocation alloc(size_t requestedSize)
{
+ ASSERT(requestedSize);
+ AllocationTableSizeClass sizeClass = classForSize(requestedSize);
+ size_t size = sizeClass.size();
ASSERT(size);
- AllocationTableSizeClass sizeClass = classForSize(size);
- ASSERT(sizeClass.size());
- if (sizeClass.size() >= FixedVMPoolPageTables::size())
- CRASH();
+ if (size >= FixedVMPoolPageTables::size())
+ return ExecutablePool::Allocation(0, 0);
if (m_pages.isFull())
- CRASH();
+ return ExecutablePool::Allocation(0, 0);
+
size_t offset = m_pages.allocate(sizeClass);
if (offset == notFound)
- CRASH();
+ return ExecutablePool::Allocation(0, 0);
- void* result = offsetToPointer(offset);
- reuse(result, size);
- return result;
+ void* pointer = offsetToPointer(offset);
+ m_reservation.commit(pointer, size);
+ return ExecutablePool::Allocation(pointer, size);
}
- void free(void* pointer, size_t size)
+ void free(ExecutablePool::Allocation allocation)
{
- release(pointer, size);
-
+ void* pointer = allocation.base();
+ size_t size = allocation.size();
ASSERT(size);
- AllocationTableSizeClass sizeClass = classForSize(size);
- ASSERT(sizeClass.size());
- ASSERT(sizeClass.size() < FixedVMPoolPageTables::size());
- m_pages.free(pointerToOffset(pointer), sizeClass);
- }
+ m_reservation.decommit(pointer, size);
- bool isValid() const
- {
- return !!m_base;
+ AllocationTableSizeClass sizeClass = classForSize(size);
+ ASSERT(sizeClass.size() == size);
+ m_pages.free(pointerToOffset(pointer), sizeClass);
}
-private:
- // Use madvise as apropriate to prevent freed pages from being spilled,
- // and to attempt to ensure that used memory is reported correctly.
-#if HAVE(MADV_FREE_REUSE)
- void release(void* position, size_t size)
+ size_t allocated()
{
- while (madvise(position, size, MADV_FREE_REUSABLE) == -1 && errno == EAGAIN) { }
+ return m_reservation.committed();
}
- void reuse(void* position, size_t size)
- {
- while (madvise(position, size, MADV_FREE_REUSE) == -1 && errno == EAGAIN) { }
- }
-#elif HAVE(MADV_FREE)
- void release(void* position, size_t size)
- {
- while (madvise(position, size, MADV_FREE) == -1 && errno == EAGAIN) { }
- }
-
- void reuse(void*, size_t) {}
-#elif HAVE(MADV_DONTNEED)
- void release(void* position, size_t size)
+ bool isValid() const
{
- while (madvise(position, size, MADV_DONTNEED) == -1 && errno == EAGAIN) { }
+ return !!m_reservation;
}
- void reuse(void*, size_t) {}
-#else
- void release(void*, size_t) {}
- void reuse(void*, size_t) {}
-#endif
-
+private:
AllocationTableSizeClass classForSize(size_t size)
{
return FixedVMPoolPageTables::classForSize(size);
void* offsetToPointer(size_t offset)
{
- return reinterpret_cast<void*>(reinterpret_cast<intptr_t>(m_base) + offset);
+ return reinterpret_cast<void*>(reinterpret_cast<intptr_t>(m_reservation.base()) + offset);
}
size_t pointerToOffset(void* pointer)
{
- return reinterpret_cast<intptr_t>(pointer) - reinterpret_cast<intptr_t>(m_base);
+ return reinterpret_cast<intptr_t>(pointer) - reinterpret_cast<intptr_t>(m_reservation.base());
}
- void* m_base;
+ PageReservation m_reservation;
FixedVMPoolPageTables m_pages;
};
+
+static SpinLock spinlock = SPINLOCK_INITIALIZER;
+static FixedVMPoolAllocator* allocator = 0;
+
+
+size_t ExecutableAllocator::committedByteCount()
+{
+ SpinLockHolder lockHolder(&spinlock);
+ return allocator ? allocator->allocated() : 0;
+}
+
void ExecutableAllocator::intializePageSize()
{
ExecutableAllocator::pageSize = getpagesize();
}
-static FixedVMPoolAllocator* allocator = 0;
-static size_t allocatedCount = 0;
-static SpinLock spinlock = SPINLOCK_INITIALIZER;
-
bool ExecutableAllocator::isValid() const
{
SpinLockHolder lock_holder(&spinlock);
return allocator->isValid();
}
-ExecutablePool::Allocation ExecutablePool::systemAlloc(size_t size)
+bool ExecutableAllocator::underMemoryPressure()
{
- SpinLockHolder lock_holder(&spinlock);
-
- if (!allocator)
- allocator = new FixedVMPoolAllocator();
- ExecutablePool::Allocation alloc = {reinterpret_cast<char*>(allocator->alloc(size)), size};
- allocatedCount += size;
- return alloc;
+ // Technically we should take the spin lock here, but we don't care if we get stale data.
+ // This is only really a heuristic anyway.
+ return allocator && (allocator->allocated() > (FixedVMPoolPageTables::size() / 2));
}
-void ExecutablePool::systemRelease(const ExecutablePool::Allocation& allocation)
+ExecutablePool::Allocation ExecutablePool::systemAlloc(size_t size)
{
SpinLockHolder lock_holder(&spinlock);
-
ASSERT(allocator);
- allocator->free(allocation.pages, allocation.size);
- allocatedCount -= allocation.size;
+ return allocator->alloc(size);
}
-bool ExecutablePool::underMemoryPressure()
+void ExecutablePool::systemRelease(ExecutablePool::Allocation& allocation)
{
- // Technically we should take the spin lock here, but we don't
- // care if we get stale data. This is only really a heuristic
- // anyway.
- return allocatedCount > (FixedVMPoolPageTables::size() / 2);
+ SpinLockHolder lock_holder(&spinlock);
+ ASSERT(allocator);
+ allocator->free(allocation);
}
}
+
#endif // HAVE(ASSEMBLER)
+
+#if !ENABLE(JIT)
+// FIXME: Needed to satisfy JavaScriptCore.exp requirements when building only the interpreter.
+namespace JSC {
+size_t ExecutableAllocator::committedByteCount()
+{
+ return 0;
+}
+} // namespace JSC
+#endif // !ENABLE(JIT)
+++ /dev/null
-/*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-
-#include "ExecutableAllocator.h"
-
-#if ENABLE(EXECUTABLE_ALLOCATOR_DEMAND) && !OS(WINDOWS) && !OS(SYMBIAN)
-
-#include <sys/mman.h>
-#include <unistd.h>
-#include <wtf/VMTags.h>
-
-namespace JSC {
-
-void ExecutableAllocator::intializePageSize()
-{
- ExecutableAllocator::pageSize = getpagesize();
-}
-
-ExecutablePool::Allocation ExecutablePool::systemAlloc(size_t n)
-{
- void* allocation = mmap(NULL, n, INITIAL_PROTECTION_FLAGS, MAP_PRIVATE | MAP_ANON, VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY, 0);
- if (allocation == MAP_FAILED)
- CRASH();
- ExecutablePool::Allocation alloc = { reinterpret_cast<char*>(allocation), n };
- return alloc;
-}
-
-void ExecutablePool::systemRelease(const ExecutablePool::Allocation& alloc)
-{
- int result = munmap(alloc.pages, alloc.size);
- ASSERT_UNUSED(result, !result);
-}
-
-bool ExecutablePool::underMemoryPressure()
-{
- return false;
-}
-
-bool ExecutableAllocator::isValid() const
-{
- return true;
-}
-
-#if CPU(ARM_TRADITIONAL) && OS(LINUX) && COMPILER(RVCT)
-__asm void ExecutableAllocator::cacheFlush(void* code, size_t size)
-{
- ARM
- push {r7}
- add r1, r1, r0
- mov r7, #0xf0000
- add r7, r7, #0x2
- mov r2, #0x0
- svc #0x0
- pop {r7}
- bx lr
-}
-#endif
-
-}
-
-#endif
+++ /dev/null
-/*
- * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA
- *
- */
-
-#include "config.h"
-
-#include "ExecutableAllocator.h"
-
-#if ENABLE(EXECUTABLE_ALLOCATOR_DEMAND) && OS(SYMBIAN)
-
-#include <e32hal.h>
-#include <e32std.h>
-
-// Set the page size to 256 Kb to compensate for moving memory model limitation
-const size_t MOVING_MEM_PAGE_SIZE = 256 * 1024;
-
-namespace JSC {
-
-void ExecutableAllocator::intializePageSize()
-{
-#if CPU(ARMV5_OR_LOWER)
- // The moving memory model (as used in ARMv5 and earlier platforms)
- // on Symbian OS limits the number of chunks for each process to 16.
- // To mitigate this limitation increase the pagesize to
- // allocate less of larger chunks.
- ExecutableAllocator::pageSize = MOVING_MEM_PAGE_SIZE;
-#else
- TInt page_size;
- UserHal::PageSizeInBytes(page_size);
- ExecutableAllocator::pageSize = page_size;
-#endif
-}
-
-ExecutablePool::Allocation ExecutablePool::systemAlloc(size_t n)
-{
- RChunk* codeChunk = new RChunk();
-
- TInt errorCode = codeChunk->CreateLocalCode(n, n);
-
- char* allocation = reinterpret_cast<char*>(codeChunk->Base());
- if (!allocation)
- CRASH();
- ExecutablePool::Allocation alloc = { allocation, n, codeChunk };
- return alloc;
-}
-
-void ExecutablePool::systemRelease(const ExecutablePool::Allocation& alloc)
-{
- alloc.chunk->Close();
- delete alloc.chunk;
-}
-
-#if ENABLE(ASSEMBLER_WX_EXCLUSIVE)
-#error "ASSEMBLER_WX_EXCLUSIVE not yet suported on this platform."
-#endif
-
-}
-
-#endif // HAVE(ASSEMBLER)
+++ /dev/null
-/*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-
-#include "ExecutableAllocator.h"
-
-#if ENABLE(EXECUTABLE_ALLOCATOR_DEMAND) && OS(WINDOWS)
-
-#include "windows.h"
-
-namespace JSC {
-
-void ExecutableAllocator::intializePageSize()
-{
- SYSTEM_INFO system_info;
- GetSystemInfo(&system_info);
- ExecutableAllocator::pageSize = system_info.dwPageSize;
-}
-
-ExecutablePool::Allocation ExecutablePool::systemAlloc(size_t n)
-{
- void* allocation = VirtualAlloc(0, n, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
- if (!allocation)
- CRASH();
- ExecutablePool::Allocation alloc = {reinterpret_cast<char*>(allocation), n};
- return alloc;
-}
-
-void ExecutablePool::systemRelease(const ExecutablePool::Allocation& alloc)
-{
- VirtualFree(alloc.pages, 0, MEM_RELEASE);
-}
-
-bool ExecutablePool::underMemoryPressure()
-{
- return false;
-}
-
-bool ExecutableAllocator::isValid() const
-{
- return true;
-}
-
-#if ENABLE(ASSEMBLER_WX_EXCLUSIVE)
-#error "ASSEMBLER_WX_EXCLUSIVE not yet suported on this platform."
-#endif
-
-}
-
-#endif // HAVE(ASSEMBLER)
*/
#include "config.h"
+
+#if ENABLE(JIT)
#include "JIT.h"
// This probably does not belong here; adding here for now as a quick Windows build fix.
JSC::MacroAssemblerX86Common::SSE2CheckState JSC::MacroAssemblerX86Common::s_sse2CheckState = NotCheckedSSE2;
#endif
-#if ENABLE(JIT)
-
#include "CodeBlock.h"
+#include "CryptographicallyRandomNumber.h"
#include "Interpreter.h"
#include "JITInlineMethods.h"
#include "JITStubCall.h"
#include "RepatchBuffer.h"
#include "ResultType.h"
#include "SamplingTool.h"
-
-#ifndef NDEBUG
-#include <stdio.h>
-#endif
+#include "dfg/DFGNode.h" // for DFG_SUCCESS_STATS
using namespace std;
repatchBuffer.relinkCallerToFunction(returnAddress, newCalleeFunction);
}
-JIT::JIT(JSGlobalData* globalData, CodeBlock* codeBlock, void* linkerOffset)
+JIT::JIT(JSGlobalData* globalData, CodeBlock* codeBlock)
: m_interpreter(globalData->interpreter)
, m_globalData(globalData)
, m_codeBlock(codeBlock)
, m_labels(codeBlock ? codeBlock->instructions().size() : 0)
, m_propertyAccessCompilationInfo(codeBlock ? codeBlock->numberOfStructureStubInfos() : 0)
, m_callStructureStubCompilationInfo(codeBlock ? codeBlock->numberOfCallLinkInfos() : 0)
- , m_bytecodeIndex((unsigned)-1)
+ , m_bytecodeOffset((unsigned)-1)
#if USE(JSVALUE32_64)
, m_jumpTargetIndex(0)
- , m_mappedBytecodeIndex((unsigned)-1)
+ , m_mappedBytecodeOffset((unsigned)-1)
, m_mappedVirtualRegisterIndex((unsigned)-1)
, m_mappedTag((RegisterID)-1)
, m_mappedPayload((RegisterID)-1)
, m_lastResultBytecodeRegister(std::numeric_limits<int>::max())
, m_jumpTargetsPosition(0)
#endif
- , m_linkerOffset(linkerOffset)
+#if USE(OS_RANDOMNESS)
+ , m_randomGenerator(cryptographicallyRandomNumber())
+#else
+ , m_randomGenerator(static_cast<unsigned>(randomNumber() * 0xFFFFFFF))
+#endif
{
}
#if USE(JSVALUE32_64)
void JIT::emitTimeoutCheck()
{
- Jump skipTimeout = branchSub32(NonZero, Imm32(1), timeoutCheckRegister);
+ Jump skipTimeout = branchSub32(NonZero, TrustedImm32(1), timeoutCheckRegister);
JITStubCall stubCall(this, cti_timeout_check);
stubCall.addArgument(regT1, regT0); // save last result registers.
stubCall.call(timeoutCheckRegister);
#else
void JIT::emitTimeoutCheck()
{
- Jump skipTimeout = branchSub32(NonZero, Imm32(1), timeoutCheckRegister);
+ Jump skipTimeout = branchSub32(NonZero, TrustedImm32(1), timeoutCheckRegister);
JITStubCall(this, cti_timeout_check).call(timeoutCheckRegister);
skipTimeout.link(this);
#endif
#define NEXT_OPCODE(name) \
- m_bytecodeIndex += OPCODE_LENGTH(name); \
+ m_bytecodeOffset += OPCODE_LENGTH(name); \
break;
#if USE(JSVALUE32_64)
m_globalResolveInfoIndex = 0;
m_callLinkInfoIndex = 0;
- for (m_bytecodeIndex = 0; m_bytecodeIndex < instructionCount; ) {
- Instruction* currentInstruction = instructionsBegin + m_bytecodeIndex;
- ASSERT_WITH_MESSAGE(m_interpreter->isOpcode(currentInstruction->u.opcode), "privateCompileMainPass gone bad @ %d", m_bytecodeIndex);
+ for (m_bytecodeOffset = 0; m_bytecodeOffset < instructionCount; ) {
+ Instruction* currentInstruction = instructionsBegin + m_bytecodeOffset;
+ ASSERT_WITH_MESSAGE(m_interpreter->isOpcode(currentInstruction->u.opcode), "privateCompileMainPass gone bad @ %d", m_bytecodeOffset);
#if ENABLE(OPCODE_SAMPLING)
- if (m_bytecodeIndex > 0) // Avoid the overhead of sampling op_enter twice.
+ if (m_bytecodeOffset > 0) // Avoid the overhead of sampling op_enter twice.
sampleInstruction(currentInstruction);
#endif
-#if !USE(JSVALUE32_64)
- if (m_labels[m_bytecodeIndex].isUsed())
+#if USE(JSVALUE64)
+ if (atJumpTarget())
killLastResultRegister();
#endif
- m_labels[m_bytecodeIndex] = label();
+ m_labels[m_bytecodeOffset] = label();
switch (m_interpreter->getOpcodeID(currentInstruction->u.opcode)) {
DEFINE_BINARY_OP(op_del_by_val)
-#if USE(JSVALUE32)
- DEFINE_BINARY_OP(op_div)
-#endif
DEFINE_BINARY_OP(op_in)
DEFINE_BINARY_OP(op_less)
DEFINE_BINARY_OP(op_lesseq)
DEFINE_UNARY_OP(op_is_object)
DEFINE_UNARY_OP(op_is_string)
DEFINE_UNARY_OP(op_is_undefined)
-#if !USE(JSVALUE32_64)
+#if USE(JSVALUE64)
DEFINE_UNARY_OP(op_negate)
#endif
DEFINE_UNARY_OP(op_typeof)
DEFINE_OP(op_call_varargs)
DEFINE_OP(op_catch)
DEFINE_OP(op_construct)
- DEFINE_OP(op_construct_verify)
+ DEFINE_OP(op_get_callee)
+ DEFINE_OP(op_create_this)
DEFINE_OP(op_convert_this)
- DEFINE_OP(op_init_arguments)
+ DEFINE_OP(op_convert_this_strict)
+ DEFINE_OP(op_init_lazy_reg)
DEFINE_OP(op_create_arguments)
DEFINE_OP(op_debug)
DEFINE_OP(op_del_by_id)
-#if !USE(JSVALUE32)
DEFINE_OP(op_div)
-#endif
DEFINE_OP(op_end)
DEFINE_OP(op_enter)
- DEFINE_OP(op_enter_with_activation)
+ DEFINE_OP(op_create_activation)
DEFINE_OP(op_eq)
DEFINE_OP(op_eq_null)
DEFINE_OP(op_get_by_id)
+ DEFINE_OP(op_get_arguments_length)
DEFINE_OP(op_get_by_val)
+ DEFINE_OP(op_get_argument_by_val)
DEFINE_OP(op_get_by_pname)
DEFINE_OP(op_get_global_var)
DEFINE_OP(op_get_pnames)
DEFINE_OP(op_get_scoped_var)
+ DEFINE_OP(op_check_has_instance)
DEFINE_OP(op_instanceof)
DEFINE_OP(op_jeq_null)
DEFINE_OP(op_jfalse)
DEFINE_OP(op_neq)
DEFINE_OP(op_neq_null)
DEFINE_OP(op_new_array)
- DEFINE_OP(op_new_error)
+ DEFINE_OP(op_new_array_buffer)
DEFINE_OP(op_new_func)
DEFINE_OP(op_new_func_exp)
DEFINE_OP(op_new_object)
DEFINE_OP(op_put_setter)
DEFINE_OP(op_resolve)
DEFINE_OP(op_resolve_base)
+ DEFINE_OP(op_ensure_property_exists)
DEFINE_OP(op_resolve_global)
DEFINE_OP(op_resolve_global_dynamic)
DEFINE_OP(op_resolve_skip)
DEFINE_OP(op_resolve_with_base)
DEFINE_OP(op_ret)
+ DEFINE_OP(op_call_put_result)
+ DEFINE_OP(op_ret_object_or_this)
DEFINE_OP(op_rshift)
DEFINE_OP(op_urshift)
DEFINE_OP(op_sret)
DEFINE_OP(op_tear_off_activation)
DEFINE_OP(op_tear_off_arguments)
DEFINE_OP(op_throw)
+ DEFINE_OP(op_throw_reference_error)
DEFINE_OP(op_to_jsnumber)
DEFINE_OP(op_to_primitive)
#ifndef NDEBUG
// Reset this, in order to guard its use with ASSERTs.
- m_bytecodeIndex = (unsigned)-1;
+ m_bytecodeOffset = (unsigned)-1;
#endif
}
{
unsigned jmpTableCount = m_jmpTable.size();
for (unsigned i = 0; i < jmpTableCount; ++i)
- m_jmpTable[i].from.linkTo(m_labels[m_jmpTable[i].toBytecodeIndex], this);
+ m_jmpTable[i].from.linkTo(m_labels[m_jmpTable[i].toBytecodeOffset], this);
m_jmpTable.clear();
}
m_callLinkInfoIndex = 0;
for (Vector<SlowCaseEntry>::iterator iter = m_slowCases.begin(); iter != m_slowCases.end();) {
-#if !USE(JSVALUE32_64)
+#if USE(JSVALUE64)
killLastResultRegister();
#endif
- m_bytecodeIndex = iter->to;
+ m_bytecodeOffset = iter->to;
#ifndef NDEBUG
- unsigned firstTo = m_bytecodeIndex;
+ unsigned firstTo = m_bytecodeOffset;
#endif
- Instruction* currentInstruction = instructionsBegin + m_bytecodeIndex;
+ Instruction* currentInstruction = instructionsBegin + m_bytecodeOffset;
switch (m_interpreter->getOpcodeID(currentInstruction->u.opcode)) {
DEFINE_SLOWCASE_OP(op_add)
DEFINE_SLOWCASE_OP(op_call_eval)
DEFINE_SLOWCASE_OP(op_call_varargs)
DEFINE_SLOWCASE_OP(op_construct)
- DEFINE_SLOWCASE_OP(op_construct_verify)
DEFINE_SLOWCASE_OP(op_convert_this)
-#if !USE(JSVALUE32)
+ DEFINE_SLOWCASE_OP(op_convert_this_strict)
DEFINE_SLOWCASE_OP(op_div)
-#endif
DEFINE_SLOWCASE_OP(op_eq)
DEFINE_SLOWCASE_OP(op_get_by_id)
+ DEFINE_SLOWCASE_OP(op_get_arguments_length)
DEFINE_SLOWCASE_OP(op_get_by_val)
+ DEFINE_SLOWCASE_OP(op_get_argument_by_val)
DEFINE_SLOWCASE_OP(op_get_by_pname)
+ DEFINE_SLOWCASE_OP(op_check_has_instance)
DEFINE_SLOWCASE_OP(op_instanceof)
DEFINE_SLOWCASE_OP(op_jfalse)
DEFINE_SLOWCASE_OP(op_jnless)
DEFINE_SLOWCASE_OP(op_jlesseq)
DEFINE_SLOWCASE_OP(op_jnlesseq)
DEFINE_SLOWCASE_OP(op_jtrue)
+ DEFINE_SLOWCASE_OP(op_load_varargs)
DEFINE_SLOWCASE_OP(op_loop_if_less)
DEFINE_SLOWCASE_OP(op_loop_if_lesseq)
DEFINE_SLOWCASE_OP(op_loop_if_true)
#ifndef NDEBUG
// Reset this, in order to guard its use with ASSERTs.
- m_bytecodeIndex = (unsigned)-1;
+ m_bytecodeOffset = (unsigned)-1;
#endif
}
-JITCode JIT::privateCompile()
+JITCode JIT::privateCompile(CodePtr* functionEntryArityCheck)
{
- sampleCodeBlock(m_codeBlock);
-#if ENABLE(OPCODE_SAMPLING)
- sampleInstruction(m_codeBlock->instructions().begin());
-#endif
+ // Just add a little bit of randomness to the codegen
+ if (m_randomGenerator.getUint32() & 1)
+ nop();
// Could use a pop_m, but would need to offset the following instruction if so.
preserveReturnAddressAfterCall(regT2);
emitPutToCallFrameHeader(regT2, RegisterFile::ReturnPC);
- Jump slowRegisterFileCheck;
- Label afterRegisterFileCheck;
+ Label beginLabel(this);
+
+ sampleCodeBlock(m_codeBlock);
+#if ENABLE(OPCODE_SAMPLING)
+ sampleInstruction(m_codeBlock->instructions().begin());
+#endif
+
+ Jump registerFileCheck;
if (m_codeBlock->codeType() == FunctionCode) {
+#if DFG_SUCCESS_STATS
+ static SamplingCounter counter("orignalJIT");
+ emitCount(counter);
+#endif
+
// In the case of a fast linked call, we do not set this up in the caller.
emitPutImmediateToCallFrameHeader(m_codeBlock, RegisterFile::CodeBlock);
- peek(regT0, OBJECT_OFFSETOF(JITStackFrame, registerFile) / sizeof (void*));
addPtr(Imm32(m_codeBlock->m_numCalleeRegisters * sizeof(Register)), callFrameRegister, regT1);
-
- slowRegisterFileCheck = branchPtr(Above, regT1, Address(regT0, OBJECT_OFFSETOF(RegisterFile, m_end)));
- afterRegisterFileCheck = label();
+ registerFileCheck = branchPtr(Below, AbsoluteAddress(m_globalData->interpreter->registerFile().addressOfEnd()), regT1);
}
+ Label functionBody = label();
+
privateCompileMainPass();
privateCompileLinkPass();
privateCompileSlowCases();
+ Label arityCheck;
if (m_codeBlock->codeType() == FunctionCode) {
- slowRegisterFileCheck.link(this);
- m_bytecodeIndex = 0;
+ registerFileCheck.link(this);
+ m_bytecodeOffset = 0;
JITStubCall(this, cti_register_file_check).call();
#ifndef NDEBUG
- m_bytecodeIndex = (unsigned)-1; // Reset this, in order to guard its use with ASSERTs.
+ m_bytecodeOffset = (unsigned)-1; // Reset this, in order to guard its use with ASSERTs.
#endif
- jump(afterRegisterFileCheck);
+ jump(functionBody);
+
+ arityCheck = label();
+ preserveReturnAddressAfterCall(regT2);
+ emitPutToCallFrameHeader(regT2, RegisterFile::ReturnPC);
+ branch32(Equal, regT1, TrustedImm32(m_codeBlock->m_numParameters)).linkTo(beginLabel, this);
+ restoreArgumentReference();
+
+ JITStubCall(this, m_codeBlock->m_isConstructor ? cti_op_construct_arityCheck : cti_op_call_arityCheck).call(callFrameRegister);
+
+ jump(beginLabel);
}
ASSERT(m_jmpTable.isEmpty());
- RefPtr<ExecutablePool> executablePool = m_globalData->executableAllocator.poolForSize(m_assembler.size());
- if (!executablePool)
- return JITCode();
- LinkBuffer patchBuffer(this, executablePool.release(), m_linkerOffset);
+ LinkBuffer patchBuffer(*m_globalData, this, m_globalData->executableAllocator);
// Translate vPC offsets into addresses in JIT generated code, for switch tables.
for (unsigned i = 0; i < m_switches.size(); ++i) {
SwitchRecord record = m_switches[i];
- unsigned bytecodeIndex = record.bytecodeIndex;
+ unsigned bytecodeOffset = record.bytecodeOffset;
if (record.type != SwitchRecord::String) {
ASSERT(record.type == SwitchRecord::Immediate || record.type == SwitchRecord::Character);
ASSERT(record.jumpTable.simpleJumpTable->branchOffsets.size() == record.jumpTable.simpleJumpTable->ctiOffsets.size());
- record.jumpTable.simpleJumpTable->ctiDefault = patchBuffer.locationOf(m_labels[bytecodeIndex + record.defaultOffset]);
+ record.jumpTable.simpleJumpTable->ctiDefault = patchBuffer.locationOf(m_labels[bytecodeOffset + record.defaultOffset]);
for (unsigned j = 0; j < record.jumpTable.simpleJumpTable->branchOffsets.size(); ++j) {
unsigned offset = record.jumpTable.simpleJumpTable->branchOffsets[j];
- record.jumpTable.simpleJumpTable->ctiOffsets[j] = offset ? patchBuffer.locationOf(m_labels[bytecodeIndex + offset]) : record.jumpTable.simpleJumpTable->ctiDefault;
+ record.jumpTable.simpleJumpTable->ctiOffsets[j] = offset ? patchBuffer.locationOf(m_labels[bytecodeOffset + offset]) : record.jumpTable.simpleJumpTable->ctiDefault;
}
} else {
ASSERT(record.type == SwitchRecord::String);
- record.jumpTable.stringJumpTable->ctiDefault = patchBuffer.locationOf(m_labels[bytecodeIndex + record.defaultOffset]);
+ record.jumpTable.stringJumpTable->ctiDefault = patchBuffer.locationOf(m_labels[bytecodeOffset + record.defaultOffset]);
StringJumpTable::StringOffsetTable::iterator end = record.jumpTable.stringJumpTable->offsetTable.end();
for (StringJumpTable::StringOffsetTable::iterator it = record.jumpTable.stringJumpTable->offsetTable.begin(); it != end; ++it) {
unsigned offset = it->second.branchOffset;
- it->second.ctiOffset = offset ? patchBuffer.locationOf(m_labels[bytecodeIndex + offset]) : record.jumpTable.stringJumpTable->ctiDefault;
+ it->second.ctiOffset = offset ? patchBuffer.locationOf(m_labels[bytecodeOffset + offset]) : record.jumpTable.stringJumpTable->ctiDefault;
}
}
}
patchBuffer.link(iter->from, FunctionPtr(iter->to));
}
- if (m_codeBlock->hasExceptionInfo()) {
+ if (m_codeBlock->needsCallReturnIndices()) {
m_codeBlock->callReturnIndexVector().reserveCapacity(m_calls.size());
for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter)
- m_codeBlock->callReturnIndexVector().append(CallReturnOffsetToBytecodeIndex(patchBuffer.returnAddressOffset(iter->from), iter->bytecodeIndex));
+ m_codeBlock->callReturnIndexVector().append(CallReturnOffsetToBytecodeOffset(patchBuffer.returnAddressOffset(iter->from), iter->bytecodeOffset));
}
// Link absolute addresses for jsr
#if ENABLE(JIT_OPTIMIZE_CALL)
for (unsigned i = 0; i < m_codeBlock->numberOfCallLinkInfos(); ++i) {
CallLinkInfo& info = m_codeBlock->callLinkInfo(i);
- info.ownerCodeBlock = m_codeBlock;
+ info.isCall = m_callStructureStubCompilationInfo[i].isCall;
info.callReturnLocation = patchBuffer.locationOfNearCall(m_callStructureStubCompilationInfo[i].callReturnLocation);
info.hotPathBegin = patchBuffer.locationOf(m_callStructureStubCompilationInfo[i].hotPathBegin);
info.hotPathOther = patchBuffer.locationOfNearCall(m_callStructureStubCompilationInfo[i].hotPathOther);
m_codeBlock->addMethodCallLinkInfos(methodCallCount);
for (unsigned i = 0; i < methodCallCount; ++i) {
MethodCallLinkInfo& info = m_codeBlock->methodCallLinkInfo(i);
- info.structureLabel = patchBuffer.locationOf(m_methodCallCompilationInfo[i].structureToCompare);
+ info.cachedStructure.setLocation(patchBuffer.locationOf(m_methodCallCompilationInfo[i].structureToCompare));
info.callReturnLocation = m_codeBlock->structureStubInfo(m_methodCallCompilationInfo[i].propertyAccessIndex).callReturnLocation;
}
+ if (m_codeBlock->codeType() == FunctionCode && functionEntryArityCheck)
+ *functionEntryArityCheck = patchBuffer.locationOf(arityCheck);
+
return patchBuffer.finalizeCode();
}
-#if !USE(JSVALUE32_64)
-void JIT::emitGetVariableObjectRegister(RegisterID variableObject, int index, RegisterID dst)
-{
- loadPtr(Address(variableObject, OBJECT_OFFSETOF(JSVariableObject, d)), dst);
- loadPtr(Address(dst, OBJECT_OFFSETOF(JSVariableObject::JSVariableObjectData, registers)), dst);
- loadPtr(Address(dst, index * sizeof(Register)), dst);
-}
+#if ENABLE(JIT_OPTIMIZE_CALL)
-void JIT::emitPutVariableObjectRegister(RegisterID src, RegisterID variableObject, int index)
+void JIT::linkCall(JSFunction* callee, CodeBlock* callerCodeBlock, CodeBlock* calleeCodeBlock, JIT::CodePtr code, CallLinkInfo* callLinkInfo, int callerArgCount, JSGlobalData* globalData)
{
- loadPtr(Address(variableObject, OBJECT_OFFSETOF(JSVariableObject, d)), variableObject);
- loadPtr(Address(variableObject, OBJECT_OFFSETOF(JSVariableObject::JSVariableObjectData, registers)), variableObject);
- storePtr(src, Address(variableObject, index * sizeof(Register)));
-}
-#endif
+ RepatchBuffer repatchBuffer(callerCodeBlock);
-#if ENABLE(JIT_OPTIMIZE_CALL)
-void JIT::unlinkCall(CallLinkInfo* callLinkInfo)
-{
- // When the JSFunction is deleted the pointer embedded in the instruction stream will no longer be valid
- // (and, if a new JSFunction happened to be constructed at the same location, we could get a false positive
- // match). Reset the check so it no longer matches.
- RepatchBuffer repatchBuffer(callLinkInfo->ownerCodeBlock);
-#if USE(JSVALUE32_64)
- repatchBuffer.repatch(callLinkInfo->hotPathBegin, 0);
-#else
- repatchBuffer.repatch(callLinkInfo->hotPathBegin, JSValue::encode(JSValue()));
-#endif
+ // Currently we only link calls with the exact number of arguments.
+ // If this is a native call calleeCodeBlock is null so the number of parameters is unimportant
+ if (!calleeCodeBlock || (callerArgCount == calleeCodeBlock->m_numParameters)) {
+ ASSERT(!callLinkInfo->isLinked());
+ callLinkInfo->callee.set(*globalData, callLinkInfo->hotPathBegin, callerCodeBlock->ownerExecutable(), callee);
+ repatchBuffer.relink(callLinkInfo->hotPathOther, code);
+ }
+
+ // patch the call so we do not continue to try to link.
+ repatchBuffer.relink(callLinkInfo->callReturnLocation, globalData->jitStubs->ctiVirtualCall());
}
-void JIT::linkCall(JSFunction* callee, CodeBlock* callerCodeBlock, CodeBlock* calleeCodeBlock, JITCode& code, CallLinkInfo* callLinkInfo, int callerArgCount, JSGlobalData* globalData)
+void JIT::linkConstruct(JSFunction* callee, CodeBlock* callerCodeBlock, CodeBlock* calleeCodeBlock, JIT::CodePtr code, CallLinkInfo* callLinkInfo, int callerArgCount, JSGlobalData* globalData)
{
RepatchBuffer repatchBuffer(callerCodeBlock);
// If this is a native call calleeCodeBlock is null so the number of parameters is unimportant
if (!calleeCodeBlock || (callerArgCount == calleeCodeBlock->m_numParameters)) {
ASSERT(!callLinkInfo->isLinked());
-
- if (calleeCodeBlock)
- calleeCodeBlock->addCaller(callLinkInfo);
-
- repatchBuffer.repatch(callLinkInfo->hotPathBegin, callee);
- repatchBuffer.relink(callLinkInfo->hotPathOther, code.addressForCall());
+ callLinkInfo->callee.set(*globalData, callLinkInfo->hotPathBegin, callerCodeBlock->ownerExecutable(), callee);
+ repatchBuffer.relink(callLinkInfo->hotPathOther, code);
}
// patch the call so we do not continue to try to link.
- repatchBuffer.relink(callLinkInfo->callReturnLocation, globalData->jitStubs->ctiVirtualCall());
+ repatchBuffer.relink(callLinkInfo->callReturnLocation, globalData->jitStubs->ctiVirtualConstruct());
}
#endif // ENABLE(JIT_OPTIMIZE_CALL)
#define JIT_CLASS_ALIGNMENT
#endif
-#define ASSERT_JIT_OFFSET(actual, expected) ASSERT_WITH_MESSAGE(actual == expected, "JIT Offset \"%s\" should be %d, not %d.\n", #expected, static_cast<int>(actual), static_cast<int>(expected));
+#define ASSERT_JIT_OFFSET_UNUSED(variable, actual, expected) ASSERT_WITH_MESSAGE_UNUSED(variable, actual == expected, "JIT Offset \"%s\" should be %d, not %d.\n", #expected, static_cast<int>(expected), static_cast<int>(actual));
+#define ASSERT_JIT_OFFSET(actual, expected) ASSERT_WITH_MESSAGE(actual == expected, "JIT Offset \"%s\" should be %d, not %d.\n", #expected, static_cast<int>(expected), static_cast<int>(actual));
#include "CodeBlock.h"
#include "Interpreter.h"
struct CallRecord {
MacroAssembler::Call from;
- unsigned bytecodeIndex;
+ unsigned bytecodeOffset;
void* to;
CallRecord()
{
}
- CallRecord(MacroAssembler::Call from, unsigned bytecodeIndex, void* to = 0)
+ CallRecord(MacroAssembler::Call from, unsigned bytecodeOffset, void* to = 0)
: from(from)
- , bytecodeIndex(bytecodeIndex)
+ , bytecodeOffset(bytecodeOffset)
, to(to)
{
}
struct JumpTable {
MacroAssembler::Jump from;
- unsigned toBytecodeIndex;
+ unsigned toBytecodeOffset;
JumpTable(MacroAssembler::Jump f, unsigned t)
: from(f)
- , toBytecodeIndex(t)
+ , toBytecodeOffset(t)
{
}
};
StringJumpTable* stringJumpTable;
} jumpTable;
- unsigned bytecodeIndex;
+ unsigned bytecodeOffset;
unsigned defaultOffset;
- SwitchRecord(SimpleJumpTable* jumpTable, unsigned bytecodeIndex, unsigned defaultOffset, Type type)
+ SwitchRecord(SimpleJumpTable* jumpTable, unsigned bytecodeOffset, unsigned defaultOffset, Type type)
: type(type)
- , bytecodeIndex(bytecodeIndex)
+ , bytecodeOffset(bytecodeOffset)
, defaultOffset(defaultOffset)
{
this->jumpTable.simpleJumpTable = jumpTable;
}
- SwitchRecord(StringJumpTable* jumpTable, unsigned bytecodeIndex, unsigned defaultOffset)
+ SwitchRecord(StringJumpTable* jumpTable, unsigned bytecodeOffset, unsigned defaultOffset)
: type(String)
- , bytecodeIndex(bytecodeIndex)
+ , bytecodeOffset(bytecodeOffset)
, defaultOffset(defaultOffset)
{
this->jumpTable.stringJumpTable = jumpTable;
MacroAssembler::DataLabelPtr hotPathBegin;
MacroAssembler::Call hotPathOther;
MacroAssembler::Call callReturnLocation;
+ bool isCall;
};
struct MethodCallCompilationInfo {
using MacroAssembler::Label;
static const int patchGetByIdDefaultStructure = -1;
+ static const int patchGetByIdDefaultOffset = 0;
// Magic number - initial offset cannot be representable as a signed 8bit value, or the X86Assembler
// will compress the displacement, and we may not be able to fit a patched offset.
- static const int patchGetByIdDefaultOffset = 256;
+ static const int patchPutByIdDefaultOffset = 256;
public:
- static JITCode compile(JSGlobalData* globalData, CodeBlock* codeBlock, void* offsetBase = 0)
+ static JITCode compile(JSGlobalData* globalData, CodeBlock* codeBlock, CodePtr* functionEntryArityCheck = 0)
{
- return JIT(globalData, codeBlock, offsetBase).privateCompile();
+ return JIT(globalData, codeBlock).privateCompile(functionEntryArityCheck);
}
static void compileGetByIdProto(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress)
{
if (!globalData->canUseJIT())
return;
- JIT jit(globalData, 0, 0);
+ JIT jit(globalData, 0);
jit.privateCompileCTIMachineTrampolines(executablePool, globalData, trampolines);
}
+ static CodePtr compileCTINativeCall(JSGlobalData* globalData, PassRefPtr<ExecutablePool> executablePool, NativeFunction func)
+ {
+ if (!globalData->canUseJIT())
+ return CodePtr();
+ JIT jit(globalData, 0);
+ return jit.privateCompileCTINativeCall(executablePool, globalData, func);
+ }
+
static void patchGetByIdSelf(CodeBlock* codeblock, StructureStubInfo*, Structure*, size_t cachedOffset, ReturnAddressPtr returnAddress);
static void patchPutByIdReplace(CodeBlock* codeblock, StructureStubInfo*, Structure*, size_t cachedOffset, ReturnAddressPtr returnAddress, bool direct);
- static void patchMethodCallProto(CodeBlock* codeblock, MethodCallLinkInfo&, JSFunction*, Structure*, JSObject*, ReturnAddressPtr);
+ static void patchMethodCallProto(JSGlobalData&, CodeBlock* codeblock, MethodCallLinkInfo&, JSObjectWithGlobalObject*, Structure*, JSObject*, ReturnAddressPtr);
static void compilePatchGetArrayLength(JSGlobalData* globalData, CodeBlock* codeBlock, ReturnAddressPtr returnAddress)
{
return jit.privateCompilePatchGetArrayLength(returnAddress);
}
- static void linkCall(JSFunction* callee, CodeBlock* callerCodeBlock, CodeBlock* calleeCodeBlock, JITCode&, CallLinkInfo*, int callerArgCount, JSGlobalData*);
- static void unlinkCall(CallLinkInfo*);
+ static void linkCall(JSFunction* callee, CodeBlock* callerCodeBlock, CodeBlock* calleeCodeBlock, CodePtr, CallLinkInfo*, int callerArgCount, JSGlobalData*);
+ static void linkConstruct(JSFunction* callee, CodeBlock* callerCodeBlock, CodeBlock* calleeCodeBlock, CodePtr, CallLinkInfo*, int callerArgCount, JSGlobalData*);
private:
struct JSRInfo {
}
};
- JIT(JSGlobalData*, CodeBlock* = 0, void* = 0);
+ JIT(JSGlobalData*, CodeBlock* = 0);
void privateCompileMainPass();
void privateCompileLinkPass();
void privateCompileSlowCases();
- JITCode privateCompile();
+ JITCode privateCompile(CodePtr* functionEntryArityCheck);
void privateCompileGetByIdProto(StructureStubInfo*, Structure*, Structure* prototypeStructure, const Identifier&, const PropertySlot&, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame);
void privateCompileGetByIdSelfList(StructureStubInfo*, PolymorphicAccessStructureList*, int, Structure*, const Identifier&, const PropertySlot&, size_t cachedOffset);
void privateCompileGetByIdProtoList(StructureStubInfo*, PolymorphicAccessStructureList*, int, Structure*, Structure* prototypeStructure, const Identifier&, const PropertySlot&, size_t cachedOffset, CallFrame* callFrame);
void privateCompilePutByIdTransition(StructureStubInfo*, Structure*, Structure*, size_t cachedOffset, StructureChain*, ReturnAddressPtr returnAddress, bool direct);
void privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executablePool, JSGlobalData* data, TrampolineStructure *trampolines);
+ Label privateCompileCTINativeCall(JSGlobalData*, bool isConstruct = false);
+ CodePtr privateCompileCTINativeCall(PassRefPtr<ExecutablePool> executablePool, JSGlobalData* data, NativeFunction func);
void privateCompilePatchGetArrayLength(ReturnAddressPtr returnAddress);
void addSlowCase(Jump);
void compileOpCall(OpcodeID, Instruction* instruction, unsigned callLinkInfoIndex);
void compileOpCallVarargs(Instruction* instruction);
void compileOpCallInitializeCallFrame();
- void compileOpCallSetupArgs(Instruction*);
- void compileOpCallVarargsSetupArgs(Instruction*);
void compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned callLinkInfoIndex, OpcodeID opcodeID);
void compileOpCallVarargsSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter);
- void compileOpConstructSetupArgs(Instruction*);
enum CompileOpStrictEqType { OpStrictEq, OpNStrictEq };
void compileOpStrictEq(Instruction* instruction, CompileOpStrictEqType type);
void emitLoadDouble(unsigned index, FPRegisterID value);
void emitLoadInt32ToDouble(unsigned index, FPRegisterID value);
- void testPrototype(Structure*, JumpList& failureCases);
+ void testPrototype(JSValue, JumpList& failureCases);
#if USE(JSVALUE32_64)
bool getOperandConstantImmediateInt(unsigned op1, unsigned op2, unsigned& op, int32_t& constant);
void emitStore(unsigned index, RegisterID tag, RegisterID payload, RegisterID base = callFrameRegister);
void emitStore(unsigned index, const JSValue constant, RegisterID base = callFrameRegister);
void emitStoreInt32(unsigned index, RegisterID payload, bool indexIsInt32 = false);
- void emitStoreInt32(unsigned index, Imm32 payload, bool indexIsInt32 = false);
+ void emitStoreInt32(unsigned index, TrustedImm32 payload, bool indexIsInt32 = false);
void emitStoreCell(unsigned index, RegisterID payload, bool indexIsCell = false);
- void emitStoreBool(unsigned index, RegisterID tag, bool indexIsBool = false);
+ void emitStoreBool(unsigned index, RegisterID payload, bool indexIsBool = false);
void emitStoreDouble(unsigned index, FPRegisterID value);
- bool isLabeled(unsigned bytecodeIndex);
- void map(unsigned bytecodeIndex, unsigned virtualRegisterIndex, RegisterID tag, RegisterID payload);
+ bool isLabeled(unsigned bytecodeOffset);
+ void map(unsigned bytecodeOffset, unsigned virtualRegisterIndex, RegisterID tag, RegisterID payload);
void unmap(RegisterID);
void unmap();
bool isMapped(unsigned virtualRegisterIndex);
void compileGetByIdSlowCase(int resultVReg, int baseVReg, Identifier* ident, Vector<SlowCaseEntry>::iterator& iter, bool isMethodCheck = false);
#endif
void compileGetDirectOffset(RegisterID base, RegisterID resultTag, RegisterID resultPayload, Structure* structure, size_t cachedOffset);
- void compileGetDirectOffset(JSObject* base, RegisterID temp, RegisterID resultTag, RegisterID resultPayload, size_t cachedOffset);
- void compileGetDirectOffset(RegisterID base, RegisterID resultTag, RegisterID resultPayload, RegisterID structure, RegisterID offset);
+ void compileGetDirectOffset(JSObject* base, RegisterID resultTag, RegisterID resultPayload, size_t cachedOffset);
+ void compileGetDirectOffset(RegisterID base, RegisterID resultTag, RegisterID resultPayload, RegisterID offset);
void compilePutDirectOffset(RegisterID base, RegisterID valueTag, RegisterID valuePayload, Structure* structure, size_t cachedOffset);
// Arithmetic opcode helpers
#if CPU(X86)
// These architecture specific value are used to enable patching - see comment on op_put_by_id.
static const int patchOffsetPutByIdStructure = 7;
- static const int patchOffsetPutByIdExternalLoad = 13;
- static const int patchLengthPutByIdExternalLoad = 3;
static const int patchOffsetPutByIdPropertyMapOffset1 = 22;
static const int patchOffsetPutByIdPropertyMapOffset2 = 28;
// These architecture specific value are used to enable patching - see comment on op_get_by_id.
static const int patchOffsetGetByIdStructure = 7;
static const int patchOffsetGetByIdBranchToSlowCase = 13;
- static const int patchOffsetGetByIdExternalLoad = 13;
- static const int patchLengthGetByIdExternalLoad = 3;
- static const int patchOffsetGetByIdPropertyMapOffset1 = 22;
- static const int patchOffsetGetByIdPropertyMapOffset2 = 28;
- static const int patchOffsetGetByIdPutResult = 28;
-#if ENABLE(OPCODE_SAMPLING) && USE(JIT_STUB_ARGUMENT_VA_LIST)
- static const int patchOffsetGetByIdSlowCaseCall = 35;
-#elif ENABLE(OPCODE_SAMPLING)
+ static const int patchOffsetGetByIdPropertyMapOffset1 = 19;
+ static const int patchOffsetGetByIdPropertyMapOffset2 = 22;
+ static const int patchOffsetGetByIdPutResult = 22;
+#if ENABLE(OPCODE_SAMPLING)
static const int patchOffsetGetByIdSlowCaseCall = 37;
-#elif USE(JIT_STUB_ARGUMENT_VA_LIST)
- static const int patchOffsetGetByIdSlowCaseCall = 25;
#else
static const int patchOffsetGetByIdSlowCaseCall = 27;
#endif
#elif CPU(ARM_TRADITIONAL)
// These architecture specific value are used to enable patching - see comment on op_put_by_id.
static const int patchOffsetPutByIdStructure = 4;
- static const int patchOffsetPutByIdExternalLoad = 16;
- static const int patchLengthPutByIdExternalLoad = 4;
static const int patchOffsetPutByIdPropertyMapOffset1 = 20;
static const int patchOffsetPutByIdPropertyMapOffset2 = 28;
// These architecture specific value are used to enable patching - see comment on op_get_by_id.
static const int patchOffsetGetByIdStructure = 4;
static const int patchOffsetGetByIdBranchToSlowCase = 16;
- static const int patchOffsetGetByIdExternalLoad = 16;
- static const int patchLengthGetByIdExternalLoad = 4;
static const int patchOffsetGetByIdPropertyMapOffset1 = 20;
static const int patchOffsetGetByIdPropertyMapOffset2 = 28;
static const int patchOffsetGetByIdPutResult = 36;
static const int sequenceGetByIdHotPathInstructionSpace = 36;
static const int sequenceGetByIdHotPathConstantSpace = 4;
// sequenceGetByIdSlowCase
- static const int sequenceGetByIdSlowCaseInstructionSpace = 40;
+ static const int sequenceGetByIdSlowCaseInstructionSpace = 56;
static const int sequenceGetByIdSlowCaseConstantSpace = 2;
// sequencePutById
static const int sequencePutByIdInstructionSpace = 36;
#elif CPU(ARM_THUMB2)
// These architecture specific value are used to enable patching - see comment on op_put_by_id.
static const int patchOffsetPutByIdStructure = 10;
- static const int patchOffsetPutByIdExternalLoad = 26;
- static const int patchLengthPutByIdExternalLoad = 12;
- static const int patchOffsetPutByIdPropertyMapOffset1 = 46;
- static const int patchOffsetPutByIdPropertyMapOffset2 = 58;
+ static const int patchOffsetPutByIdPropertyMapOffset1 = 36;
+ static const int patchOffsetPutByIdPropertyMapOffset2 = 48;
// These architecture specific value are used to enable patching - see comment on op_get_by_id.
static const int patchOffsetGetByIdStructure = 10;
static const int patchOffsetGetByIdBranchToSlowCase = 26;
- static const int patchOffsetGetByIdExternalLoad = 26;
- static const int patchLengthGetByIdExternalLoad = 12;
- static const int patchOffsetGetByIdPropertyMapOffset1 = 46;
- static const int patchOffsetGetByIdPropertyMapOffset2 = 58;
- static const int patchOffsetGetByIdPutResult = 62;
+ static const int patchOffsetGetByIdPropertyMapOffset1 = 28;
+ static const int patchOffsetGetByIdPropertyMapOffset2 = 30;
+ static const int patchOffsetGetByIdPutResult = 32;
#if ENABLE(OPCODE_SAMPLING)
#error "OPCODE_SAMPLING is not yet supported"
#else
// sequencePutById
static const int sequencePutByIdInstructionSpace = 36;
static const int sequencePutByIdConstantSpace = 4;
+#elif CPU(MIPS)
+#if WTF_MIPS_ISA(1)
+ static const int patchOffsetPutByIdStructure = 16;
+ static const int patchOffsetPutByIdPropertyMapOffset1 = 56;
+ static const int patchOffsetPutByIdPropertyMapOffset2 = 72;
+ static const int patchOffsetGetByIdStructure = 16;
+ static const int patchOffsetGetByIdBranchToSlowCase = 48;
+ static const int patchOffsetGetByIdPropertyMapOffset1 = 56;
+ static const int patchOffsetGetByIdPropertyMapOffset2 = 76;
+ static const int patchOffsetGetByIdPutResult = 96;
+#if ENABLE(OPCODE_SAMPLING)
+ #error "OPCODE_SAMPLING is not yet supported"
+#else
+ static const int patchOffsetGetByIdSlowCaseCall = 44;
+#endif
+ static const int patchOffsetOpCallCompareToJump = 32;
+ static const int patchOffsetMethodCheckProtoObj = 32;
+ static const int patchOffsetMethodCheckProtoStruct = 56;
+ static const int patchOffsetMethodCheckPutFunction = 88;
+#else // WTF_MIPS_ISA(1)
+ static const int patchOffsetPutByIdStructure = 12;
+ static const int patchOffsetPutByIdPropertyMapOffset1 = 48;
+ static const int patchOffsetPutByIdPropertyMapOffset2 = 64;
+ static const int patchOffsetGetByIdStructure = 12;
+ static const int patchOffsetGetByIdBranchToSlowCase = 44;
+ static const int patchOffsetGetByIdPropertyMapOffset1 = 48;
+ static const int patchOffsetGetByIdPropertyMapOffset2 = 64;
+ static const int patchOffsetGetByIdPutResult = 80;
+#if ENABLE(OPCODE_SAMPLING)
+ #error "OPCODE_SAMPLING is not yet supported"
+#else
+ static const int patchOffsetGetByIdSlowCaseCall = 44;
+#endif
+ static const int patchOffsetOpCallCompareToJump = 32;
+ static const int patchOffsetMethodCheckProtoObj = 32;
+ static const int patchOffsetMethodCheckProtoStruct = 52;
+ static const int patchOffsetMethodCheckPutFunction = 84;
+#endif
+#elif CPU(SH4)
+ // These architecture specific value are used to enable patching - see comment on op_put_by_id.
+ static const int patchOffsetGetByIdStructure = 6;
+ static const int patchOffsetPutByIdPropertyMapOffset = 24;
+ static const int patchOffsetPutByIdStructure = 6;
+ // These architecture specific value are used to enable patching - see comment on op_get_by_id.
+ static const int patchOffsetGetByIdBranchToSlowCase = 10;
+ static const int patchOffsetGetByIdPropertyMapOffset = 24;
+ static const int patchOffsetGetByIdPutResult = 32;
+
+ // sequenceOpCall
+ static const int sequenceOpCallInstructionSpace = 12;
+ static const int sequenceOpCallConstantSpace = 2;
+ // sequenceMethodCheck
+ static const int sequenceMethodCheckInstructionSpace = 40;
+ static const int sequenceMethodCheckConstantSpace = 6;
+ // sequenceGetByIdHotPath
+ static const int sequenceGetByIdHotPathInstructionSpace = 36;
+ static const int sequenceGetByIdHotPathConstantSpace = 5;
+ // sequenceGetByIdSlowCase
+ static const int sequenceGetByIdSlowCaseInstructionSpace = 26;
+ static const int sequenceGetByIdSlowCaseConstantSpace = 2;
+ // sequencePutById
+ static const int sequencePutByIdInstructionSpace = 36;
+ static const int sequencePutByIdConstantSpace = 5;
+
+ static const int patchOffsetGetByIdPropertyMapOffset1 = 20;
+ static const int patchOffsetGetByIdPropertyMapOffset2 = 26;
+
+ static const int patchOffsetPutByIdPropertyMapOffset1 = 20;
+ static const int patchOffsetPutByIdPropertyMapOffset2 = 26;
+
+#if ENABLE(OPCODE_SAMPLING)
+ static const int patchOffsetGetByIdSlowCaseCall = 0; // FIMXE
+#else
+ static const int patchOffsetGetByIdSlowCaseCall = 22;
+#endif
+ static const int patchOffsetOpCallCompareToJump = 4;
+
+ static const int patchOffsetMethodCheckProtoObj = 12;
+ static const int patchOffsetMethodCheckProtoStruct = 20;
+ static const int patchOffsetMethodCheckPutFunction = 32;
#else
#error "JSVALUE32_64 not supported on this platform."
#endif
int32_t getConstantOperandImmediateInt(unsigned src);
- void emitGetVariableObjectRegister(RegisterID variableObject, int index, RegisterID dst);
- void emitPutVariableObjectRegister(RegisterID src, RegisterID variableObject, int index);
-
void killLastResultRegister();
Jump emitJumpIfJSCell(RegisterID);
Jump emitJumpIfNotJSCell(RegisterID);
void emitJumpSlowCaseIfNotJSCell(RegisterID);
void emitJumpSlowCaseIfNotJSCell(RegisterID, int VReg);
-#if USE(JSVALUE64)
-#else
+#if USE(JSVALUE32_64)
JIT::Jump emitJumpIfImmediateNumber(RegisterID reg)
{
return emitJumpIfImmediateInteger(reg);
void emitJumpSlowCaseIfNotImmediateNumber(RegisterID);
void emitJumpSlowCaseIfNotImmediateIntegers(RegisterID, RegisterID, RegisterID);
-#if !USE(JSVALUE64)
+#if USE(JSVALUE32_64)
void emitFastArithDeTagImmediate(RegisterID);
Jump emitFastArithDeTagImmediateJumpIfZero(RegisterID);
#endif
void compileGetByIdSlowCase(int resultVReg, int baseVReg, Identifier* ident, Vector<SlowCaseEntry>::iterator& iter, bool isMethodCheck = false);
#endif
void compileGetDirectOffset(RegisterID base, RegisterID result, Structure* structure, size_t cachedOffset);
- void compileGetDirectOffset(JSObject* base, RegisterID temp, RegisterID result, size_t cachedOffset);
- void compileGetDirectOffset(RegisterID base, RegisterID result, RegisterID structure, RegisterID offset, RegisterID scratch);
+ void compileGetDirectOffset(JSObject* base, RegisterID result, size_t cachedOffset);
+ void compileGetDirectOffset(RegisterID base, RegisterID result, RegisterID offset, RegisterID scratch);
void compilePutDirectOffset(RegisterID base, RegisterID value, Structure* structure, size_t cachedOffset);
#if CPU(X86_64)
// These architecture specific value are used to enable patching - see comment on op_put_by_id.
static const int patchOffsetPutByIdStructure = 10;
- static const int patchOffsetPutByIdExternalLoad = 20;
- static const int patchLengthPutByIdExternalLoad = 4;
static const int patchOffsetPutByIdPropertyMapOffset = 31;
// These architecture specific value are used to enable patching - see comment on op_get_by_id.
static const int patchOffsetGetByIdStructure = 10;
static const int patchOffsetGetByIdBranchToSlowCase = 20;
- static const int patchOffsetGetByIdExternalLoad = 20;
- static const int patchLengthGetByIdExternalLoad = 4;
- static const int patchOffsetGetByIdPropertyMapOffset = 31;
- static const int patchOffsetGetByIdPutResult = 31;
+ static const int patchOffsetGetByIdPropertyMapOffset = 28;
+ static const int patchOffsetGetByIdPutResult = 28;
#if ENABLE(OPCODE_SAMPLING)
static const int patchOffsetGetByIdSlowCaseCall = 64;
#else
#elif CPU(X86)
// These architecture specific value are used to enable patching - see comment on op_put_by_id.
static const int patchOffsetPutByIdStructure = 7;
- static const int patchOffsetPutByIdExternalLoad = 13;
- static const int patchLengthPutByIdExternalLoad = 3;
static const int patchOffsetPutByIdPropertyMapOffset = 22;
// These architecture specific value are used to enable patching - see comment on op_get_by_id.
static const int patchOffsetGetByIdStructure = 7;
static const int patchOffsetGetByIdBranchToSlowCase = 13;
- static const int patchOffsetGetByIdExternalLoad = 13;
- static const int patchLengthGetByIdExternalLoad = 3;
static const int patchOffsetGetByIdPropertyMapOffset = 22;
static const int patchOffsetGetByIdPutResult = 22;
-#if ENABLE(OPCODE_SAMPLING) && USE(JIT_STUB_ARGUMENT_VA_LIST)
- static const int patchOffsetGetByIdSlowCaseCall = 31;
-#elif ENABLE(OPCODE_SAMPLING)
+#if ENABLE(OPCODE_SAMPLING)
static const int patchOffsetGetByIdSlowCaseCall = 33;
-#elif USE(JIT_STUB_ARGUMENT_VA_LIST)
- static const int patchOffsetGetByIdSlowCaseCall = 21;
#else
static const int patchOffsetGetByIdSlowCaseCall = 23;
#endif
#elif CPU(ARM_THUMB2)
// These architecture specific value are used to enable patching - see comment on op_put_by_id.
static const int patchOffsetPutByIdStructure = 10;
- static const int patchOffsetPutByIdExternalLoad = 26;
- static const int patchLengthPutByIdExternalLoad = 12;
static const int patchOffsetPutByIdPropertyMapOffset = 46;
// These architecture specific value are used to enable patching - see comment on op_get_by_id.
static const int patchOffsetGetByIdStructure = 10;
static const int patchOffsetGetByIdBranchToSlowCase = 26;
- static const int patchOffsetGetByIdExternalLoad = 26;
- static const int patchLengthGetByIdExternalLoad = 12;
static const int patchOffsetGetByIdPropertyMapOffset = 46;
static const int patchOffsetGetByIdPutResult = 50;
#if ENABLE(OPCODE_SAMPLING)
#elif CPU(ARM_TRADITIONAL)
// These architecture specific value are used to enable patching - see comment on op_put_by_id.
static const int patchOffsetPutByIdStructure = 4;
- static const int patchOffsetPutByIdExternalLoad = 16;
- static const int patchLengthPutByIdExternalLoad = 4;
static const int patchOffsetPutByIdPropertyMapOffset = 20;
// These architecture specific value are used to enable patching - see comment on op_get_by_id.
static const int patchOffsetGetByIdStructure = 4;
static const int patchOffsetGetByIdBranchToSlowCase = 16;
- static const int patchOffsetGetByIdExternalLoad = 16;
- static const int patchLengthGetByIdExternalLoad = 4;
static const int patchOffsetGetByIdPropertyMapOffset = 20;
static const int patchOffsetGetByIdPutResult = 28;
#if ENABLE(OPCODE_SAMPLING)
#elif CPU(MIPS)
#if WTF_MIPS_ISA(1)
static const int patchOffsetPutByIdStructure = 16;
- static const int patchOffsetPutByIdExternalLoad = 48;
- static const int patchLengthPutByIdExternalLoad = 20;
static const int patchOffsetPutByIdPropertyMapOffset = 68;
static const int patchOffsetGetByIdStructure = 16;
static const int patchOffsetGetByIdBranchToSlowCase = 48;
- static const int patchOffsetGetByIdExternalLoad = 48;
- static const int patchLengthGetByIdExternalLoad = 20;
static const int patchOffsetGetByIdPropertyMapOffset = 68;
static const int patchOffsetGetByIdPutResult = 88;
#if ENABLE(OPCODE_SAMPLING)
static const int patchOffsetMethodCheckPutFunction = 88;
#else // WTF_MIPS_ISA(1)
static const int patchOffsetPutByIdStructure = 12;
- static const int patchOffsetPutByIdExternalLoad = 44;
- static const int patchLengthPutByIdExternalLoad = 16;
static const int patchOffsetPutByIdPropertyMapOffset = 60;
static const int patchOffsetGetByIdStructure = 12;
static const int patchOffsetGetByIdBranchToSlowCase = 44;
- static const int patchOffsetGetByIdExternalLoad = 44;
- static const int patchLengthGetByIdExternalLoad = 16;
static const int patchOffsetGetByIdPropertyMapOffset = 60;
static const int patchOffsetGetByIdPutResult = 76;
#if ENABLE(OPCODE_SAMPLING)
#endif // USE(JSVALUE32_64)
#if (defined(ASSEMBLER_HAS_CONSTANT_POOL) && ASSEMBLER_HAS_CONSTANT_POOL)
-#define BEGIN_UNINTERRUPTED_SEQUENCE(name) do { beginUninterruptedSequence(); beginUninterruptedSequence(name ## InstructionSpace, name ## ConstantSpace); } while (false)
-#define END_UNINTERRUPTED_SEQUENCE(name) do { endUninterruptedSequence(name ## InstructionSpace, name ## ConstantSpace); endUninterruptedSequence(); } while (false)
+#define BEGIN_UNINTERRUPTED_SEQUENCE(name) do { beginUninterruptedSequence(name ## InstructionSpace, name ## ConstantSpace); } while (false)
+#define END_UNINTERRUPTED_SEQUENCE_FOR_PUT(name, dst) do { endUninterruptedSequence(name ## InstructionSpace, name ## ConstantSpace, dst); } while (false)
+#define END_UNINTERRUPTED_SEQUENCE(name) END_UNINTERRUPTED_SEQUENCE_FOR_PUT(name, 0)
void beginUninterruptedSequence(int, int);
- void endUninterruptedSequence(int, int);
+ void endUninterruptedSequence(int, int, int);
#else
#define BEGIN_UNINTERRUPTED_SEQUENCE(name) do { beginUninterruptedSequence(); } while (false)
#define END_UNINTERRUPTED_SEQUENCE(name) do { endUninterruptedSequence(); } while (false)
+#define END_UNINTERRUPTED_SEQUENCE_FOR_PUT(name, dst) do { endUninterruptedSequence(); } while (false)
#endif
void emit_op_add(Instruction*);
void emit_op_call(Instruction*);
void emit_op_call_eval(Instruction*);
void emit_op_call_varargs(Instruction*);
+ void emit_op_call_put_result(Instruction*);
void emit_op_catch(Instruction*);
void emit_op_construct(Instruction*);
- void emit_op_construct_verify(Instruction*);
+ void emit_op_get_callee(Instruction*);
+ void emit_op_create_this(Instruction*);
void emit_op_convert_this(Instruction*);
+ void emit_op_convert_this_strict(Instruction*);
void emit_op_create_arguments(Instruction*);
void emit_op_debug(Instruction*);
void emit_op_del_by_id(Instruction*);
void emit_op_div(Instruction*);
void emit_op_end(Instruction*);
void emit_op_enter(Instruction*);
- void emit_op_enter_with_activation(Instruction*);
+ void emit_op_create_activation(Instruction*);
void emit_op_eq(Instruction*);
void emit_op_eq_null(Instruction*);
void emit_op_get_by_id(Instruction*);
+ void emit_op_get_arguments_length(Instruction*);
void emit_op_get_by_val(Instruction*);
+ void emit_op_get_argument_by_val(Instruction*);
void emit_op_get_by_pname(Instruction*);
void emit_op_get_global_var(Instruction*);
void emit_op_get_scoped_var(Instruction*);
- void emit_op_init_arguments(Instruction*);
+ void emit_op_init_lazy_reg(Instruction*);
+ void emit_op_check_has_instance(Instruction*);
void emit_op_instanceof(Instruction*);
void emit_op_jeq_null(Instruction*);
void emit_op_jfalse(Instruction*);
void emit_op_neq(Instruction*);
void emit_op_neq_null(Instruction*);
void emit_op_new_array(Instruction*);
- void emit_op_new_error(Instruction*);
+ void emit_op_new_array_buffer(Instruction*);
void emit_op_new_func(Instruction*);
void emit_op_new_func_exp(Instruction*);
void emit_op_new_object(Instruction*);
void emit_op_put_setter(Instruction*);
void emit_op_resolve(Instruction*);
void emit_op_resolve_base(Instruction*);
+ void emit_op_ensure_property_exists(Instruction*);
void emit_op_resolve_global(Instruction*, bool dynamic = false);
void emit_op_resolve_global_dynamic(Instruction*);
void emit_op_resolve_skip(Instruction*);
void emit_op_resolve_with_base(Instruction*);
void emit_op_ret(Instruction*);
+ void emit_op_ret_object_or_this(Instruction*);
void emit_op_rshift(Instruction*);
void emit_op_sret(Instruction*);
void emit_op_strcat(Instruction*);
void emit_op_tear_off_activation(Instruction*);
void emit_op_tear_off_arguments(Instruction*);
void emit_op_throw(Instruction*);
+ void emit_op_throw_reference_error(Instruction*);
void emit_op_to_jsnumber(Instruction*);
void emit_op_to_primitive(Instruction*);
void emit_op_unexpected_load(Instruction*);
void emit_op_urshift(Instruction*);
-#if ENABLE(JIT_OPTIMIZE_MOD)
+#if ENABLE(JIT_USE_SOFT_MODULO)
void softModulo();
#endif
void emitSlow_op_call_eval(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_call_varargs(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_construct(Instruction*, Vector<SlowCaseEntry>::iterator&);
- void emitSlow_op_construct_verify(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_convert_this(Instruction*, Vector<SlowCaseEntry>::iterator&);
+ void emitSlow_op_convert_this_strict(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_div(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_eq(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_get_by_id(Instruction*, Vector<SlowCaseEntry>::iterator&);
+ void emitSlow_op_get_arguments_length(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_get_by_val(Instruction*, Vector<SlowCaseEntry>::iterator&);
+ void emitSlow_op_get_argument_by_val(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_get_by_pname(Instruction*, Vector<SlowCaseEntry>::iterator&);
+ void emitSlow_op_check_has_instance(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_instanceof(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_jfalse(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_jnless(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_jlesseq(Instruction*, Vector<SlowCaseEntry>::iterator&, bool invert = false);
void emitSlow_op_jnlesseq(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_jtrue(Instruction*, Vector<SlowCaseEntry>::iterator&);
+ void emitSlow_op_load_varargs(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_loop_if_less(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_loop_if_lesseq(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_loop_if_true(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitRightShift(Instruction*, bool isUnsigned);
void emitRightShiftSlowCase(Instruction*, Vector<SlowCaseEntry>::iterator&, bool isUnsigned);
- /* These functions are deprecated: Please use JITStubCall instead. */
- void emitPutJITStubArg(RegisterID src, unsigned argumentNumber);
-#if USE(JSVALUE32_64)
- void emitPutJITStubArg(RegisterID tag, RegisterID payload, unsigned argumentNumber);
- void emitPutJITStubArgFromVirtualRegister(unsigned src, unsigned argumentNumber, RegisterID scratch1, RegisterID scratch2);
-#else
- void emitPutJITStubArgFromVirtualRegister(unsigned src, unsigned argumentNumber, RegisterID scratch);
-#endif
- void emitPutJITStubArgConstant(unsigned value, unsigned argumentNumber);
- void emitPutJITStubArgConstant(void* value, unsigned argumentNumber);
+ /* This function is deprecated. */
void emitGetJITStubArg(unsigned argumentNumber, RegisterID dst);
void emitInitRegister(unsigned dst);
void emitPutToCallFrameHeader(RegisterID from, RegisterFile::CallFrameHeaderEntry entry);
+ void emitPutCellToCallFrameHeader(RegisterID from, RegisterFile::CallFrameHeaderEntry);
+ void emitPutIntToCallFrameHeader(RegisterID from, RegisterFile::CallFrameHeaderEntry);
void emitPutImmediateToCallFrameHeader(void* value, RegisterFile::CallFrameHeaderEntry entry);
void emitGetFromCallFrameHeaderPtr(RegisterFile::CallFrameHeaderEntry entry, RegisterID to, RegisterID from = callFrameRegister);
void emitGetFromCallFrameHeader32(RegisterFile::CallFrameHeaderEntry entry, RegisterID to, RegisterID from = callFrameRegister);
bool isOperandConstantImmediateInt(unsigned src);
bool isOperandConstantImmediateChar(unsigned src);
+ bool atJumpTarget();
+
Jump getSlowCase(Vector<SlowCaseEntry>::iterator& iter)
{
return iter++->from;
Vector<MethodCallCompilationInfo> m_methodCallCompilationInfo;
Vector<JumpTable> m_jmpTable;
- unsigned m_bytecodeIndex;
+ unsigned m_bytecodeOffset;
Vector<JSRInfo> m_jsrSites;
Vector<SlowCaseEntry> m_slowCases;
Vector<SwitchRecord> m_switches;
#if USE(JSVALUE32_64)
unsigned m_jumpTargetIndex;
- unsigned m_mappedBytecodeIndex;
+ unsigned m_mappedBytecodeOffset;
unsigned m_mappedVirtualRegisterIndex;
RegisterID m_mappedTag;
RegisterID m_mappedPayload;
#else
int m_lastResultBytecodeRegister;
- unsigned m_jumpTargetsPosition;
#endif
+ unsigned m_jumpTargetsPosition;
#ifndef NDEBUG
#if defined(ASSEMBLER_HAS_CONSTANT_POOL) && ASSEMBLER_HAS_CONSTANT_POOL
int m_uninterruptedConstantSequenceBegin;
#endif
#endif
- void* m_linkerOffset;
- static PassRefPtr<NativeExecutable> stringGetByValStubGenerator(JSGlobalData* globalData, ExecutablePool* pool);
+ WeakRandom m_randomGenerator;
+ static CodePtr stringGetByValStubGenerator(JSGlobalData* globalData, ExecutablePool* pool);
} JIT_CLASS_ALIGNMENT;
inline void JIT::emit_op_loop(Instruction* currentInstruction)
*/
#include "config.h"
-#include "JIT.h"
#if ENABLE(JIT)
+#if USE(JSVALUE64)
+#include "JIT.h"
#include "CodeBlock.h"
#include "JITInlineMethods.h"
namespace JSC {
-#if !USE(JSVALUE32_64)
-
void JIT::emit_op_lshift(Instruction* currentInstruction)
{
unsigned result = currentInstruction[1].u.operand;
emitFastArithImmToInt(regT0);
emitFastArithImmToInt(regT2);
lshift32(regT2, regT0);
-#if USE(JSVALUE32)
- addSlowCase(branchAdd32(Overflow, regT0, regT0));
- signExtend32ToPtr(regT0, regT0);
-#endif
emitFastArithReTagImmediate(regT0, regT0);
emitPutVirtualRegister(result);
}
unsigned op1 = currentInstruction[2].u.operand;
unsigned op2 = currentInstruction[3].u.operand;
-#if USE(JSVALUE64)
UNUSED_PARAM(op1);
UNUSED_PARAM(op2);
linkSlowCase(iter);
linkSlowCase(iter);
-#else
- // If we are limited to 32-bit immediates there is a third slow case, which required the operands to have been reloaded.
- Jump notImm1 = getSlowCase(iter);
- Jump notImm2 = getSlowCase(iter);
- linkSlowCase(iter);
- emitGetVirtualRegisters(op1, regT0, op2, regT2);
- notImm1.link(this);
- notImm2.link(this);
-#endif
JITStubCall stubCall(this, cti_op_lshift);
stubCall.addArgument(regT0);
stubCall.addArgument(regT2);
emitGetVirtualRegisters(op1, regT0, op2, regT2);
if (supportsFloatingPointTruncate()) {
Jump lhsIsInt = emitJumpIfImmediateInteger(regT0);
-#if USE(JSVALUE64)
// supportsFloatingPoint() && USE(JSVALUE64) => 3 SlowCases
addSlowCase(emitJumpIfNotImmediateNumber(regT0));
addPtr(tagTypeNumberRegister, regT0);
movePtrToDouble(regT0, fpRegT0);
addSlowCase(branchTruncateDoubleToInt32(fpRegT0, regT0));
-#else
- // supportsFloatingPoint() && !USE(JSVALUE64) => 5 SlowCases (of which 1 IfNotJSCell)
- emitJumpSlowCaseIfNotJSCell(regT0, op1);
- addSlowCase(checkStructure(regT0, m_globalData->numberStructure.get()));
- loadDouble(Address(regT0, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT0);
- addSlowCase(branchTruncateDoubleToInt32(fpRegT0, regT0));
- addSlowCase(branchAdd32(Overflow, regT0, regT0));
-#endif
lhsIsInt.link(this);
emitJumpSlowCaseIfNotImmediateInteger(regT2);
} else {
}
emitFastArithImmToInt(regT2);
rshift32(regT2, regT0);
-#if USE(JSVALUE32)
- signExtend32ToPtr(regT0, regT0);
-#endif
}
-#if USE(JSVALUE64)
emitFastArithIntToImmNoCheck(regT0, regT0);
-#else
- orPtr(Imm32(JSImmediate::TagTypeNumber), regT0);
-#endif
emitPutVirtualRegister(result);
}
stubCall.addArgument(op2, regT2);
} else {
if (supportsFloatingPointTruncate()) {
-#if USE(JSVALUE64)
linkSlowCase(iter);
linkSlowCase(iter);
linkSlowCase(iter);
-#else
- linkSlowCaseIfNotJSCell(iter, op1);
- linkSlowCase(iter);
- linkSlowCase(iter);
- linkSlowCase(iter);
- linkSlowCase(iter);
-#endif
// We're reloading op1 to regT0 as we can no longer guarantee that
// we have not munged the operand. It may have already been shifted
// correctly, but it still will not have been tagged.
// a toUint conversion, which can result in a value we can represent
// as an immediate int.
if (shift < 0 || !(shift & 31))
- addSlowCase(branch32(LessThan, regT0, Imm32(0)));
-#if USE(JSVALUE32)
- addSlowCase(branchAdd32(Overflow, regT0, regT0));
- signExtend32ToPtr(regT0, regT0);
-#endif
+ addSlowCase(branch32(LessThan, regT0, TrustedImm32(0)));
emitFastArithReTagImmediate(regT0, regT0);
emitPutVirtualRegister(dst, regT0);
return;
emitFastArithImmToInt(regT0);
emitFastArithImmToInt(regT1);
urshift32(regT1, regT0);
- addSlowCase(branch32(LessThan, regT0, Imm32(0)));
-#if USE(JSVALUE32)
- addSlowCase(branchAdd32(Overflow, regT0, regT0));
- signExtend32ToPtr(regT0, regT0);
-#endif
+ addSlowCase(branch32(LessThan, regT0, TrustedImm32(0)));
emitFastArithReTagImmediate(regT0, regT0);
emitPutVirtualRegister(dst, regT0);
}
int shift = getConstantOperand(op2).asInt32();
// op1 = regT0
linkSlowCase(iter); // int32 check
-#if USE(JSVALUE64)
if (supportsFloatingPointTruncate()) {
JumpList failures;
failures.append(emitJumpIfNotImmediateNumber(regT0)); // op1 is not a double
if (shift)
urshift32(Imm32(shift & 0x1f), regT0);
if (shift < 0 || !(shift & 31))
- failures.append(branch32(LessThan, regT0, Imm32(0)));
+ failures.append(branch32(LessThan, regT0, TrustedImm32(0)));
emitFastArithReTagImmediate(regT0, regT0);
emitPutVirtualRegister(dst, regT0);
emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_rshift));
failures.link(this);
}
-#endif // JSVALUE64
if (shift < 0 || !(shift & 31))
linkSlowCase(iter); // failed to box in hot path
-#if USE(JSVALUE32)
- linkSlowCase(iter); // Couldn't box result
-#endif
} else {
// op1 = regT0
// op2 = regT1
if (!isOperandConstantImmediateInt(op1)) {
linkSlowCase(iter); // int32 check -- op1 is not an int
-#if USE(JSVALUE64)
if (supportsFloatingPointTruncate()) {
JumpList failures;
failures.append(emitJumpIfNotImmediateNumber(regT0)); // op1 is not a double
failures.append(emitJumpIfNotImmediateInteger(regT1)); // op2 is not an int
emitFastArithImmToInt(regT1);
urshift32(regT1, regT0);
- failures.append(branch32(LessThan, regT0, Imm32(0)));
+ failures.append(branch32(LessThan, regT0, TrustedImm32(0)));
emitFastArithReTagImmediate(regT0, regT0);
emitPutVirtualRegister(dst, regT0);
emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_rshift));
failures.link(this);
}
-#endif
}
linkSlowCase(iter); // int32 check - op2 is not an int
linkSlowCase(iter); // Can't represent unsigned result as an immediate
-#if USE(JSVALUE32)
- linkSlowCase(iter); // Couldn't box result
-#endif
}
JITStubCall stubCall(this, cti_op_urshift);
if (isOperandConstantImmediateInt(op2)) {
emitGetVirtualRegister(op1, regT0);
emitJumpSlowCaseIfNotImmediateInteger(regT0);
-#if USE(JSVALUE64)
int32_t op2imm = getConstantOperandImmediateInt(op2);
-#else
- int32_t op2imm = static_cast<int32_t>(JSImmediate::rawValue(getConstantOperand(op2)));
-#endif
addJump(branch32(GreaterThanOrEqual, regT0, Imm32(op2imm)), target);
} else if (isOperandConstantImmediateInt(op1)) {
emitGetVirtualRegister(op2, regT1);
emitJumpSlowCaseIfNotImmediateInteger(regT1);
-#if USE(JSVALUE64)
int32_t op1imm = getConstantOperandImmediateInt(op1);
-#else
- int32_t op1imm = static_cast<int32_t>(JSImmediate::rawValue(getConstantOperand(op1)));
-#endif
addJump(branch32(LessThanOrEqual, regT1, Imm32(op1imm)), target);
} else {
emitGetVirtualRegisters(op1, regT0, op2, regT1);
linkSlowCase(iter);
if (supportsFloatingPoint()) {
-#if USE(JSVALUE64)
Jump fail1 = emitJumpIfNotImmediateNumber(regT0);
addPtr(tagTypeNumberRegister, regT0);
movePtrToDouble(regT0, fpRegT0);
-#else
- Jump fail1;
- if (!m_codeBlock->isKnownNotImmediate(op1))
- fail1 = emitJumpIfNotJSCell(regT0);
-
- Jump fail2 = checkStructure(regT0, m_globalData->numberStructure.get());
- loadDouble(Address(regT0, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT0);
-#endif
int32_t op2imm = getConstantOperand(op2).asInt32();;
emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnless));
-#if USE(JSVALUE64)
fail1.link(this);
-#else
- if (!m_codeBlock->isKnownNotImmediate(op1))
- fail1.link(this);
- fail2.link(this);
-#endif
}
JITStubCall stubCall(this, cti_op_jless);
linkSlowCase(iter);
if (supportsFloatingPoint()) {
-#if USE(JSVALUE64)
Jump fail1 = emitJumpIfNotImmediateNumber(regT1);
addPtr(tagTypeNumberRegister, regT1);
movePtrToDouble(regT1, fpRegT1);
-#else
- Jump fail1;
- if (!m_codeBlock->isKnownNotImmediate(op2))
- fail1 = emitJumpIfNotJSCell(regT1);
-
- Jump fail2 = checkStructure(regT1, m_globalData->numberStructure.get());
- loadDouble(Address(regT1, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT1);
-#endif
int32_t op1imm = getConstantOperand(op1).asInt32();;
emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnless));
-#if USE(JSVALUE64)
fail1.link(this);
-#else
- if (!m_codeBlock->isKnownNotImmediate(op2))
- fail1.link(this);
- fail2.link(this);
-#endif
}
JITStubCall stubCall(this, cti_op_jless);
linkSlowCase(iter);
if (supportsFloatingPoint()) {
-#if USE(JSVALUE64)
Jump fail1 = emitJumpIfNotImmediateNumber(regT0);
Jump fail2 = emitJumpIfNotImmediateNumber(regT1);
Jump fail3 = emitJumpIfImmediateInteger(regT1);
addPtr(tagTypeNumberRegister, regT1);
movePtrToDouble(regT0, fpRegT0);
movePtrToDouble(regT1, fpRegT1);
-#else
- Jump fail1;
- if (!m_codeBlock->isKnownNotImmediate(op1))
- fail1 = emitJumpIfNotJSCell(regT0);
-
- Jump fail2;
- if (!m_codeBlock->isKnownNotImmediate(op2))
- fail2 = emitJumpIfNotJSCell(regT1);
-
- Jump fail3 = checkStructure(regT0, m_globalData->numberStructure.get());
- Jump fail4 = checkStructure(regT1, m_globalData->numberStructure.get());
- loadDouble(Address(regT0, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT0);
- loadDouble(Address(regT1, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT1);
-#endif
emitJumpSlowToHot(branchDouble(DoubleLessThanOrEqualOrUnordered, fpRegT1, fpRegT0), target);
emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnless));
-#if USE(JSVALUE64)
fail1.link(this);
fail2.link(this);
fail3.link(this);
-#else
- if (!m_codeBlock->isKnownNotImmediate(op1))
- fail1.link(this);
- if (!m_codeBlock->isKnownNotImmediate(op2))
- fail2.link(this);
- fail3.link(this);
- fail4.link(this);
-#endif
}
linkSlowCase(iter);
if (isOperandConstantImmediateInt(op2)) {
emitGetVirtualRegister(op1, regT0);
emitJumpSlowCaseIfNotImmediateInteger(regT0);
-#if USE(JSVALUE64)
int32_t op2imm = getConstantOperandImmediateInt(op2);
-#else
- int32_t op2imm = static_cast<int32_t>(JSImmediate::rawValue(getConstantOperand(op2)));
-#endif
addJump(branch32(LessThan, regT0, Imm32(op2imm)), target);
} else if (isOperandConstantImmediateInt(op1)) {
emitGetVirtualRegister(op2, regT1);
emitJumpSlowCaseIfNotImmediateInteger(regT1);
-#if USE(JSVALUE64)
int32_t op1imm = getConstantOperandImmediateInt(op1);
-#else
- int32_t op1imm = static_cast<int32_t>(JSImmediate::rawValue(getConstantOperand(op1)));
-#endif
addJump(branch32(GreaterThan, regT1, Imm32(op1imm)), target);
} else {
emitGetVirtualRegisters(op1, regT0, op2, regT1);
linkSlowCase(iter);
if (supportsFloatingPoint()) {
-#if USE(JSVALUE64)
Jump fail1 = emitJumpIfNotImmediateNumber(regT0);
addPtr(tagTypeNumberRegister, regT0);
movePtrToDouble(regT0, fpRegT0);
-#else
- Jump fail1;
- if (!m_codeBlock->isKnownNotImmediate(op1))
- fail1 = emitJumpIfNotJSCell(regT0);
-
- Jump fail2 = checkStructure(regT0, m_globalData->numberStructure.get());
- loadDouble(Address(regT0, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT0);
-#endif
int32_t op2imm = getConstantOperand(op2).asInt32();
emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnless));
-#if USE(JSVALUE64)
fail1.link(this);
-#else
- if (!m_codeBlock->isKnownNotImmediate(op1))
- fail1.link(this);
- fail2.link(this);
-#endif
}
JITStubCall stubCall(this, cti_op_jless);
linkSlowCase(iter);
if (supportsFloatingPoint()) {
-#if USE(JSVALUE64)
Jump fail1 = emitJumpIfNotImmediateNumber(regT1);
addPtr(tagTypeNumberRegister, regT1);
movePtrToDouble(regT1, fpRegT1);
-#else
- Jump fail1;
- if (!m_codeBlock->isKnownNotImmediate(op2))
- fail1 = emitJumpIfNotJSCell(regT1);
-
- Jump fail2 = checkStructure(regT1, m_globalData->numberStructure.get());
- loadDouble(Address(regT1, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT1);
-#endif
int32_t op1imm = getConstantOperand(op1).asInt32();
emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnless));
-#if USE(JSVALUE64)
fail1.link(this);
-#else
- if (!m_codeBlock->isKnownNotImmediate(op2))
- fail1.link(this);
- fail2.link(this);
-#endif
}
JITStubCall stubCall(this, cti_op_jless);
linkSlowCase(iter);
if (supportsFloatingPoint()) {
-#if USE(JSVALUE64)
Jump fail1 = emitJumpIfNotImmediateNumber(regT0);
Jump fail2 = emitJumpIfNotImmediateNumber(regT1);
Jump fail3 = emitJumpIfImmediateInteger(regT1);
addPtr(tagTypeNumberRegister, regT1);
movePtrToDouble(regT0, fpRegT0);
movePtrToDouble(regT1, fpRegT1);
-#else
- Jump fail1;
- if (!m_codeBlock->isKnownNotImmediate(op1))
- fail1 = emitJumpIfNotJSCell(regT0);
-
- Jump fail2;
- if (!m_codeBlock->isKnownNotImmediate(op2))
- fail2 = emitJumpIfNotJSCell(regT1);
-
- Jump fail3 = checkStructure(regT0, m_globalData->numberStructure.get());
- Jump fail4 = checkStructure(regT1, m_globalData->numberStructure.get());
- loadDouble(Address(regT0, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT0);
- loadDouble(Address(regT1, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT1);
-#endif
emitJumpSlowToHot(branchDouble(DoubleLessThan, fpRegT0, fpRegT1), target);
emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnless));
-#if USE(JSVALUE64)
fail1.link(this);
fail2.link(this);
fail3.link(this);
-#else
- if (!m_codeBlock->isKnownNotImmediate(op1))
- fail1.link(this);
- if (!m_codeBlock->isKnownNotImmediate(op2))
- fail2.link(this);
- fail3.link(this);
- fail4.link(this);
-#endif
}
linkSlowCase(iter);
if (isOperandConstantImmediateInt(op2)) {
emitGetVirtualRegister(op1, regT0);
emitJumpSlowCaseIfNotImmediateInteger(regT0);
-#if USE(JSVALUE64)
int32_t op2imm = getConstantOperandImmediateInt(op2);
-#else
- int32_t op2imm = static_cast<int32_t>(JSImmediate::rawValue(getConstantOperand(op2)));
-#endif
addJump(branch32(invert ? GreaterThan : LessThanOrEqual, regT0, Imm32(op2imm)), target);
} else if (isOperandConstantImmediateInt(op1)) {
emitGetVirtualRegister(op2, regT1);
emitJumpSlowCaseIfNotImmediateInteger(regT1);
-#if USE(JSVALUE64)
int32_t op1imm = getConstantOperandImmediateInt(op1);
-#else
- int32_t op1imm = static_cast<int32_t>(JSImmediate::rawValue(getConstantOperand(op1)));
-#endif
addJump(branch32(invert ? LessThan : GreaterThanOrEqual, regT1, Imm32(op1imm)), target);
} else {
emitGetVirtualRegisters(op1, regT0, op2, regT1);
linkSlowCase(iter);
if (supportsFloatingPoint()) {
-#if USE(JSVALUE64)
Jump fail1 = emitJumpIfNotImmediateNumber(regT0);
addPtr(tagTypeNumberRegister, regT0);
movePtrToDouble(regT0, fpRegT0);
-#else
- Jump fail1;
- if (!m_codeBlock->isKnownNotImmediate(op1))
- fail1 = emitJumpIfNotJSCell(regT0);
-
- Jump fail2 = checkStructure(regT0, m_globalData->numberStructure.get());
- loadDouble(Address(regT0, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT0);
-#endif
int32_t op2imm = getConstantOperand(op2).asInt32();;
emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnlesseq));
-#if USE(JSVALUE64)
fail1.link(this);
-#else
- if (!m_codeBlock->isKnownNotImmediate(op1))
- fail1.link(this);
- fail2.link(this);
-#endif
}
JITStubCall stubCall(this, cti_op_jlesseq);
linkSlowCase(iter);
if (supportsFloatingPoint()) {
-#if USE(JSVALUE64)
Jump fail1 = emitJumpIfNotImmediateNumber(regT1);
addPtr(tagTypeNumberRegister, regT1);
movePtrToDouble(regT1, fpRegT1);
-#else
- Jump fail1;
- if (!m_codeBlock->isKnownNotImmediate(op2))
- fail1 = emitJumpIfNotJSCell(regT1);
-
- Jump fail2 = checkStructure(regT1, m_globalData->numberStructure.get());
- loadDouble(Address(regT1, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT1);
-#endif
int32_t op1imm = getConstantOperand(op1).asInt32();;
emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnlesseq));
-#if USE(JSVALUE64)
fail1.link(this);
-#else
- if (!m_codeBlock->isKnownNotImmediate(op2))
- fail1.link(this);
- fail2.link(this);
-#endif
}
JITStubCall stubCall(this, cti_op_jlesseq);
linkSlowCase(iter);
if (supportsFloatingPoint()) {
-#if USE(JSVALUE64)
Jump fail1 = emitJumpIfNotImmediateNumber(regT0);
Jump fail2 = emitJumpIfNotImmediateNumber(regT1);
Jump fail3 = emitJumpIfImmediateInteger(regT1);
addPtr(tagTypeNumberRegister, regT1);
movePtrToDouble(regT0, fpRegT0);
movePtrToDouble(regT1, fpRegT1);
-#else
- Jump fail1;
- if (!m_codeBlock->isKnownNotImmediate(op1))
- fail1 = emitJumpIfNotJSCell(regT0);
-
- Jump fail2;
- if (!m_codeBlock->isKnownNotImmediate(op2))
- fail2 = emitJumpIfNotJSCell(regT1);
-
- Jump fail3 = checkStructure(regT0, m_globalData->numberStructure.get());
- Jump fail4 = checkStructure(regT1, m_globalData->numberStructure.get());
- loadDouble(Address(regT0, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT0);
- loadDouble(Address(regT1, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT1);
-#endif
emitJumpSlowToHot(branchDouble(invert ? DoubleLessThanOrUnordered : DoubleGreaterThanOrEqual, fpRegT1, fpRegT0), target);
emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnlesseq));
-#if USE(JSVALUE64)
fail1.link(this);
fail2.link(this);
fail3.link(this);
-#else
- if (!m_codeBlock->isKnownNotImmediate(op1))
- fail1.link(this);
- if (!m_codeBlock->isKnownNotImmediate(op2))
- fail2.link(this);
- fail3.link(this);
- fail4.link(this);
-#endif
}
linkSlowCase(iter);
if (isOperandConstantImmediateInt(op1)) {
emitGetVirtualRegister(op2, regT0);
emitJumpSlowCaseIfNotImmediateInteger(regT0);
-#if USE(JSVALUE64)
int32_t imm = getConstantOperandImmediateInt(op1);
andPtr(Imm32(imm), regT0);
if (imm >= 0)
emitFastArithIntToImmNoCheck(regT0, regT0);
-#else
- andPtr(Imm32(static_cast<int32_t>(JSImmediate::rawValue(getConstantOperand(op1)))), regT0);
-#endif
} else if (isOperandConstantImmediateInt(op2)) {
emitGetVirtualRegister(op1, regT0);
emitJumpSlowCaseIfNotImmediateInteger(regT0);
-#if USE(JSVALUE64)
int32_t imm = getConstantOperandImmediateInt(op2);
andPtr(Imm32(imm), regT0);
if (imm >= 0)
emitFastArithIntToImmNoCheck(regT0, regT0);
-#else
- andPtr(Imm32(static_cast<int32_t>(JSImmediate::rawValue(getConstantOperand(op2)))), regT0);
-#endif
} else {
emitGetVirtualRegisters(op1, regT0, op2, regT1);
andPtr(regT1, regT0);
emitGetVirtualRegister(srcDst, regT0);
move(regT0, regT1);
emitJumpSlowCaseIfNotImmediateInteger(regT0);
-#if USE(JSVALUE64)
- addSlowCase(branchAdd32(Overflow, Imm32(1), regT1));
+ addSlowCase(branchAdd32(Overflow, TrustedImm32(1), regT1));
emitFastArithIntToImmNoCheck(regT1, regT1);
-#else
- addSlowCase(branchAdd32(Overflow, Imm32(1 << JSImmediate::IntegerPayloadShift), regT1));
- signExtend32ToPtr(regT1, regT1);
-#endif
emitPutVirtualRegister(srcDst, regT1);
emitPutVirtualRegister(result);
}
emitGetVirtualRegister(srcDst, regT0);
move(regT0, regT1);
emitJumpSlowCaseIfNotImmediateInteger(regT0);
-#if USE(JSVALUE64)
- addSlowCase(branchSub32(Zero, Imm32(1), regT1));
+ addSlowCase(branchSub32(Zero, TrustedImm32(1), regT1));
emitFastArithIntToImmNoCheck(regT1, regT1);
-#else
- addSlowCase(branchSub32(Zero, Imm32(1 << JSImmediate::IntegerPayloadShift), regT1));
- signExtend32ToPtr(regT1, regT1);
-#endif
emitPutVirtualRegister(srcDst, regT1);
emitPutVirtualRegister(result);
}
emitGetVirtualRegister(srcDst, regT0);
emitJumpSlowCaseIfNotImmediateInteger(regT0);
-#if USE(JSVALUE64)
- addSlowCase(branchAdd32(Overflow, Imm32(1), regT0));
+ addSlowCase(branchAdd32(Overflow, TrustedImm32(1), regT0));
emitFastArithIntToImmNoCheck(regT0, regT0);
-#else
- addSlowCase(branchAdd32(Overflow, Imm32(1 << JSImmediate::IntegerPayloadShift), regT0));
- signExtend32ToPtr(regT0, regT0);
-#endif
emitPutVirtualRegister(srcDst);
}
emitGetVirtualRegister(srcDst, regT0);
emitJumpSlowCaseIfNotImmediateInteger(regT0);
-#if USE(JSVALUE64)
- addSlowCase(branchSub32(Zero, Imm32(1), regT0));
+ addSlowCase(branchSub32(Zero, TrustedImm32(1), regT0));
emitFastArithIntToImmNoCheck(regT0, regT0);
-#else
- addSlowCase(branchSub32(Zero, Imm32(1 << JSImmediate::IntegerPayloadShift), regT0));
- signExtend32ToPtr(regT0, regT0);
-#endif
emitPutVirtualRegister(srcDst);
}
/* ------------------------------ BEGIN: OP_MOD ------------------------------ */
-#if CPU(X86) || CPU(X86_64)
+#if CPU(X86) || CPU(X86_64) || CPU(MIPS)
void JIT::emit_op_mod(Instruction* currentInstruction)
{
unsigned op1 = currentInstruction[2].u.operand;
unsigned op2 = currentInstruction[3].u.operand;
- emitGetVirtualRegisters(op1, X86Registers::eax, op2, X86Registers::ecx);
- emitJumpSlowCaseIfNotImmediateInteger(X86Registers::eax);
- emitJumpSlowCaseIfNotImmediateInteger(X86Registers::ecx);
-#if USE(JSVALUE64)
- addSlowCase(branchPtr(Equal, X86Registers::ecx, ImmPtr(JSValue::encode(jsNumber(m_globalData, 0)))));
- m_assembler.cdq();
- m_assembler.idivl_r(X86Registers::ecx);
-#else
- emitFastArithDeTagImmediate(X86Registers::eax);
- addSlowCase(emitFastArithDeTagImmediateJumpIfZero(X86Registers::ecx));
- m_assembler.cdq();
- m_assembler.idivl_r(X86Registers::ecx);
- signExtend32ToPtr(X86Registers::edx, X86Registers::edx);
+#if CPU(X86) || CPU(X86_64)
+ // Make sure registers are correct for x86 IDIV instructions.
+ ASSERT(regT0 == X86Registers::eax);
+ ASSERT(regT1 == X86Registers::edx);
+ ASSERT(regT2 == X86Registers::ecx);
#endif
- emitFastArithReTagImmediate(X86Registers::edx, X86Registers::eax);
+
+ emitGetVirtualRegisters(op1, regT0, op2, regT2);
+ emitJumpSlowCaseIfNotImmediateInteger(regT0);
+ emitJumpSlowCaseIfNotImmediateInteger(regT2);
+
+ addSlowCase(branchPtr(Equal, regT2, TrustedImmPtr(JSValue::encode(jsNumber(0)))));
+ m_assembler.cdq();
+ m_assembler.idivl_r(regT2);
+ emitFastArithReTagImmediate(regT1, regT0);
emitPutVirtualRegister(result);
}
{
unsigned result = currentInstruction[1].u.operand;
-#if USE(JSVALUE64)
- linkSlowCase(iter);
linkSlowCase(iter);
linkSlowCase(iter);
-#else
- Jump notImm1 = getSlowCase(iter);
- Jump notImm2 = getSlowCase(iter);
linkSlowCase(iter);
- emitFastArithReTagImmediate(X86Registers::eax, X86Registers::eax);
- emitFastArithReTagImmediate(X86Registers::ecx, X86Registers::ecx);
- notImm1.link(this);
- notImm2.link(this);
-#endif
JITStubCall stubCall(this, cti_op_mod);
- stubCall.addArgument(X86Registers::eax);
- stubCall.addArgument(X86Registers::ecx);
+ stubCall.addArgument(regT0);
+ stubCall.addArgument(regT2);
stubCall.call(result);
}
-#else // CPU(X86) || CPU(X86_64)
+#else // CPU(X86) || CPU(X86_64) || CPU(MIPS)
void JIT::emit_op_mod(Instruction* currentInstruction)
{
unsigned op1 = currentInstruction[2].u.operand;
unsigned op2 = currentInstruction[3].u.operand;
-#if ENABLE(JIT_OPTIMIZE_MOD)
- emitGetVirtualRegisters(op1, regT0, op2, regT2);
- emitJumpSlowCaseIfNotImmediateInteger(regT0);
- emitJumpSlowCaseIfNotImmediateInteger(regT2);
-
- addSlowCase(branch32(Equal, regT2, Imm32(1)));
-
- emitNakedCall(m_globalData->jitStubs.ctiSoftModulo());
-
- emitPutVirtualRegister(result, regT0);
-#else
JITStubCall stubCall(this, cti_op_mod);
stubCall.addArgument(op1, regT2);
stubCall.addArgument(op2, regT2);
stubCall.call(result);
-#endif
}
void JIT::emitSlow_op_mod(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
{
-#if ENABLE(JIT_OPTIMIZE_MOD)
+#if ENABLE(JIT_USE_SOFT_MODULO)
unsigned result = currentInstruction[1].u.operand;
unsigned op1 = currentInstruction[2].u.operand;
unsigned op2 = currentInstruction[3].u.operand;
/* ------------------------------ END: OP_MOD ------------------------------ */
-#if USE(JSVALUE64)
-
/* ------------------------------ BEGIN: USE(JSVALUE64) (OP_ADD, OP_SUB, OP_MUL) ------------------------------ */
void JIT::compileBinaryArithOp(OpcodeID opcodeID, unsigned, unsigned op1, unsigned op2, OperandTypes)
void JIT::compileBinaryArithOpSlowCase(OpcodeID opcodeID, Vector<SlowCaseEntry>::iterator& iter, unsigned result, unsigned op1, unsigned op2, OperandTypes types, bool op1HasImmediateIntFastCase, bool op2HasImmediateIntFastCase)
{
// We assume that subtracting TagTypeNumber is equivalent to adding DoubleEncodeOffset.
- COMPILE_ASSERT(((JSImmediate::TagTypeNumber + JSImmediate::DoubleEncodeOffset) == 0), TagTypeNumber_PLUS_DoubleEncodeOffset_EQUALS_0);
+ COMPILE_ASSERT(((TagTypeNumber + DoubleEncodeOffset) == 0), TagTypeNumber_PLUS_DoubleEncodeOffset_EQUALS_0);
Jump notImm1;
Jump notImm2;
bool op1HasImmediateIntFastCase = isOperandConstantImmediateInt(op1);
bool op2HasImmediateIntFastCase = !op1HasImmediateIntFastCase && isOperandConstantImmediateInt(op2);
- compileBinaryArithOpSlowCase(op_add, iter, result, op1, op2, OperandTypes::fromInt(currentInstruction[4].u.operand), op1HasImmediateIntFastCase, op2HasImmediateIntFastCase);
+ compileBinaryArithOpSlowCase(op_add, iter, result, op1, op2, types, op1HasImmediateIntFastCase, op2HasImmediateIntFastCase);
}
void JIT::emit_op_mul(Instruction* currentInstruction)
bool op1HasImmediateIntFastCase = isOperandConstantImmediateInt(op1) && getConstantOperandImmediateInt(op1) > 0;
bool op2HasImmediateIntFastCase = !op1HasImmediateIntFastCase && isOperandConstantImmediateInt(op2) && getConstantOperandImmediateInt(op2) > 0;
- compileBinaryArithOpSlowCase(op_mul, iter, result, op1, op2, OperandTypes::fromInt(currentInstruction[4].u.operand), op1HasImmediateIntFastCase, op2HasImmediateIntFastCase);
+ compileBinaryArithOpSlowCase(op_mul, iter, result, op1, op2, types, op1HasImmediateIntFastCase, op2HasImmediateIntFastCase);
}
void JIT::emit_op_div(Instruction* currentInstruction)
compileBinaryArithOpSlowCase(op_sub, iter, result, op1, op2, types, false, false);
}
-#else // USE(JSVALUE64)
-
-/* ------------------------------ BEGIN: !USE(JSVALUE64) (OP_ADD, OP_SUB, OP_MUL) ------------------------------ */
-
-void JIT::compileBinaryArithOp(OpcodeID opcodeID, unsigned dst, unsigned src1, unsigned src2, OperandTypes types)
-{
- Structure* numberStructure = m_globalData->numberStructure.get();
- Jump wasJSNumberCell1;
- Jump wasJSNumberCell2;
-
- emitGetVirtualRegisters(src1, regT0, src2, regT1);
-
- if (types.second().isReusable() && supportsFloatingPoint()) {
- ASSERT(types.second().mightBeNumber());
-
- // Check op2 is a number
- Jump op2imm = emitJumpIfImmediateInteger(regT1);
- if (!types.second().definitelyIsNumber()) {
- emitJumpSlowCaseIfNotJSCell(regT1, src2);
- addSlowCase(checkStructure(regT1, numberStructure));
- }
-
- // (1) In this case src2 is a reusable number cell.
- // Slow case if src1 is not a number type.
- Jump op1imm = emitJumpIfImmediateInteger(regT0);
- if (!types.first().definitelyIsNumber()) {
- emitJumpSlowCaseIfNotJSCell(regT0, src1);
- addSlowCase(checkStructure(regT0, numberStructure));
- }
-
- // (1a) if we get here, src1 is also a number cell
- loadDouble(Address(regT0, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT0);
- Jump loadedDouble = jump();
- // (1b) if we get here, src1 is an immediate
- op1imm.link(this);
- emitFastArithImmToInt(regT0);
- convertInt32ToDouble(regT0, fpRegT0);
- // (1c)
- loadedDouble.link(this);
- if (opcodeID == op_add)
- addDouble(Address(regT1, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT0);
- else if (opcodeID == op_sub)
- subDouble(Address(regT1, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT0);
- else {
- ASSERT(opcodeID == op_mul);
- mulDouble(Address(regT1, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT0);
- }
-
- // Store the result to the JSNumberCell and jump.
- storeDouble(fpRegT0, Address(regT1, OBJECT_OFFSETOF(JSNumberCell, m_value)));
- move(regT1, regT0);
- emitPutVirtualRegister(dst);
- wasJSNumberCell2 = jump();
-
- // (2) This handles cases where src2 is an immediate number.
- // Two slow cases - either src1 isn't an immediate, or the subtract overflows.
- op2imm.link(this);
- emitJumpSlowCaseIfNotImmediateInteger(regT0);
- } else if (types.first().isReusable() && supportsFloatingPoint()) {
- ASSERT(types.first().mightBeNumber());
-
- // Check op1 is a number
- Jump op1imm = emitJumpIfImmediateInteger(regT0);
- if (!types.first().definitelyIsNumber()) {
- emitJumpSlowCaseIfNotJSCell(regT0, src1);
- addSlowCase(checkStructure(regT0, numberStructure));
- }
-
- // (1) In this case src1 is a reusable number cell.
- // Slow case if src2 is not a number type.
- Jump op2imm = emitJumpIfImmediateInteger(regT1);
- if (!types.second().definitelyIsNumber()) {
- emitJumpSlowCaseIfNotJSCell(regT1, src2);
- addSlowCase(checkStructure(regT1, numberStructure));
- }
-
- // (1a) if we get here, src2 is also a number cell
- loadDouble(Address(regT1, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT1);
- Jump loadedDouble = jump();
- // (1b) if we get here, src2 is an immediate
- op2imm.link(this);
- emitFastArithImmToInt(regT1);
- convertInt32ToDouble(regT1, fpRegT1);
- // (1c)
- loadedDouble.link(this);
- loadDouble(Address(regT0, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT0);
- if (opcodeID == op_add)
- addDouble(fpRegT1, fpRegT0);
- else if (opcodeID == op_sub)
- subDouble(fpRegT1, fpRegT0);
- else {
- ASSERT(opcodeID == op_mul);
- mulDouble(fpRegT1, fpRegT0);
- }
- storeDouble(fpRegT0, Address(regT0, OBJECT_OFFSETOF(JSNumberCell, m_value)));
- emitPutVirtualRegister(dst);
-
- // Store the result to the JSNumberCell and jump.
- storeDouble(fpRegT0, Address(regT0, OBJECT_OFFSETOF(JSNumberCell, m_value)));
- emitPutVirtualRegister(dst);
- wasJSNumberCell1 = jump();
-
- // (2) This handles cases where src1 is an immediate number.
- // Two slow cases - either src2 isn't an immediate, or the subtract overflows.
- op1imm.link(this);
- emitJumpSlowCaseIfNotImmediateInteger(regT1);
- } else
- emitJumpSlowCaseIfNotImmediateIntegers(regT0, regT1, regT2);
-
- if (opcodeID == op_add) {
- emitFastArithDeTagImmediate(regT0);
- addSlowCase(branchAdd32(Overflow, regT1, regT0));
- } else if (opcodeID == op_sub) {
- addSlowCase(branchSub32(Overflow, regT1, regT0));
- signExtend32ToPtr(regT0, regT0);
- emitFastArithReTagImmediate(regT0, regT0);
- } else {
- ASSERT(opcodeID == op_mul);
- // convert eax & edx from JSImmediates to ints, and check if either are zero
- emitFastArithImmToInt(regT1);
- Jump op1Zero = emitFastArithDeTagImmediateJumpIfZero(regT0);
- Jump op2NonZero = branchTest32(NonZero, regT1);
- op1Zero.link(this);
- // if either input is zero, add the two together, and check if the result is < 0.
- // If it is, we have a problem (N < 0), (N * 0) == -0, not representatble as a JSImmediate.
- move(regT0, regT2);
- addSlowCase(branchAdd32(Signed, regT1, regT2));
- // Skip the above check if neither input is zero
- op2NonZero.link(this);
- addSlowCase(branchMul32(Overflow, regT1, regT0));
- signExtend32ToPtr(regT0, regT0);
- emitFastArithReTagImmediate(regT0, regT0);
- }
- emitPutVirtualRegister(dst);
-
- if (types.second().isReusable() && supportsFloatingPoint())
- wasJSNumberCell2.link(this);
- else if (types.first().isReusable() && supportsFloatingPoint())
- wasJSNumberCell1.link(this);
-}
-
-void JIT::compileBinaryArithOpSlowCase(OpcodeID opcodeID, Vector<SlowCaseEntry>::iterator& iter, unsigned dst, unsigned src1, unsigned src2, OperandTypes types)
-{
- linkSlowCase(iter);
- if (types.second().isReusable() && supportsFloatingPoint()) {
- if (!types.first().definitelyIsNumber()) {
- linkSlowCaseIfNotJSCell(iter, src1);
- linkSlowCase(iter);
- }
- if (!types.second().definitelyIsNumber()) {
- linkSlowCaseIfNotJSCell(iter, src2);
- linkSlowCase(iter);
- }
- } else if (types.first().isReusable() && supportsFloatingPoint()) {
- if (!types.first().definitelyIsNumber()) {
- linkSlowCaseIfNotJSCell(iter, src1);
- linkSlowCase(iter);
- }
- if (!types.second().definitelyIsNumber()) {
- linkSlowCaseIfNotJSCell(iter, src2);
- linkSlowCase(iter);
- }
- }
- linkSlowCase(iter);
-
- // additional entry point to handle -0 cases.
- if (opcodeID == op_mul)
- linkSlowCase(iter);
-
- JITStubCall stubCall(this, opcodeID == op_add ? cti_op_add : opcodeID == op_sub ? cti_op_sub : cti_op_mul);
- stubCall.addArgument(src1, regT2);
- stubCall.addArgument(src2, regT2);
- stubCall.call(dst);
-}
-
-void JIT::emit_op_add(Instruction* currentInstruction)
-{
- unsigned result = currentInstruction[1].u.operand;
- unsigned op1 = currentInstruction[2].u.operand;
- unsigned op2 = currentInstruction[3].u.operand;
- OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand);
-
- if (!types.first().mightBeNumber() || !types.second().mightBeNumber()) {
- JITStubCall stubCall(this, cti_op_add);
- stubCall.addArgument(op1, regT2);
- stubCall.addArgument(op2, regT2);
- stubCall.call(result);
- return;
- }
-
- if (isOperandConstantImmediateInt(op1)) {
- emitGetVirtualRegister(op2, regT0);
- emitJumpSlowCaseIfNotImmediateInteger(regT0);
- addSlowCase(branchAdd32(Overflow, Imm32(getConstantOperandImmediateInt(op1) << JSImmediate::IntegerPayloadShift), regT0));
- signExtend32ToPtr(regT0, regT0);
- emitPutVirtualRegister(result);
- } else if (isOperandConstantImmediateInt(op2)) {
- emitGetVirtualRegister(op1, regT0);
- emitJumpSlowCaseIfNotImmediateInteger(regT0);
- addSlowCase(branchAdd32(Overflow, Imm32(getConstantOperandImmediateInt(op2) << JSImmediate::IntegerPayloadShift), regT0));
- signExtend32ToPtr(regT0, regT0);
- emitPutVirtualRegister(result);
- } else {
- compileBinaryArithOp(op_add, result, op1, op2, OperandTypes::fromInt(currentInstruction[4].u.operand));
- }
-}
-
-void JIT::emitSlow_op_add(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
-{
- unsigned result = currentInstruction[1].u.operand;
- unsigned op1 = currentInstruction[2].u.operand;
- unsigned op2 = currentInstruction[3].u.operand;
-
- OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand);
- if (!types.first().mightBeNumber() || !types.second().mightBeNumber())
- return;
-
- if (isOperandConstantImmediateInt(op1)) {
- Jump notImm = getSlowCase(iter);
- linkSlowCase(iter);
- sub32(Imm32(getConstantOperandImmediateInt(op1) << JSImmediate::IntegerPayloadShift), regT0);
- notImm.link(this);
- JITStubCall stubCall(this, cti_op_add);
- stubCall.addArgument(op1, regT2);
- stubCall.addArgument(regT0);
- stubCall.call(result);
- } else if (isOperandConstantImmediateInt(op2)) {
- Jump notImm = getSlowCase(iter);
- linkSlowCase(iter);
- sub32(Imm32(getConstantOperandImmediateInt(op2) << JSImmediate::IntegerPayloadShift), regT0);
- notImm.link(this);
- JITStubCall stubCall(this, cti_op_add);
- stubCall.addArgument(regT0);
- stubCall.addArgument(op2, regT2);
- stubCall.call(result);
- } else {
- OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand);
- ASSERT(types.first().mightBeNumber() && types.second().mightBeNumber());
- compileBinaryArithOpSlowCase(op_add, iter, result, op1, op2, types);
- }
-}
-
-void JIT::emit_op_mul(Instruction* currentInstruction)
-{
- unsigned result = currentInstruction[1].u.operand;
- unsigned op1 = currentInstruction[2].u.operand;
- unsigned op2 = currentInstruction[3].u.operand;
-
- // For now, only plant a fast int case if the constant operand is greater than zero.
- int32_t value;
- if (isOperandConstantImmediateInt(op1) && ((value = getConstantOperandImmediateInt(op1)) > 0)) {
- emitGetVirtualRegister(op2, regT0);
- emitJumpSlowCaseIfNotImmediateInteger(regT0);
- emitFastArithDeTagImmediate(regT0);
- addSlowCase(branchMul32(Overflow, Imm32(value), regT0, regT0));
- signExtend32ToPtr(regT0, regT0);
- emitFastArithReTagImmediate(regT0, regT0);
- emitPutVirtualRegister(result);
- } else if (isOperandConstantImmediateInt(op2) && ((value = getConstantOperandImmediateInt(op2)) > 0)) {
- emitGetVirtualRegister(op1, regT0);
- emitJumpSlowCaseIfNotImmediateInteger(regT0);
- emitFastArithDeTagImmediate(regT0);
- addSlowCase(branchMul32(Overflow, Imm32(value), regT0, regT0));
- signExtend32ToPtr(regT0, regT0);
- emitFastArithReTagImmediate(regT0, regT0);
- emitPutVirtualRegister(result);
- } else
- compileBinaryArithOp(op_mul, result, op1, op2, OperandTypes::fromInt(currentInstruction[4].u.operand));
-}
-
-void JIT::emitSlow_op_mul(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
-{
- unsigned result = currentInstruction[1].u.operand;
- unsigned op1 = currentInstruction[2].u.operand;
- unsigned op2 = currentInstruction[3].u.operand;
-
- if ((isOperandConstantImmediateInt(op1) && (getConstantOperandImmediateInt(op1) > 0))
- || (isOperandConstantImmediateInt(op2) && (getConstantOperandImmediateInt(op2) > 0))) {
- linkSlowCase(iter);
- linkSlowCase(iter);
- // There is an extra slow case for (op1 * -N) or (-N * op2), to check for 0 since this should produce a result of -0.
- JITStubCall stubCall(this, cti_op_mul);
- stubCall.addArgument(op1, regT2);
- stubCall.addArgument(op2, regT2);
- stubCall.call(result);
- } else
- compileBinaryArithOpSlowCase(op_mul, iter, result, op1, op2, OperandTypes::fromInt(currentInstruction[4].u.operand));
-}
-
-void JIT::emit_op_sub(Instruction* currentInstruction)
-{
- compileBinaryArithOp(op_sub, currentInstruction[1].u.operand, currentInstruction[2].u.operand, currentInstruction[3].u.operand, OperandTypes::fromInt(currentInstruction[4].u.operand));
-}
-
-void JIT::emitSlow_op_sub(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
-{
- compileBinaryArithOpSlowCase(op_sub, iter, currentInstruction[1].u.operand, currentInstruction[2].u.operand, currentInstruction[3].u.operand, OperandTypes::fromInt(currentInstruction[4].u.operand));
-}
-
-#endif // USE(JSVALUE64)
-
/* ------------------------------ END: OP_ADD, OP_SUB, OP_MUL ------------------------------ */
-#endif // !USE(JSVALUE32_64)
-
} // namespace JSC
+#endif // USE(JSVALUE64)
#endif // ENABLE(JIT)
*/
#include "config.h"
-#include "JIT.h"
#if ENABLE(JIT)
+#if USE(JSVALUE32_64)
+#include "JIT.h"
#include "CodeBlock.h"
#include "JITInlineMethods.h"
namespace JSC {
-#if USE(JSVALUE32_64)
-
void JIT::emit_op_negate(Instruction* currentInstruction)
{
unsigned dst = currentInstruction[1].u.operand;
emitLoad(src, regT1, regT0);
- Jump srcNotInt = branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag));
- addSlowCase(branchTest32(Zero, regT0, Imm32(0x7fffffff)));
+ Jump srcNotInt = branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag));
+ addSlowCase(branchTest32(Zero, regT0, TrustedImm32(0x7fffffff)));
neg32(regT0);
emitStoreInt32(dst, regT0, (dst == src));
Jump end = jump();
srcNotInt.link(this);
- addSlowCase(branch32(Above, regT1, Imm32(JSValue::LowestTag)));
+ addSlowCase(branch32(Above, regT1, TrustedImm32(JSValue::LowestTag)));
- xor32(Imm32(1 << 31), regT1);
+ xor32(TrustedImm32(1 << 31), regT1);
store32(regT1, tagFor(dst));
if (dst != src)
store32(regT0, payloadFor(dst));
// Character less.
if (isOperandConstantImmediateChar(op1)) {
emitLoad(op2, regT1, regT0);
- addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::CellTag)));
+ addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)));
JumpList failures;
emitLoadCharacterString(regT0, regT0, failures);
addSlowCase(failures);
}
if (isOperandConstantImmediateChar(op2)) {
emitLoad(op1, regT1, regT0);
- addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::CellTag)));
+ addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)));
JumpList failures;
emitLoadCharacterString(regT0, regT0, failures);
addSlowCase(failures);
if (isOperandConstantImmediateInt(op1)) {
// Int32 less.
emitLoad(op2, regT3, regT2);
- notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
+ notInt32Op2.append(branch32(NotEqual, regT3, TrustedImm32(JSValue::Int32Tag)));
addJump(branch32(LessThanOrEqual, regT2, Imm32(getConstantOperand(op1).asInt32())), target);
} else if (isOperandConstantImmediateInt(op2)) {
emitLoad(op1, regT1, regT0);
- notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
+ notInt32Op1.append(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)));
addJump(branch32(GreaterThanOrEqual, regT0, Imm32(getConstantOperand(op2).asInt32())), target);
} else {
emitLoad2(op1, regT1, regT0, op2, regT3, regT2);
- notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
- notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
+ notInt32Op1.append(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)));
+ notInt32Op2.append(branch32(NotEqual, regT3, TrustedImm32(JSValue::Int32Tag)));
addJump(branch32(GreaterThanOrEqual, regT0, regT2), target);
}
// Character less.
if (isOperandConstantImmediateChar(op1)) {
emitLoad(op2, regT1, regT0);
- addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::CellTag)));
+ addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)));
JumpList failures;
emitLoadCharacterString(regT0, regT0, failures);
addSlowCase(failures);
}
if (isOperandConstantImmediateChar(op2)) {
emitLoad(op1, regT1, regT0);
- addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::CellTag)));
+ addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)));
JumpList failures;
emitLoadCharacterString(regT0, regT0, failures);
addSlowCase(failures);
}
if (isOperandConstantImmediateInt(op1)) {
emitLoad(op2, regT3, regT2);
- notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
+ notInt32Op2.append(branch32(NotEqual, regT3, TrustedImm32(JSValue::Int32Tag)));
addJump(branch32(GreaterThan, regT2, Imm32(getConstantOperand(op1).asInt32())), target);
} else if (isOperandConstantImmediateInt(op2)) {
emitLoad(op1, regT1, regT0);
- notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
+ notInt32Op1.append(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)));
addJump(branch32(LessThan, regT0, Imm32(getConstantOperand(op2).asInt32())), target);
} else {
emitLoad2(op1, regT1, regT0, op2, regT3, regT2);
- notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
- notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
+ notInt32Op1.append(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)));
+ notInt32Op2.append(branch32(NotEqual, regT3, TrustedImm32(JSValue::Int32Tag)));
addJump(branch32(LessThan, regT0, regT2), target);
}
// Character less.
if (isOperandConstantImmediateChar(op1)) {
emitLoad(op2, regT1, regT0);
- addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::CellTag)));
+ addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)));
JumpList failures;
emitLoadCharacterString(regT0, regT0, failures);
addSlowCase(failures);
}
if (isOperandConstantImmediateChar(op2)) {
emitLoad(op1, regT1, regT0);
- addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::CellTag)));
+ addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)));
JumpList failures;
emitLoadCharacterString(regT0, regT0, failures);
addSlowCase(failures);
}
if (isOperandConstantImmediateInt(op1)) {
emitLoad(op2, regT3, regT2);
- notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
+ notInt32Op2.append(branch32(NotEqual, regT3, TrustedImm32(JSValue::Int32Tag)));
addJump(branch32(invert ? LessThan : GreaterThanOrEqual, regT2, Imm32(getConstantOperand(op1).asInt32())), target);
} else if (isOperandConstantImmediateInt(op2)) {
emitLoad(op1, regT1, regT0);
- notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
+ notInt32Op1.append(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)));
addJump(branch32(invert ? GreaterThan : LessThanOrEqual, regT0, Imm32(getConstantOperand(op2).asInt32())), target);
} else {
emitLoad2(op1, regT1, regT0, op2, regT3, regT2);
- notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
- notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
+ notInt32Op1.append(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)));
+ notInt32Op2.append(branch32(NotEqual, regT3, TrustedImm32(JSValue::Int32Tag)));
addJump(branch32(invert ? GreaterThan : LessThanOrEqual, regT0, regT2), target);
}
if (isOperandConstantImmediateInt(op2)) {
emitLoad(op1, regT1, regT0);
- addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
+ addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)));
lshift32(Imm32(getConstantOperand(op2).asInt32()), regT0);
emitStoreInt32(dst, regT0, dst == op1);
return;
emitLoad2(op1, regT1, regT0, op2, regT3, regT2);
if (!isOperandConstantImmediateInt(op1))
- addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
- addSlowCase(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
+ addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)));
+ addSlowCase(branch32(NotEqual, regT3, TrustedImm32(JSValue::Int32Tag)));
lshift32(regT2, regT0);
emitStoreInt32(dst, regT0, dst == op1 || dst == op2);
}
// shift arguments, so any changes must be updated there as well.
if (isOperandConstantImmediateInt(op2)) {
emitLoad(op1, regT1, regT0);
- addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
+ addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)));
int shift = getConstantOperand(op2).asInt32();
if (isUnsigned) {
if (shift)
// a toUint conversion, which can result in a value we can represent
// as an immediate int.
if (shift < 0 || !(shift & 31))
- addSlowCase(branch32(LessThan, regT0, Imm32(0)));
+ addSlowCase(branch32(LessThan, regT0, TrustedImm32(0)));
} else if (shift) { // signed right shift by zero is simply toInt conversion
rshift32(Imm32(shift & 0x1f), regT0);
}
emitLoad2(op1, regT1, regT0, op2, regT3, regT2);
if (!isOperandConstantImmediateInt(op1))
- addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
- addSlowCase(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
+ addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)));
+ addSlowCase(branch32(NotEqual, regT3, TrustedImm32(JSValue::Int32Tag)));
if (isUnsigned) {
urshift32(regT2, regT0);
- addSlowCase(branch32(LessThan, regT0, Imm32(0)));
+ addSlowCase(branch32(LessThan, regT0, TrustedImm32(0)));
} else
rshift32(regT2, regT0);
emitStoreInt32(dst, regT0, dst == op1 || dst == op2);
linkSlowCase(iter); // int32 check
if (supportsFloatingPointTruncate()) {
JumpList failures;
- failures.append(branch32(AboveOrEqual, regT1, Imm32(JSValue::LowestTag)));
+ failures.append(branch32(AboveOrEqual, regT1, TrustedImm32(JSValue::LowestTag)));
emitLoadDouble(op1, fpRegT0);
failures.append(branchTruncateDoubleToInt32(fpRegT0, regT0));
if (isUnsigned) {
if (shift)
urshift32(Imm32(shift & 0x1f), regT0);
if (shift < 0 || !(shift & 31))
- failures.append(branch32(LessThan, regT0, Imm32(0)));
+ failures.append(branch32(LessThan, regT0, TrustedImm32(0)));
} else if (shift)
rshift32(Imm32(shift & 0x1f), regT0);
emitStoreInt32(dst, regT0, false);
if (!isOperandConstantImmediateInt(op1)) {
linkSlowCase(iter); // int32 check -- op1 is not an int
if (supportsFloatingPointTruncate()) {
- Jump notDouble = branch32(Above, regT1, Imm32(JSValue::LowestTag)); // op1 is not a double
+ Jump notDouble = branch32(Above, regT1, TrustedImm32(JSValue::LowestTag)); // op1 is not a double
emitLoadDouble(op1, fpRegT0);
- Jump notInt = branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)); // op2 is not an int
+ Jump notInt = branch32(NotEqual, regT3, TrustedImm32(JSValue::Int32Tag)); // op2 is not an int
Jump cantTruncate = branchTruncateDoubleToInt32(fpRegT0, regT0);
if (isUnsigned)
urshift32(regT2, regT0);
int32_t constant;
if (getOperandConstantImmediateInt(op1, op2, op, constant)) {
emitLoad(op, regT1, regT0);
- addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
+ addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)));
and32(Imm32(constant), regT0);
emitStoreInt32(dst, regT0, (op == dst));
return;
}
emitLoad2(op1, regT1, regT0, op2, regT3, regT2);
- addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
- addSlowCase(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
+ addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)));
+ addSlowCase(branch32(NotEqual, regT3, TrustedImm32(JSValue::Int32Tag)));
and32(regT2, regT0);
emitStoreInt32(dst, regT0, (op1 == dst || op2 == dst));
}
int32_t constant;
if (getOperandConstantImmediateInt(op1, op2, op, constant)) {
emitLoad(op, regT1, regT0);
- addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
+ addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)));
or32(Imm32(constant), regT0);
emitStoreInt32(dst, regT0, (op == dst));
return;
}
emitLoad2(op1, regT1, regT0, op2, regT3, regT2);
- addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
- addSlowCase(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
+ addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)));
+ addSlowCase(branch32(NotEqual, regT3, TrustedImm32(JSValue::Int32Tag)));
or32(regT2, regT0);
emitStoreInt32(dst, regT0, (op1 == dst || op2 == dst));
}
int32_t constant;
if (getOperandConstantImmediateInt(op1, op2, op, constant)) {
emitLoad(op, regT1, regT0);
- addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
+ addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)));
xor32(Imm32(constant), regT0);
emitStoreInt32(dst, regT0, (op == dst));
return;
}
emitLoad2(op1, regT1, regT0, op2, regT3, regT2);
- addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
- addSlowCase(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
+ addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)));
+ addSlowCase(branch32(NotEqual, regT3, TrustedImm32(JSValue::Int32Tag)));
xor32(regT2, regT0);
emitStoreInt32(dst, regT0, (op1 == dst || op2 == dst));
}
unsigned src = currentInstruction[2].u.operand;
emitLoad(src, regT1, regT0);
- addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
+ addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)));
not32(regT0);
emitStoreInt32(dst, regT0, (dst == src));
unsigned srcDst = currentInstruction[2].u.operand;
emitLoad(srcDst, regT1, regT0);
- addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
+ addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)));
if (dst == srcDst) // x = x++ is a noop for ints.
return;
emitStoreInt32(dst, regT0);
- addSlowCase(branchAdd32(Overflow, Imm32(1), regT0));
+ addSlowCase(branchAdd32(Overflow, TrustedImm32(1), regT0));
emitStoreInt32(srcDst, regT0, true);
}
unsigned srcDst = currentInstruction[2].u.operand;
emitLoad(srcDst, regT1, regT0);
- addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
+ addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)));
if (dst == srcDst) // x = x-- is a noop for ints.
return;
emitStoreInt32(dst, regT0);
- addSlowCase(branchSub32(Overflow, Imm32(1), regT0));
+ addSlowCase(branchSub32(Overflow, TrustedImm32(1), regT0));
emitStoreInt32(srcDst, regT0, true);
}
JITStubCall stubCall(this, cti_op_post_dec);
stubCall.addArgument(srcDst);
- stubCall.addArgument(Imm32(srcDst));
+ stubCall.addArgument(TrustedImm32(srcDst));
stubCall.call(dst);
}
emitLoad(srcDst, regT1, regT0);
- addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
- addSlowCase(branchAdd32(Overflow, Imm32(1), regT0));
+ addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)));
+ addSlowCase(branchAdd32(Overflow, TrustedImm32(1), regT0));
emitStoreInt32(srcDst, regT0, true);
}
emitLoad(srcDst, regT1, regT0);
- addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
- addSlowCase(branchSub32(Overflow, Imm32(1), regT0));
+ addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)));
+ addSlowCase(branchSub32(Overflow, TrustedImm32(1), regT0));
emitStoreInt32(srcDst, regT0, true);
}
}
emitLoad2(op1, regT1, regT0, op2, regT3, regT2);
- notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
- notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
+ notInt32Op1.append(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)));
+ notInt32Op2.append(branch32(NotEqual, regT3, TrustedImm32(JSValue::Int32Tag)));
// Int32 case.
addSlowCase(branchAdd32(Overflow, regT2, regT0));
{
// Int32 case.
emitLoad(op, regT1, regT0);
- Jump notInt32 = branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag));
+ Jump notInt32 = branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag));
addSlowCase(branchAdd32(Overflow, Imm32(constant), regT0));
emitStoreInt32(dst, regT0, (op == dst));
notInt32.link(this);
if (!opType.definitelyIsNumber())
- addSlowCase(branch32(Above, regT1, Imm32(JSValue::LowestTag)));
+ addSlowCase(branch32(Above, regT1, TrustedImm32(JSValue::LowestTag)));
move(Imm32(constant), regT2);
convertInt32ToDouble(regT2, fpRegT0);
emitLoadDouble(op, fpRegT1);
}
emitLoad2(op1, regT1, regT0, op2, regT3, regT2);
- notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
- notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
+ notInt32Op1.append(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)));
+ notInt32Op2.append(branch32(NotEqual, regT3, TrustedImm32(JSValue::Int32Tag)));
// Int32 case.
addSlowCase(branchSub32(Overflow, regT2, regT0));
{
// Int32 case.
emitLoad(op, regT1, regT0);
- Jump notInt32 = branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag));
+ Jump notInt32 = branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag));
addSlowCase(branchSub32(Overflow, Imm32(constant), regT0));
emitStoreInt32(dst, regT0, (op == dst));
notInt32.link(this);
if (!opType.definitelyIsNumber())
- addSlowCase(branch32(Above, regT1, Imm32(JSValue::LowestTag)));
+ addSlowCase(branch32(Above, regT1, TrustedImm32(JSValue::LowestTag)));
move(Imm32(constant), regT2);
convertInt32ToDouble(regT2, fpRegT0);
emitLoadDouble(op, fpRegT1);
// Verify Op1 is double.
if (!types.first().definitelyIsNumber())
- addSlowCase(branch32(Above, regT1, Imm32(JSValue::LowestTag)));
+ addSlowCase(branch32(Above, regT1, TrustedImm32(JSValue::LowestTag)));
if (!op2IsInRegisters)
emitLoad(op2, regT3, regT2);
- Jump doubleOp2 = branch32(Below, regT3, Imm32(JSValue::LowestTag));
+ Jump doubleOp2 = branch32(Below, regT3, TrustedImm32(JSValue::LowestTag));
if (!types.second().definitelyIsNumber())
- addSlowCase(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
+ addSlowCase(branch32(NotEqual, regT3, TrustedImm32(JSValue::Int32Tag)));
convertInt32ToDouble(regT2, fpRegT0);
Jump doTheMath = jump();
// Verify op2 is double.
if (!types.second().definitelyIsNumber())
- addSlowCase(branch32(Above, regT3, Imm32(JSValue::LowestTag)));
+ addSlowCase(branch32(Above, regT3, TrustedImm32(JSValue::LowestTag)));
// Do the math.
switch (opcodeID) {
JumpList notInt32Op2;
emitLoad2(op1, regT1, regT0, op2, regT3, regT2);
- notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
- notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
+ notInt32Op1.append(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)));
+ notInt32Op2.append(branch32(NotEqual, regT3, TrustedImm32(JSValue::Int32Tag)));
// Int32 case.
move(regT0, regT3);
linkSlowCase(iter); // zero result check
Jump negZero = branchOr32(Signed, regT2, regT3);
- emitStoreInt32(dst, Imm32(0), (op1 == dst || op2 == dst));
+ emitStoreInt32(dst, TrustedImm32(0), (op1 == dst || op2 == dst));
emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_mul));
emitLoad2(op1, regT1, regT0, op2, regT3, regT2);
- notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
- notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
+ notInt32Op1.append(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)));
+ notInt32Op2.append(branch32(NotEqual, regT3, TrustedImm32(JSValue::Int32Tag)));
convertInt32ToDouble(regT0, fpRegT0);
convertInt32ToDouble(regT2, fpRegT1);
divDouble(fpRegT1, fpRegT0);
-
- JumpList doubleResult;
- branchConvertDoubleToInt32(fpRegT0, regT0, doubleResult, fpRegT1);
-
- // Int32 result.
- emitStoreInt32(dst, regT0, (op1 == dst || op2 == dst));
- end.append(jump());
-
- // Double result.
- doubleResult.link(this);
emitStoreDouble(dst, fpRegT0);
end.append(jump());
/* ------------------------------ BEGIN: OP_MOD ------------------------------ */
-#if CPU(X86) || CPU(X86_64)
+#if CPU(X86) || CPU(X86_64) || CPU(MIPS)
void JIT::emit_op_mod(Instruction* currentInstruction)
{
unsigned op1 = currentInstruction[2].u.operand;
unsigned op2 = currentInstruction[3].u.operand;
+#if CPU(X86) || CPU(X86_64)
+ // Make sure registers are correct for x86 IDIV instructions.
+ ASSERT(regT0 == X86Registers::eax);
+ ASSERT(regT1 == X86Registers::edx);
+ ASSERT(regT2 == X86Registers::ecx);
+ ASSERT(regT3 == X86Registers::ebx);
+#endif
+
if (isOperandConstantImmediateInt(op2) && getConstantOperand(op2).asInt32() != 0) {
- emitLoad(op1, X86Registers::edx, X86Registers::eax);
- move(Imm32(getConstantOperand(op2).asInt32()), X86Registers::ecx);
- addSlowCase(branch32(NotEqual, X86Registers::edx, Imm32(JSValue::Int32Tag)));
+ emitLoad(op1, regT1, regT0);
+ move(Imm32(getConstantOperand(op2).asInt32()), regT2);
+ addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)));
if (getConstantOperand(op2).asInt32() == -1)
- addSlowCase(branch32(Equal, X86Registers::eax, Imm32(0x80000000))); // -2147483648 / -1 => EXC_ARITHMETIC
+ addSlowCase(branch32(Equal, regT0, TrustedImm32(0x80000000))); // -2147483648 / -1 => EXC_ARITHMETIC
} else {
- emitLoad2(op1, X86Registers::edx, X86Registers::eax, op2, X86Registers::ebx, X86Registers::ecx);
- addSlowCase(branch32(NotEqual, X86Registers::edx, Imm32(JSValue::Int32Tag)));
- addSlowCase(branch32(NotEqual, X86Registers::ebx, Imm32(JSValue::Int32Tag)));
+ emitLoad2(op1, regT1, regT0, op2, regT3, regT2);
+ addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)));
+ addSlowCase(branch32(NotEqual, regT3, TrustedImm32(JSValue::Int32Tag)));
- addSlowCase(branch32(Equal, X86Registers::eax, Imm32(0x80000000))); // -2147483648 / -1 => EXC_ARITHMETIC
- addSlowCase(branch32(Equal, X86Registers::ecx, Imm32(0))); // divide by 0
+ addSlowCase(branch32(Equal, regT0, TrustedImm32(0x80000000))); // -2147483648 / -1 => EXC_ARITHMETIC
+ addSlowCase(branch32(Equal, regT2, TrustedImm32(0))); // divide by 0
}
- move(X86Registers::eax, X86Registers::ebx); // Save dividend payload, in case of 0.
+ move(regT0, regT3); // Save dividend payload, in case of 0.
+#if CPU(X86) || CPU(X86_64)
m_assembler.cdq();
- m_assembler.idivl_r(X86Registers::ecx);
+ m_assembler.idivl_r(regT2);
+#elif CPU(MIPS)
+ m_assembler.div(regT0, regT2);
+ m_assembler.mfhi(regT1);
+#endif
// If the remainder is zero and the dividend is negative, the result is -0.
- Jump storeResult1 = branchTest32(NonZero, X86Registers::edx);
- Jump storeResult2 = branchTest32(Zero, X86Registers::ebx, Imm32(0x80000000)); // not negative
- emitStore(dst, jsNumber(m_globalData, -0.0));
+ Jump storeResult1 = branchTest32(NonZero, regT1);
+ Jump storeResult2 = branchTest32(Zero, regT3, TrustedImm32(0x80000000)); // not negative
+ emitStore(dst, jsNumber(-0.0));
Jump end = jump();
storeResult1.link(this);
storeResult2.link(this);
- emitStoreInt32(dst, X86Registers::edx, (op1 == dst || op2 == dst));
+ emitStoreInt32(dst, regT1, (op1 == dst || op2 == dst));
end.link(this);
}
stubCall.call(dst);
}
-#else // CPU(X86) || CPU(X86_64)
+#else // CPU(X86) || CPU(X86_64) || CPU(MIPS)
void JIT::emit_op_mod(Instruction* currentInstruction)
{
unsigned op1 = currentInstruction[2].u.operand;
unsigned op2 = currentInstruction[3].u.operand;
-#if ENABLE(JIT_OPTIMIZE_MOD)
+#if ENABLE(JIT_USE_SOFT_MODULO)
emitLoad2(op1, regT1, regT0, op2, regT3, regT2);
- addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
- addSlowCase(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
+ addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)));
+ addSlowCase(branch32(NotEqual, regT3, TrustedImm32(JSValue::Int32Tag)));
- addSlowCase(branch32(Equal, regT2, Imm32(0)));
+ addSlowCase(branch32(Equal, regT2, TrustedImm32(0)));
- emitNakedCall(m_globalData->jitStubs.ctiSoftModulo());
+ emitNakedCall(m_globalData->jitStubs->ctiSoftModulo());
emitStoreInt32(dst, regT0, (op1 == dst || op2 == dst));
#else
void JIT::emitSlow_op_mod(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
{
-#if ENABLE(JIT_OPTIMIZE_MOD)
+ UNUSED_PARAM(currentInstruction);
+ UNUSED_PARAM(iter);
+#if ENABLE(JIT_USE_SOFT_MODULO)
unsigned result = currentInstruction[1].u.operand;
unsigned op1 = currentInstruction[2].u.operand;
unsigned op2 = currentInstruction[3].u.operand;
/* ------------------------------ END: OP_MOD ------------------------------ */
-#endif // USE(JSVALUE32_64)
-
-}
+} // namespace JSC
+#endif // USE(JSVALUE32_64)
#endif // ENABLE(JIT)
*/
#include "config.h"
-#include "JIT.h"
#if ENABLE(JIT)
+#if USE(JSVALUE64)
+#include "JIT.h"
#include "CodeBlock.h"
#include "JITInlineMethods.h"
namespace JSC {
-#if USE(JSVALUE32_64)
-
void JIT::compileOpCallInitializeCallFrame()
{
// regT0 holds callee, regT1 holds argCount
- store32(regT1, Address(callFrameRegister, RegisterFile::ArgumentCount * static_cast<int>(sizeof(Register))));
-
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_data) + OBJECT_OFFSETOF(ScopeChain, m_node)), regT1); // scopeChain
-
- emitStore(static_cast<unsigned>(RegisterFile::OptionalCalleeArguments), JSValue());
- storePtr(regT0, Address(callFrameRegister, RegisterFile::Callee * static_cast<int>(sizeof(Register)))); // callee
- storePtr(regT1, Address(callFrameRegister, RegisterFile::ScopeChain * static_cast<int>(sizeof(Register)))); // scopeChain
-}
-
-void JIT::compileOpCallSetupArgs(Instruction* instruction)
-{
- int argCount = instruction[3].u.operand;
- int registerOffset = instruction[4].u.operand;
-
- emitPutJITStubArg(regT1, regT0, 0);
- emitPutJITStubArgConstant(registerOffset, 1);
- emitPutJITStubArgConstant(argCount, 2);
-}
-
-void JIT::compileOpConstructSetupArgs(Instruction* instruction)
-{
- int argCount = instruction[3].u.operand;
- int registerOffset = instruction[4].u.operand;
- int proto = instruction[5].u.operand;
- int thisRegister = instruction[6].u.operand;
-
- emitPutJITStubArg(regT1, regT0, 0);
- emitPutJITStubArgConstant(registerOffset, 1);
- emitPutJITStubArgConstant(argCount, 2);
- emitPutJITStubArgFromVirtualRegister(proto, 3, regT2, regT3);
- emitPutJITStubArgConstant(thisRegister, 4);
-}
-
-void JIT::compileOpCallVarargsSetupArgs(Instruction*)
-{
- emitPutJITStubArg(regT1, regT0, 0);
- emitPutJITStubArg(regT3, 1); // registerOffset
- emitPutJITStubArg(regT2, 2); // argCount
-}
-
-void JIT::compileOpCallVarargs(Instruction* instruction)
-{
- int dst = instruction[1].u.operand;
- int callee = instruction[2].u.operand;
- int argCountRegister = instruction[3].u.operand;
- int registerOffset = instruction[4].u.operand;
-
- emitLoad(callee, regT1, regT0);
- emitLoadPayload(argCountRegister, regT2); // argCount
- addPtr(Imm32(registerOffset), regT2, regT3); // registerOffset
-
- compileOpCallVarargsSetupArgs(instruction);
-
- emitJumpSlowCaseIfNotJSCell(callee, regT1);
- addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsFunctionVPtr)));
-
- // Speculatively roll the callframe, assuming argCount will match the arity.
- mul32(Imm32(sizeof(Register)), regT3, regT3);
- addPtr(callFrameRegister, regT3);
- storePtr(callFrameRegister, Address(regT3, RegisterFile::CallerFrame * static_cast<int>(sizeof(Register))));
- move(regT3, callFrameRegister);
-
- move(regT2, regT1); // argCount
-
- emitNakedCall(m_globalData->jitStubs->ctiVirtualCall());
-
- emitStore(dst, regT1, regT0);
-
- sampleCodeBlock(m_codeBlock);
-}
-
-void JIT::compileOpCallVarargsSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter)
-{
- int dst = instruction[1].u.operand;
- int callee = instruction[2].u.operand;
-
- linkSlowCaseIfNotJSCell(iter, callee);
- linkSlowCase(iter);
-
- JITStubCall stubCall(this, cti_op_call_NotJSFunction);
- stubCall.call(dst); // In the interpreter, the callee puts the return value in dst.
-
- map(m_bytecodeIndex + OPCODE_LENGTH(op_call_varargs), dst, regT1, regT0);
- sampleCodeBlock(m_codeBlock);
-}
-
-void JIT::emit_op_ret(Instruction* currentInstruction)
-{
- unsigned dst = currentInstruction[1].u.operand;
-
- // We could JIT generate the deref, only calling out to C when the refcount hits zero.
- if (m_codeBlock->needsFullScopeChain())
- JITStubCall(this, cti_op_ret_scopeChain).call();
-
- emitLoad(dst, regT1, regT0);
- emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT2);
- emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister);
-
- restoreReturnAddressBeforeReturn(regT2);
- ret();
-}
-
-void JIT::emit_op_construct_verify(Instruction* currentInstruction)
-{
- unsigned dst = currentInstruction[1].u.operand;
-
- emitLoad(dst, regT1, regT0);
- addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::CellTag)));
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2);
- addSlowCase(branch8(NotEqual, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo) + OBJECT_OFFSETOF(TypeInfo, m_type)), Imm32(ObjectType)));
-}
-
-void JIT::emitSlow_op_construct_verify(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
-{
- unsigned dst = currentInstruction[1].u.operand;
- unsigned src = currentInstruction[2].u.operand;
-
- linkSlowCase(iter);
- linkSlowCase(iter);
- emitLoad(src, regT1, regT0);
- emitStore(dst, regT1, regT0);
-}
-
-void JIT::emitSlow_op_call(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
-{
- compileOpCallSlowCase(currentInstruction, iter, m_callLinkInfoIndex++, op_call);
-}
-
-void JIT::emitSlow_op_call_eval(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
-{
- compileOpCallSlowCase(currentInstruction, iter, m_callLinkInfoIndex++, op_call_eval);
-}
-
-void JIT::emitSlow_op_call_varargs(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
-{
- compileOpCallVarargsSlowCase(currentInstruction, iter);
-}
-
-void JIT::emitSlow_op_construct(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
-{
- compileOpCallSlowCase(currentInstruction, iter, m_callLinkInfoIndex++, op_construct);
-}
-
-void JIT::emit_op_call(Instruction* currentInstruction)
-{
- compileOpCall(op_call, currentInstruction, m_callLinkInfoIndex++);
-}
-
-void JIT::emit_op_call_eval(Instruction* currentInstruction)
-{
- compileOpCall(op_call_eval, currentInstruction, m_callLinkInfoIndex++);
-}
-
-void JIT::emit_op_load_varargs(Instruction* currentInstruction)
-{
- int argCountDst = currentInstruction[1].u.operand;
- int argsOffset = currentInstruction[2].u.operand;
-
- JITStubCall stubCall(this, cti_op_load_varargs);
- stubCall.addArgument(Imm32(argsOffset));
- stubCall.call();
- // Stores a naked int32 in the register file.
- store32(returnValueRegister, Address(callFrameRegister, argCountDst * sizeof(Register)));
-}
-
-void JIT::emit_op_call_varargs(Instruction* currentInstruction)
-{
- compileOpCallVarargs(currentInstruction);
-}
-
-void JIT::emit_op_construct(Instruction* currentInstruction)
-{
- compileOpCall(op_construct, currentInstruction, m_callLinkInfoIndex++);
-}
-
-#if !ENABLE(JIT_OPTIMIZE_CALL)
-
-/* ------------------------------ BEGIN: !ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */
-
-void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned)
-{
- int dst = instruction[1].u.operand;
- int callee = instruction[2].u.operand;
- int argCount = instruction[3].u.operand;
- int registerOffset = instruction[4].u.operand;
-
- Jump wasEval;
- if (opcodeID == op_call_eval) {
- JITStubCall stubCall(this, cti_op_call_eval);
- stubCall.addArgument(callee);
- stubCall.addArgument(JIT::Imm32(registerOffset));
- stubCall.addArgument(JIT::Imm32(argCount));
- stubCall.call();
- wasEval = branch32(NotEqual, regT1, Imm32(JSValue::EmptyValueTag));
- }
-
- emitLoad(callee, regT1, regT0);
-
- if (opcodeID == op_call)
- compileOpCallSetupArgs(instruction);
- else if (opcodeID == op_construct)
- compileOpConstructSetupArgs(instruction);
-
- emitJumpSlowCaseIfNotJSCell(callee, regT1);
- addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsFunctionVPtr)));
-
- // First, in the case of a construct, allocate the new object.
- if (opcodeID == op_construct) {
- JITStubCall(this, cti_op_construct_JSConstruct).call(registerOffset - RegisterFile::CallFrameHeaderSize - argCount);
- emitLoad(callee, regT1, regT0);
- }
-
- // Speculatively roll the callframe, assuming argCount will match the arity.
- storePtr(callFrameRegister, Address(callFrameRegister, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register))));
- addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), callFrameRegister);
- move(Imm32(argCount), regT1);
-
- emitNakedCall(m_globalData->jitStubs.ctiVirtualCall());
-
- if (opcodeID == op_call_eval)
- wasEval.link(this);
-
- emitStore(dst, regT1, regT0);
-
- sampleCodeBlock(m_codeBlock);
-}
-
-void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned, OpcodeID opcodeID)
-{
- int dst = instruction[1].u.operand;
- int callee = instruction[2].u.operand;
-
- linkSlowCaseIfNotJSCell(iter, callee);
- linkSlowCase(iter);
-
- JITStubCall stubCall(this, opcodeID == op_construct ? cti_op_construct_NotJSConstruct : cti_op_call_NotJSFunction);
- stubCall.call(dst); // In the interpreter, the callee puts the return value in dst.
-
- sampleCodeBlock(m_codeBlock);
-}
-
-#else // !ENABLE(JIT_OPTIMIZE_CALL)
-
-/* ------------------------------ BEGIN: ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */
-
-void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned callLinkInfoIndex)
-{
- int dst = instruction[1].u.operand;
- int callee = instruction[2].u.operand;
- int argCount = instruction[3].u.operand;
- int registerOffset = instruction[4].u.operand;
-
- Jump wasEval;
- if (opcodeID == op_call_eval) {
- JITStubCall stubCall(this, cti_op_call_eval);
- stubCall.addArgument(callee);
- stubCall.addArgument(JIT::Imm32(registerOffset));
- stubCall.addArgument(JIT::Imm32(argCount));
- stubCall.call();
- wasEval = branch32(NotEqual, regT1, Imm32(JSValue::EmptyValueTag));
- }
-
- emitLoad(callee, regT1, regT0);
-
- DataLabelPtr addressOfLinkedFunctionCheck;
-
- BEGIN_UNINTERRUPTED_SEQUENCE(sequenceOpCall);
-
- Jump jumpToSlow = branchPtrWithPatch(NotEqual, regT0, addressOfLinkedFunctionCheck, ImmPtr(0));
-
- END_UNINTERRUPTED_SEQUENCE(sequenceOpCall);
-
- addSlowCase(jumpToSlow);
- ASSERT(differenceBetween(addressOfLinkedFunctionCheck, jumpToSlow) == patchOffsetOpCallCompareToJump);
- m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathBegin = addressOfLinkedFunctionCheck;
-
- addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::CellTag)));
-
- // The following is the fast case, only used whan a callee can be linked.
-
- // In the case of OpConstruct, call out to a cti_ function to create the new object.
- if (opcodeID == op_construct) {
- int proto = instruction[5].u.operand;
- int thisRegister = instruction[6].u.operand;
-
- JITStubCall stubCall(this, cti_op_construct_JSConstruct);
- stubCall.addArgument(regT1, regT0);
- stubCall.addArgument(Imm32(0)); // FIXME: Remove this unused JITStub argument.
- stubCall.addArgument(Imm32(0)); // FIXME: Remove this unused JITStub argument.
- stubCall.addArgument(proto);
- stubCall.call(thisRegister);
-
- emitLoad(callee, regT1, regT0);
- }
-
- // Fast version of stack frame initialization, directly relative to edi.
- // Note that this omits to set up RegisterFile::CodeBlock, which is set in the callee
- emitStore(registerOffset + RegisterFile::OptionalCalleeArguments, JSValue());
- emitStore(registerOffset + RegisterFile::Callee, regT1, regT0);
-
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_data) + OBJECT_OFFSETOF(ScopeChain, m_node)), regT1); // newScopeChain
- store32(Imm32(argCount), Address(callFrameRegister, (registerOffset + RegisterFile::ArgumentCount) * static_cast<int>(sizeof(Register))));
- storePtr(callFrameRegister, Address(callFrameRegister, (registerOffset + RegisterFile::CallerFrame) * static_cast<int>(sizeof(Register))));
- storePtr(regT1, Address(callFrameRegister, (registerOffset + RegisterFile::ScopeChain) * static_cast<int>(sizeof(Register))));
- addPtr(Imm32(registerOffset * sizeof(Register)), callFrameRegister);
-
- // Call to the callee
- m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedCall();
-
- if (opcodeID == op_call_eval)
- wasEval.link(this);
-
- // Put the return value in dst. In the interpreter, op_ret does this.
- emitStore(dst, regT1, regT0);
- map(m_bytecodeIndex + opcodeLengths[opcodeID], dst, regT1, regT0);
-
- sampleCodeBlock(m_codeBlock);
+ loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_scopeChain)), regT3); // scopeChain
+ emitPutIntToCallFrameHeader(regT1, RegisterFile::ArgumentCount);
+ emitPutCellToCallFrameHeader(regT0, RegisterFile::Callee);
+ emitPutCellToCallFrameHeader(regT3, RegisterFile::ScopeChain);
}
-void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned callLinkInfoIndex, OpcodeID opcodeID)
+void JIT::emit_op_call_put_result(Instruction* instruction)
{
int dst = instruction[1].u.operand;
- int callee = instruction[2].u.operand;
- int argCount = instruction[3].u.operand;
- int registerOffset = instruction[4].u.operand;
-
- linkSlowCase(iter);
- linkSlowCase(iter);
-
- // The arguments have been set up on the hot path for op_call_eval
- if (opcodeID == op_call)
- compileOpCallSetupArgs(instruction);
- else if (opcodeID == op_construct)
- compileOpConstructSetupArgs(instruction);
-
- // Fast check for JS function.
- Jump callLinkFailNotObject = branch32(NotEqual, regT1, Imm32(JSValue::CellTag));
- Jump callLinkFailNotJSFunction = branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsFunctionVPtr));
-
- // First, in the case of a construct, allocate the new object.
- if (opcodeID == op_construct) {
- JITStubCall(this, cti_op_construct_JSConstruct).call(registerOffset - RegisterFile::CallFrameHeaderSize - argCount);
- emitLoad(callee, regT1, regT0);
- }
-
- // Speculatively roll the callframe, assuming argCount will match the arity.
- storePtr(callFrameRegister, Address(callFrameRegister, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register))));
- addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), callFrameRegister);
- move(Imm32(argCount), regT1);
-
- m_callStructureStubCompilationInfo[callLinkInfoIndex].callReturnLocation = emitNakedCall(m_globalData->jitStubs->ctiVirtualCallLink());
-
- // Put the return value in dst.
- emitStore(dst, regT1, regT0);;
- sampleCodeBlock(m_codeBlock);
-
- // If not, we need an extra case in the if below!
- ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_call_eval));
-
- // Done! - return back to the hot path.
- if (opcodeID == op_construct)
- emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_construct));
- else
- emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_call));
-
- // This handles host functions
- callLinkFailNotObject.link(this);
- callLinkFailNotJSFunction.link(this);
- JITStubCall(this, opcodeID == op_construct ? cti_op_construct_NotJSConstruct : cti_op_call_NotJSFunction).call();
-
- emitStore(dst, regT1, regT0);;
- sampleCodeBlock(m_codeBlock);
-}
-
-/* ------------------------------ END: !ENABLE / ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */
-
-#endif // !ENABLE(JIT_OPTIMIZE_CALL)
-
-#else // USE(JSVALUE32_64)
-
-void JIT::compileOpCallInitializeCallFrame()
-{
- store32(regT1, Address(callFrameRegister, RegisterFile::ArgumentCount * static_cast<int>(sizeof(Register))));
-
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_data) + OBJECT_OFFSETOF(ScopeChain, m_node)), regT1); // newScopeChain
-
- storePtr(ImmPtr(JSValue::encode(JSValue())), Address(callFrameRegister, RegisterFile::OptionalCalleeArguments * static_cast<int>(sizeof(Register))));
- storePtr(regT0, Address(callFrameRegister, RegisterFile::Callee * static_cast<int>(sizeof(Register))));
- storePtr(regT1, Address(callFrameRegister, RegisterFile::ScopeChain * static_cast<int>(sizeof(Register))));
-}
-
-void JIT::compileOpCallSetupArgs(Instruction* instruction)
-{
- int argCount = instruction[3].u.operand;
- int registerOffset = instruction[4].u.operand;
-
- // ecx holds func
- emitPutJITStubArg(regT0, 0);
- emitPutJITStubArgConstant(argCount, 2);
- emitPutJITStubArgConstant(registerOffset, 1);
-}
-
-void JIT::compileOpCallVarargsSetupArgs(Instruction* instruction)
-{
- int registerOffset = instruction[4].u.operand;
-
- // ecx holds func
- emitPutJITStubArg(regT0, 0);
- emitPutJITStubArg(regT1, 2);
- addPtr(Imm32(registerOffset), regT1, regT2);
- emitPutJITStubArg(regT2, 1);
-}
-
-void JIT::compileOpConstructSetupArgs(Instruction* instruction)
-{
- int argCount = instruction[3].u.operand;
- int registerOffset = instruction[4].u.operand;
- int proto = instruction[5].u.operand;
- int thisRegister = instruction[6].u.operand;
-
- // ecx holds func
- emitPutJITStubArg(regT0, 0);
- emitPutJITStubArgConstant(registerOffset, 1);
- emitPutJITStubArgConstant(argCount, 2);
- emitPutJITStubArgFromVirtualRegister(proto, 3, regT2);
- emitPutJITStubArgConstant(thisRegister, 4);
+ emitPutVirtualRegister(dst);
}
void JIT::compileOpCallVarargs(Instruction* instruction)
{
- int dst = instruction[1].u.operand;
- int callee = instruction[2].u.operand;
- int argCountRegister = instruction[3].u.operand;
+ int callee = instruction[1].u.operand;
+ int argCountRegister = instruction[2].u.operand;
+ int registerOffset = instruction[3].u.operand;
emitGetVirtualRegister(argCountRegister, regT1);
+ emitFastArithImmToInt(regT1);
emitGetVirtualRegister(callee, regT0);
- compileOpCallVarargsSetupArgs(instruction);
+ addPtr(Imm32(registerOffset), regT1, regT2);
// Check for JSFunctions.
emitJumpSlowCaseIfNotJSCell(regT0);
- addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsFunctionVPtr)));
+ addSlowCase(branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsFunctionVPtr)));
// Speculatively roll the callframe, assuming argCount will match the arity.
- mul32(Imm32(sizeof(Register)), regT2, regT2);
+ mul32(TrustedImm32(sizeof(Register)), regT2, regT2);
intptr_t offset = (intptr_t)sizeof(Register) * (intptr_t)RegisterFile::CallerFrame;
addPtr(Imm32((int32_t)offset), regT2, regT3);
addPtr(callFrameRegister, regT3);
addPtr(regT2, callFrameRegister);
emitNakedCall(m_globalData->jitStubs->ctiVirtualCall());
- // Put the return value in dst. In the interpreter, op_ret does this.
- emitPutVirtualRegister(dst);
-
sampleCodeBlock(m_codeBlock);
}
-void JIT::compileOpCallVarargsSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter)
+void JIT::compileOpCallVarargsSlowCase(Instruction*, Vector<SlowCaseEntry>::iterator& iter)
{
- int dst = instruction[1].u.operand;
-
linkSlowCase(iter);
linkSlowCase(iter);
+
JITStubCall stubCall(this, cti_op_call_NotJSFunction);
- stubCall.call(dst); // In the interpreter, the callee puts the return value in dst.
+ stubCall.addArgument(regT0);
+ stubCall.addArgument(regT2);
+ stubCall.addArgument(regT1);
+ stubCall.call();
sampleCodeBlock(m_codeBlock);
}
void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned)
{
- int dst = instruction[1].u.operand;
- int callee = instruction[2].u.operand;
- int argCount = instruction[3].u.operand;
- int registerOffset = instruction[4].u.operand;
+ int callee = instruction[1].u.operand;
+ int argCount = instruction[2].u.operand;
+ int registerOffset = instruction[3].u.operand;
// Handle eval
Jump wasEval;
stubCall.addArgument(JIT::Imm32(registerOffset));
stubCall.addArgument(JIT::Imm32(argCount));
stubCall.call();
- wasEval = branchPtr(NotEqual, regT0, ImmPtr(JSValue::encode(JSValue())));
+ wasEval = branchPtr(NotEqual, regT0, TrustedImmPtr(JSValue::encode(JSValue())));
}
emitGetVirtualRegister(callee, regT0);
- // The arguments have been set up on the hot path for op_call_eval
- if (opcodeID == op_call)
- compileOpCallSetupArgs(instruction);
- else if (opcodeID == op_construct)
- compileOpConstructSetupArgs(instruction);
// Check for JSFunctions.
emitJumpSlowCaseIfNotJSCell(regT0);
- addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsFunctionVPtr)));
-
- // First, in the case of a construct, allocate the new object.
- if (opcodeID == op_construct) {
- JITStubCall(this, cti_op_construct_JSConstruct).call(registerOffset - RegisterFile::CallFrameHeaderSize - argCount);
- emitGetVirtualRegister(callee, regT0);
- }
+ addSlowCase(branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsFunctionVPtr)));
// Speculatively roll the callframe, assuming argCount will match the arity.
storePtr(callFrameRegister, Address(callFrameRegister, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register))));
addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), callFrameRegister);
move(Imm32(argCount), regT1);
- emitNakedCall(m_globalData->jitStubs.ctiVirtualCall());
+ emitNakedCall(opcodeID == op_construct ? m_globalData->jitStubs->ctiVirtualConstruct() : m_globalData->jitStubs->ctiVirtualCall());
if (opcodeID == op_call_eval)
wasEval.link(this);
- // Put the return value in dst. In the interpreter, op_ret does this.
- emitPutVirtualRegister(dst);
-
sampleCodeBlock(m_codeBlock);
}
void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned, OpcodeID opcodeID)
{
- int dst = instruction[1].u.operand;
+ int argCount = instruction[2].u.operand;
+ int registerOffset = instruction[3].u.operand;
linkSlowCase(iter);
linkSlowCase(iter);
+
JITStubCall stubCall(this, opcodeID == op_construct ? cti_op_construct_NotJSConstruct : cti_op_call_NotJSFunction);
- stubCall.call(dst); // In the interpreter, the callee puts the return value in dst.
+ stubCall.addArgument(regT0);
+ stubCall.addArgument(JIT::Imm32(registerOffset));
+ stubCall.addArgument(JIT::Imm32(argCount));
+ stubCall.call();
sampleCodeBlock(m_codeBlock);
}
void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned callLinkInfoIndex)
{
- int dst = instruction[1].u.operand;
- int callee = instruction[2].u.operand;
- int argCount = instruction[3].u.operand;
- int registerOffset = instruction[4].u.operand;
+ int callee = instruction[1].u.operand;
+ int argCount = instruction[2].u.operand;
+ int registerOffset = instruction[3].u.operand;
// Handle eval
Jump wasEval;
stubCall.addArgument(JIT::Imm32(registerOffset));
stubCall.addArgument(JIT::Imm32(argCount));
stubCall.call();
- wasEval = branchPtr(NotEqual, regT0, ImmPtr(JSValue::encode(JSValue())));
+ wasEval = branchPtr(NotEqual, regT0, TrustedImmPtr(JSValue::encode(JSValue())));
}
// This plants a check for a cached JSFunction value, so we can plant a fast link to the callee.
BEGIN_UNINTERRUPTED_SEQUENCE(sequenceOpCall);
- Jump jumpToSlow = branchPtrWithPatch(NotEqual, regT0, addressOfLinkedFunctionCheck, ImmPtr(JSValue::encode(JSValue())));
+ Jump jumpToSlow = branchPtrWithPatch(NotEqual, regT0, addressOfLinkedFunctionCheck, TrustedImmPtr(JSValue::encode(JSValue())));
END_UNINTERRUPTED_SEQUENCE(sequenceOpCall);
addSlowCase(jumpToSlow);
ASSERT_JIT_OFFSET(differenceBetween(addressOfLinkedFunctionCheck, jumpToSlow), patchOffsetOpCallCompareToJump);
m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathBegin = addressOfLinkedFunctionCheck;
+ m_callStructureStubCompilationInfo[callLinkInfoIndex].isCall = opcodeID != op_construct;
// The following is the fast case, only used whan a callee can be linked.
- // In the case of OpConstruct, call out to a cti_ function to create the new object.
- if (opcodeID == op_construct) {
- int proto = instruction[5].u.operand;
- int thisRegister = instruction[6].u.operand;
-
- emitPutJITStubArg(regT0, 0);
- emitPutJITStubArgFromVirtualRegister(proto, 3, regT2);
- JITStubCall stubCall(this, cti_op_construct_JSConstruct);
- stubCall.call(thisRegister);
- emitGetVirtualRegister(callee, regT0);
- }
-
// Fast version of stack frame initialization, directly relative to edi.
// Note that this omits to set up RegisterFile::CodeBlock, which is set in the callee
- storePtr(ImmPtr(JSValue::encode(JSValue())), Address(callFrameRegister, (registerOffset + RegisterFile::OptionalCalleeArguments) * static_cast<int>(sizeof(Register))));
- storePtr(regT0, Address(callFrameRegister, (registerOffset + RegisterFile::Callee) * static_cast<int>(sizeof(Register))));
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_data) + OBJECT_OFFSETOF(ScopeChain, m_node)), regT1); // newScopeChain
- store32(Imm32(argCount), Address(callFrameRegister, (registerOffset + RegisterFile::ArgumentCount) * static_cast<int>(sizeof(Register))));
+
+ loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_scopeChain)), regT1); // newScopeChain
+
+ store32(TrustedImm32(Int32Tag), intTagFor(registerOffset + RegisterFile::ArgumentCount));
+ store32(Imm32(argCount), intPayloadFor(registerOffset + RegisterFile::ArgumentCount));
storePtr(callFrameRegister, Address(callFrameRegister, (registerOffset + RegisterFile::CallerFrame) * static_cast<int>(sizeof(Register))));
+ storePtr(regT0, Address(callFrameRegister, (registerOffset + RegisterFile::Callee) * static_cast<int>(sizeof(Register))));
storePtr(regT1, Address(callFrameRegister, (registerOffset + RegisterFile::ScopeChain) * static_cast<int>(sizeof(Register))));
addPtr(Imm32(registerOffset * sizeof(Register)), callFrameRegister);
if (opcodeID == op_call_eval)
wasEval.link(this);
- // Put the return value in dst. In the interpreter, op_ret does this.
- emitPutVirtualRegister(dst);
-
sampleCodeBlock(m_codeBlock);
}
void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned callLinkInfoIndex, OpcodeID opcodeID)
{
- int dst = instruction[1].u.operand;
- int callee = instruction[2].u.operand;
- int argCount = instruction[3].u.operand;
- int registerOffset = instruction[4].u.operand;
+ int argCount = instruction[2].u.operand;
+ int registerOffset = instruction[3].u.operand;
linkSlowCase(iter);
- // The arguments have been set up on the hot path for op_call_eval
- if (opcodeID == op_call)
- compileOpCallSetupArgs(instruction);
- else if (opcodeID == op_construct)
- compileOpConstructSetupArgs(instruction);
-
// Fast check for JS function.
Jump callLinkFailNotObject = emitJumpIfNotJSCell(regT0);
- Jump callLinkFailNotJSFunction = branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsFunctionVPtr));
-
- // First, in the case of a construct, allocate the new object.
- if (opcodeID == op_construct) {
- JITStubCall(this, cti_op_construct_JSConstruct).call(registerOffset - RegisterFile::CallFrameHeaderSize - argCount);
- emitGetVirtualRegister(callee, regT0);
- }
+ Jump callLinkFailNotJSFunction = branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsFunctionVPtr));
// Speculatively roll the callframe, assuming argCount will match the arity.
storePtr(callFrameRegister, Address(callFrameRegister, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register))));
addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), callFrameRegister);
move(Imm32(argCount), regT1);
- move(regT0, regT2);
-
- m_callStructureStubCompilationInfo[callLinkInfoIndex].callReturnLocation = emitNakedCall(m_globalData->jitStubs->ctiVirtualCallLink());
-
- // Put the return value in dst.
- emitPutVirtualRegister(dst);
- sampleCodeBlock(m_codeBlock);
-
- // If not, we need an extra case in the if below!
- ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_call_eval));
+ m_callStructureStubCompilationInfo[callLinkInfoIndex].callReturnLocation = emitNakedCall(opcodeID == op_construct ? m_globalData->jitStubs->ctiVirtualConstructLink() : m_globalData->jitStubs->ctiVirtualCallLink());
// Done! - return back to the hot path.
- if (opcodeID == op_construct)
- emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_construct));
- else
- emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_call));
+ ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_call_eval));
+ ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_construct));
+ emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_call));
// This handles host functions
callLinkFailNotObject.link(this);
callLinkFailNotJSFunction.link(this);
- JITStubCall(this, opcodeID == op_construct ? cti_op_construct_NotJSConstruct : cti_op_call_NotJSFunction).call();
- emitPutVirtualRegister(dst);
+ JITStubCall stubCall(this, opcodeID == op_construct ? cti_op_construct_NotJSConstruct : cti_op_call_NotJSFunction);
+ stubCall.addArgument(regT0);
+ stubCall.addArgument(JIT::Imm32(registerOffset));
+ stubCall.addArgument(JIT::Imm32(argCount));
+ stubCall.call();
+
sampleCodeBlock(m_codeBlock);
}
#endif // !ENABLE(JIT_OPTIMIZE_CALL)
-#endif // USE(JSVALUE32_64)
-
} // namespace JSC
+#endif // USE(JSVALUE64)
#endif // ENABLE(JIT)
--- /dev/null
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(JIT)
+#if USE(JSVALUE32_64)
+#include "JIT.h"
+
+#include "CodeBlock.h"
+#include "Interpreter.h"
+#include "JITInlineMethods.h"
+#include "JITStubCall.h"
+#include "JSArray.h"
+#include "JSFunction.h"
+#include "ResultType.h"
+#include "SamplingTool.h"
+
+#ifndef NDEBUG
+#include <stdio.h>
+#endif
+
+using namespace std;
+
+namespace JSC {
+
+void JIT::compileOpCallInitializeCallFrame()
+{
+ // regT0 holds callee, regT1 holds argCount
+ loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_scopeChain)), regT3); // scopeChain
+ emitPutIntToCallFrameHeader(regT1, RegisterFile::ArgumentCount);
+ emitPutCellToCallFrameHeader(regT0, RegisterFile::Callee);
+ emitPutCellToCallFrameHeader(regT3, RegisterFile::ScopeChain);
+}
+
+void JIT::emit_op_call_put_result(Instruction* instruction)
+{
+ int dst = instruction[1].u.operand;
+ emitStore(dst, regT1, regT0);
+}
+
+void JIT::compileOpCallVarargs(Instruction* instruction)
+{
+ int callee = instruction[1].u.operand;
+ int argCountRegister = instruction[2].u.operand;
+ int registerOffset = instruction[3].u.operand;
+
+ emitLoad(callee, regT1, regT0);
+ emitLoadPayload(argCountRegister, regT2); // argCount
+ addPtr(Imm32(registerOffset), regT2, regT3); // registerOffset
+
+ emitJumpSlowCaseIfNotJSCell(callee, regT1);
+ addSlowCase(branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsFunctionVPtr)));
+
+ // Speculatively roll the callframe, assuming argCount will match the arity.
+ mul32(TrustedImm32(sizeof(Register)), regT3, regT3);
+ addPtr(callFrameRegister, regT3);
+ store32(TrustedImm32(JSValue::CellTag), tagFor(RegisterFile::CallerFrame, regT3));
+ storePtr(callFrameRegister, payloadFor(RegisterFile::CallerFrame, regT3));
+ move(regT3, callFrameRegister);
+
+ move(regT2, regT1); // argCount
+
+ emitNakedCall(m_globalData->jitStubs->ctiVirtualCall());
+
+ sampleCodeBlock(m_codeBlock);
+}
+
+void JIT::compileOpCallVarargsSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+ int callee = instruction[1].u.operand;
+
+ linkSlowCaseIfNotJSCell(iter, callee);
+ linkSlowCase(iter);
+
+ JITStubCall stubCall(this, cti_op_call_NotJSFunction);
+ stubCall.addArgument(regT1, regT0);
+ stubCall.addArgument(regT3);
+ stubCall.addArgument(regT2);
+ stubCall.call();
+
+ sampleCodeBlock(m_codeBlock);
+}
+
+void JIT::emit_op_ret(Instruction* currentInstruction)
+{
+ unsigned dst = currentInstruction[1].u.operand;
+
+ emitLoad(dst, regT1, regT0);
+ emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT2);
+ emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister);
+
+ restoreReturnAddressBeforeReturn(regT2);
+ ret();
+}
+
+void JIT::emit_op_ret_object_or_this(Instruction* currentInstruction)
+{
+ unsigned result = currentInstruction[1].u.operand;
+ unsigned thisReg = currentInstruction[2].u.operand;
+
+ emitLoad(result, regT1, regT0);
+ Jump notJSCell = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag));
+ loadPtr(Address(regT0, JSCell::structureOffset()), regT2);
+ Jump notObject = branch8(NotEqual, Address(regT2, Structure::typeInfoTypeOffset()), TrustedImm32(ObjectType));
+
+ emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT2);
+ emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister);
+
+ restoreReturnAddressBeforeReturn(regT2);
+ ret();
+
+ notJSCell.link(this);
+ notObject.link(this);
+ emitLoad(thisReg, regT1, regT0);
+
+ emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT2);
+ emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister);
+
+ restoreReturnAddressBeforeReturn(regT2);
+ ret();
+}
+
+void JIT::emitSlow_op_call(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+ compileOpCallSlowCase(currentInstruction, iter, m_callLinkInfoIndex++, op_call);
+}
+
+void JIT::emitSlow_op_call_eval(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+ compileOpCallSlowCase(currentInstruction, iter, m_callLinkInfoIndex++, op_call_eval);
+}
+
+void JIT::emitSlow_op_call_varargs(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+ compileOpCallVarargsSlowCase(currentInstruction, iter);
+}
+
+void JIT::emitSlow_op_construct(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+ compileOpCallSlowCase(currentInstruction, iter, m_callLinkInfoIndex++, op_construct);
+}
+
+void JIT::emit_op_call(Instruction* currentInstruction)
+{
+ compileOpCall(op_call, currentInstruction, m_callLinkInfoIndex++);
+}
+
+void JIT::emit_op_call_eval(Instruction* currentInstruction)
+{
+ compileOpCall(op_call_eval, currentInstruction, m_callLinkInfoIndex++);
+}
+
+void JIT::emit_op_call_varargs(Instruction* currentInstruction)
+{
+ compileOpCallVarargs(currentInstruction);
+}
+
+void JIT::emit_op_construct(Instruction* currentInstruction)
+{
+ compileOpCall(op_construct, currentInstruction, m_callLinkInfoIndex++);
+}
+
+#if !ENABLE(JIT_OPTIMIZE_CALL)
+
+/* ------------------------------ BEGIN: !ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */
+
+void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned)
+{
+ int callee = instruction[1].u.operand;
+ int argCount = instruction[2].u.operand;
+ int registerOffset = instruction[3].u.operand;
+
+ Jump wasEval;
+ if (opcodeID == op_call_eval) {
+ JITStubCall stubCall(this, cti_op_call_eval);
+ stubCall.addArgument(callee);
+ stubCall.addArgument(JIT::Imm32(registerOffset));
+ stubCall.addArgument(JIT::Imm32(argCount));
+ stubCall.call();
+ wasEval = branch32(NotEqual, regT1, TrustedImm32(JSValue::EmptyValueTag));
+ }
+
+ emitLoad(callee, regT1, regT0);
+
+ emitJumpSlowCaseIfNotJSCell(callee, regT1);
+ addSlowCase(branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsFunctionVPtr)));
+
+ // Speculatively roll the callframe, assuming argCount will match the arity.
+ store32(TrustedImm32(JSValue::CellTag), tagFor(RegisterFile::CallerFrame + registerOffset, callFrameRegister));
+ storePtr(callFrameRegister, payloadFor(RegisterFile::CallerFrame + registerOffset, callFrameRegister));
+ addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), callFrameRegister);
+ move(TrustedImm32(argCount), regT1);
+
+ emitNakedCall(opcodeID == op_construct ? m_globalData->jitStubs->ctiVirtualConstruct() : m_globalData->jitStubs->ctiVirtualCall());
+
+ if (opcodeID == op_call_eval)
+ wasEval.link(this);
+
+ sampleCodeBlock(m_codeBlock);
+}
+
+void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned, OpcodeID opcodeID)
+{
+ int callee = instruction[1].u.operand;
+ int argCount = instruction[2].u.operand;
+ int registerOffset = instruction[3].u.operand;
+
+ linkSlowCaseIfNotJSCell(iter, callee);
+ linkSlowCase(iter);
+
+ JITStubCall stubCall(this, opcodeID == op_construct ? cti_op_construct_NotJSConstruct : cti_op_call_NotJSFunction);
+ stubCall.addArgument(callee);
+ stubCall.addArgument(JIT::Imm32(registerOffset));
+ stubCall.addArgument(JIT::Imm32(argCount));
+ stubCall.call();
+
+ sampleCodeBlock(m_codeBlock);
+}
+
+#else // !ENABLE(JIT_OPTIMIZE_CALL)
+
+/* ------------------------------ BEGIN: ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */
+
+void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned callLinkInfoIndex)
+{
+ int callee = instruction[1].u.operand;
+ int argCount = instruction[2].u.operand;
+ int registerOffset = instruction[3].u.operand;
+
+ Jump wasEval;
+ if (opcodeID == op_call_eval) {
+ JITStubCall stubCall(this, cti_op_call_eval);
+ stubCall.addArgument(callee);
+ stubCall.addArgument(JIT::Imm32(registerOffset));
+ stubCall.addArgument(JIT::Imm32(argCount));
+ stubCall.call();
+ wasEval = branch32(NotEqual, regT1, TrustedImm32(JSValue::EmptyValueTag));
+ }
+
+ emitLoad(callee, regT1, regT0);
+
+ DataLabelPtr addressOfLinkedFunctionCheck;
+
+ BEGIN_UNINTERRUPTED_SEQUENCE(sequenceOpCall);
+
+ Jump jumpToSlow = branchPtrWithPatch(NotEqual, regT0, addressOfLinkedFunctionCheck, TrustedImmPtr(0));
+
+ END_UNINTERRUPTED_SEQUENCE(sequenceOpCall);
+
+ addSlowCase(jumpToSlow);
+ ASSERT_JIT_OFFSET(differenceBetween(addressOfLinkedFunctionCheck, jumpToSlow), patchOffsetOpCallCompareToJump);
+ m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathBegin = addressOfLinkedFunctionCheck;
+ m_callStructureStubCompilationInfo[callLinkInfoIndex].isCall = opcodeID != op_construct;
+
+ addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)));
+
+ // The following is the fast case, only used whan a callee can be linked.
+
+ // Fast version of stack frame initialization, directly relative to edi.
+ // Note that this omits to set up RegisterFile::CodeBlock, which is set in the callee
+ loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_scopeChain)), regT2);
+
+ store32(TrustedImm32(JSValue::Int32Tag), tagFor(registerOffset + RegisterFile::ArgumentCount));
+ store32(Imm32(argCount), payloadFor(registerOffset + RegisterFile::ArgumentCount));
+ storePtr(callFrameRegister, payloadFor(RegisterFile::CallerFrame + registerOffset, callFrameRegister));
+ emitStore(registerOffset + RegisterFile::Callee, regT1, regT0);
+ store32(TrustedImm32(JSValue::CellTag), tagFor(registerOffset + RegisterFile::ScopeChain));
+ store32(regT2, payloadFor(registerOffset + RegisterFile::ScopeChain));
+ addPtr(Imm32(registerOffset * sizeof(Register)), callFrameRegister);
+
+ // Call to the callee
+ m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedCall();
+
+ if (opcodeID == op_call_eval)
+ wasEval.link(this);
+
+ sampleCodeBlock(m_codeBlock);
+}
+
+void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned callLinkInfoIndex, OpcodeID opcodeID)
+{
+ int callee = instruction[1].u.operand;
+ int argCount = instruction[2].u.operand;
+ int registerOffset = instruction[3].u.operand;
+
+ linkSlowCase(iter);
+ linkSlowCase(iter);
+
+ // Fast check for JS function.
+ Jump callLinkFailNotObject = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag));
+ Jump callLinkFailNotJSFunction = branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsFunctionVPtr));
+
+ // Speculatively roll the callframe, assuming argCount will match the arity.
+ store32(TrustedImm32(JSValue::CellTag), tagFor(RegisterFile::CallerFrame + registerOffset, callFrameRegister));
+ storePtr(callFrameRegister, payloadFor(RegisterFile::CallerFrame + registerOffset, callFrameRegister));
+ addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), callFrameRegister);
+ move(Imm32(argCount), regT1);
+
+ m_callStructureStubCompilationInfo[callLinkInfoIndex].callReturnLocation = emitNakedCall(opcodeID == op_construct ? m_globalData->jitStubs->ctiVirtualConstructLink() : m_globalData->jitStubs->ctiVirtualCallLink());
+
+ // Done! - return back to the hot path.
+ ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_call_eval));
+ ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_construct));
+ emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_call));
+
+ // This handles host functions
+ callLinkFailNotObject.link(this);
+ callLinkFailNotJSFunction.link(this);
+
+ JITStubCall stubCall(this, opcodeID == op_construct ? cti_op_construct_NotJSConstruct : cti_op_call_NotJSFunction);
+ stubCall.addArgument(callee);
+ stubCall.addArgument(JIT::Imm32(registerOffset));
+ stubCall.addArgument(JIT::Imm32(argCount));
+ stubCall.call();
+
+ sampleCodeBlock(m_codeBlock);
+}
+
+/* ------------------------------ END: !ENABLE / ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */
+
+#endif // !ENABLE(JIT_OPTIMIZE_CALL)
+
+} // namespace JSC
+
+#endif // USE(JSVALUE32_64)
+#endif // ENABLE(JIT)
}
// Execute the code!
- inline JSValue execute(RegisterFile* registerFile, CallFrame* callFrame, JSGlobalData* globalData, JSValue* exception)
+ inline JSValue execute(RegisterFile* registerFile, CallFrame* callFrame, JSGlobalData* globalData)
{
- return JSValue::decode(ctiTrampoline(m_ref.m_code.executableAddress(), registerFile, callFrame, exception, Profiler::enabledProfilerReference(), globalData));
+ JSValue result = JSValue::decode(ctiTrampoline(m_ref.m_code.executableAddress(), registerFile, callFrame, 0, Profiler::enabledProfilerReference(), globalData));
+ return globalData->exception ? jsNull() : result;
}
void* start()
return JITCode(code.dataLocation(), 0, 0);
}
+ void clear()
+ {
+ m_ref.~CodeRef();
+ new (&m_ref) CodeRef();
+ }
+
private:
JITCode(void* code, PassRefPtr<ExecutablePool> executablePool, size_t size)
: m_ref(code, executablePool, size)
/* Deprecated: Please use JITStubCall instead. */
-// puts an arg onto the stack, as an arg to a context threaded function.
-ALWAYS_INLINE void JIT::emitPutJITStubArg(RegisterID src, unsigned argumentNumber)
-{
- unsigned argumentStackOffset = (argumentNumber * (sizeof(JSValue) / sizeof(void*))) + JITSTACKFRAME_ARGS_INDEX;
- poke(src, argumentStackOffset);
-}
-
-/* Deprecated: Please use JITStubCall instead. */
-
-ALWAYS_INLINE void JIT::emitPutJITStubArgConstant(unsigned value, unsigned argumentNumber)
-{
- unsigned argumentStackOffset = (argumentNumber * (sizeof(JSValue) / sizeof(void*))) + JITSTACKFRAME_ARGS_INDEX;
- poke(Imm32(value), argumentStackOffset);
-}
-
-/* Deprecated: Please use JITStubCall instead. */
-
-ALWAYS_INLINE void JIT::emitPutJITStubArgConstant(void* value, unsigned argumentNumber)
-{
- unsigned argumentStackOffset = (argumentNumber * (sizeof(JSValue) / sizeof(void*))) + JITSTACKFRAME_ARGS_INDEX;
- poke(ImmPtr(value), argumentStackOffset);
-}
-
-/* Deprecated: Please use JITStubCall instead. */
-
ALWAYS_INLINE void JIT::emitGetJITStubArg(unsigned argumentNumber, RegisterID dst)
{
unsigned argumentStackOffset = (argumentNumber * (sizeof(JSValue) / sizeof(void*))) + JITSTACKFRAME_ARGS_INDEX;
ALWAYS_INLINE void JIT::emitPutToCallFrameHeader(RegisterID from, RegisterFile::CallFrameHeaderEntry entry)
{
- storePtr(from, Address(callFrameRegister, entry * sizeof(Register)));
+ storePtr(from, payloadFor(entry, callFrameRegister));
+}
+
+ALWAYS_INLINE void JIT::emitPutCellToCallFrameHeader(RegisterID from, RegisterFile::CallFrameHeaderEntry entry)
+{
+#if USE(JSVALUE32_64)
+ store32(TrustedImm32(JSValue::CellTag), tagFor(entry, callFrameRegister));
+#endif
+ storePtr(from, payloadFor(entry, callFrameRegister));
+}
+
+ALWAYS_INLINE void JIT::emitPutIntToCallFrameHeader(RegisterID from, RegisterFile::CallFrameHeaderEntry entry)
+{
+ store32(TrustedImm32(Int32Tag), intTagFor(entry, callFrameRegister));
+ store32(from, intPayloadFor(entry, callFrameRegister));
}
ALWAYS_INLINE void JIT::emitPutImmediateToCallFrameHeader(void* value, RegisterFile::CallFrameHeaderEntry entry)
{
- storePtr(ImmPtr(value), Address(callFrameRegister, entry * sizeof(Register)));
+ storePtr(TrustedImmPtr(value), Address(callFrameRegister, entry * sizeof(Register)));
}
ALWAYS_INLINE void JIT::emitGetFromCallFrameHeaderPtr(RegisterFile::CallFrameHeaderEntry entry, RegisterID to, RegisterID from)
{
loadPtr(Address(from, entry * sizeof(Register)), to);
-#if !USE(JSVALUE32_64)
+#if USE(JSVALUE64)
killLastResultRegister();
#endif
}
ALWAYS_INLINE void JIT::emitLoadCharacterString(RegisterID src, RegisterID dst, JumpList& failures)
{
- failures.append(branchPtr(NotEqual, Address(src), ImmPtr(m_globalData->jsStringVPtr)));
+ failures.append(branchPtr(NotEqual, Address(src), TrustedImmPtr(m_globalData->jsStringVPtr)));
failures.append(branchTest32(NonZero, Address(src, OBJECT_OFFSETOF(JSString, m_fiberCount))));
- failures.append(branch32(NotEqual, MacroAssembler::Address(src, ThunkHelpers::jsStringLengthOffset()), Imm32(1)));
+ failures.append(branch32(NotEqual, MacroAssembler::Address(src, ThunkHelpers::jsStringLengthOffset()), TrustedImm32(1)));
loadPtr(MacroAssembler::Address(src, ThunkHelpers::jsStringValueOffset()), dst);
loadPtr(MacroAssembler::Address(dst, ThunkHelpers::stringImplDataOffset()), dst);
load16(MacroAssembler::Address(dst, 0), dst);
ALWAYS_INLINE void JIT::emitGetFromCallFrameHeader32(RegisterFile::CallFrameHeaderEntry entry, RegisterID to, RegisterID from)
{
load32(Address(from, entry * sizeof(Register)), to);
-#if !USE(JSVALUE32_64)
+#if USE(JSVALUE64)
killLastResultRegister();
#endif
}
ALWAYS_INLINE JIT::Call JIT::emitNakedCall(CodePtr function)
{
- ASSERT(m_bytecodeIndex != (unsigned)-1); // This method should only be called during hot/cold path generation, so that m_bytecodeIndex is set.
+ ASSERT(m_bytecodeOffset != (unsigned)-1); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set.
Call nakedCall = nearCall();
- m_calls.append(CallRecord(nakedCall, m_bytecodeIndex, function.executableAddress()));
+ m_calls.append(CallRecord(nakedCall, m_bytecodeOffset, function.executableAddress()));
return nakedCall;
}
+ALWAYS_INLINE bool JIT::atJumpTarget()
+{
+ while (m_jumpTargetsPosition < m_codeBlock->numberOfJumpTargets() && m_codeBlock->jumpTarget(m_jumpTargetsPosition) <= m_bytecodeOffset) {
+ if (m_codeBlock->jumpTarget(m_jumpTargetsPosition) == m_bytecodeOffset)
+ return true;
+ ++m_jumpTargetsPosition;
+ }
+ return false;
+}
+
#if defined(ASSEMBLER_HAS_CONSTANT_POOL) && ASSEMBLER_HAS_CONSTANT_POOL
ALWAYS_INLINE void JIT::beginUninterruptedSequence(int insnSpace, int constSpace)
{
+ JSInterfaceJIT::beginUninterruptedSequence();
#if CPU(ARM_TRADITIONAL)
#ifndef NDEBUG
// Ensure the label after the sequence can also fit
ensureSpace(insnSpace, constSpace);
+#elif CPU(SH4)
+#ifndef NDEBUG
+ insnSpace += sizeof(SH4Word);
+ constSpace += sizeof(uint64_t);
+#endif
+
+ m_assembler.ensureSpace(insnSpace + m_assembler.maxInstructionSize + 2, constSpace + 8);
#endif
#if defined(ASSEMBLER_HAS_CONSTANT_POOL) && ASSEMBLER_HAS_CONSTANT_POOL
#endif
}
-ALWAYS_INLINE void JIT::endUninterruptedSequence(int insnSpace, int constSpace)
+ALWAYS_INLINE void JIT::endUninterruptedSequence(int insnSpace, int constSpace, int dst)
{
+ UNUSED_PARAM(dst);
#if defined(ASSEMBLER_HAS_CONSTANT_POOL) && ASSEMBLER_HAS_CONSTANT_POOL
- ASSERT(differenceBetween(m_uninterruptedInstructionSequenceBegin, label()) == insnSpace);
- ASSERT(sizeOfConstantPool() - m_uninterruptedConstantSequenceBegin == constSpace);
+ /* There are several cases when the uninterrupted sequence is larger than
+ * maximum required offset for pathing the same sequence. Eg.: if in a
+ * uninterrupted sequence the last macroassembler's instruction is a stub
+ * call, it emits store instruction(s) which should not be included in the
+ * calculation of length of uninterrupted sequence. So, the insnSpace and
+ * constSpace should be upper limit instead of hard limit.
+ */
+#if CPU(SH4)
+ if ((dst > 15) || (dst < -16)) {
+ insnSpace += 8;
+ constSpace += 2;
+ }
+
+ if (((dst >= -16) && (dst < 0)) || ((dst > 7) && (dst <= 15)))
+ insnSpace += 8;
+#endif
+ ASSERT(differenceBetween(m_uninterruptedInstructionSequenceBegin, label()) <= insnSpace);
+ ASSERT(sizeOfConstantPool() - m_uninterruptedConstantSequenceBegin <= constSpace);
#endif
+ JSInterfaceJIT::endUninterruptedSequence();
}
#endif
{
loadPtr(address, linkRegister);
}
+#elif CPU(SH4)
+
+ALWAYS_INLINE void JIT::preserveReturnAddressAfterCall(RegisterID reg)
+{
+ m_assembler.stspr(reg);
+}
+
+ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(RegisterID reg)
+{
+ m_assembler.ldspr(reg);
+}
+
+ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(Address address)
+{
+ loadPtrLinkReg(address);
+}
#elif CPU(MIPS)
#endif
-#if USE(JIT_STUB_ARGUMENT_VA_LIST)
-ALWAYS_INLINE void JIT::restoreArgumentReference()
-{
- poke(callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof (void*));
-}
-ALWAYS_INLINE void JIT::restoreArgumentReferenceForTrampoline() {}
-#else
ALWAYS_INLINE void JIT::restoreArgumentReference()
{
move(stackPointerRegister, firstArgumentRegister);
- poke(callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof (void*));
+ poke(callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*));
}
+
ALWAYS_INLINE void JIT::restoreArgumentReferenceForTrampoline()
{
#if CPU(X86)
// Within a trampoline the return address will be on the stack at this point.
- addPtr(Imm32(sizeof(void*)), stackPointerRegister, firstArgumentRegister);
+ addPtr(TrustedImm32(sizeof(void*)), stackPointerRegister, firstArgumentRegister);
#elif CPU(ARM)
move(stackPointerRegister, firstArgumentRegister);
+#elif CPU(SH4)
+ move(stackPointerRegister, firstArgumentRegister);
#endif
// In the trampoline on x86-64, the first argument register is not overwritten.
}
-#endif
ALWAYS_INLINE JIT::Jump JIT::checkStructure(RegisterID reg, Structure* structure)
{
- return branchPtr(NotEqual, Address(reg, OBJECT_OFFSETOF(JSCell, m_structure)), ImmPtr(structure));
+ return branchPtr(NotEqual, Address(reg, JSCell::structureOffset()), TrustedImmPtr(structure));
}
ALWAYS_INLINE void JIT::linkSlowCaseIfNotJSCell(Vector<SlowCaseEntry>::iterator& iter, int vReg)
ALWAYS_INLINE void JIT::addSlowCase(Jump jump)
{
- ASSERT(m_bytecodeIndex != (unsigned)-1); // This method should only be called during hot/cold path generation, so that m_bytecodeIndex is set.
+ ASSERT(m_bytecodeOffset != (unsigned)-1); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set.
- m_slowCases.append(SlowCaseEntry(jump, m_bytecodeIndex));
+ m_slowCases.append(SlowCaseEntry(jump, m_bytecodeOffset));
}
ALWAYS_INLINE void JIT::addSlowCase(JumpList jumpList)
{
- ASSERT(m_bytecodeIndex != (unsigned)-1); // This method should only be called during hot/cold path generation, so that m_bytecodeIndex is set.
+ ASSERT(m_bytecodeOffset != (unsigned)-1); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set.
const JumpList::JumpVector& jumpVector = jumpList.jumps();
size_t size = jumpVector.size();
for (size_t i = 0; i < size; ++i)
- m_slowCases.append(SlowCaseEntry(jumpVector[i], m_bytecodeIndex));
+ m_slowCases.append(SlowCaseEntry(jumpVector[i], m_bytecodeOffset));
}
ALWAYS_INLINE void JIT::addJump(Jump jump, int relativeOffset)
{
- ASSERT(m_bytecodeIndex != (unsigned)-1); // This method should only be called during hot/cold path generation, so that m_bytecodeIndex is set.
+ ASSERT(m_bytecodeOffset != (unsigned)-1); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set.
- m_jmpTable.append(JumpTable(jump, m_bytecodeIndex + relativeOffset));
+ m_jmpTable.append(JumpTable(jump, m_bytecodeOffset + relativeOffset));
}
ALWAYS_INLINE void JIT::emitJumpSlowToHot(Jump jump, int relativeOffset)
{
- ASSERT(m_bytecodeIndex != (unsigned)-1); // This method should only be called during hot/cold path generation, so that m_bytecodeIndex is set.
+ ASSERT(m_bytecodeOffset != (unsigned)-1); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set.
- jump.linkTo(m_labels[m_bytecodeIndex + relativeOffset], this);
+ jump.linkTo(m_labels[m_bytecodeOffset + relativeOffset], this);
}
#if ENABLE(SAMPLING_FLAGS)
{
ASSERT(flag >= 1);
ASSERT(flag <= 32);
- or32(Imm32(1u << (flag - 1)), AbsoluteAddress(&SamplingFlags::s_flags));
+ or32(TrustedImm32(1u << (flag - 1)), AbsoluteAddress(SamplingFlags::addressOfFlags()));
}
ALWAYS_INLINE void JIT::clearSamplingFlag(int32_t flag)
{
ASSERT(flag >= 1);
ASSERT(flag <= 32);
- and32(Imm32(~(1u << (flag - 1))), AbsoluteAddress(&SamplingFlags::s_flags));
+ and32(TrustedImm32(~(1u << (flag - 1))), AbsoluteAddress(SamplingFlags::addressOfFlags()));
}
#endif
ALWAYS_INLINE void JIT::emitCount(AbstractSamplingCounter& counter, uint32_t count)
{
#if CPU(X86_64) // Or any other 64-bit plattform.
- addPtr(Imm32(count), AbsoluteAddress(&counter.m_counter));
+ addPtr(TrustedImm32(count), AbsoluteAddress(counter.addressOfCounter()));
#elif CPU(X86) // Or any other little-endian 32-bit plattform.
- intptr_t hiWord = reinterpret_cast<intptr_t>(&counter.m_counter) + sizeof(int32_t);
- add32(Imm32(count), AbsoluteAddress(&counter.m_counter));
- addWithCarry32(Imm32(0), AbsoluteAddress(reinterpret_cast<void*>(hiWord)));
+ intptr_t hiWord = reinterpret_cast<intptr_t>(counter.addressOfCounter()) + sizeof(int32_t);
+ add32(TrustedImm32(count), AbsoluteAddress(counter.addressOfCounter()));
+ addWithCarry32(TrustedImm32(0), AbsoluteAddress(reinterpret_cast<void*>(hiWord)));
#else
#error "SAMPLING_FLAGS not implemented on this platform."
#endif
#if CPU(X86_64)
ALWAYS_INLINE void JIT::sampleInstruction(Instruction* instruction, bool inHostFunction)
{
- move(ImmPtr(m_interpreter->sampler()->sampleSlot()), X86Registers::ecx);
- storePtr(ImmPtr(m_interpreter->sampler()->encodeSample(instruction, inHostFunction)), X86Registers::ecx);
+ move(TrustedImmPtr(m_interpreter->sampler()->sampleSlot()), X86Registers::ecx);
+ storePtr(TrustedImmPtr(m_interpreter->sampler()->encodeSample(instruction, inHostFunction)), X86Registers::ecx);
}
#else
ALWAYS_INLINE void JIT::sampleInstruction(Instruction* instruction, bool inHostFunction)
{
- storePtr(ImmPtr(m_interpreter->sampler()->encodeSample(instruction, inHostFunction)), m_interpreter->sampler()->sampleSlot());
+ storePtr(TrustedImmPtr(m_interpreter->sampler()->encodeSample(instruction, inHostFunction)), m_interpreter->sampler()->sampleSlot());
}
#endif
#endif
#if CPU(X86_64)
ALWAYS_INLINE void JIT::sampleCodeBlock(CodeBlock* codeBlock)
{
- move(ImmPtr(m_interpreter->sampler()->codeBlockSlot()), X86Registers::ecx);
- storePtr(ImmPtr(codeBlock), X86Registers::ecx);
+ move(TrustedImmPtr(m_interpreter->sampler()->codeBlockSlot()), X86Registers::ecx);
+ storePtr(TrustedImmPtr(codeBlock), X86Registers::ecx);
}
#else
ALWAYS_INLINE void JIT::sampleCodeBlock(CodeBlock* codeBlock)
{
- storePtr(ImmPtr(codeBlock), m_interpreter->sampler()->codeBlockSlot());
+ storePtr(TrustedImmPtr(codeBlock), m_interpreter->sampler()->codeBlockSlot());
}
#endif
#endif
inline void JIT::emitLoadDouble(unsigned index, FPRegisterID value)
{
if (m_codeBlock->isConstantRegisterIndex(index)) {
- Register& inConstantPool = m_codeBlock->constantRegister(index);
+ WriteBarrier<Unknown>& inConstantPool = m_codeBlock->constantRegister(index);
loadDouble(&inConstantPool, value);
} else
loadDouble(addressFor(index), value);
inline void JIT::emitLoadInt32ToDouble(unsigned index, FPRegisterID value)
{
if (m_codeBlock->isConstantRegisterIndex(index)) {
- Register& inConstantPool = m_codeBlock->constantRegister(index);
+ WriteBarrier<Unknown>& inConstantPool = m_codeBlock->constantRegister(index);
char* bytePointer = reinterpret_cast<char*>(&inConstantPool);
convertInt32ToDouble(AbsoluteAddress(bytePointer + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), value);
} else
{
store32(payload, payloadFor(index, callFrameRegister));
if (!indexIsInt32)
- store32(Imm32(JSValue::Int32Tag), tagFor(index, callFrameRegister));
+ store32(TrustedImm32(JSValue::Int32Tag), tagFor(index, callFrameRegister));
}
-inline void JIT::emitStoreInt32(unsigned index, Imm32 payload, bool indexIsInt32)
+inline void JIT::emitStoreInt32(unsigned index, TrustedImm32 payload, bool indexIsInt32)
{
store32(payload, payloadFor(index, callFrameRegister));
if (!indexIsInt32)
- store32(Imm32(JSValue::Int32Tag), tagFor(index, callFrameRegister));
+ store32(TrustedImm32(JSValue::Int32Tag), tagFor(index, callFrameRegister));
}
inline void JIT::emitStoreCell(unsigned index, RegisterID payload, bool indexIsCell)
{
store32(payload, payloadFor(index, callFrameRegister));
if (!indexIsCell)
- store32(Imm32(JSValue::CellTag), tagFor(index, callFrameRegister));
+ store32(TrustedImm32(JSValue::CellTag), tagFor(index, callFrameRegister));
}
-inline void JIT::emitStoreBool(unsigned index, RegisterID tag, bool indexIsBool)
+inline void JIT::emitStoreBool(unsigned index, RegisterID payload, bool indexIsBool)
{
+ store32(payload, payloadFor(index, callFrameRegister));
if (!indexIsBool)
- store32(Imm32(0), payloadFor(index, callFrameRegister));
- store32(tag, tagFor(index, callFrameRegister));
+ store32(TrustedImm32(JSValue::BooleanTag), tagFor(index, callFrameRegister));
}
inline void JIT::emitStoreDouble(unsigned index, FPRegisterID value)
emitStore(dst, jsUndefined());
}
-inline bool JIT::isLabeled(unsigned bytecodeIndex)
+inline bool JIT::isLabeled(unsigned bytecodeOffset)
{
for (size_t numberOfJumpTargets = m_codeBlock->numberOfJumpTargets(); m_jumpTargetIndex != numberOfJumpTargets; ++m_jumpTargetIndex) {
unsigned jumpTarget = m_codeBlock->jumpTarget(m_jumpTargetIndex);
- if (jumpTarget == bytecodeIndex)
+ if (jumpTarget == bytecodeOffset)
return true;
- if (jumpTarget > bytecodeIndex)
+ if (jumpTarget > bytecodeOffset)
return false;
}
return false;
}
-inline void JIT::map(unsigned bytecodeIndex, unsigned virtualRegisterIndex, RegisterID tag, RegisterID payload)
+inline void JIT::map(unsigned bytecodeOffset, unsigned virtualRegisterIndex, RegisterID tag, RegisterID payload)
{
- if (isLabeled(bytecodeIndex))
+ if (isLabeled(bytecodeOffset))
return;
- m_mappedBytecodeIndex = bytecodeIndex;
+ m_mappedBytecodeOffset = bytecodeOffset;
m_mappedVirtualRegisterIndex = virtualRegisterIndex;
m_mappedTag = tag;
m_mappedPayload = payload;
inline void JIT::unmap()
{
- m_mappedBytecodeIndex = (unsigned)-1;
+ m_mappedBytecodeOffset = (unsigned)-1;
m_mappedVirtualRegisterIndex = (unsigned)-1;
m_mappedTag = (RegisterID)-1;
m_mappedPayload = (RegisterID)-1;
inline bool JIT::isMapped(unsigned virtualRegisterIndex)
{
- if (m_mappedBytecodeIndex != m_bytecodeIndex)
+ if (m_mappedBytecodeOffset != m_bytecodeOffset)
return false;
if (m_mappedVirtualRegisterIndex != virtualRegisterIndex)
return false;
inline bool JIT::getMappedPayload(unsigned virtualRegisterIndex, RegisterID& payload)
{
- if (m_mappedBytecodeIndex != m_bytecodeIndex)
+ if (m_mappedBytecodeOffset != m_bytecodeOffset)
return false;
if (m_mappedVirtualRegisterIndex != virtualRegisterIndex)
return false;
inline bool JIT::getMappedTag(unsigned virtualRegisterIndex, RegisterID& tag)
{
- if (m_mappedBytecodeIndex != m_bytecodeIndex)
+ if (m_mappedBytecodeOffset != m_bytecodeOffset)
return false;
if (m_mappedVirtualRegisterIndex != virtualRegisterIndex)
return false;
if (m_codeBlock->isConstantRegisterIndex(virtualRegisterIndex))
addSlowCase(jump());
else
- addSlowCase(branch32(NotEqual, tag, Imm32(JSValue::CellTag)));
+ addSlowCase(branch32(NotEqual, tag, TrustedImm32(JSValue::CellTag)));
}
}
return false;
}
-/* Deprecated: Please use JITStubCall instead. */
-
-ALWAYS_INLINE void JIT::emitPutJITStubArg(RegisterID tag, RegisterID payload, unsigned argumentNumber)
-{
- unsigned argumentStackOffset = (argumentNumber * (sizeof(JSValue) / sizeof(void*))) + JITSTACKFRAME_ARGS_INDEX;
- poke(payload, argumentStackOffset);
- poke(tag, argumentStackOffset + 1);
-}
-
-/* Deprecated: Please use JITStubCall instead. */
-
-ALWAYS_INLINE void JIT::emitPutJITStubArgFromVirtualRegister(unsigned src, unsigned argumentNumber, RegisterID scratch1, RegisterID scratch2)
-{
- unsigned argumentStackOffset = (argumentNumber * (sizeof(JSValue) / sizeof(void*))) + JITSTACKFRAME_ARGS_INDEX;
- if (m_codeBlock->isConstantRegisterIndex(src)) {
- JSValue constant = m_codeBlock->getConstant(src);
- poke(Imm32(constant.payload()), argumentStackOffset);
- poke(Imm32(constant.tag()), argumentStackOffset + 1);
- } else {
- emitLoad(src, scratch1, scratch2);
- poke(scratch2, argumentStackOffset);
- poke(scratch1, argumentStackOffset + 1);
- }
-}
-
#else // USE(JSVALUE32_64)
ALWAYS_INLINE void JIT::killLastResultRegister()
// get arg puts an arg from the SF register array into a h/w register
ALWAYS_INLINE void JIT::emitGetVirtualRegister(int src, RegisterID dst)
{
- ASSERT(m_bytecodeIndex != (unsigned)-1); // This method should only be called during hot/cold path generation, so that m_bytecodeIndex is set.
+ ASSERT(m_bytecodeOffset != (unsigned)-1); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set.
// TODO: we want to reuse values that are already in registers if we can - add a register allocator!
if (m_codeBlock->isConstantRegisterIndex(src)) {
return;
}
- if (src == m_lastResultBytecodeRegister && m_codeBlock->isTemporaryRegisterIndex(src)) {
- bool atJumpTarget = false;
- while (m_jumpTargetsPosition < m_codeBlock->numberOfJumpTargets() && m_codeBlock->jumpTarget(m_jumpTargetsPosition) <= m_bytecodeIndex) {
- if (m_codeBlock->jumpTarget(m_jumpTargetsPosition) == m_bytecodeIndex)
- atJumpTarget = true;
- ++m_jumpTargetsPosition;
- }
-
- if (!atJumpTarget) {
- // The argument we want is already stored in eax
- if (dst != cachedResultRegister)
- move(cachedResultRegister, dst);
- killLastResultRegister();
- return;
- }
+ if (src == m_lastResultBytecodeRegister && m_codeBlock->isTemporaryRegisterIndex(src) && !atJumpTarget()) {
+ // The argument we want is already stored in eax
+ if (dst != cachedResultRegister)
+ move(cachedResultRegister, dst);
+ killLastResultRegister();
+ return;
}
loadPtr(Address(callFrameRegister, src * sizeof(Register)), dst);
ALWAYS_INLINE void JIT::emitPutVirtualRegister(unsigned dst, RegisterID from)
{
storePtr(from, Address(callFrameRegister, dst * sizeof(Register)));
- m_lastResultBytecodeRegister = (from == cachedResultRegister) ? dst : std::numeric_limits<int>::max();
+ m_lastResultBytecodeRegister = (from == cachedResultRegister) ? static_cast<int>(dst) : std::numeric_limits<int>::max();
}
ALWAYS_INLINE void JIT::emitInitRegister(unsigned dst)
{
- storePtr(ImmPtr(JSValue::encode(jsUndefined())), Address(callFrameRegister, dst * sizeof(Register)));
+ storePtr(TrustedImmPtr(JSValue::encode(jsUndefined())), Address(callFrameRegister, dst * sizeof(Register)));
}
ALWAYS_INLINE JIT::Jump JIT::emitJumpIfJSCell(RegisterID reg)
#if USE(JSVALUE64)
return branchTestPtr(Zero, reg, tagMaskRegister);
#else
- return branchTest32(Zero, reg, Imm32(JSImmediate::TagMask));
+ return branchTest32(Zero, reg, TrustedImm32(TagMask));
#endif
}
#if USE(JSVALUE64)
return branchTestPtr(NonZero, reg, tagMaskRegister);
#else
- return branchTest32(NonZero, reg, Imm32(JSImmediate::TagMask));
+ return branchTest32(NonZero, reg, TrustedImm32(TagMask));
#endif
}
inline void JIT::emitLoadDouble(unsigned index, FPRegisterID value)
{
if (m_codeBlock->isConstantRegisterIndex(index)) {
- Register& inConstantPool = m_codeBlock->constantRegister(index);
+ WriteBarrier<Unknown>& inConstantPool = m_codeBlock->constantRegister(index);
loadDouble(&inConstantPool, value);
} else
loadDouble(addressFor(index), value);
inline void JIT::emitLoadInt32ToDouble(unsigned index, FPRegisterID value)
{
if (m_codeBlock->isConstantRegisterIndex(index)) {
- Register& inConstantPool = m_codeBlock->constantRegister(index);
- convertInt32ToDouble(AbsoluteAddress(&inConstantPool), value);
+ ASSERT(isOperandConstantImmediateInt(index));
+ convertInt32ToDouble(Imm32(getConstantOperand(index).asInt32()), value);
} else
convertInt32ToDouble(addressFor(index), value);
}
#if USE(JSVALUE64)
return branchPtr(AboveOrEqual, reg, tagTypeNumberRegister);
#else
- return branchTest32(NonZero, reg, Imm32(JSImmediate::TagTypeNumber));
+ return branchTest32(NonZero, reg, TrustedImm32(TagTypeNumber));
#endif
}
#if USE(JSVALUE64)
return branchPtr(Below, reg, tagTypeNumberRegister);
#else
- return branchTest32(Zero, reg, Imm32(JSImmediate::TagTypeNumber));
+ return branchTest32(Zero, reg, TrustedImm32(TagTypeNumber));
#endif
}
addSlowCase(emitJumpIfNotImmediateNumber(reg));
}
-#if !USE(JSVALUE64)
+#if USE(JSVALUE32_64)
ALWAYS_INLINE void JIT::emitFastArithDeTagImmediate(RegisterID reg)
{
- subPtr(Imm32(JSImmediate::TagTypeNumber), reg);
+ subPtr(TrustedImm32(TagTypeNumber), reg);
}
ALWAYS_INLINE JIT::Jump JIT::emitFastArithDeTagImmediateJumpIfZero(RegisterID reg)
{
- return branchSubPtr(Zero, Imm32(JSImmediate::TagTypeNumber), reg);
+ return branchSubPtr(Zero, TrustedImm32(TagTypeNumber), reg);
}
#endif
#else
if (src != dest)
move(src, dest);
- addPtr(Imm32(JSImmediate::TagTypeNumber), dest);
+ addPtr(TrustedImm32(TagTypeNumber), dest);
#endif
}
ALWAYS_INLINE void JIT::emitTagAsBoolImmediate(RegisterID reg)
{
- lshift32(Imm32(JSImmediate::ExtendedPayloadShift), reg);
- or32(Imm32(static_cast<int32_t>(JSImmediate::FullTagTypeBool)), reg);
-}
-
-/* Deprecated: Please use JITStubCall instead. */
-
-// get arg puts an arg from the SF register array onto the stack, as an arg to a context threaded function.
-ALWAYS_INLINE void JIT::emitPutJITStubArgFromVirtualRegister(unsigned src, unsigned argumentNumber, RegisterID scratch)
-{
- unsigned argumentStackOffset = (argumentNumber * (sizeof(JSValue) / sizeof(void*))) + JITSTACKFRAME_ARGS_INDEX;
- if (m_codeBlock->isConstantRegisterIndex(src)) {
- JSValue value = m_codeBlock->getConstant(src);
- poke(ImmPtr(JSValue::encode(value)), argumentStackOffset);
- } else {
- loadPtr(Address(callFrameRegister, src * sizeof(Register)), scratch);
- poke(scratch, argumentStackOffset);
- }
-
- killLastResultRegister();
+ or32(TrustedImm32(static_cast<int32_t>(ValueFalse)), reg);
}
#endif // USE(JSVALUE32_64)
*/
#include "config.h"
-#include "JIT.h"
-
#if ENABLE(JIT)
+#include "JIT.h"
+#include "Arguments.h"
#include "JITInlineMethods.h"
#include "JITStubCall.h"
#include "JSArray.h"
namespace JSC {
-#if !USE(JSVALUE32_64)
-
-#define RECORD_JUMP_TARGET(targetOffset) \
- do { m_labels[m_bytecodeIndex + (targetOffset)].used(); } while (false)
+#if USE(JSVALUE64)
void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executablePool, JSGlobalData* globalData, TrampolineStructure *trampolines)
{
-#if ENABLE(JIT_OPTIMIZE_MOD)
- Label softModBegin = align();
- softModulo();
-#endif
#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
// (2) The second function provides fast property access for string length
Label stringLengthBegin = align();
// Check eax is a string
Jump string_failureCases1 = emitJumpIfNotJSCell(regT0);
- Jump string_failureCases2 = branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsStringVPtr));
+ Jump string_failureCases2 = branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsStringVPtr));
// Checks out okay! - get the length from the Ustring.
load32(Address(regT0, OBJECT_OFFSETOF(JSString, m_length)), regT0);
- Jump string_failureCases3 = branch32(Above, regT0, Imm32(JSImmediate::maxImmediateInt));
+ Jump string_failureCases3 = branch32(LessThan, regT0, TrustedImm32(0));
// regT0 contains a 64 bit value (is positive, is zero extended) so we don't need sign extend here.
emitFastArithIntToImmNoCheck(regT0, regT0);
// VirtualCallLink Trampoline
// regT0 holds callee, regT1 holds argCount. regT2 will hold the FunctionExecutable.
+ JumpList callLinkFailures;
Label virtualCallLinkBegin = align();
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
-
- Jump isNativeFunc2 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), Imm32(0));
-
- Jump hasCodeBlock2 = branch32(GreaterThan, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), Imm32(0));
- preserveReturnAddressAfterCall(regT3);
- restoreArgumentReference();
- Call callJSFunction2 = call();
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
- emitGetJITStubArg(2, regT1); // argCount
- restoreReturnAddressBeforeReturn(regT3);
- hasCodeBlock2.link(this);
-
- // Check argCount matches callee arity.
- Jump arityCheckOkay2 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), regT1);
+ compileOpCallInitializeCallFrame();
preserveReturnAddressAfterCall(regT3);
- emitPutJITStubArg(regT3, 1); // return address
+ emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
restoreArgumentReference();
- Call callArityCheck2 = call();
- move(regT1, callFrameRegister);
- emitGetJITStubArg(2, regT1); // argCount
+ Call callLazyLinkCall = call();
+ callLinkFailures.append(branchTestPtr(Zero, regT0));
restoreReturnAddressBeforeReturn(regT3);
- arityCheckOkay2.link(this);
-
- isNativeFunc2.link(this);
+ emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1);
+ jump(regT0);
+ // VirtualConstructLink Trampoline
+ // regT0 holds callee, regT1 holds argCount. regT2 will hold the FunctionExecutable.
+ Label virtualConstructLinkBegin = align();
compileOpCallInitializeCallFrame();
preserveReturnAddressAfterCall(regT3);
- emitPutJITStubArg(regT3, 1); // return address
+ emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
restoreArgumentReference();
- Call callLazyLinkCall = call();
+ Call callLazyLinkConstruct = call();
+ callLinkFailures.append(branchTestPtr(Zero, regT0));
restoreReturnAddressBeforeReturn(regT3);
+ emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1);
jump(regT0);
// VirtualCall Trampoline
// regT0 holds callee, regT1 holds argCount. regT2 will hold the FunctionExecutable.
Label virtualCallBegin = align();
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
+ compileOpCallInitializeCallFrame();
- Jump isNativeFunc3 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), Imm32(0));
+ loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
- Jump hasCodeBlock3 = branch32(GreaterThan, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), Imm32(0));
+ Jump hasCodeBlock3 = branch32(GreaterThanOrEqual, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), TrustedImm32(0));
preserveReturnAddressAfterCall(regT3);
restoreArgumentReference();
- Call callJSFunction1 = call();
- emitGetJITStubArg(2, regT1); // argCount
+ Call callCompileCall = call();
+ callLinkFailures.append(branchTestPtr(Zero, regT0));
+ emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1);
restoreReturnAddressBeforeReturn(regT3);
loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
hasCodeBlock3.link(this);
-
- // Check argCount matches callee arity.
- Jump arityCheckOkay3 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), regT1);
- preserveReturnAddressAfterCall(regT3);
- emitPutJITStubArg(regT3, 1); // return address
- restoreArgumentReference();
- Call callArityCheck1 = call();
- move(regT1, callFrameRegister);
- emitGetJITStubArg(2, regT1); // argCount
- restoreReturnAddressBeforeReturn(regT3);
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
- arityCheckOkay3.link(this);
-
- isNativeFunc3.link(this);
- compileOpCallInitializeCallFrame();
- loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCode)), regT0);
+ loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCodeForCallWithArityCheck)), regT0);
jump(regT0);
- Label nativeCallThunk = align();
- preserveReturnAddressAfterCall(regT0);
- emitPutToCallFrameHeader(regT0, RegisterFile::ReturnPC); // Push return address
+ // VirtualConstruct Trampoline
+ // regT0 holds callee, regT1 holds argCount. regT2 will hold the FunctionExecutable.
+ Label virtualConstructBegin = align();
+ compileOpCallInitializeCallFrame();
- // Load caller frame's scope chain into this callframe so that whatever we call can
- // get to its global data.
- emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT1);
- emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT1);
- emitPutToCallFrameHeader(regT1, RegisterFile::ScopeChain);
-
+ loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
-#if CPU(X86_64)
- emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, X86Registers::ecx);
+ Jump hasCodeBlock4 = branch32(GreaterThanOrEqual, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), TrustedImm32(0));
+ preserveReturnAddressAfterCall(regT3);
+ restoreArgumentReference();
+ Call callCompileConstruct = call();
+ callLinkFailures.append(branchTestPtr(Zero, regT0));
+ emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1);
+ restoreReturnAddressBeforeReturn(regT3);
+ loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
+ hasCodeBlock4.link(this);
- // Allocate stack space for our arglist
- subPtr(Imm32(sizeof(ArgList)), stackPointerRegister);
- COMPILE_ASSERT((sizeof(ArgList) & 0xf) == 0, ArgList_should_by_16byte_aligned);
+ loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCodeForConstructWithArityCheck)), regT0);
+ jump(regT0);
- // Set up arguments
- subPtr(Imm32(1), X86Registers::ecx); // Don't include 'this' in argcount
+ // If the parser fails we want to be able to be able to keep going,
+ // So we handle this as a parse failure.
+ callLinkFailures.link(this);
+ emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT1);
+ emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister);
+ restoreReturnAddressBeforeReturn(regT1);
+ move(TrustedImmPtr(&globalData->exceptionLocation), regT2);
+ storePtr(regT1, regT2);
+ poke(callFrameRegister, 1 + OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*));
+ poke(TrustedImmPtr(FunctionPtr(ctiVMThrowTrampoline).value()));
+ ret();
- // Push argcount
- storePtr(X86Registers::ecx, Address(stackPointerRegister, OBJECT_OFFSETOF(ArgList, m_argCount)));
+ // NativeCall Trampoline
+ Label nativeCallThunk = privateCompileCTINativeCall(globalData);
+ Label nativeConstructThunk = privateCompileCTINativeCall(globalData, true);
- // Calculate the start of the callframe header, and store in edx
- addPtr(Imm32(-RegisterFile::CallFrameHeaderSize * (int32_t)sizeof(Register)), callFrameRegister, X86Registers::edx);
-
- // Calculate start of arguments as callframe header - sizeof(Register) * argcount (ecx)
- mul32(Imm32(sizeof(Register)), X86Registers::ecx, X86Registers::ecx);
- subPtr(X86Registers::ecx, X86Registers::edx);
+#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
+ Call string_failureCases1Call = makeTailRecursiveCall(string_failureCases1);
+ Call string_failureCases2Call = makeTailRecursiveCall(string_failureCases2);
+ Call string_failureCases3Call = makeTailRecursiveCall(string_failureCases3);
+#endif
- // push pointer to arguments
- storePtr(X86Registers::edx, Address(stackPointerRegister, OBJECT_OFFSETOF(ArgList, m_args)));
-
- // ArgList is passed by reference so is stackPointerRegister
- move(stackPointerRegister, X86Registers::ecx);
-
- // edx currently points to the first argument, edx-sizeof(Register) points to 'this'
- loadPtr(Address(X86Registers::edx, -(int32_t)sizeof(Register)), X86Registers::edx);
-
- emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, X86Registers::esi);
+ // All trampolines constructed! copy the code, link up calls, and set the pointers on the Machine object.
+ LinkBuffer patchBuffer(*m_globalData, this, m_globalData->executableAllocator);
- move(callFrameRegister, X86Registers::edi);
+#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
+ patchBuffer.link(string_failureCases1Call, FunctionPtr(cti_op_get_by_id_string_fail));
+ patchBuffer.link(string_failureCases2Call, FunctionPtr(cti_op_get_by_id_string_fail));
+ patchBuffer.link(string_failureCases3Call, FunctionPtr(cti_op_get_by_id_string_fail));
+#endif
+#if ENABLE(JIT_OPTIMIZE_CALL)
+ patchBuffer.link(callLazyLinkCall, FunctionPtr(cti_vm_lazyLinkCall));
+ patchBuffer.link(callLazyLinkConstruct, FunctionPtr(cti_vm_lazyLinkConstruct));
+#endif
+ patchBuffer.link(callCompileCall, FunctionPtr(cti_op_call_jitCompile));
+ patchBuffer.link(callCompileConstruct, FunctionPtr(cti_op_construct_jitCompile));
- call(Address(X86Registers::esi, OBJECT_OFFSETOF(JSFunction, m_data)));
-
- addPtr(Imm32(sizeof(ArgList)), stackPointerRegister);
-#elif CPU(X86)
- emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT0);
+ CodeRef finalCode = patchBuffer.finalizeCode();
+ *executablePool = finalCode.m_executablePool;
- /* We have two structs that we use to describe the stackframe we set up for our
- * call to native code. NativeCallFrameStructure describes the how we set up the stack
- * in advance of the call. NativeFunctionCalleeSignature describes the callframe
- * as the native code expects it. We do this as we are using the fastcall calling
- * convention which results in the callee popping its arguments off the stack, but
- * not the rest of the callframe so we need a nice way to ensure we increment the
- * stack pointer by the right amount after the call.
- */
-#if COMPILER(MSVC) || OS(LINUX)
- struct NativeCallFrameStructure {
- // CallFrame* callFrame; // passed in EDX
- JSObject* callee;
- JSValue thisValue;
- ArgList* argPointer;
- ArgList args;
- JSValue result;
- };
- struct NativeFunctionCalleeSignature {
- JSObject* callee;
- JSValue thisValue;
- ArgList* argPointer;
- };
-#else
- struct NativeCallFrameStructure {
- // CallFrame* callFrame; // passed in ECX
- // JSObject* callee; // passed in EDX
- JSValue thisValue;
- ArgList* argPointer;
- ArgList args;
- };
- struct NativeFunctionCalleeSignature {
- JSValue thisValue;
- ArgList* argPointer;
- };
+ trampolines->ctiVirtualCallLink = patchBuffer.trampolineAt(virtualCallLinkBegin);
+ trampolines->ctiVirtualConstructLink = patchBuffer.trampolineAt(virtualConstructLinkBegin);
+ trampolines->ctiVirtualCall = patchBuffer.trampolineAt(virtualCallBegin);
+ trampolines->ctiVirtualConstruct = patchBuffer.trampolineAt(virtualConstructBegin);
+ trampolines->ctiNativeCall = patchBuffer.trampolineAt(nativeCallThunk);
+ trampolines->ctiNativeConstruct = patchBuffer.trampolineAt(nativeConstructThunk);
+#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
+ trampolines->ctiStringLengthTrampoline = patchBuffer.trampolineAt(stringLengthBegin);
#endif
- const int NativeCallFrameSize = (sizeof(NativeCallFrameStructure) + 15) & ~15;
- // Allocate system stack frame
- subPtr(Imm32(NativeCallFrameSize), stackPointerRegister);
+}
- // Set up arguments
- subPtr(Imm32(1), regT0); // Don't include 'this' in argcount
+JIT::Label JIT::privateCompileCTINativeCall(JSGlobalData* globalData, bool isConstruct)
+{
+ int executableOffsetToFunction = isConstruct ? OBJECT_OFFSETOF(NativeExecutable, m_constructor) : OBJECT_OFFSETOF(NativeExecutable, m_function);
- // push argcount
- storePtr(regT0, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, args) + OBJECT_OFFSETOF(ArgList, m_argCount)));
-
- // Calculate the start of the callframe header, and store in regT1
- addPtr(Imm32(-RegisterFile::CallFrameHeaderSize * (int)sizeof(Register)), callFrameRegister, regT1);
+ Label nativeCallThunk = align();
- // Calculate start of arguments as callframe header - sizeof(Register) * argcount (regT0)
- mul32(Imm32(sizeof(Register)), regT0, regT0);
- subPtr(regT0, regT1);
- storePtr(regT1, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, args) + OBJECT_OFFSETOF(ArgList, m_args)));
-
- // ArgList is passed by reference so is stackPointerRegister + 4 * sizeof(Register)
- addPtr(Imm32(OBJECT_OFFSETOF(NativeCallFrameStructure, args)), stackPointerRegister, regT0);
- storePtr(regT0, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, argPointer)));
+ emitPutImmediateToCallFrameHeader(0, RegisterFile::CodeBlock);
- // regT1 currently points to the first argument, regT1 - sizeof(Register) points to 'this'
- loadPtr(Address(regT1, -(int)sizeof(Register)), regT1);
- storePtr(regT1, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, thisValue)));
-
-#if COMPILER(MSVC) || OS(LINUX)
- // ArgList is passed by reference so is stackPointerRegister + 4 * sizeof(Register)
- addPtr(Imm32(OBJECT_OFFSETOF(NativeCallFrameStructure, result)), stackPointerRegister, X86Registers::ecx);
-
- // Plant callee
- emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, X86Registers::eax);
- storePtr(X86Registers::eax, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, callee)));
+#if CPU(X86_64)
+ // Load caller frame's scope chain into this callframe so that whatever we call can
+ // get to its global data.
+ emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT0);
+ emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT0);
+ emitPutCellToCallFrameHeader(regT1, RegisterFile::ScopeChain);
- // Plant callframe
- move(callFrameRegister, X86Registers::edx);
+ peek(regT1);
+ emitPutToCallFrameHeader(regT1, RegisterFile::ReturnPC);
- call(Address(X86Registers::eax, OBJECT_OFFSETOF(JSFunction, m_data)));
+ // Calling convention: f(edi, esi, edx, ecx, ...);
+ // Host function signature: f(ExecState*);
+ move(callFrameRegister, X86Registers::edi);
- // JSValue is a non-POD type
- loadPtr(Address(X86Registers::eax), X86Registers::eax);
-#else
- // Plant callee
- emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, X86Registers::edx);
+ subPtr(TrustedImm32(16 - sizeof(void*)), stackPointerRegister); // Align stack after call.
- // Plant callframe
- move(callFrameRegister, X86Registers::ecx);
- call(Address(X86Registers::edx, OBJECT_OFFSETOF(JSFunction, m_data)));
-#endif
+ emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, X86Registers::esi);
+ loadPtr(Address(X86Registers::esi, OBJECT_OFFSETOF(JSFunction, m_executable)), X86Registers::r9);
+ move(regT0, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack.
+ call(Address(X86Registers::r9, executableOffsetToFunction));
- // We've put a few temporaries on the stack in addition to the actual arguments
- // so pull them off now
- addPtr(Imm32(NativeCallFrameSize - sizeof(NativeFunctionCalleeSignature)), stackPointerRegister);
+ addPtr(TrustedImm32(16 - sizeof(void*)), stackPointerRegister);
#elif CPU(ARM)
- emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT0);
-
- // Allocate stack space for our arglist
- COMPILE_ASSERT((sizeof(ArgList) & 0x7) == 0, ArgList_should_by_8byte_aligned);
- subPtr(Imm32(sizeof(ArgList)), stackPointerRegister);
-
- // Set up arguments
- subPtr(Imm32(1), regT0); // Don't include 'this' in argcount
-
- // Push argcount
- storePtr(regT0, Address(stackPointerRegister, OBJECT_OFFSETOF(ArgList, m_argCount)));
-
- // Calculate the start of the callframe header, and store in regT1
- move(callFrameRegister, regT1);
- sub32(Imm32(RegisterFile::CallFrameHeaderSize * (int32_t)sizeof(Register)), regT1);
-
- // Calculate start of arguments as callframe header - sizeof(Register) * argcount (regT1)
- mul32(Imm32(sizeof(Register)), regT0, regT0);
- subPtr(regT0, regT1);
-
- // push pointer to arguments
- storePtr(regT1, Address(stackPointerRegister, OBJECT_OFFSETOF(ArgList, m_args)));
-
- // regT1 currently points to the first argument, regT1-sizeof(Register) points to 'this'
-
-#if OS(WINCE)
- // Setup arg3:
- loadPtr(Address(regT1, -(int32_t)sizeof(Register)), ARMRegisters::r3);
-
- // Setup arg2:
- emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT2);
-
- // Setup arg1:
- move(callFrameRegister, regT1);
-
- // Setup arg0:
- move(stackPointerRegister, regT0);
- subPtr(Imm32(sizeof(Register)), stackPointerRegister);
- storePtr(regT0, Address(stackPointerRegister));
-
- call(Address(regT2, OBJECT_OFFSETOF(JSFunction, m_data)));
-
- loadPtr(Address(regT0), regT0);
-
- addPtr(Imm32(sizeof(Register) + sizeof(ArgList)), stackPointerRegister);
-#else // OS(WINCE)
- // Setup arg3:
- loadPtr(Address(regT1, -(int32_t)sizeof(Register)), regT2);
-
- // Setup arg2:
- emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT1);
+ // Load caller frame's scope chain into this callframe so that whatever we call can
+ // get to its global data.
+ emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT2);
+ emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT2);
+ emitPutCellToCallFrameHeader(regT1, RegisterFile::ScopeChain);
- // Setup arg1:
- move(callFrameRegister, regT0);
+ preserveReturnAddressAfterCall(regT3); // Callee preserved
+ emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
- // Setup arg4: This is a plain hack
- move(stackPointerRegister, ARMRegisters::r3);
+ // Calling convention: f(r0 == regT0, r1 == regT1, ...);
+ // Host function signature: f(ExecState*);
+ move(callFrameRegister, ARMRegisters::r0);
- call(Address(regT1, OBJECT_OFFSETOF(JSFunction, m_data)));
+ emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, ARMRegisters::r1);
+ move(regT2, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack.
+ loadPtr(Address(ARMRegisters::r1, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
+ call(Address(regT2, executableOffsetToFunction));
- addPtr(Imm32(sizeof(ArgList)), stackPointerRegister);
-#endif // OS(WINCE)
+ restoreReturnAddressBeforeReturn(regT3);
#elif CPU(MIPS)
- emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT0);
-
- // Allocate stack space for our arglist
- COMPILE_ASSERT(!(sizeof(ArgList) & 0x7), ArgList_should_by_8byte_aligned);
- subPtr(Imm32(sizeof(ArgList) + 24), stackPointerRegister);
-
- // Set up arguments
- subPtr(Imm32(1), regT0); // Don't include 'this' in argcount
-
- // Push argcount to 24 + offset($sp)
- storePtr(regT0, Address(stackPointerRegister, 24 + OBJECT_OFFSETOF(ArgList, m_argCount)));
-
- // Calculate the start of the callframe header, and store in regT1
- move(callFrameRegister, regT1);
- sub32(Imm32(RegisterFile::CallFrameHeaderSize * (int32_t)sizeof(Register)), regT1);
-
- // Calculate start of arguments as callframe header - sizeof(Register) * argcount (regT1)
- mul32(Imm32(sizeof(Register)), regT0, regT0);
- subPtr(regT0, regT1);
-
- // push pointer to arguments to 24 + offset($sp)
- storePtr(regT1, Address(stackPointerRegister, 24 + OBJECT_OFFSETOF(ArgList, m_args)));
-
- // Setup arg3: regT1 currently points to the first argument, regT1-sizeof(Register) points to 'this'
- loadPtr(Address(regT1, -(int32_t)sizeof(Register)), MIPSRegisters::a3);
+ // Load caller frame's scope chain into this callframe so that whatever we call can
+ // get to its global data.
+ emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT0);
+ emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT0);
+ emitPutCellToCallFrameHeader(regT1, RegisterFile::ScopeChain);
- // Setup arg2:
- emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, MIPSRegisters::a2);
+ preserveReturnAddressAfterCall(regT3); // Callee preserved
+ emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
- // Setup arg1:
- move(callFrameRegister, MIPSRegisters::a1);
+ // Calling convention: f(a0, a1, a2, a3);
+ // Host function signature: f(ExecState*);
- // Setup arg4: ArgList is passed by reference. At 16($sp), store ($sp + 24)
- addPtr(Imm32(24), stackPointerRegister, regT2);
- storePtr(regT2, Address(stackPointerRegister, 16));
+ // Allocate stack space for 16 bytes (8-byte aligned)
+ // 16 bytes (unused) for 4 arguments
+ subPtr(TrustedImm32(16), stackPointerRegister);
- // Setup arg0 as 20($sp) to hold the returned structure.
- ASSERT(sizeof(JSValue) == 4);
- addPtr(Imm32(20), stackPointerRegister, MIPSRegisters::a0);
+ // Setup arg0
+ move(callFrameRegister, MIPSRegisters::a0);
// Call
- call(Address(MIPSRegisters::a2, OBJECT_OFFSETOF(JSFunction, m_data)));
-
- // Get returned value from 0($v0) which is the same as 20($sp)
- loadPtr(Address(returnValueRegister, 0), returnValueRegister);
+ emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, MIPSRegisters::a2);
+ loadPtr(Address(MIPSRegisters::a2, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
+ move(regT0, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack.
+ call(Address(regT2, executableOffsetToFunction));
// Restore stack space
- addPtr(Imm32(sizeof(ArgList) + 24), stackPointerRegister);
+ addPtr(TrustedImm32(16), stackPointerRegister);
+
+ restoreReturnAddressBeforeReturn(regT3);
#elif ENABLE(JIT_OPTIMIZE_NATIVE_CALL)
#error "JIT_OPTIMIZE_NATIVE_CALL not yet supported on this platform."
#else
+ UNUSED_PARAM(executableOffsetToFunction);
breakpoint();
#endif
loadPtr(&(globalData->exception), regT2);
Jump exceptionHandler = branchTestPtr(NonZero, regT2);
- // Grab the return address.
- emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT1);
-
- // Restore our caller's "r".
- emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister);
-
// Return.
- restoreReturnAddressBeforeReturn(regT1);
ret();
// Handle an exception
exceptionHandler.link(this);
+
// Grab the return address.
- emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT1);
- move(ImmPtr(&globalData->exceptionLocation), regT2);
- storePtr(regT1, regT2);
- move(ImmPtr(FunctionPtr(ctiVMThrowTrampoline).value()), regT2);
- emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister);
- poke(callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof (void*));
- restoreReturnAddressBeforeReturn(regT2);
- ret();
-
+ preserveReturnAddressAfterCall(regT1);
-#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
- Call string_failureCases1Call = makeTailRecursiveCall(string_failureCases1);
- Call string_failureCases2Call = makeTailRecursiveCall(string_failureCases2);
- Call string_failureCases3Call = makeTailRecursiveCall(string_failureCases3);
-#endif
+ move(TrustedImmPtr(&globalData->exceptionLocation), regT2);
+ storePtr(regT1, regT2);
+ poke(callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*));
- // All trampolines constructed! copy the code, link up calls, and set the pointers on the Machine object.
- LinkBuffer patchBuffer(this, m_globalData->executableAllocator.poolForSize(m_assembler.size()));
+ // Set the return address.
+ move(TrustedImmPtr(FunctionPtr(ctiVMThrowTrampoline).value()), regT1);
+ restoreReturnAddressBeforeReturn(regT1);
-#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
- patchBuffer.link(string_failureCases1Call, FunctionPtr(cti_op_get_by_id_string_fail));
- patchBuffer.link(string_failureCases2Call, FunctionPtr(cti_op_get_by_id_string_fail));
- patchBuffer.link(string_failureCases3Call, FunctionPtr(cti_op_get_by_id_string_fail));
-#endif
- patchBuffer.link(callArityCheck1, FunctionPtr(cti_op_call_arityCheck));
- patchBuffer.link(callJSFunction1, FunctionPtr(cti_op_call_JSFunction));
-#if ENABLE(JIT_OPTIMIZE_CALL)
- patchBuffer.link(callArityCheck2, FunctionPtr(cti_op_call_arityCheck));
- patchBuffer.link(callJSFunction2, FunctionPtr(cti_op_call_JSFunction));
- patchBuffer.link(callLazyLinkCall, FunctionPtr(cti_vm_lazyLinkCall));
-#endif
+ ret();
- CodeRef finalCode = patchBuffer.finalizeCode();
- *executablePool = finalCode.m_executablePool;
+ return nativeCallThunk;
+}
- trampolines->ctiVirtualCallLink = trampolineAt(finalCode, virtualCallLinkBegin);
- trampolines->ctiVirtualCall = trampolineAt(finalCode, virtualCallBegin);
- trampolines->ctiNativeCallThunk = adoptRef(new NativeExecutable(JITCode(JITCode::HostFunction(trampolineAt(finalCode, nativeCallThunk)))));
-#if ENABLE(JIT_OPTIMIZE_MOD)
- trampolines->ctiSoftModulo = trampolineAt(finalCode, softModBegin);
-#endif
-#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
- trampolines->ctiStringLengthTrampoline = trampolineAt(finalCode, stringLengthBegin);
-#else
- UNUSED_PARAM(ctiStringLengthTrampoline);
-#endif
+JIT::CodePtr JIT::privateCompileCTINativeCall(PassRefPtr<ExecutablePool>, JSGlobalData* globalData, NativeFunction)
+{
+ return globalData->jitStubs->ctiNativeCall();
}
void JIT::emit_op_mov(Instruction* currentInstruction)
void JIT::emit_op_end(Instruction* currentInstruction)
{
- if (m_codeBlock->needsFullScopeChain())
- JITStubCall(this, cti_op_end).call();
ASSERT(returnValueRegister != callFrameRegister);
emitGetVirtualRegister(currentInstruction[1].u.operand, returnValueRegister);
restoreReturnAddressBeforeReturn(Address(callFrameRegister, RegisterFile::ReturnPC * static_cast<int>(sizeof(Register))));
{
unsigned target = currentInstruction[1].u.operand;
addJump(jump(), target);
- RECORD_JUMP_TARGET(target);
}
void JIT::emit_op_loop_if_lesseq(Instruction* currentInstruction)
if (isOperandConstantImmediateInt(op2)) {
emitGetVirtualRegister(op1, regT0);
emitJumpSlowCaseIfNotImmediateInteger(regT0);
-#if USE(JSVALUE64)
int32_t op2imm = getConstantOperandImmediateInt(op2);
-#else
- int32_t op2imm = static_cast<int32_t>(JSImmediate::rawValue(getConstantOperand(op2)));
-#endif
addJump(branch32(LessThanOrEqual, regT0, Imm32(op2imm)), target);
} else {
emitGetVirtualRegisters(op1, regT0, op2, regT1);
JITStubCall(this, cti_op_new_object).call(currentInstruction[1].u.operand);
}
+void JIT::emit_op_check_has_instance(Instruction* currentInstruction)
+{
+ unsigned baseVal = currentInstruction[1].u.operand;
+
+ emitGetVirtualRegister(baseVal, regT0);
+
+ // Check that baseVal is a cell.
+ emitJumpSlowCaseIfNotJSCell(regT0, baseVal);
+
+ // Check that baseVal 'ImplementsHasInstance'.
+ loadPtr(Address(regT0, JSCell::structureOffset()), regT0);
+ addSlowCase(branchTest8(Zero, Address(regT0, Structure::typeInfoFlagsOffset()), TrustedImm32(ImplementsHasInstance)));
+}
+
void JIT::emit_op_instanceof(Instruction* currentInstruction)
{
unsigned dst = currentInstruction[1].u.operand;
emitGetVirtualRegister(baseVal, regT0);
emitGetVirtualRegister(proto, regT1);
- // Check that baseVal & proto are cells.
+ // Check that proto are cells. baseVal must be a cell - this is checked by op_check_has_instance.
emitJumpSlowCaseIfNotJSCell(regT2, value);
- emitJumpSlowCaseIfNotJSCell(regT0, baseVal);
emitJumpSlowCaseIfNotJSCell(regT1, proto);
+ // Check that prototype is an object
+ loadPtr(Address(regT1, JSCell::structureOffset()), regT3);
+ addSlowCase(branch8(NotEqual, Address(regT3, Structure::typeInfoTypeOffset()), TrustedImm32(ObjectType)));
+
+ // Fixme: this check is only needed because the JSC API allows HasInstance to be overridden; we should deprecate this.
// Check that baseVal 'ImplementsDefaultHasInstance'.
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT0);
- addSlowCase(branchTest8(Zero, Address(regT0, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(ImplementsDefaultHasInstance)));
+ loadPtr(Address(regT0, JSCell::structureOffset()), regT0);
+ addSlowCase(branchTest8(Zero, Address(regT0, Structure::typeInfoFlagsOffset()), TrustedImm32(ImplementsDefaultHasInstance)));
// Optimistically load the result true, and start looping.
// Initially, regT1 still contains proto and regT2 still contains value.
// As we loop regT2 will be updated with its prototype, recursively walking the prototype chain.
- move(ImmPtr(JSValue::encode(jsBoolean(true))), regT0);
+ move(TrustedImmPtr(JSValue::encode(jsBoolean(true))), regT0);
Label loop(this);
// Load the prototype of the object in regT2. If this is equal to regT1 - WIN!
// Otherwise, check if we've hit null - if we have then drop out of the loop, if not go again.
- loadPtr(Address(regT2, OBJECT_OFFSETOF(JSCell, m_structure)), regT2);
- loadPtr(Address(regT2, OBJECT_OFFSETOF(Structure, m_prototype)), regT2);
+ loadPtr(Address(regT2, JSCell::structureOffset()), regT2);
+ loadPtr(Address(regT2, Structure::prototypeOffset()), regT2);
Jump isInstance = branchPtr(Equal, regT2, regT1);
emitJumpIfJSCell(regT2).linkTo(loop, this);
// We get here either by dropping out of the loop, or if value was not an Object. Result is false.
- move(ImmPtr(JSValue::encode(jsBoolean(false))), regT0);
+ move(TrustedImmPtr(JSValue::encode(jsBoolean(false))), regT0);
// isInstance jumps right down to here, to skip setting the result to false (it has already set true).
isInstance.link(this);
emitPutVirtualRegister(dst);
}
-void JIT::emit_op_new_func(Instruction* currentInstruction)
-{
- JITStubCall stubCall(this, cti_op_new_func);
- stubCall.addArgument(ImmPtr(m_codeBlock->functionDecl(currentInstruction[2].u.operand)));
- stubCall.call(currentInstruction[1].u.operand);
-}
-
void JIT::emit_op_call(Instruction* currentInstruction)
{
compileOpCall(op_call, currentInstruction, m_callLinkInfoIndex++);
compileOpCall(op_call_eval, currentInstruction, m_callLinkInfoIndex++);
}
-void JIT::emit_op_load_varargs(Instruction* currentInstruction)
-{
- int argCountDst = currentInstruction[1].u.operand;
- int argsOffset = currentInstruction[2].u.operand;
-
- JITStubCall stubCall(this, cti_op_load_varargs);
- stubCall.addArgument(Imm32(argsOffset));
- stubCall.call();
- // Stores a naked int32 in the register file.
- store32(returnValueRegister, Address(callFrameRegister, argCountDst * sizeof(Register)));
-}
-
void JIT::emit_op_call_varargs(Instruction* currentInstruction)
{
compileOpCallVarargs(currentInstruction);
void JIT::emit_op_get_global_var(Instruction* currentInstruction)
{
- JSVariableObject* globalObject = static_cast<JSVariableObject*>(currentInstruction[2].u.jsCell);
- move(ImmPtr(globalObject), regT0);
- emitGetVariableObjectRegister(regT0, currentInstruction[3].u.operand, regT0);
+ JSVariableObject* globalObject = m_codeBlock->globalObject();
+ loadPtr(&globalObject->m_registers, regT0);
+ loadPtr(Address(regT0, currentInstruction[2].u.operand * sizeof(Register)), regT0);
emitPutVirtualRegister(currentInstruction[1].u.operand);
}
void JIT::emit_op_put_global_var(Instruction* currentInstruction)
{
- emitGetVirtualRegister(currentInstruction[3].u.operand, regT1);
- JSVariableObject* globalObject = static_cast<JSVariableObject*>(currentInstruction[1].u.jsCell);
- move(ImmPtr(globalObject), regT0);
- emitPutVariableObjectRegister(regT1, regT0, currentInstruction[2].u.operand);
+ emitGetVirtualRegister(currentInstruction[2].u.operand, regT1);
+ JSVariableObject* globalObject = m_codeBlock->globalObject();
+ loadPtr(&globalObject->m_registers, regT0);
+ storePtr(regT1, Address(regT0, currentInstruction[1].u.operand * sizeof(Register)));
}
void JIT::emit_op_get_scoped_var(Instruction* currentInstruction)
{
- int skip = currentInstruction[3].u.operand + m_codeBlock->needsFullScopeChain();
+ int skip = currentInstruction[3].u.operand;
emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT0);
+ bool checkTopLevel = m_codeBlock->codeType() == FunctionCode && m_codeBlock->needsFullScopeChain();
+ ASSERT(skip || !checkTopLevel);
+ if (checkTopLevel && skip--) {
+ Jump activationNotCreated;
+ if (checkTopLevel)
+ activationNotCreated = branchTestPtr(Zero, addressFor(m_codeBlock->activationRegister()));
+ loadPtr(Address(regT0, OBJECT_OFFSETOF(ScopeChainNode, next)), regT0);
+ activationNotCreated.link(this);
+ }
while (skip--)
loadPtr(Address(regT0, OBJECT_OFFSETOF(ScopeChainNode, next)), regT0);
loadPtr(Address(regT0, OBJECT_OFFSETOF(ScopeChainNode, object)), regT0);
- emitGetVariableObjectRegister(regT0, currentInstruction[2].u.operand, regT0);
+ loadPtr(Address(regT0, OBJECT_OFFSETOF(JSVariableObject, m_registers)), regT0);
+ loadPtr(Address(regT0, currentInstruction[2].u.operand * sizeof(Register)), regT0);
emitPutVirtualRegister(currentInstruction[1].u.operand);
}
void JIT::emit_op_put_scoped_var(Instruction* currentInstruction)
{
- int skip = currentInstruction[2].u.operand + m_codeBlock->needsFullScopeChain();
+ int skip = currentInstruction[2].u.operand;
emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1);
emitGetVirtualRegister(currentInstruction[3].u.operand, regT0);
+ bool checkTopLevel = m_codeBlock->codeType() == FunctionCode && m_codeBlock->needsFullScopeChain();
+ ASSERT(skip || !checkTopLevel);
+ if (checkTopLevel && skip--) {
+ Jump activationNotCreated;
+ if (checkTopLevel)
+ activationNotCreated = branchTestPtr(Zero, addressFor(m_codeBlock->activationRegister()));
+ loadPtr(Address(regT1, OBJECT_OFFSETOF(ScopeChainNode, next)), regT1);
+ activationNotCreated.link(this);
+ }
while (skip--)
loadPtr(Address(regT1, OBJECT_OFFSETOF(ScopeChainNode, next)), regT1);
loadPtr(Address(regT1, OBJECT_OFFSETOF(ScopeChainNode, object)), regT1);
- emitPutVariableObjectRegister(regT0, regT1, currentInstruction[1].u.operand);
+ loadPtr(Address(regT1, OBJECT_OFFSETOF(JSVariableObject, m_registers)), regT1);
+ storePtr(regT0, Address(regT1, currentInstruction[1].u.operand * sizeof(Register)));
}
void JIT::emit_op_tear_off_activation(Instruction* currentInstruction)
{
+ unsigned activation = currentInstruction[1].u.operand;
+ unsigned arguments = currentInstruction[2].u.operand;
+ Jump activationCreated = branchTestPtr(NonZero, addressFor(activation));
+ Jump argumentsNotCreated = branchTestPtr(Zero, addressFor(arguments));
+ activationCreated.link(this);
JITStubCall stubCall(this, cti_op_tear_off_activation);
- stubCall.addArgument(currentInstruction[1].u.operand, regT2);
+ stubCall.addArgument(activation, regT2);
+ stubCall.addArgument(unmodifiedArgumentsRegister(arguments), regT2);
stubCall.call();
+ argumentsNotCreated.link(this);
}
-void JIT::emit_op_tear_off_arguments(Instruction*)
+void JIT::emit_op_tear_off_arguments(Instruction* currentInstruction)
{
- JITStubCall(this, cti_op_tear_off_arguments).call();
+ unsigned dst = currentInstruction[1].u.operand;
+
+ Jump argsNotCreated = branchTestPtr(Zero, Address(callFrameRegister, sizeof(Register) * (unmodifiedArgumentsRegister(dst))));
+ JITStubCall stubCall(this, cti_op_tear_off_arguments);
+ stubCall.addArgument(unmodifiedArgumentsRegister(dst), regT2);
+ stubCall.call();
+ argsNotCreated.link(this);
}
void JIT::emit_op_ret(Instruction* currentInstruction)
{
- // We could JIT generate the deref, only calling out to C when the refcount hits zero.
- if (m_codeBlock->needsFullScopeChain())
- JITStubCall(this, cti_op_ret_scopeChain).call();
-
ASSERT(callFrameRegister != regT1);
ASSERT(regT1 != returnValueRegister);
ASSERT(returnValueRegister != callFrameRegister);
ret();
}
-void JIT::emit_op_new_array(Instruction* currentInstruction)
+void JIT::emit_op_ret_object_or_this(Instruction* currentInstruction)
{
- JITStubCall stubCall(this, cti_op_new_array);
- stubCall.addArgument(Imm32(currentInstruction[2].u.operand));
- stubCall.addArgument(Imm32(currentInstruction[3].u.operand));
- stubCall.call(currentInstruction[1].u.operand);
+ ASSERT(callFrameRegister != regT1);
+ ASSERT(regT1 != returnValueRegister);
+ ASSERT(returnValueRegister != callFrameRegister);
+
+ // Return the result in %eax.
+ emitGetVirtualRegister(currentInstruction[1].u.operand, returnValueRegister);
+ Jump notJSCell = emitJumpIfNotJSCell(returnValueRegister);
+ loadPtr(Address(returnValueRegister, JSCell::structureOffset()), regT2);
+ Jump notObject = branch8(NotEqual, Address(regT2, Structure::typeInfoTypeOffset()), TrustedImm32(ObjectType));
+
+ // Grab the return address.
+ emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT1);
+
+ // Restore our caller's "r".
+ emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister);
+
+ // Return.
+ restoreReturnAddressBeforeReturn(regT1);
+ ret();
+
+ // Return 'this' in %eax.
+ notJSCell.link(this);
+ notObject.link(this);
+ emitGetVirtualRegister(currentInstruction[2].u.operand, returnValueRegister);
+
+ // Grab the return address.
+ emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT1);
+
+ // Restore our caller's "r".
+ emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister);
+
+ // Return.
+ restoreReturnAddressBeforeReturn(regT1);
+ ret();
}
void JIT::emit_op_resolve(Instruction* currentInstruction)
{
JITStubCall stubCall(this, cti_op_resolve);
- stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
+ stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
stubCall.call(currentInstruction[1].u.operand);
}
-void JIT::emit_op_construct_verify(Instruction* currentInstruction)
-{
- emitGetVirtualRegister(currentInstruction[1].u.operand, regT0);
-
- emitJumpSlowCaseIfNotJSCell(regT0);
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2);
- addSlowCase(branch8(NotEqual, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_type)), Imm32(ObjectType)));
-
-}
-
void JIT::emit_op_to_primitive(Instruction* currentInstruction)
{
int dst = currentInstruction[1].u.operand;
emitGetVirtualRegister(src, regT0);
Jump isImm = emitJumpIfNotJSCell(regT0);
- addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsStringVPtr)));
+ addSlowCase(branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsStringVPtr)));
isImm.link(this);
if (dst != src)
void JIT::emit_op_resolve_base(Instruction* currentInstruction)
{
- JITStubCall stubCall(this, cti_op_resolve_base);
- stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
+ JITStubCall stubCall(this, currentInstruction[3].u.operand ? cti_op_resolve_base_strict_put : cti_op_resolve_base);
+ stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
+ stubCall.call(currentInstruction[1].u.operand);
+}
+
+void JIT::emit_op_ensure_property_exists(Instruction* currentInstruction)
+{
+ JITStubCall stubCall(this, cti_op_ensure_property_exists);
+ stubCall.addArgument(Imm32(currentInstruction[1].u.operand));
+ stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
stubCall.call(currentInstruction[1].u.operand);
}
void JIT::emit_op_resolve_skip(Instruction* currentInstruction)
{
JITStubCall stubCall(this, cti_op_resolve_skip);
- stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
- stubCall.addArgument(Imm32(currentInstruction[3].u.operand + m_codeBlock->needsFullScopeChain()));
+ stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
+ stubCall.addArgument(Imm32(currentInstruction[3].u.operand));
stubCall.call(currentInstruction[1].u.operand);
}
void JIT::emit_op_resolve_global(Instruction* currentInstruction, bool)
{
// Fast case
- void* globalObject = currentInstruction[2].u.jsCell;
+ void* globalObject = m_codeBlock->globalObject();
unsigned currentIndex = m_globalResolveInfoIndex++;
- void* structureAddress = &(m_codeBlock->globalResolveInfo(currentIndex).structure);
- void* offsetAddr = &(m_codeBlock->globalResolveInfo(currentIndex).offset);
+ GlobalResolveInfo* resolveInfoAddress = &(m_codeBlock->globalResolveInfo(currentIndex));
// Check Structure of global object
- move(ImmPtr(globalObject), regT0);
- loadPtr(structureAddress, regT1);
- addSlowCase(branchPtr(NotEqual, regT1, Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)))); // Structures don't match
+ move(TrustedImmPtr(globalObject), regT0);
+ move(TrustedImmPtr(resolveInfoAddress), regT2);
+ loadPtr(Address(regT2, OBJECT_OFFSETOF(GlobalResolveInfo, structure)), regT1);
+ addSlowCase(branchPtr(NotEqual, regT1, Address(regT0, JSCell::structureOffset()))); // Structures don't match
// Load cached property
// Assume that the global object always uses external storage.
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSGlobalObject, m_externalStorage)), regT0);
- load32(offsetAddr, regT1);
+ loadPtr(Address(regT0, OBJECT_OFFSETOF(JSGlobalObject, m_propertyStorage)), regT0);
+ load32(Address(regT2, OBJECT_OFFSETOF(GlobalResolveInfo, offset)), regT1);
loadPtr(BaseIndex(regT0, regT1, ScalePtr), regT0);
emitPutVirtualRegister(currentInstruction[1].u.operand);
}
void JIT::emitSlow_op_resolve_global(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
{
unsigned dst = currentInstruction[1].u.operand;
- void* globalObject = currentInstruction[2].u.jsCell;
- Identifier* ident = &m_codeBlock->identifier(currentInstruction[3].u.operand);
+ Identifier* ident = &m_codeBlock->identifier(currentInstruction[2].u.operand);
unsigned currentIndex = m_globalResolveInfoIndex++;
linkSlowCase(iter);
JITStubCall stubCall(this, cti_op_resolve_global);
- stubCall.addArgument(ImmPtr(globalObject));
- stubCall.addArgument(ImmPtr(ident));
+ stubCall.addArgument(TrustedImmPtr(ident));
stubCall.addArgument(Imm32(currentIndex));
+ stubCall.addArgument(regT0);
stubCall.call(dst);
}
void JIT::emit_op_not(Instruction* currentInstruction)
{
emitGetVirtualRegister(currentInstruction[2].u.operand, regT0);
- xorPtr(Imm32(static_cast<int32_t>(JSImmediate::FullTagTypeBool)), regT0);
- addSlowCase(branchTestPtr(NonZero, regT0, Imm32(static_cast<int32_t>(~JSImmediate::ExtendedPayloadBitBoolValue))));
- xorPtr(Imm32(static_cast<int32_t>(JSImmediate::FullTagTypeBool | JSImmediate::ExtendedPayloadBitBoolValue)), regT0);
+
+ // Invert against JSValue(false); if the value was tagged as a boolean, then all bits will be
+ // clear other than the low bit (which will be 0 or 1 for false or true inputs respectively).
+ // Then invert against JSValue(true), which will add the tag back in, and flip the low bit.
+ xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), regT0);
+ addSlowCase(branchTestPtr(NonZero, regT0, TrustedImm32(static_cast<int32_t>(~1))));
+ xorPtr(TrustedImm32(static_cast<int32_t>(ValueTrue)), regT0);
+
emitPutVirtualRegister(currentInstruction[1].u.operand);
}
unsigned target = currentInstruction[2].u.operand;
emitGetVirtualRegister(currentInstruction[1].u.operand, regT0);
- addJump(branchPtr(Equal, regT0, ImmPtr(JSValue::encode(jsNumber(m_globalData, 0)))), target);
+ addJump(branchPtr(Equal, regT0, TrustedImmPtr(JSValue::encode(jsNumber(0)))), target);
Jump isNonZero = emitJumpIfImmediateInteger(regT0);
- addJump(branchPtr(Equal, regT0, ImmPtr(JSValue::encode(jsBoolean(false)))), target);
- addSlowCase(branchPtr(NotEqual, regT0, ImmPtr(JSValue::encode(jsBoolean(true)))));
+ addJump(branchPtr(Equal, regT0, TrustedImmPtr(JSValue::encode(jsBoolean(false)))), target);
+ addSlowCase(branchPtr(NotEqual, regT0, TrustedImmPtr(JSValue::encode(jsBoolean(true)))));
isNonZero.link(this);
- RECORD_JUMP_TARGET(target);
}
void JIT::emit_op_jeq_null(Instruction* currentInstruction)
Jump isImmediate = emitJumpIfNotJSCell(regT0);
// First, handle JSCell cases - check MasqueradesAsUndefined bit on the structure.
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2);
- addJump(branchTest8(NonZero, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(MasqueradesAsUndefined)), target);
+ loadPtr(Address(regT0, JSCell::structureOffset()), regT2);
+ addJump(branchTest8(NonZero, Address(regT2, Structure::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined)), target);
Jump wasNotImmediate = jump();
// Now handle the immediate cases - undefined & null
isImmediate.link(this);
- andPtr(Imm32(~JSImmediate::ExtendedTagBitUndefined), regT0);
- addJump(branchPtr(Equal, regT0, ImmPtr(JSValue::encode(jsNull()))), target);
+ andPtr(TrustedImm32(~TagBitUndefined), regT0);
+ addJump(branchPtr(Equal, regT0, TrustedImmPtr(JSValue::encode(jsNull()))), target);
wasNotImmediate.link(this);
- RECORD_JUMP_TARGET(target);
};
void JIT::emit_op_jneq_null(Instruction* currentInstruction)
{
Jump isImmediate = emitJumpIfNotJSCell(regT0);
// First, handle JSCell cases - check MasqueradesAsUndefined bit on the structure.
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2);
- addJump(branchTest8(Zero, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(MasqueradesAsUndefined)), target);
+ loadPtr(Address(regT0, JSCell::structureOffset()), regT2);
+ addJump(branchTest8(Zero, Address(regT2, Structure::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined)), target);
Jump wasNotImmediate = jump();
// Now handle the immediate cases - undefined & null
isImmediate.link(this);
- andPtr(Imm32(~JSImmediate::ExtendedTagBitUndefined), regT0);
- addJump(branchPtr(NotEqual, regT0, ImmPtr(JSValue::encode(jsNull()))), target);
+ andPtr(TrustedImm32(~TagBitUndefined), regT0);
+ addJump(branchPtr(NotEqual, regT0, TrustedImmPtr(JSValue::encode(jsNull()))), target);
wasNotImmediate.link(this);
- RECORD_JUMP_TARGET(target);
}
void JIT::emit_op_jneq_ptr(Instruction* currentInstruction)
{
unsigned src = currentInstruction[1].u.operand;
- JSCell* ptr = currentInstruction[2].u.jsCell;
+ JSCell* ptr = currentInstruction[2].u.jsCell.get();
unsigned target = currentInstruction[3].u.operand;
emitGetVirtualRegister(src, regT0);
- addJump(branchPtr(NotEqual, regT0, ImmPtr(JSValue::encode(JSValue(ptr)))), target);
-
- RECORD_JUMP_TARGET(target);
+ addJump(branchPtr(NotEqual, regT0, TrustedImmPtr(JSValue::encode(JSValue(ptr)))), target);
}
void JIT::emit_op_jsr(Instruction* currentInstruction)
{
int retAddrDst = currentInstruction[1].u.operand;
int target = currentInstruction[2].u.operand;
- DataLabelPtr storeLocation = storePtrWithPatch(ImmPtr(0), Address(callFrameRegister, sizeof(Register) * retAddrDst));
+ DataLabelPtr storeLocation = storePtrWithPatch(TrustedImmPtr(0), Address(callFrameRegister, sizeof(Register) * retAddrDst));
addJump(jump(), target);
m_jsrSites.append(JSRInfo(storeLocation, label()));
killLastResultRegister();
- RECORD_JUMP_TARGET(target);
}
void JIT::emit_op_sret(Instruction* currentInstruction)
{
emitGetVirtualRegisters(currentInstruction[2].u.operand, regT0, currentInstruction[3].u.operand, regT1);
emitJumpSlowCaseIfNotImmediateIntegers(regT0, regT1, regT2);
- set32(Equal, regT1, regT0, regT0);
+ compare32(Equal, regT1, regT0, regT0);
emitTagAsBoolImmediate(regT0);
emitPutVirtualRegister(currentInstruction[1].u.operand);
}
{
emitGetVirtualRegister(currentInstruction[2].u.operand, regT0);
emitJumpSlowCaseIfNotImmediateInteger(regT0);
-#if USE(JSVALUE64)
not32(regT0);
emitFastArithIntToImmNoCheck(regT0, regT0);
-#else
- xorPtr(Imm32(~JSImmediate::TagTypeNumber), regT0);
-#endif
emitPutVirtualRegister(currentInstruction[1].u.operand);
}
void JIT::emit_op_resolve_with_base(Instruction* currentInstruction)
{
JITStubCall stubCall(this, cti_op_resolve_with_base);
- stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[3].u.operand)));
+ stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[3].u.operand)));
stubCall.addArgument(Imm32(currentInstruction[1].u.operand));
stubCall.call(currentInstruction[2].u.operand);
}
void JIT::emit_op_new_func_exp(Instruction* currentInstruction)
{
JITStubCall stubCall(this, cti_op_new_func_exp);
- stubCall.addArgument(ImmPtr(m_codeBlock->functionExpr(currentInstruction[2].u.operand)));
+ stubCall.addArgument(TrustedImmPtr(m_codeBlock->functionExpr(currentInstruction[2].u.operand)));
stubCall.call(currentInstruction[1].u.operand);
}
unsigned target = currentInstruction[2].u.operand;
emitGetVirtualRegister(currentInstruction[1].u.operand, regT0);
- Jump isZero = branchPtr(Equal, regT0, ImmPtr(JSValue::encode(jsNumber(m_globalData, 0))));
+ Jump isZero = branchPtr(Equal, regT0, TrustedImmPtr(JSValue::encode(jsNumber(0))));
addJump(emitJumpIfImmediateInteger(regT0), target);
- addJump(branchPtr(Equal, regT0, ImmPtr(JSValue::encode(jsBoolean(true)))), target);
- addSlowCase(branchPtr(NotEqual, regT0, ImmPtr(JSValue::encode(jsBoolean(false)))));
+ addJump(branchPtr(Equal, regT0, TrustedImmPtr(JSValue::encode(jsBoolean(true)))), target);
+ addSlowCase(branchPtr(NotEqual, regT0, TrustedImmPtr(JSValue::encode(jsBoolean(false)))));
isZero.link(this);
- RECORD_JUMP_TARGET(target);
}
void JIT::emit_op_neq(Instruction* currentInstruction)
{
emitGetVirtualRegisters(currentInstruction[2].u.operand, regT0, currentInstruction[3].u.operand, regT1);
emitJumpSlowCaseIfNotImmediateIntegers(regT0, regT1, regT2);
- set32(NotEqual, regT1, regT0, regT0);
+ compare32(NotEqual, regT1, regT0, regT0);
emitTagAsBoolImmediate(regT0);
emitPutVirtualRegister(currentInstruction[1].u.operand);
emitGetVirtualRegister(base, regT0);
if (!m_codeBlock->isKnownNotImmediate(base))
isNotObject.append(emitJumpIfNotJSCell(regT0));
- if (base != m_codeBlock->thisRegister()) {
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2);
- isNotObject.append(branch8(NotEqual, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_type)), Imm32(ObjectType)));
+ if (base != m_codeBlock->thisRegister() || m_codeBlock->isStrictMode()) {
+ loadPtr(Address(regT0, JSCell::structureOffset()), regT2);
+ isNotObject.append(branch8(NotEqual, Address(regT2, Structure::typeInfoTypeOffset()), TrustedImm32(ObjectType)));
}
// We could inline the case where you have a valid cache, but
getPnamesStubCall.addArgument(regT0);
getPnamesStubCall.call(dst);
load32(Address(regT0, OBJECT_OFFSETOF(JSPropertyNameIterator, m_jsStringsSize)), regT3);
- store32(Imm32(0), addressFor(i));
- store32(regT3, addressFor(size));
+ storePtr(tagTypeNumberRegister, payloadFor(i));
+ store32(TrustedImm32(Int32Tag), intTagFor(size));
+ store32(regT3, intPayloadFor(size));
Jump end = jump();
isNotObject.link(this);
move(regT0, regT1);
- and32(Imm32(~JSImmediate::ExtendedTagBitUndefined), regT1);
- addJump(branch32(Equal, regT1, Imm32(JSImmediate::FullTagTypeNull)), breakTarget);
+ and32(TrustedImm32(~TagBitUndefined), regT1);
+ addJump(branch32(Equal, regT1, TrustedImm32(ValueNull)), breakTarget);
JITStubCall toObjectStubCall(this, cti_to_object);
toObjectStubCall.addArgument(regT0);
JumpList callHasProperty;
Label begin(this);
- load32(addressFor(i), regT0);
- Jump end = branch32(Equal, regT0, addressFor(size));
+ load32(intPayloadFor(i), regT0);
+ Jump end = branch32(Equal, regT0, intPayloadFor(size));
// Grab key @ i
loadPtr(addressFor(it), regT1);
loadPtr(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_jsStrings)), regT2);
-#if USE(JSVALUE64)
loadPtr(BaseIndex(regT2, regT0, TimesEight), regT2);
-#else
- loadPtr(BaseIndex(regT2, regT0, TimesFour), regT2);
-#endif
emitPutVirtualRegister(dst, regT2);
// Increment i
- add32(Imm32(1), regT0);
- store32(regT0, addressFor(i));
+ add32(TrustedImm32(1), regT0);
+ store32(regT0, intPayloadFor(i));
// Verify that i is valid:
emitGetVirtualRegister(base, regT0);
// Test base's structure
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2);
+ loadPtr(Address(regT0, JSCell::structureOffset()), regT2);
callHasProperty.append(branchPtr(NotEqual, regT2, Address(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedStructure)))));
// Test base's prototype chain
addJump(branchTestPtr(Zero, Address(regT3)), target);
Label checkPrototype(this);
- loadPtr(Address(regT2, OBJECT_OFFSETOF(Structure, m_prototype)), regT2);
+ loadPtr(Address(regT2, Structure::prototypeOffset()), regT2);
callHasProperty.append(emitJumpIfNotJSCell(regT2));
- loadPtr(Address(regT2, OBJECT_OFFSETOF(JSCell, m_structure)), regT2);
+ loadPtr(Address(regT2, JSCell::structureOffset()), regT2);
callHasProperty.append(branchPtr(NotEqual, regT2, Address(regT3)));
- addPtr(Imm32(sizeof(Structure*)), regT3);
+ addPtr(TrustedImm32(sizeof(Structure*)), regT3);
branchTestPtr(NonZero, Address(regT3)).linkTo(checkPrototype, this);
// Continue loop.
addSlowCase(emitJumpIfImmediateNumber(regT2));
if (type == OpStrictEq)
- set32(Equal, regT1, regT0, regT0);
+ compare32(Equal, regT1, regT0, regT0);
else
- set32(NotEqual, regT1, regT0, regT0);
+ compare32(NotEqual, regT1, regT0, regT0);
emitTagAsBoolImmediate(regT0);
emitPutVirtualRegister(dst);
Jump wasImmediate = emitJumpIfImmediateInteger(regT0);
emitJumpSlowCaseIfNotJSCell(regT0, srcVReg);
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2);
- addSlowCase(branch8(NotEqual, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_type)), Imm32(NumberType)));
+ loadPtr(Address(regT0, JSCell::structureOffset()), regT2);
+ addSlowCase(branch8(NotEqual, Address(regT2, Structure::typeInfoTypeOffset()), TrustedImm32(NumberType)));
wasImmediate.link(this);
void JIT::emit_op_push_new_scope(Instruction* currentInstruction)
{
JITStubCall stubCall(this, cti_op_push_new_scope);
- stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
+ stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
stubCall.addArgument(currentInstruction[3].u.operand, regT2);
stubCall.call(currentInstruction[1].u.operand);
}
void JIT::emit_op_catch(Instruction* currentInstruction)
{
killLastResultRegister(); // FIXME: Implicitly treat op_catch as a labeled statement, and remove this line of code.
- peek(callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof (void*));
+ move(regT0, callFrameRegister);
+ peek(regT3, OBJECT_OFFSETOF(struct JITStackFrame, globalData) / sizeof(void*));
+ loadPtr(Address(regT3, OBJECT_OFFSETOF(JSGlobalData, exception)), regT0);
+ storePtr(TrustedImmPtr(JSValue::encode(JSValue())), Address(regT3, OBJECT_OFFSETOF(JSGlobalData, exception)));
emitPutVirtualRegister(currentInstruction[1].u.operand);
}
stubCall.addArgument(Imm32(currentInstruction[1].u.operand));
stubCall.call();
addJump(jump(), currentInstruction[2].u.operand);
- RECORD_JUMP_TARGET(currentInstruction[2].u.operand);
}
void JIT::emit_op_switch_imm(Instruction* currentInstruction)
// create jump table for switch destinations, track this switch statement.
SimpleJumpTable* jumpTable = &m_codeBlock->immediateSwitchJumpTable(tableIndex);
- m_switches.append(SwitchRecord(jumpTable, m_bytecodeIndex, defaultOffset, SwitchRecord::Immediate));
+ m_switches.append(SwitchRecord(jumpTable, m_bytecodeOffset, defaultOffset, SwitchRecord::Immediate));
jumpTable->ctiOffsets.grow(jumpTable->branchOffsets.size());
JITStubCall stubCall(this, cti_op_switch_imm);
// create jump table for switch destinations, track this switch statement.
SimpleJumpTable* jumpTable = &m_codeBlock->characterSwitchJumpTable(tableIndex);
- m_switches.append(SwitchRecord(jumpTable, m_bytecodeIndex, defaultOffset, SwitchRecord::Character));
+ m_switches.append(SwitchRecord(jumpTable, m_bytecodeOffset, defaultOffset, SwitchRecord::Character));
jumpTable->ctiOffsets.grow(jumpTable->branchOffsets.size());
JITStubCall stubCall(this, cti_op_switch_char);
// create jump table for switch destinations, track this switch statement.
StringJumpTable* jumpTable = &m_codeBlock->stringSwitchJumpTable(tableIndex);
- m_switches.append(SwitchRecord(jumpTable, m_bytecodeIndex, defaultOffset));
+ m_switches.append(SwitchRecord(jumpTable, m_bytecodeOffset, defaultOffset));
JITStubCall stubCall(this, cti_op_switch_string);
stubCall.addArgument(scrutinee, regT2);
jump(regT0);
}
-void JIT::emit_op_new_error(Instruction* currentInstruction)
+void JIT::emit_op_throw_reference_error(Instruction* currentInstruction)
{
- JITStubCall stubCall(this, cti_op_new_error);
- stubCall.addArgument(Imm32(currentInstruction[2].u.operand));
- stubCall.addArgument(ImmPtr(JSValue::encode(m_codeBlock->getConstant(currentInstruction[3].u.operand))));
- stubCall.addArgument(Imm32(m_bytecodeIndex));
- stubCall.call(currentInstruction[1].u.operand);
+ JITStubCall stubCall(this, cti_op_throw_reference_error);
+ stubCall.addArgument(ImmPtr(JSValue::encode(m_codeBlock->getConstant(currentInstruction[1].u.operand))));
+ stubCall.call();
}
void JIT::emit_op_debug(Instruction* currentInstruction)
emitGetVirtualRegister(src1, regT0);
Jump isImmediate = emitJumpIfNotJSCell(regT0);
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2);
- setTest8(NonZero, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(MasqueradesAsUndefined), regT0);
+ loadPtr(Address(regT0, JSCell::structureOffset()), regT2);
+ test8(NonZero, Address(regT2, Structure::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined), regT0);
Jump wasNotImmediate = jump();
isImmediate.link(this);
- andPtr(Imm32(~JSImmediate::ExtendedTagBitUndefined), regT0);
- setPtr(Equal, regT0, Imm32(JSImmediate::FullTagTypeNull), regT0);
+ andPtr(TrustedImm32(~TagBitUndefined), regT0);
+ comparePtr(Equal, regT0, TrustedImm32(ValueNull), regT0);
wasNotImmediate.link(this);
emitGetVirtualRegister(src1, regT0);
Jump isImmediate = emitJumpIfNotJSCell(regT0);
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2);
- setTest8(Zero, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(MasqueradesAsUndefined), regT0);
+ loadPtr(Address(regT0, JSCell::structureOffset()), regT2);
+ test8(Zero, Address(regT2, Structure::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined), regT0);
Jump wasNotImmediate = jump();
isImmediate.link(this);
- andPtr(Imm32(~JSImmediate::ExtendedTagBitUndefined), regT0);
- setPtr(NotEqual, regT0, Imm32(JSImmediate::FullTagTypeNull), regT0);
+ andPtr(TrustedImm32(~TagBitUndefined), regT0);
+ comparePtr(NotEqual, regT0, TrustedImm32(ValueNull), regT0);
wasNotImmediate.link(this);
emitTagAsBoolImmediate(regT0);
emitPutVirtualRegister(dst);
-
}
void JIT::emit_op_enter(Instruction*)
}
-void JIT::emit_op_enter_with_activation(Instruction* currentInstruction)
+void JIT::emit_op_create_activation(Instruction* currentInstruction)
{
- // Even though CTI doesn't use them, we initialize our constant
- // registers to zap stale pointers, to avoid unnecessarily prolonging
- // object lifetime and increasing GC pressure.
- size_t count = m_codeBlock->m_numVars;
- for (size_t j = 0; j < count; ++j)
- emitInitRegister(j);
-
+ unsigned dst = currentInstruction[1].u.operand;
+
+ Jump activationCreated = branchTestPtr(NonZero, Address(callFrameRegister, sizeof(Register) * dst));
JITStubCall(this, cti_op_push_activation).call(currentInstruction[1].u.operand);
+ emitPutVirtualRegister(dst);
+ activationCreated.link(this);
}
-void JIT::emit_op_create_arguments(Instruction*)
+void JIT::emit_op_create_arguments(Instruction* currentInstruction)
{
- Jump argsCreated = branchTestPtr(NonZero, Address(callFrameRegister, sizeof(Register) * RegisterFile::ArgumentsRegister));
+ unsigned dst = currentInstruction[1].u.operand;
+
+ Jump argsCreated = branchTestPtr(NonZero, Address(callFrameRegister, sizeof(Register) * dst));
if (m_codeBlock->m_numParameters == 1)
JITStubCall(this, cti_op_create_arguments_no_params).call();
else
JITStubCall(this, cti_op_create_arguments).call();
+ emitPutVirtualRegister(dst);
+ emitPutVirtualRegister(unmodifiedArgumentsRegister(dst));
argsCreated.link(this);
}
-
-void JIT::emit_op_init_arguments(Instruction*)
+
+void JIT::emit_op_init_lazy_reg(Instruction* currentInstruction)
{
- storePtr(ImmPtr(0), Address(callFrameRegister, sizeof(Register) * RegisterFile::ArgumentsRegister));
+ unsigned dst = currentInstruction[1].u.operand;
+
+ storePtr(TrustedImmPtr(0), Address(callFrameRegister, sizeof(Register) * dst));
}
void JIT::emit_op_convert_this(Instruction* currentInstruction)
emitGetVirtualRegister(currentInstruction[1].u.operand, regT0);
emitJumpSlowCaseIfNotJSCell(regT0);
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT1);
- addSlowCase(branchTest8(NonZero, Address(regT1, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(NeedsThisConversion)));
+ loadPtr(Address(regT0, JSCell::structureOffset()), regT1);
+ addSlowCase(branchTest8(NonZero, Address(regT1, Structure::typeInfoFlagsOffset()), TrustedImm32(NeedsThisConversion)));
+}
+void JIT::emit_op_convert_this_strict(Instruction* currentInstruction)
+{
+ emitGetVirtualRegister(currentInstruction[1].u.operand, regT0);
+ Jump notNull = branchTestPtr(NonZero, regT0);
+ move(TrustedImmPtr(JSValue::encode(jsNull())), regT0);
+ emitPutVirtualRegister(currentInstruction[1].u.operand, regT0);
+ Jump setThis = jump();
+ notNull.link(this);
+ Jump isImmediate = emitJumpIfNotJSCell(regT0);
+ loadPtr(Address(regT0, JSCell::structureOffset()), regT1);
+ Jump notAnObject = branch8(NotEqual, Address(regT1, Structure::typeInfoTypeOffset()), TrustedImm32(ObjectType));
+ addSlowCase(branchTest8(NonZero, Address(regT1, Structure::typeInfoFlagsOffset()), TrustedImm32(NeedsThisConversion)));
+ isImmediate.link(this);
+ notAnObject.link(this);
+ setThis.link(this);
+}
+
+void JIT::emit_op_get_callee(Instruction* currentInstruction)
+{
+ unsigned result = currentInstruction[1].u.operand;
+ emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT0);
+ emitPutVirtualRegister(result);
+}
+
+void JIT::emit_op_create_this(Instruction* currentInstruction)
+{
+ JITStubCall stubCall(this, cti_op_create_this);
+ stubCall.addArgument(currentInstruction[2].u.operand, regT1);
+ stubCall.call(currentInstruction[1].u.operand);
}
void JIT::emit_op_profile_will_call(Instruction* currentInstruction)
{
- peek(regT1, OBJECT_OFFSETOF(JITStackFrame, enabledProfilerReference) / sizeof (void*));
+ peek(regT1, OBJECT_OFFSETOF(JITStackFrame, enabledProfilerReference) / sizeof(void*));
Jump noProfiler = branchTestPtr(Zero, Address(regT1));
JITStubCall stubCall(this, cti_op_profile_will_call);
void JIT::emit_op_profile_did_call(Instruction* currentInstruction)
{
- peek(regT1, OBJECT_OFFSETOF(JITStackFrame, enabledProfilerReference) / sizeof (void*));
+ peek(regT1, OBJECT_OFFSETOF(JITStackFrame, enabledProfilerReference) / sizeof(void*));
Jump noProfiler = branchTestPtr(Zero, Address(regT1));
JITStubCall stubCall(this, cti_op_profile_did_call);
stubCall.call(currentInstruction[1].u.operand);
}
-void JIT::emitSlow_op_construct_verify(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+void JIT::emitSlow_op_convert_this_strict(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
{
linkSlowCase(iter);
- linkSlowCase(iter);
- emitGetVirtualRegister(currentInstruction[2].u.operand, regT0);
- emitPutVirtualRegister(currentInstruction[1].u.operand);
+ JITStubCall stubCall(this, cti_op_convert_this_strict);
+ stubCall.addArgument(regT0);
+ stubCall.call(currentInstruction[1].u.operand);
}
void JIT::emitSlow_op_to_primitive(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
void JIT::emitSlow_op_not(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
{
linkSlowCase(iter);
- xorPtr(Imm32(static_cast<int32_t>(JSImmediate::FullTagTypeBool)), regT0);
+ xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), regT0);
JITStubCall stubCall(this, cti_op_not);
stubCall.addArgument(regT0);
stubCall.call(currentInstruction[1].u.operand);
stubCall.addArgument(regT0);
stubCall.addArgument(regT1);
stubCall.call();
- xor32(Imm32(0x1), regT0);
+ xor32(TrustedImm32(0x1), regT0);
emitTagAsBoolImmediate(regT0);
emitPutVirtualRegister(currentInstruction[1].u.operand);
}
stubCall.call(currentInstruction[1].u.operand);
}
+void JIT::emitSlow_op_check_has_instance(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+ unsigned baseVal = currentInstruction[1].u.operand;
+
+ linkSlowCaseIfNotJSCell(iter, baseVal);
+ linkSlowCase(iter);
+ JITStubCall stubCall(this, cti_op_check_has_instance);
+ stubCall.addArgument(baseVal, regT2);
+ stubCall.call();
+}
+
void JIT::emitSlow_op_instanceof(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
{
unsigned dst = currentInstruction[1].u.operand;
unsigned proto = currentInstruction[4].u.operand;
linkSlowCaseIfNotJSCell(iter, value);
- linkSlowCaseIfNotJSCell(iter, baseVal);
linkSlowCaseIfNotJSCell(iter, proto);
linkSlowCase(iter);
+ linkSlowCase(iter);
JITStubCall stubCall(this, cti_op_instanceof);
stubCall.addArgument(value, regT2);
stubCall.addArgument(baseVal, regT2);
stubCall.call(currentInstruction[1].u.operand);
}
-#endif // !USE(JSVALUE32_64)
+void JIT::emit_op_get_arguments_length(Instruction* currentInstruction)
+{
+ int dst = currentInstruction[1].u.operand;
+ int argumentsRegister = currentInstruction[2].u.operand;
+ addSlowCase(branchTestPtr(NonZero, addressFor(argumentsRegister)));
+ emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT0);
+ sub32(TrustedImm32(1), regT0);
+ emitFastArithReTagImmediate(regT0, regT0);
+ emitPutVirtualRegister(dst, regT0);
+}
+
+void JIT::emitSlow_op_get_arguments_length(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+ linkSlowCase(iter);
+ unsigned dst = currentInstruction[1].u.operand;
+ unsigned base = currentInstruction[2].u.operand;
+ Identifier* ident = &(m_codeBlock->identifier(currentInstruction[3].u.operand));
+
+ emitGetVirtualRegister(base, regT0);
+ JITStubCall stubCall(this, cti_op_get_by_id_generic);
+ stubCall.addArgument(regT0);
+ stubCall.addArgument(TrustedImmPtr(ident));
+ stubCall.call(dst);
+}
+
+void JIT::emit_op_get_argument_by_val(Instruction* currentInstruction)
+{
+ int dst = currentInstruction[1].u.operand;
+ int argumentsRegister = currentInstruction[2].u.operand;
+ int property = currentInstruction[3].u.operand;
+ addSlowCase(branchTestPtr(NonZero, addressFor(argumentsRegister)));
+ emitGetVirtualRegister(property, regT1);
+ addSlowCase(emitJumpIfNotImmediateInteger(regT1));
+ add32(TrustedImm32(1), regT1);
+ // regT1 now contains the integer index of the argument we want, including this
+ emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT2);
+ addSlowCase(branch32(AboveOrEqual, regT1, regT2));
+
+ Jump skipOutofLineParams;
+ int numArgs = m_codeBlock->m_numParameters;
+ if (numArgs) {
+ Jump notInInPlaceArgs = branch32(AboveOrEqual, regT1, Imm32(numArgs));
+ addPtr(Imm32(static_cast<unsigned>(-(RegisterFile::CallFrameHeaderSize + numArgs) * sizeof(Register))), callFrameRegister, regT0);
+ loadPtr(BaseIndex(regT0, regT1, TimesEight, 0), regT0);
+ skipOutofLineParams = jump();
+ notInInPlaceArgs.link(this);
+ }
+
+ addPtr(Imm32(static_cast<unsigned>(-(RegisterFile::CallFrameHeaderSize + numArgs) * sizeof(Register))), callFrameRegister, regT0);
+ mul32(TrustedImm32(sizeof(Register)), regT2, regT2);
+ subPtr(regT2, regT0);
+ loadPtr(BaseIndex(regT0, regT1, TimesEight, 0), regT0);
+ if (numArgs)
+ skipOutofLineParams.link(this);
+ emitPutVirtualRegister(dst, regT0);
+}
+
+void JIT::emitSlow_op_get_argument_by_val(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+ unsigned dst = currentInstruction[1].u.operand;
+ unsigned arguments = currentInstruction[2].u.operand;
+ unsigned property = currentInstruction[3].u.operand;
+
+ linkSlowCase(iter);
+ Jump skipArgumentsCreation = jump();
+
+ linkSlowCase(iter);
+ linkSlowCase(iter);
+ if (m_codeBlock->m_numParameters == 1)
+ JITStubCall(this, cti_op_create_arguments_no_params).call();
+ else
+ JITStubCall(this, cti_op_create_arguments).call();
+ emitPutVirtualRegister(arguments);
+ emitPutVirtualRegister(unmodifiedArgumentsRegister(arguments));
+
+ skipArgumentsCreation.link(this);
+ JITStubCall stubCall(this, cti_op_get_by_val);
+ stubCall.addArgument(arguments, regT2);
+ stubCall.addArgument(property, regT2);
+ stubCall.call(dst);
+}
+
+#endif // USE(JSVALUE64)
void JIT::emit_op_resolve_global_dynamic(Instruction* currentInstruction)
{
- int skip = currentInstruction[6].u.operand + m_codeBlock->needsFullScopeChain();
+ int skip = currentInstruction[5].u.operand;
emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT0);
+
+ bool checkTopLevel = m_codeBlock->codeType() == FunctionCode && m_codeBlock->needsFullScopeChain();
+ ASSERT(skip || !checkTopLevel);
+ if (checkTopLevel && skip--) {
+ Jump activationNotCreated;
+ if (checkTopLevel)
+ activationNotCreated = branchTestPtr(Zero, addressFor(m_codeBlock->activationRegister()));
+ loadPtr(Address(regT0, OBJECT_OFFSETOF(ScopeChainNode, object)), regT1);
+ addSlowCase(checkStructure(regT1, m_globalData->activationStructure.get()));
+ loadPtr(Address(regT0, OBJECT_OFFSETOF(ScopeChainNode, next)), regT0);
+ activationNotCreated.link(this);
+ }
while (skip--) {
loadPtr(Address(regT0, OBJECT_OFFSETOF(ScopeChainNode, object)), regT1);
addSlowCase(checkStructure(regT1, m_globalData->activationStructure.get()));
void JIT::emitSlow_op_resolve_global_dynamic(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
{
unsigned dst = currentInstruction[1].u.operand;
- void* globalObject = currentInstruction[2].u.jsCell;
- Identifier* ident = &m_codeBlock->identifier(currentInstruction[3].u.operand);
- int skip = currentInstruction[6].u.operand + m_codeBlock->needsFullScopeChain();
+ Identifier* ident = &m_codeBlock->identifier(currentInstruction[2].u.operand);
+ int skip = currentInstruction[5].u.operand;
while (skip--)
linkSlowCase(iter);
JITStubCall resolveStubCall(this, cti_op_resolve);
- resolveStubCall.addArgument(ImmPtr(ident));
+ resolveStubCall.addArgument(TrustedImmPtr(ident));
resolveStubCall.call(dst);
emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_resolve_global_dynamic));
linkSlowCase(iter); // We managed to skip all the nodes in the scope chain, but the cache missed.
JITStubCall stubCall(this, cti_op_resolve_global);
- stubCall.addArgument(ImmPtr(globalObject));
- stubCall.addArgument(ImmPtr(ident));
+ stubCall.addArgument(TrustedImmPtr(ident));
stubCall.addArgument(Imm32(currentIndex));
+ stubCall.addArgument(regT0);
stubCall.call(dst);
}
void JIT::emit_op_new_regexp(Instruction* currentInstruction)
{
JITStubCall stubCall(this, cti_op_new_regexp);
- stubCall.addArgument(ImmPtr(m_codeBlock->regexp(currentInstruction[2].u.operand)));
+ stubCall.addArgument(TrustedImmPtr(m_codeBlock->regexp(currentInstruction[2].u.operand)));
stubCall.call(currentInstruction[1].u.operand);
}
-// For both JSValue32_64 and JSValue32
-#if ENABLE(JIT_OPTIMIZE_MOD)
-#if CPU(ARM_TRADITIONAL)
-void JIT::softModulo()
+void JIT::emit_op_load_varargs(Instruction* currentInstruction)
{
- push(regS0);
- push(regS1);
- push(regT1);
- push(regT3);
+ int argCountDst = currentInstruction[1].u.operand;
+ int argsOffset = currentInstruction[2].u.operand;
+ int registerOffset = currentInstruction[3].u.operand;
+ ASSERT(argsOffset <= registerOffset);
+
+ int expectedParams = m_codeBlock->m_numParameters - 1;
+ // Don't do inline copying if we aren't guaranteed to have a single stream
+ // of arguments
+ if (expectedParams) {
+ JITStubCall stubCall(this, cti_op_load_varargs);
+ stubCall.addArgument(Imm32(argsOffset));
+ stubCall.call();
+ // Stores a naked int32 in the register file.
+ store32(returnValueRegister, Address(callFrameRegister, argCountDst * sizeof(Register)));
+ return;
+ }
+
#if USE(JSVALUE32_64)
- m_assembler.mov_r(regT3, regT2);
- m_assembler.mov_r(regT2, regT0);
+ addSlowCase(branch32(NotEqual, tagFor(argsOffset), TrustedImm32(JSValue::EmptyValueTag)));
#else
- m_assembler.mov_r(regT3, m_assembler.asr(regT2, 1));
- m_assembler.mov_r(regT2, m_assembler.asr(regT0, 1));
+ addSlowCase(branchTestPtr(NonZero, addressFor(argsOffset)));
#endif
- m_assembler.mov_r(regT1, ARMAssembler::getOp2(0));
-
- m_assembler.teq_r(regT3, ARMAssembler::getOp2(0));
- m_assembler.rsb_r(regT3, regT3, ARMAssembler::getOp2(0), ARMAssembler::MI);
- m_assembler.eor_r(regT1, regT1, ARMAssembler::getOp2(1), ARMAssembler::MI);
-
- m_assembler.teq_r(regT2, ARMAssembler::getOp2(0));
- m_assembler.rsb_r(regT2, regT2, ARMAssembler::getOp2(0), ARMAssembler::MI);
- m_assembler.eor_r(regT1, regT1, ARMAssembler::getOp2(2), ARMAssembler::MI);
+ // Load arg count into regT0
+ emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT0);
+ store32(TrustedImm32(Int32Tag), intTagFor(argCountDst));
+ store32(regT0, intPayloadFor(argCountDst));
+ Jump endBranch = branch32(Equal, regT0, TrustedImm32(1));
+
+ mul32(TrustedImm32(sizeof(Register)), regT0, regT3);
+ addPtr(TrustedImm32(static_cast<unsigned>(sizeof(Register) - RegisterFile::CallFrameHeaderSize * sizeof(Register))), callFrameRegister, regT1);
+ subPtr(regT3, regT1); // regT1 is now the start of the out of line arguments
+ addPtr(Imm32(argsOffset * sizeof(Register)), callFrameRegister, regT2); // regT2 is the target buffer
- Jump exitBranch = branch32(LessThan, regT2, regT3);
+ // Bounds check the registerfile
+ addPtr(regT2, regT3);
+ addPtr(Imm32((registerOffset - argsOffset) * sizeof(Register)), regT3);
+ addSlowCase(branchPtr(Below, AbsoluteAddress(m_globalData->interpreter->registerFile().addressOfEnd()), regT3));
+
+ sub32(TrustedImm32(1), regT0);
+ Label loopStart = label();
+ loadPtr(BaseIndex(regT1, regT0, TimesEight, static_cast<unsigned>(0 - 2 * sizeof(Register))), regT3);
+ storePtr(regT3, BaseIndex(regT2, regT0, TimesEight, static_cast<unsigned>(0 - sizeof(Register))));
+#if USE(JSVALUE32_64)
+ loadPtr(BaseIndex(regT1, regT0, TimesEight, static_cast<unsigned>(sizeof(void*) - 2 * sizeof(Register))), regT3);
+ storePtr(regT3, BaseIndex(regT2, regT0, TimesEight, static_cast<unsigned>(sizeof(void*) - sizeof(Register))));
+#endif
+ branchSubPtr(NonZero, TrustedImm32(1), regT0).linkTo(loopStart, this);
+ endBranch.link(this);
+}
- m_assembler.sub_r(regS1, regT3, ARMAssembler::getOp2(1));
- m_assembler.tst_r(regS1, regT3);
- m_assembler.and_r(regT2, regT2, regS1, ARMAssembler::EQ);
- m_assembler.and_r(regT0, regS1, regT3);
- Jump exitBranch2 = branchTest32(Zero, regT0);
+void JIT::emitSlow_op_load_varargs(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+ int argCountDst = currentInstruction[1].u.operand;
+ int argsOffset = currentInstruction[2].u.operand;
+ int expectedParams = m_codeBlock->m_numParameters - 1;
+ if (expectedParams)
+ return;
- m_assembler.clz_r(regS1, regT2);
- m_assembler.clz_r(regS0, regT3);
- m_assembler.sub_r(regS0, regS0, regS1);
-
- m_assembler.rsbs_r(regS0, regS0, ARMAssembler::getOp2(31));
-
- m_assembler.mov_r(regS0, m_assembler.lsl(regS0, 1), ARMAssembler::NE);
-
- m_assembler.add_r(ARMRegisters::pc, ARMRegisters::pc, m_assembler.lsl(regS0, 2), ARMAssembler::NE);
- m_assembler.mov_r(regT0, regT0);
+ linkSlowCase(iter);
+ linkSlowCase(iter);
+ JITStubCall stubCall(this, cti_op_load_varargs);
+ stubCall.addArgument(Imm32(argsOffset));
+ stubCall.call();
- for (int i = 31; i > 0; --i) {
- m_assembler.cmp_r(regT2, m_assembler.lsl(regT3, i));
- m_assembler.sub_r(regT2, regT2, m_assembler.lsl(regT3, i), ARMAssembler::CS);
- }
+ store32(TrustedImm32(Int32Tag), intTagFor(argCountDst));
+ store32(returnValueRegister, intPayloadFor(argCountDst));
+}
- m_assembler.cmp_r(regT2, regT3);
- m_assembler.sub_r(regT2, regT2, regT3, ARMAssembler::CS);
-
- exitBranch.link(this);
- exitBranch2.link(this);
-
- m_assembler.teq_r(regT1, ARMAssembler::getOp2(0));
- m_assembler.rsb_r(regT2, regT2, ARMAssembler::getOp2(0), ARMAssembler::GT);
-
+void JIT::emit_op_new_func(Instruction* currentInstruction)
+{
+ Jump lazyJump;
+ int dst = currentInstruction[1].u.operand;
+ if (currentInstruction[3].u.operand) {
#if USE(JSVALUE32_64)
- m_assembler.mov_r(regT0, regT2);
+ lazyJump = branch32(NotEqual, tagFor(dst), TrustedImm32(JSValue::EmptyValueTag));
#else
- m_assembler.mov_r(regT0, m_assembler.lsl(regT2, 1));
- m_assembler.eor_r(regT0, regT0, ARMAssembler::getOp2(1));
+ lazyJump = branchTestPtr(NonZero, addressFor(dst));
#endif
- pop(regT3);
- pop(regT1);
- pop(regS1);
- pop(regS0);
- ret();
+ }
+ JITStubCall stubCall(this, cti_op_new_func);
+ stubCall.addArgument(TrustedImmPtr(m_codeBlock->functionDecl(currentInstruction[2].u.operand)));
+ stubCall.call(currentInstruction[1].u.operand);
+ if (currentInstruction[3].u.operand)
+ lazyJump.link(this);
}
-#else
-#error "JIT_OPTIMIZE_MOD not yet supported on this platform."
-#endif // CPU(ARM_TRADITIONAL)
-#endif
+
+void JIT::emit_op_new_array(Instruction* currentInstruction)
+{
+ JITStubCall stubCall(this, cti_op_new_array);
+ stubCall.addArgument(Imm32(currentInstruction[2].u.operand));
+ stubCall.addArgument(Imm32(currentInstruction[3].u.operand));
+ stubCall.call(currentInstruction[1].u.operand);
+}
+
+void JIT::emit_op_new_array_buffer(Instruction* currentInstruction)
+{
+ JITStubCall stubCall(this, cti_op_new_array_buffer);
+ stubCall.addArgument(Imm32(currentInstruction[2].u.operand));
+ stubCall.addArgument(Imm32(currentInstruction[3].u.operand));
+ stubCall.call(currentInstruction[1].u.operand);
+}
+
} // namespace JSC
#endif // ENABLE(JIT)
*/
#include "config.h"
-#include "JIT.h"
-#if ENABLE(JIT) && USE(JSVALUE32_64)
+#if ENABLE(JIT)
+#if USE(JSVALUE32_64)
+#include "JIT.h"
#include "JITInlineMethods.h"
#include "JITStubCall.h"
void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executablePool, JSGlobalData* globalData, TrampolineStructure *trampolines)
{
-#if ENABLE(JIT_OPTIMIZE_MOD)
+#if ENABLE(JIT_USE_SOFT_MODULO)
Label softModBegin = align();
softModulo();
#endif
// regT0 holds payload, regT1 holds tag
- Jump string_failureCases1 = branch32(NotEqual, regT1, Imm32(JSValue::CellTag));
- Jump string_failureCases2 = branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsStringVPtr));
+ Jump string_failureCases1 = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag));
+ Jump string_failureCases2 = branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsStringVPtr));
// Checks out okay! - get the length from the Ustring.
load32(Address(regT0, OBJECT_OFFSETOF(JSString, m_length)), regT2);
- Jump string_failureCases3 = branch32(Above, regT2, Imm32(INT_MAX));
+ Jump string_failureCases3 = branch32(Above, regT2, TrustedImm32(INT_MAX));
move(regT2, regT0);
- move(Imm32(JSValue::Int32Tag), regT1);
+ move(TrustedImm32(JSValue::Int32Tag), regT1);
ret();
#endif
-
+
+ JumpList callLinkFailures;
// (2) Trampolines for the slow cases of op_call / op_call_eval / op_construct.
-
#if ENABLE(JIT_OPTIMIZE_CALL)
// VirtualCallLink Trampoline
// regT0 holds callee, regT1 holds argCount. regT2 will hold the FunctionExecutable.
Label virtualCallLinkBegin = align();
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
-
- Jump isNativeFunc2 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), Imm32(0));
-
- Jump hasCodeBlock2 = branch32(GreaterThan, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), Imm32(0));
- preserveReturnAddressAfterCall(regT3);
- restoreArgumentReference();
- Call callJSFunction2 = call();
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
- emitGetJITStubArg(2, regT1); // argCount
- restoreReturnAddressBeforeReturn(regT3);
- hasCodeBlock2.link(this);
-
- // Check argCount matches callee arity.
- Jump arityCheckOkay2 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), regT1);
+ compileOpCallInitializeCallFrame();
preserveReturnAddressAfterCall(regT3);
- emitPutJITStubArg(regT3, 1); // return address
+ emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
restoreArgumentReference();
- Call callArityCheck2 = call();
- move(regT1, callFrameRegister);
- emitGetJITStubArg(2, regT1); // argCount
+ Call callLazyLinkCall = call();
+ callLinkFailures.append(branchTestPtr(Zero, regT0));
restoreReturnAddressBeforeReturn(regT3);
- arityCheckOkay2.link(this);
-
- isNativeFunc2.link(this);
+ emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1);
+ jump(regT0);
+ // VirtualConstructLink Trampoline
+ // regT0 holds callee, regT1 holds argCount. regT2 will hold the FunctionExecutable.
+ Label virtualConstructLinkBegin = align();
compileOpCallInitializeCallFrame();
-
preserveReturnAddressAfterCall(regT3);
- emitPutJITStubArg(regT3, 1); // return address
+ emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
restoreArgumentReference();
- Call callLazyLinkCall = call();
+ Call callLazyLinkConstruct = call();
restoreReturnAddressBeforeReturn(regT3);
+ callLinkFailures.append(branchTestPtr(Zero, regT0));
+ emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1);
jump(regT0);
+
#endif // ENABLE(JIT_OPTIMIZE_CALL)
// VirtualCall Trampoline
// regT0 holds callee, regT1 holds argCount. regT2 will hold the FunctionExecutable.
Label virtualCallBegin = align();
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
+ compileOpCallInitializeCallFrame();
- Jump isNativeFunc3 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), Imm32(0));
+ loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
- Jump hasCodeBlock3 = branch32(GreaterThan, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), Imm32(0));
+ Jump hasCodeBlock3 = branch32(GreaterThanOrEqual, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), TrustedImm32(0));
preserveReturnAddressAfterCall(regT3);
restoreArgumentReference();
- Call callJSFunction1 = call();
- emitGetJITStubArg(2, regT1); // argCount
+ Call callCompileCall = call();
+ callLinkFailures.append(branchTestPtr(Zero, regT0));
+ emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1);
restoreReturnAddressBeforeReturn(regT3);
loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
hasCodeBlock3.link(this);
- // Check argCount matches callee arity.
- Jump arityCheckOkay3 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), regT1);
+ loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCodeForCallWithArityCheck)), regT0);
+ jump(regT0);
+
+ // VirtualConstruct Trampoline
+ // regT0 holds callee, regT1 holds argCount. regT2 will hold the FunctionExecutable.
+ Label virtualConstructBegin = align();
+ compileOpCallInitializeCallFrame();
+
+ loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
+
+ Jump hasCodeBlock4 = branch32(GreaterThanOrEqual, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), TrustedImm32(0));
preserveReturnAddressAfterCall(regT3);
- emitPutJITStubArg(regT3, 1); // return address
restoreArgumentReference();
- Call callArityCheck1 = call();
- move(regT1, callFrameRegister);
- emitGetJITStubArg(2, regT1); // argCount
+ Call callCompileCconstruct = call();
+ callLinkFailures.append(branchTestPtr(Zero, regT0));
+ emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1);
restoreReturnAddressBeforeReturn(regT3);
loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
- arityCheckOkay3.link(this);
-
- isNativeFunc3.link(this);
+ hasCodeBlock4.link(this);
- compileOpCallInitializeCallFrame();
- loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCode)), regT0);
+ loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCodeForConstructWithArityCheck)), regT0);
jump(regT0);
+
+ // If the parser fails we want to be able to be able to keep going,
+ // So we handle this as a parse failure.
+ callLinkFailures.link(this);
+ emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT1);
+ emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister);
+ restoreReturnAddressBeforeReturn(regT1);
+ move(TrustedImmPtr(&globalData->exceptionLocation), regT2);
+ storePtr(regT1, regT2);
+ poke(callFrameRegister, 1 + OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*));
+ poke(TrustedImmPtr(FunctionPtr(ctiVMThrowTrampoline).value()));
+ ret();
+
+ // NativeCall Trampoline
+ Label nativeCallThunk = privateCompileCTINativeCall(globalData);
+ Label nativeConstructThunk = privateCompileCTINativeCall(globalData, true);
+
+#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
+ Call string_failureCases1Call = makeTailRecursiveCall(string_failureCases1);
+ Call string_failureCases2Call = makeTailRecursiveCall(string_failureCases2);
+ Call string_failureCases3Call = makeTailRecursiveCall(string_failureCases3);
+#endif
+
+ // All trampolines constructed! copy the code, link up calls, and set the pointers on the Machine object.
+ LinkBuffer patchBuffer(*m_globalData, this, m_globalData->executableAllocator);
+
+#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
+ patchBuffer.link(string_failureCases1Call, FunctionPtr(cti_op_get_by_id_string_fail));
+ patchBuffer.link(string_failureCases2Call, FunctionPtr(cti_op_get_by_id_string_fail));
+ patchBuffer.link(string_failureCases3Call, FunctionPtr(cti_op_get_by_id_string_fail));
+#endif
+#if ENABLE(JIT_OPTIMIZE_CALL)
+ patchBuffer.link(callLazyLinkCall, FunctionPtr(cti_vm_lazyLinkCall));
+ patchBuffer.link(callLazyLinkConstruct, FunctionPtr(cti_vm_lazyLinkConstruct));
+#endif
+ patchBuffer.link(callCompileCall, FunctionPtr(cti_op_call_jitCompile));
+ patchBuffer.link(callCompileCconstruct, FunctionPtr(cti_op_construct_jitCompile));
+
+ CodeRef finalCode = patchBuffer.finalizeCode();
+ *executablePool = finalCode.m_executablePool;
+
+ trampolines->ctiVirtualCall = patchBuffer.trampolineAt(virtualCallBegin);
+ trampolines->ctiVirtualConstruct = patchBuffer.trampolineAt(virtualConstructBegin);
+#if ENABLE(JIT_OPTIMIZE_NATIVE_CALL)
+ trampolines->ctiNativeCall = patchBuffer.trampolineAt(nativeCallThunk);
+ trampolines->ctiNativeConstruct = patchBuffer.trampolineAt(nativeConstructThunk);
+#endif
+#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
+ trampolines->ctiStringLengthTrampoline = patchBuffer.trampolineAt(stringLengthBegin);
+#endif
+#if ENABLE(JIT_OPTIMIZE_CALL)
+ trampolines->ctiVirtualCallLink = patchBuffer.trampolineAt(virtualCallLinkBegin);
+ trampolines->ctiVirtualConstructLink = patchBuffer.trampolineAt(virtualConstructLinkBegin);
+#endif
+#if ENABLE(JIT_USE_SOFT_MODULO)
+ trampolines->ctiSoftModulo = patchBuffer.trampolineAt(softModBegin);
+#endif
+}
+
+JIT::Label JIT::privateCompileCTINativeCall(JSGlobalData* globalData, bool isConstruct)
+{
+ int executableOffsetToFunction = isConstruct ? OBJECT_OFFSETOF(NativeExecutable, m_constructor) : OBJECT_OFFSETOF(NativeExecutable, m_function);
-#if CPU(X86) || CPU(ARM_TRADITIONAL)
Label nativeCallThunk = align();
- preserveReturnAddressAfterCall(regT0);
- emitPutToCallFrameHeader(regT0, RegisterFile::ReturnPC); // Push return address
+ emitPutImmediateToCallFrameHeader(0, RegisterFile::CodeBlock);
+
+#if CPU(X86)
// Load caller frame's scope chain into this callframe so that whatever we call can
// get to its global data.
- emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT1);
- emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT1);
- emitPutToCallFrameHeader(regT1, RegisterFile::ScopeChain);
+ emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT0);
+ emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT0);
+ emitPutCellToCallFrameHeader(regT1, RegisterFile::ScopeChain);
-#if CPU(X86)
- emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT0);
+ peek(regT1);
+ emitPutToCallFrameHeader(regT1, RegisterFile::ReturnPC);
- /* We have two structs that we use to describe the stackframe we set up for our
- * call to native code. NativeCallFrameStructure describes the how we set up the stack
- * in advance of the call. NativeFunctionCalleeSignature describes the callframe
- * as the native code expects it. We do this as we are using the fastcall calling
- * convention which results in the callee popping its arguments off the stack, but
- * not the rest of the callframe so we need a nice way to ensure we increment the
- * stack pointer by the right amount after the call.
- */
-
-#if COMPILER(MSVC) || OS(LINUX)
-#if COMPILER(MSVC)
-#pragma pack(push)
-#pragma pack(4)
-#endif // COMPILER(MSVC)
- struct NativeCallFrameStructure {
- // CallFrame* callFrame; // passed in EDX
- JSObject* callee;
- JSValue thisValue;
- ArgList* argPointer;
- ArgList args;
- JSValue result;
- };
- struct NativeFunctionCalleeSignature {
- JSObject* callee;
- JSValue thisValue;
- ArgList* argPointer;
- };
-#if COMPILER(MSVC)
-#pragma pack(pop)
-#endif // COMPILER(MSVC)
-#else
- struct NativeCallFrameStructure {
- // CallFrame* callFrame; // passed in ECX
- // JSObject* callee; // passed in EDX
- JSValue thisValue;
- ArgList* argPointer;
- ArgList args;
- };
- struct NativeFunctionCalleeSignature {
- JSValue thisValue;
- ArgList* argPointer;
- };
-#endif
+ // Calling convention: f(ecx, edx, ...);
+ // Host function signature: f(ExecState*);
+ move(callFrameRegister, X86Registers::ecx);
- const int NativeCallFrameSize = (sizeof(NativeCallFrameStructure) + 15) & ~15;
- // Allocate system stack frame
- subPtr(Imm32(NativeCallFrameSize), stackPointerRegister);
+ subPtr(TrustedImm32(16 - sizeof(void*)), stackPointerRegister); // Align stack after call.
- // Set up arguments
- subPtr(Imm32(1), regT0); // Don't include 'this' in argcount
+ // call the function
+ emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT1);
+ loadPtr(Address(regT1, OBJECT_OFFSETOF(JSFunction, m_executable)), regT1);
+ move(regT0, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack.
+ call(Address(regT1, executableOffsetToFunction));
- // push argcount
- storePtr(regT0, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, args) + OBJECT_OFFSETOF(ArgList, m_argCount)));
+ addPtr(TrustedImm32(16 - sizeof(void*)), stackPointerRegister);
- // Calculate the start of the callframe header, and store in regT1
- addPtr(Imm32(-RegisterFile::CallFrameHeaderSize * (int)sizeof(Register)), callFrameRegister, regT1);
+#elif CPU(ARM)
+ // Load caller frame's scope chain into this callframe so that whatever we call can
+ // get to its global data.
+ emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT2);
+ emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT2);
+ emitPutCellToCallFrameHeader(regT1, RegisterFile::ScopeChain);
- // Calculate start of arguments as callframe header - sizeof(Register) * argcount (regT0)
- mul32(Imm32(sizeof(Register)), regT0, regT0);
- subPtr(regT0, regT1);
- storePtr(regT1, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, args) + OBJECT_OFFSETOF(ArgList, m_args)));
+ preserveReturnAddressAfterCall(regT3); // Callee preserved
+ emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
- // ArgList is passed by reference so is stackPointerRegister + 4 * sizeof(Register)
- addPtr(Imm32(OBJECT_OFFSETOF(NativeCallFrameStructure, args)), stackPointerRegister, regT0);
- storePtr(regT0, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, argPointer)));
+ // Calling convention: f(r0 == regT0, r1 == regT1, ...);
+ // Host function signature: f(ExecState*);
+ move(callFrameRegister, ARMRegisters::r0);
- // regT1 currently points to the first argument, regT1 - sizeof(Register) points to 'this'
- loadPtr(Address(regT1, -(int)sizeof(Register) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT2);
- loadPtr(Address(regT1, -(int)sizeof(Register) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT3);
- storePtr(regT2, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, thisValue) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
- storePtr(regT3, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, thisValue) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
+ // call the function
+ emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, ARMRegisters::r1);
+ move(regT2, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack.
+ loadPtr(Address(ARMRegisters::r1, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
+ call(Address(regT2, executableOffsetToFunction));
-#if COMPILER(MSVC) || OS(LINUX)
- // ArgList is passed by reference so is stackPointerRegister + 4 * sizeof(Register)
- addPtr(Imm32(OBJECT_OFFSETOF(NativeCallFrameStructure, result)), stackPointerRegister, X86Registers::ecx);
+ restoreReturnAddressBeforeReturn(regT3);
+#elif CPU(SH4)
+ // Load caller frame's scope chain into this callframe so that whatever we call can
+ // get to its global data.
+ emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT2);
+ emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT2);
+ emitPutToCallFrameHeader(regT1, RegisterFile::ScopeChain);
+
+ preserveReturnAddressAfterCall(regT3); // Callee preserved
+ emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
+
+ // Calling convention: f(r0 == regT4, r1 == regT5, ...);
+ // Host function signature: f(ExecState*);
+ move(callFrameRegister, regT4);
+
+ emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT5);
+ move(regT2, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack.
+ loadPtr(Address(regT5, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
+
+ call(Address(regT2, executableOffsetToFunction), regT0);
+ restoreReturnAddressBeforeReturn(regT3);
+#elif CPU(MIPS)
+ // Load caller frame's scope chain into this callframe so that whatever we call can
+ // get to its global data.
+ emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT0);
+ emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT0);
+ emitPutCellToCallFrameHeader(regT1, RegisterFile::ScopeChain);
- // Plant callee
- emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, X86Registers::eax);
- storePtr(X86Registers::eax, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, callee)));
+ preserveReturnAddressAfterCall(regT3); // Callee preserved
+ emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
- // Plant callframe
- move(callFrameRegister, X86Registers::edx);
+ // Calling convention: f(a0, a1, a2, a3);
+ // Host function signature: f(ExecState*);
- call(Address(X86Registers::eax, OBJECT_OFFSETOF(JSFunction, m_data)));
+ // Allocate stack space for 16 bytes (8-byte aligned)
+ // 16 bytes (unused) for 4 arguments
+ subPtr(TrustedImm32(16), stackPointerRegister);
- // JSValue is a non-POD type, so eax points to it
- emitLoad(0, regT1, regT0, X86Registers::eax);
+ // Setup arg0
+ move(callFrameRegister, MIPSRegisters::a0);
+
+ // Call
+ emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, MIPSRegisters::a2);
+ loadPtr(Address(MIPSRegisters::a2, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
+ move(regT0, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack.
+ call(Address(regT2, executableOffsetToFunction));
+
+ // Restore stack space
+ addPtr(TrustedImm32(16), stackPointerRegister);
+
+ restoreReturnAddressBeforeReturn(regT3);
+
+#elif ENABLE(JIT_OPTIMIZE_NATIVE_CALL)
+#error "JIT_OPTIMIZE_NATIVE_CALL not yet supported on this platform."
#else
- emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, X86Registers::edx); // callee
- move(callFrameRegister, X86Registers::ecx); // callFrame
- call(Address(X86Registers::edx, OBJECT_OFFSETOF(JSFunction, m_data)));
-#endif
+ UNUSED_PARAM(executableOffsetToFunction);
+ breakpoint();
+#endif // CPU(X86)
- // We've put a few temporaries on the stack in addition to the actual arguments
- // so pull them off now
- addPtr(Imm32(NativeCallFrameSize - sizeof(NativeFunctionCalleeSignature)), stackPointerRegister);
+ // Check for an exception
+ Jump sawException = branch32(NotEqual, AbsoluteAddress(reinterpret_cast<char*>(&globalData->exception) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::EmptyValueTag));
-#elif CPU(ARM_TRADITIONAL)
- emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT0);
+ // Return.
+ ret();
+
+ // Handle an exception
+ sawException.link(this);
+
+ // Grab the return address.
+ preserveReturnAddressAfterCall(regT1);
+
+ move(TrustedImmPtr(&globalData->exceptionLocation), regT2);
+ storePtr(regT1, regT2);
+ poke(callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*));
+
+ // Set the return address.
+ move(TrustedImmPtr(FunctionPtr(ctiVMThrowTrampoline).value()), regT1);
+ restoreReturnAddressBeforeReturn(regT1);
+
+ ret();
- // Allocate stack space for our arglist
- COMPILE_ASSERT((sizeof(ArgList) & 0x7) == 0 && sizeof(JSValue) == 8 && sizeof(Register) == 8, ArgList_should_by_8byte_aligned);
- subPtr(Imm32(sizeof(ArgList)), stackPointerRegister);
+ return nativeCallThunk;
+}
- // Set up arguments
- subPtr(Imm32(1), regT0); // Don't include 'this' in argcount
+JIT::CodePtr JIT::privateCompileCTINativeCall(PassRefPtr<ExecutablePool> executablePool, JSGlobalData* globalData, NativeFunction func)
+{
+ Call nativeCall;
+ Label nativeCallThunk = align();
- // Push argcount
- storePtr(regT0, Address(stackPointerRegister, OBJECT_OFFSETOF(ArgList, m_argCount)));
+ emitPutImmediateToCallFrameHeader(0, RegisterFile::CodeBlock);
- // Calculate the start of the callframe header, and store in regT1
- move(callFrameRegister, regT1);
- sub32(Imm32(RegisterFile::CallFrameHeaderSize * (int32_t)sizeof(Register)), regT1);
+#if CPU(X86)
+ // Load caller frame's scope chain into this callframe so that whatever we call can
+ // get to its global data.
+ emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT0);
+ emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT0);
+ emitPutCellToCallFrameHeader(regT1, RegisterFile::ScopeChain);
- // Calculate start of arguments as callframe header - sizeof(Register) * argcount (regT1)
- mul32(Imm32(sizeof(Register)), regT0, regT0);
- subPtr(regT0, regT1);
+ peek(regT1);
+ emitPutToCallFrameHeader(regT1, RegisterFile::ReturnPC);
- // push pointer to arguments
- storePtr(regT1, Address(stackPointerRegister, OBJECT_OFFSETOF(ArgList, m_args)));
+ // Calling convention: f(ecx, edx, ...);
+ // Host function signature: f(ExecState*);
+ move(callFrameRegister, X86Registers::ecx);
- // Argument passing method:
- // r0 - points to return value
- // r1 - callFrame
- // r2 - callee
- // stack: this(JSValue) and a pointer to ArgList
+ subPtr(TrustedImm32(16 - sizeof(void*)), stackPointerRegister); // Align stack after call.
-#if OS(WINCE)
- // Setup arg4:
- push(stackPointerRegister);
+ move(regT0, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack.
- // Setup arg3:
- // regT1 currently points to the first argument, regT1-sizeof(Register) points to 'this'
- load32(Address(regT1, -(int32_t)sizeof(void*) * 2), ARMRegisters::r3);
- push(ARMRegisters::r3);
- load32(Address(regT1, -(int32_t)sizeof(void*)), regT3);
- storePtr(regT3, Address(stackPointerRegister));
+ // call the function
+ nativeCall = call();
- // Setup arg2:
- emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT2);
+ addPtr(TrustedImm32(16 - sizeof(void*)), stackPointerRegister);
- // Setup arg1:
- move(callFrameRegister, regT1);
+#elif CPU(ARM)
+ // Load caller frame's scope chain into this callframe so that whatever we call can
+ // get to its global data.
+ emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT2);
+ emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT2);
+ emitPutCellToCallFrameHeader(regT1, RegisterFile::ScopeChain);
- // Setup arg0:
- move(stackPointerRegister, regT0);
+ preserveReturnAddressAfterCall(regT3); // Callee preserved
+ emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
- call(Address(regT2, OBJECT_OFFSETOF(JSFunction, m_data)));
+ // Calling convention: f(r0 == regT0, r1 == regT1, ...);
+ // Host function signature: f(ExecState*);
+ move(callFrameRegister, ARMRegisters::r0);
- load32(Address(stackPointerRegister, 0), regT0);
- load32(Address(stackPointerRegister, 4), regT1);
+ emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, ARMRegisters::r1);
+ move(regT2, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack.
+ loadPtr(Address(ARMRegisters::r1, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
- addPtr(Imm32(sizeof(ArgList) + 8), stackPointerRegister);
-#else // OS(WINCE)
- move(stackPointerRegister, regT3);
- subPtr(Imm32(8), stackPointerRegister);
- move(stackPointerRegister, regT0);
- subPtr(Imm32(8 + 4 + 4 /* padding */), stackPointerRegister);
+ // call the function
+ nativeCall = call();
- // Setup arg4:
- storePtr(regT3, Address(stackPointerRegister, 8));
+ restoreReturnAddressBeforeReturn(regT3);
- // Setup arg3:
- // regT1 currently points to the first argument, regT1-sizeof(Register) points to 'this'
- load32(Address(regT1, -(int32_t)sizeof(void*) * 2), regT3);
- storePtr(regT3, Address(stackPointerRegister, 0));
- load32(Address(regT1, -(int32_t)sizeof(void*)), regT3);
- storePtr(regT3, Address(stackPointerRegister, 4));
+#elif CPU(MIPS)
+ // Load caller frame's scope chain into this callframe so that whatever we call can
+ // get to its global data.
+ emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT0);
+ emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT0);
+ emitPutCellToCallFrameHeader(regT1, RegisterFile::ScopeChain);
- // Setup arg2:
- emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT2);
+ preserveReturnAddressAfterCall(regT3); // Callee preserved
+ emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
- // Setup arg1:
- move(callFrameRegister, regT1);
+ // Calling convention: f(a0, a1, a2, a3);
+ // Host function signature: f(ExecState*);
- call(Address(regT2, OBJECT_OFFSETOF(JSFunction, m_data)));
+ // Allocate stack space for 16 bytes (8-byte aligned)
+ // 16 bytes (unused) for 4 arguments
+ subPtr(TrustedImm32(16), stackPointerRegister);
- // Load return value
- load32(Address(stackPointerRegister, 16), regT0);
- load32(Address(stackPointerRegister, 20), regT1);
+ // Setup arg0
+ move(callFrameRegister, MIPSRegisters::a0);
- addPtr(Imm32(sizeof(ArgList) + 16 + 8), stackPointerRegister);
-#endif // OS(WINCE)
+ // Call
+ emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, MIPSRegisters::a2);
+ loadPtr(Address(MIPSRegisters::a2, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
+ move(regT0, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack.
+
+ // call the function
+ nativeCall = call();
-#endif
+ // Restore stack space
+ addPtr(TrustedImm32(16), stackPointerRegister);
- // Check for an exception
- move(ImmPtr(&globalData->exception), regT2);
- Jump sawException = branch32(NotEqual, tagFor(0, regT2), Imm32(JSValue::EmptyValueTag));
+ restoreReturnAddressBeforeReturn(regT3);
+#elif CPU(SH4)
+ // Load caller frame's scope chain into this callframe so that whatever we call can
+ // get to its global data.
+ emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT2);
+ emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT2);
+ emitPutToCallFrameHeader(regT1, RegisterFile::ScopeChain);
- // Grab the return address.
- emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT3);
+ preserveReturnAddressAfterCall(regT3); // Callee preserved
+ emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
- // Restore our caller's "r".
- emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister);
+ // Calling convention: f(r0 == regT4, r1 == regT5, ...);
+ // Host function signature: f(ExecState*);
+ move(callFrameRegister, regT4);
+
+ emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT5);
+ move(regT2, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack.
+ loadPtr(Address(regT5, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
+
+ // call the function
+ nativeCall = call();
- // Return.
restoreReturnAddressBeforeReturn(regT3);
+#elif ENABLE(JIT_OPTIMIZE_NATIVE_CALL)
+#error "JIT_OPTIMIZE_NATIVE_CALL not yet supported on this platform."
+#else
+ breakpoint();
+#endif // CPU(X86)
+
+ // Check for an exception
+ Jump sawException = branch32(NotEqual, AbsoluteAddress(reinterpret_cast<char*>(&globalData->exception) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::EmptyValueTag));
+
+ // Return.
ret();
// Handle an exception
sawException.link(this);
+
// Grab the return address.
- emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT1);
- move(ImmPtr(&globalData->exceptionLocation), regT2);
+ preserveReturnAddressAfterCall(regT1);
+
+ move(TrustedImmPtr(&globalData->exceptionLocation), regT2);
storePtr(regT1, regT2);
- move(ImmPtr(FunctionPtr(ctiVMThrowTrampoline).value()), regT2);
- emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister);
poke(callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*));
- restoreReturnAddressBeforeReturn(regT2);
- ret();
-#elif ENABLE(JIT_OPTIMIZE_NATIVE_CALL)
-#error "JIT_OPTIMIZE_NATIVE_CALL not yet supported on this platform."
-#else
- UNUSED_PARAM(globalData);
- breakpoint();
-#endif
+ // Set the return address.
+ move(TrustedImmPtr(FunctionPtr(ctiVMThrowTrampoline).value()), regT1);
+ restoreReturnAddressBeforeReturn(regT1);
-#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
- Call string_failureCases1Call = makeTailRecursiveCall(string_failureCases1);
- Call string_failureCases2Call = makeTailRecursiveCall(string_failureCases2);
- Call string_failureCases3Call = makeTailRecursiveCall(string_failureCases3);
-#endif
+ ret();
// All trampolines constructed! copy the code, link up calls, and set the pointers on the Machine object.
- LinkBuffer patchBuffer(this, m_globalData->executableAllocator.poolForSize(m_assembler.size()), 0);
+ LinkBuffer patchBuffer(*m_globalData, this, executablePool);
-#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
- patchBuffer.link(string_failureCases1Call, FunctionPtr(cti_op_get_by_id_string_fail));
- patchBuffer.link(string_failureCases2Call, FunctionPtr(cti_op_get_by_id_string_fail));
- patchBuffer.link(string_failureCases3Call, FunctionPtr(cti_op_get_by_id_string_fail));
-#endif
- patchBuffer.link(callArityCheck1, FunctionPtr(cti_op_call_arityCheck));
- patchBuffer.link(callJSFunction1, FunctionPtr(cti_op_call_JSFunction));
-#if ENABLE(JIT_OPTIMIZE_CALL)
- patchBuffer.link(callArityCheck2, FunctionPtr(cti_op_call_arityCheck));
- patchBuffer.link(callJSFunction2, FunctionPtr(cti_op_call_JSFunction));
- patchBuffer.link(callLazyLinkCall, FunctionPtr(cti_vm_lazyLinkCall));
-#endif
-
- CodeRef finalCode = patchBuffer.finalizeCode();
- *executablePool = finalCode.m_executablePool;
+ patchBuffer.link(nativeCall, FunctionPtr(func));
+ patchBuffer.finalizeCode();
- trampolines->ctiVirtualCall = patchBuffer.trampolineAt(virtualCallBegin);
-#if ENABLE(JIT_OPTIMIZE_NATIVE_CALL)
- trampolines->ctiNativeCallThunk = adoptRef(new NativeExecutable(JITCode(JITCode::HostFunction(patchBuffer.trampolineAt(nativeCallThunk)))));
-#endif
-#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
- trampolines->ctiStringLengthTrampoline = patchBuffer.trampolineAt(stringLengthBegin);
-#else
- UNUSED_PARAM(ctiStringLengthTrampoline);
-#endif
-#if ENABLE(JIT_OPTIMIZE_CALL)
- trampolines->ctiVirtualCallLink = patchBuffer.trampolineAt(virtualCallLinkBegin);
-#else
- UNUSED_PARAM(ctiVirtualCallLink);
-#endif
-#if ENABLE(JIT_OPTIMIZE_MOD)
- trampolines->ctiSoftModulo = patchBuffer.trampolineAt(softModBegin);
-#endif
+ return patchBuffer.trampolineAt(nativeCallThunk);
}
void JIT::emit_op_mov(Instruction* currentInstruction)
else {
emitLoad(src, regT1, regT0);
emitStore(dst, regT1, regT0);
- map(m_bytecodeIndex + OPCODE_LENGTH(op_mov), dst, regT1, regT0);
+ map(m_bytecodeOffset + OPCODE_LENGTH(op_mov), dst, regT1, regT0);
}
}
void JIT::emit_op_end(Instruction* currentInstruction)
{
- if (m_codeBlock->needsFullScopeChain())
- JITStubCall(this, cti_op_end).call();
ASSERT(returnValueRegister != callFrameRegister);
emitLoad(currentInstruction[1].u.operand, regT1, regT0);
restoreReturnAddressBeforeReturn(Address(callFrameRegister, RegisterFile::ReturnPC * static_cast<int>(sizeof(Register))));
if (isOperandConstantImmediateInt(op1)) {
emitLoad(op2, regT1, regT0);
- addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
+ addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)));
addJump(branch32(GreaterThanOrEqual, regT0, Imm32(getConstantOperand(op1).asInt32())), target);
return;
}
if (isOperandConstantImmediateInt(op2)) {
emitLoad(op1, regT1, regT0);
- addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
+ addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)));
addJump(branch32(LessThanOrEqual, regT0, Imm32(getConstantOperand(op2).asInt32())), target);
return;
}
emitLoad2(op1, regT1, regT0, op2, regT3, regT2);
- addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
- addSlowCase(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
+ addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)));
+ addSlowCase(branch32(NotEqual, regT3, TrustedImm32(JSValue::Int32Tag)));
addJump(branch32(LessThanOrEqual, regT0, regT2), target);
}
JITStubCall(this, cti_op_new_object).call(currentInstruction[1].u.operand);
}
+void JIT::emit_op_check_has_instance(Instruction* currentInstruction)
+{
+ unsigned baseVal = currentInstruction[1].u.operand;
+
+ emitLoadPayload(baseVal, regT0);
+
+ // Check that baseVal is a cell.
+ emitJumpSlowCaseIfNotJSCell(baseVal);
+
+ // Check that baseVal 'ImplementsHasInstance'.
+ loadPtr(Address(regT0, JSCell::structureOffset()), regT0);
+ addSlowCase(branchTest8(Zero, Address(regT0, Structure::typeInfoFlagsOffset()), TrustedImm32(ImplementsHasInstance)));
+}
+
void JIT::emit_op_instanceof(Instruction* currentInstruction)
{
unsigned dst = currentInstruction[1].u.operand;
emitLoadPayload(baseVal, regT0);
emitLoadPayload(proto, regT1);
- // Check that value, baseVal, and proto are cells.
+ // Check that proto are cells. baseVal must be a cell - this is checked by op_check_has_instance.
emitJumpSlowCaseIfNotJSCell(value);
- emitJumpSlowCaseIfNotJSCell(baseVal);
emitJumpSlowCaseIfNotJSCell(proto);
+
+ // Check that prototype is an object
+ loadPtr(Address(regT1, JSCell::structureOffset()), regT3);
+ addSlowCase(branch8(NotEqual, Address(regT3, Structure::typeInfoTypeOffset()), TrustedImm32(ObjectType)));
+ // Fixme: this check is only needed because the JSC API allows HasInstance to be overridden; we should deprecate this.
// Check that baseVal 'ImplementsDefaultHasInstance'.
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT0);
- addSlowCase(branchTest8(Zero, Address(regT0, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(ImplementsDefaultHasInstance)));
+ loadPtr(Address(regT0, JSCell::structureOffset()), regT0);
+ addSlowCase(branchTest8(Zero, Address(regT0, Structure::typeInfoFlagsOffset()), TrustedImm32(ImplementsDefaultHasInstance)));
// Optimistically load the result true, and start looping.
// Initially, regT1 still contains proto and regT2 still contains value.
// As we loop regT2 will be updated with its prototype, recursively walking the prototype chain.
- move(Imm32(JSValue::TrueTag), regT0);
+ move(TrustedImm32(1), regT0);
Label loop(this);
// Load the prototype of the cell in regT2. If this is equal to regT1 - WIN!
// Otherwise, check if we've hit null - if we have then drop out of the loop, if not go again.
- loadPtr(Address(regT2, OBJECT_OFFSETOF(JSCell, m_structure)), regT2);
- load32(Address(regT2, OBJECT_OFFSETOF(Structure, m_prototype) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT2);
+ loadPtr(Address(regT2, JSCell::structureOffset()), regT2);
+ load32(Address(regT2, Structure::prototypeOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT2);
Jump isInstance = branchPtr(Equal, regT2, regT1);
branchTest32(NonZero, regT2).linkTo(loop, this);
// We get here either by dropping out of the loop, or if value was not an Object. Result is false.
- move(Imm32(JSValue::FalseTag), regT0);
+ move(TrustedImm32(0), regT0);
// isInstance jumps right down to here, to skip setting the result to false (it has already set true).
isInstance.link(this);
emitStoreBool(dst, regT0);
}
+void JIT::emitSlow_op_check_has_instance(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+ unsigned baseVal = currentInstruction[1].u.operand;
+
+ linkSlowCaseIfNotJSCell(iter, baseVal);
+ linkSlowCase(iter);
+
+ JITStubCall stubCall(this, cti_op_check_has_instance);
+ stubCall.addArgument(baseVal);
+ stubCall.call();
+}
+
void JIT::emitSlow_op_instanceof(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
{
unsigned dst = currentInstruction[1].u.operand;
unsigned proto = currentInstruction[4].u.operand;
linkSlowCaseIfNotJSCell(iter, value);
- linkSlowCaseIfNotJSCell(iter, baseVal);
linkSlowCaseIfNotJSCell(iter, proto);
linkSlowCase(iter);
+ linkSlowCase(iter);
JITStubCall stubCall(this, cti_op_instanceof);
stubCall.addArgument(value);
stubCall.call(dst);
}
-void JIT::emit_op_new_func(Instruction* currentInstruction)
-{
- JITStubCall stubCall(this, cti_op_new_func);
- stubCall.addArgument(ImmPtr(m_codeBlock->functionDecl(currentInstruction[2].u.operand)));
- stubCall.call(currentInstruction[1].u.operand);
-}
-
void JIT::emit_op_get_global_var(Instruction* currentInstruction)
{
int dst = currentInstruction[1].u.operand;
- JSGlobalObject* globalObject = static_cast<JSGlobalObject*>(currentInstruction[2].u.jsCell);
+ JSGlobalObject* globalObject = m_codeBlock->globalObject();
ASSERT(globalObject->isGlobalObject());
- int index = currentInstruction[3].u.operand;
+ int index = currentInstruction[2].u.operand;
- loadPtr(&globalObject->d()->registers, regT2);
+ loadPtr(&globalObject->m_registers, regT2);
emitLoad(index, regT1, regT0, regT2);
emitStore(dst, regT1, regT0);
- map(m_bytecodeIndex + OPCODE_LENGTH(op_get_global_var), dst, regT1, regT0);
+ map(m_bytecodeOffset + OPCODE_LENGTH(op_get_global_var), dst, regT1, regT0);
}
void JIT::emit_op_put_global_var(Instruction* currentInstruction)
{
- JSGlobalObject* globalObject = static_cast<JSGlobalObject*>(currentInstruction[1].u.jsCell);
+ JSGlobalObject* globalObject = m_codeBlock->globalObject();
ASSERT(globalObject->isGlobalObject());
- int index = currentInstruction[2].u.operand;
- int value = currentInstruction[3].u.operand;
+ int index = currentInstruction[1].u.operand;
+ int value = currentInstruction[2].u.operand;
emitLoad(value, regT1, regT0);
- loadPtr(&globalObject->d()->registers, regT2);
+ loadPtr(&globalObject->m_registers, regT2);
emitStore(index, regT1, regT0, regT2);
- map(m_bytecodeIndex + OPCODE_LENGTH(op_put_global_var), value, regT1, regT0);
+ map(m_bytecodeOffset + OPCODE_LENGTH(op_put_global_var), value, regT1, regT0);
}
void JIT::emit_op_get_scoped_var(Instruction* currentInstruction)
{
int dst = currentInstruction[1].u.operand;
int index = currentInstruction[2].u.operand;
- int skip = currentInstruction[3].u.operand + m_codeBlock->needsFullScopeChain();
+ int skip = currentInstruction[3].u.operand;
emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT2);
+ bool checkTopLevel = m_codeBlock->codeType() == FunctionCode && m_codeBlock->needsFullScopeChain();
+ ASSERT(skip || !checkTopLevel);
+ if (checkTopLevel && skip--) {
+ Jump activationNotCreated;
+ if (checkTopLevel)
+ activationNotCreated = branch32(Equal, tagFor(m_codeBlock->activationRegister()), TrustedImm32(JSValue::EmptyValueTag));
+ loadPtr(Address(regT2, OBJECT_OFFSETOF(ScopeChainNode, next)), regT2);
+ activationNotCreated.link(this);
+ }
while (skip--)
loadPtr(Address(regT2, OBJECT_OFFSETOF(ScopeChainNode, next)), regT2);
loadPtr(Address(regT2, OBJECT_OFFSETOF(ScopeChainNode, object)), regT2);
- loadPtr(Address(regT2, OBJECT_OFFSETOF(JSVariableObject, d)), regT2);
- loadPtr(Address(regT2, OBJECT_OFFSETOF(JSVariableObject::JSVariableObjectData, registers)), regT2);
+ loadPtr(Address(regT2, OBJECT_OFFSETOF(JSVariableObject, m_registers)), regT2);
emitLoad(index, regT1, regT0, regT2);
emitStore(dst, regT1, regT0);
- map(m_bytecodeIndex + OPCODE_LENGTH(op_get_scoped_var), dst, regT1, regT0);
+ map(m_bytecodeOffset + OPCODE_LENGTH(op_get_scoped_var), dst, regT1, regT0);
}
void JIT::emit_op_put_scoped_var(Instruction* currentInstruction)
{
int index = currentInstruction[1].u.operand;
- int skip = currentInstruction[2].u.operand + m_codeBlock->needsFullScopeChain();
+ int skip = currentInstruction[2].u.operand;
int value = currentInstruction[3].u.operand;
emitLoad(value, regT1, regT0);
emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT2);
+ bool checkTopLevel = m_codeBlock->codeType() == FunctionCode && m_codeBlock->needsFullScopeChain();
+ ASSERT(skip || !checkTopLevel);
+ if (checkTopLevel && skip--) {
+ Jump activationNotCreated;
+ if (checkTopLevel)
+ activationNotCreated = branch32(Equal, tagFor(m_codeBlock->activationRegister()), TrustedImm32(JSValue::EmptyValueTag));
+ loadPtr(Address(regT2, OBJECT_OFFSETOF(ScopeChainNode, next)), regT2);
+ activationNotCreated.link(this);
+ }
while (skip--)
loadPtr(Address(regT2, OBJECT_OFFSETOF(ScopeChainNode, next)), regT2);
loadPtr(Address(regT2, OBJECT_OFFSETOF(ScopeChainNode, object)), regT2);
- loadPtr(Address(regT2, OBJECT_OFFSETOF(JSVariableObject, d)), regT2);
- loadPtr(Address(regT2, OBJECT_OFFSETOF(JSVariableObject::JSVariableObjectData, registers)), regT2);
+ loadPtr(Address(regT2, OBJECT_OFFSETOF(JSVariableObject, m_registers)), regT2);
emitStore(index, regT1, regT0, regT2);
- map(m_bytecodeIndex + OPCODE_LENGTH(op_put_scoped_var), value, regT1, regT0);
+ map(m_bytecodeOffset + OPCODE_LENGTH(op_put_scoped_var), value, regT1, regT0);
}
void JIT::emit_op_tear_off_activation(Instruction* currentInstruction)
{
+ unsigned activation = currentInstruction[1].u.operand;
+ unsigned arguments = currentInstruction[2].u.operand;
+ Jump activationCreated = branch32(NotEqual, tagFor(activation), TrustedImm32(JSValue::EmptyValueTag));
+ Jump argumentsNotCreated = branch32(Equal, tagFor(arguments), TrustedImm32(JSValue::EmptyValueTag));
+ activationCreated.link(this);
JITStubCall stubCall(this, cti_op_tear_off_activation);
stubCall.addArgument(currentInstruction[1].u.operand);
+ stubCall.addArgument(unmodifiedArgumentsRegister(currentInstruction[2].u.operand));
stubCall.call();
+ argumentsNotCreated.link(this);
}
-void JIT::emit_op_tear_off_arguments(Instruction*)
+void JIT::emit_op_tear_off_arguments(Instruction* currentInstruction)
{
- JITStubCall(this, cti_op_tear_off_arguments).call();
-}
+ int dst = currentInstruction[1].u.operand;
-void JIT::emit_op_new_array(Instruction* currentInstruction)
-{
- JITStubCall stubCall(this, cti_op_new_array);
- stubCall.addArgument(Imm32(currentInstruction[2].u.operand));
- stubCall.addArgument(Imm32(currentInstruction[3].u.operand));
- stubCall.call(currentInstruction[1].u.operand);
+ Jump argsNotCreated = branch32(Equal, tagFor(unmodifiedArgumentsRegister(dst)), TrustedImm32(JSValue::EmptyValueTag));
+ JITStubCall stubCall(this, cti_op_tear_off_arguments);
+ stubCall.addArgument(unmodifiedArgumentsRegister(dst));
+ stubCall.call();
+ argsNotCreated.link(this);
}
void JIT::emit_op_resolve(Instruction* currentInstruction)
{
JITStubCall stubCall(this, cti_op_resolve);
- stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
+ stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
stubCall.call(currentInstruction[1].u.operand);
}
emitLoad(src, regT1, regT0);
- Jump isImm = branch32(NotEqual, regT1, Imm32(JSValue::CellTag));
- addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsStringVPtr)));
+ Jump isImm = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag));
+ addSlowCase(branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsStringVPtr)));
isImm.link(this);
if (dst != src)
emitStore(dst, regT1, regT0);
- map(m_bytecodeIndex + OPCODE_LENGTH(op_to_primitive), dst, regT1, regT0);
+ map(m_bytecodeOffset + OPCODE_LENGTH(op_to_primitive), dst, regT1, regT0);
}
void JIT::emitSlow_op_to_primitive(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
void JIT::emit_op_resolve_base(Instruction* currentInstruction)
{
- JITStubCall stubCall(this, cti_op_resolve_base);
- stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
+ JITStubCall stubCall(this, currentInstruction[3].u.operand ? cti_op_resolve_base_strict_put : cti_op_resolve_base);
+ stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
+ stubCall.call(currentInstruction[1].u.operand);
+}
+
+void JIT::emit_op_ensure_property_exists(Instruction* currentInstruction)
+{
+ JITStubCall stubCall(this, cti_op_ensure_property_exists);
+ stubCall.addArgument(Imm32(currentInstruction[1].u.operand));
+ stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
stubCall.call(currentInstruction[1].u.operand);
}
void JIT::emit_op_resolve_skip(Instruction* currentInstruction)
{
JITStubCall stubCall(this, cti_op_resolve_skip);
- stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
- stubCall.addArgument(Imm32(currentInstruction[3].u.operand + m_codeBlock->needsFullScopeChain()));
+ stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
+ stubCall.addArgument(Imm32(currentInstruction[3].u.operand));
stubCall.call(currentInstruction[1].u.operand);
}
// FIXME: Optimize to use patching instead of so many memory accesses.
unsigned dst = currentInstruction[1].u.operand;
- void* globalObject = currentInstruction[2].u.jsCell;
+ void* globalObject = m_codeBlock->globalObject();
unsigned currentIndex = m_globalResolveInfoIndex++;
- void* structureAddress = &(m_codeBlock->globalResolveInfo(currentIndex).structure);
- void* offsetAddr = &(m_codeBlock->globalResolveInfo(currentIndex).offset);
+ GlobalResolveInfo* resolveInfoAddress = &m_codeBlock->globalResolveInfo(currentIndex);
+
// Verify structure.
- move(ImmPtr(globalObject), regT0);
- loadPtr(structureAddress, regT1);
- addSlowCase(branchPtr(NotEqual, regT1, Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure))));
+ move(TrustedImmPtr(globalObject), regT0);
+ move(TrustedImmPtr(resolveInfoAddress), regT3);
+ loadPtr(Address(regT3, OBJECT_OFFSETOF(GlobalResolveInfo, structure)), regT1);
+ addSlowCase(branchPtr(NotEqual, regT1, Address(regT0, JSCell::structureOffset())));
// Load property.
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSGlobalObject, m_externalStorage)), regT2);
- load32(offsetAddr, regT3);
- load32(BaseIndex(regT2, regT3, TimesEight), regT0); // payload
- load32(BaseIndex(regT2, regT3, TimesEight, 4), regT1); // tag
+ loadPtr(Address(regT0, OBJECT_OFFSETOF(JSGlobalObject, m_propertyStorage)), regT2);
+ load32(Address(regT3, OBJECT_OFFSETOF(GlobalResolveInfo, offset)), regT3);
+ load32(BaseIndex(regT2, regT3, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0); // payload
+ load32(BaseIndex(regT2, regT3, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1); // tag
emitStore(dst, regT1, regT0);
- map(m_bytecodeIndex + dynamic ? OPCODE_LENGTH(op_resolve_global_dynamic) : OPCODE_LENGTH(op_resolve_global), dst, regT1, regT0);
+ map(m_bytecodeOffset + (dynamic ? OPCODE_LENGTH(op_resolve_global_dynamic) : OPCODE_LENGTH(op_resolve_global)), dst, regT1, regT0);
}
void JIT::emitSlow_op_resolve_global(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
{
unsigned dst = currentInstruction[1].u.operand;
- void* globalObject = currentInstruction[2].u.jsCell;
- Identifier* ident = &m_codeBlock->identifier(currentInstruction[3].u.operand);
+ Identifier* ident = &m_codeBlock->identifier(currentInstruction[2].u.operand);
unsigned currentIndex = m_globalResolveInfoIndex++;
linkSlowCase(iter);
JITStubCall stubCall(this, cti_op_resolve_global);
- stubCall.addArgument(ImmPtr(globalObject));
- stubCall.addArgument(ImmPtr(ident));
+ stubCall.addArgument(TrustedImmPtr(ident));
stubCall.addArgument(Imm32(currentIndex));
stubCall.call(dst);
}
emitLoadTag(src, regT0);
- xor32(Imm32(JSValue::FalseTag), regT0);
- addSlowCase(branchTest32(NonZero, regT0, Imm32(~1)));
- xor32(Imm32(JSValue::TrueTag), regT0);
+ emitLoad(src, regT1, regT0);
+ addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::BooleanTag)));
+ xor32(TrustedImm32(1), regT0);
emitStoreBool(dst, regT0, (dst == src));
}
emitLoad(cond, regT1, regT0);
- Jump isTrue = branch32(Equal, regT1, Imm32(JSValue::TrueTag));
- addJump(branch32(Equal, regT1, Imm32(JSValue::FalseTag)), target);
-
- Jump isNotInteger = branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag));
- Jump isTrue2 = branch32(NotEqual, regT0, Imm32(0));
- addJump(jump(), target);
-
- if (supportsFloatingPoint()) {
- isNotInteger.link(this);
-
- addSlowCase(branch32(Above, regT1, Imm32(JSValue::LowestTag)));
-
- emitLoadDouble(cond, fpRegT0);
- addJump(branchDoubleZeroOrNaN(fpRegT0, fpRegT1), target);
- } else
- addSlowCase(isNotInteger);
-
- isTrue.link(this);
- isTrue2.link(this);
+ ASSERT((JSValue::BooleanTag + 1 == JSValue::Int32Tag) && !(JSValue::Int32Tag + 1));
+ addSlowCase(branch32(Below, regT1, TrustedImm32(JSValue::BooleanTag)));
+ addJump(branchTest32(Zero, regT0), target);
}
void JIT::emitSlow_op_jfalse(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
unsigned target = currentInstruction[2].u.operand;
linkSlowCase(iter);
+
+ if (supportsFloatingPoint()) {
+ // regT1 contains the tag from the hot path.
+ Jump notNumber = branch32(Above, regT1, Imm32(JSValue::LowestTag));
+
+ emitLoadDouble(cond, fpRegT0);
+ emitJumpSlowToHot(branchDoubleZeroOrNaN(fpRegT0, fpRegT1), target);
+ emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jfalse));
+
+ notNumber.link(this);
+ }
+
JITStubCall stubCall(this, cti_op_jtrue);
stubCall.addArgument(cond);
stubCall.call();
emitLoad(cond, regT1, regT0);
- Jump isFalse = branch32(Equal, regT1, Imm32(JSValue::FalseTag));
- addJump(branch32(Equal, regT1, Imm32(JSValue::TrueTag)), target);
-
- Jump isNotInteger = branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag));
- Jump isFalse2 = branch32(Equal, regT0, Imm32(0));
- addJump(jump(), target);
-
- if (supportsFloatingPoint()) {
- isNotInteger.link(this);
-
- addSlowCase(branch32(Above, regT1, Imm32(JSValue::LowestTag)));
-
- emitLoadDouble(cond, fpRegT0);
- addJump(branchDoubleNonZero(fpRegT0, fpRegT1), target);
- } else
- addSlowCase(isNotInteger);
-
- isFalse.link(this);
- isFalse2.link(this);
+ ASSERT((JSValue::BooleanTag + 1 == JSValue::Int32Tag) && !(JSValue::Int32Tag + 1));
+ addSlowCase(branch32(Below, regT1, TrustedImm32(JSValue::BooleanTag)));
+ addJump(branchTest32(NonZero, regT0), target);
}
void JIT::emitSlow_op_jtrue(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
unsigned target = currentInstruction[2].u.operand;
linkSlowCase(iter);
+
+ if (supportsFloatingPoint()) {
+ // regT1 contains the tag from the hot path.
+ Jump notNumber = branch32(Above, regT1, Imm32(JSValue::LowestTag));
+
+ emitLoadDouble(cond, fpRegT0);
+ emitJumpSlowToHot(branchDoubleNonZero(fpRegT0, fpRegT1), target);
+ emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jtrue));
+
+ notNumber.link(this);
+ }
+
JITStubCall stubCall(this, cti_op_jtrue);
stubCall.addArgument(cond);
stubCall.call();
emitLoad(src, regT1, regT0);
- Jump isImmediate = branch32(NotEqual, regT1, Imm32(JSValue::CellTag));
+ Jump isImmediate = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag));
// First, handle JSCell cases - check MasqueradesAsUndefined bit on the structure.
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2);
- addJump(branchTest8(NonZero, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(MasqueradesAsUndefined)), target);
+ loadPtr(Address(regT0, JSCell::structureOffset()), regT2);
+ addJump(branchTest8(NonZero, Address(regT2, Structure::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined)), target);
Jump wasNotImmediate = jump();
// Now handle the immediate cases - undefined & null
isImmediate.link(this);
- set32(Equal, regT1, Imm32(JSValue::NullTag), regT2);
- set32(Equal, regT1, Imm32(JSValue::UndefinedTag), regT1);
- or32(regT2, regT1);
-
- addJump(branchTest32(NonZero, regT1), target);
+ ASSERT((JSValue::UndefinedTag + 1 == JSValue::NullTag) && (JSValue::NullTag & 0x1));
+ or32(TrustedImm32(1), regT1);
+ addJump(branch32(Equal, regT1, TrustedImm32(JSValue::NullTag)), target);
wasNotImmediate.link(this);
}
emitLoad(src, regT1, regT0);
- Jump isImmediate = branch32(NotEqual, regT1, Imm32(JSValue::CellTag));
+ Jump isImmediate = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag));
// First, handle JSCell cases - check MasqueradesAsUndefined bit on the structure.
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2);
- addJump(branchTest8(Zero, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(MasqueradesAsUndefined)), target);
+ loadPtr(Address(regT0, JSCell::structureOffset()), regT2);
+ addJump(branchTest8(Zero, Address(regT2, Structure::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined)), target);
Jump wasNotImmediate = jump();
// Now handle the immediate cases - undefined & null
isImmediate.link(this);
- set32(Equal, regT1, Imm32(JSValue::NullTag), regT2);
- set32(Equal, regT1, Imm32(JSValue::UndefinedTag), regT1);
- or32(regT2, regT1);
-
- addJump(branchTest32(Zero, regT1), target);
+ ASSERT((JSValue::UndefinedTag + 1 == JSValue::NullTag) && (JSValue::NullTag & 0x1));
+ or32(TrustedImm32(1), regT1);
+ addJump(branch32(NotEqual, regT1, TrustedImm32(JSValue::NullTag)), target);
wasNotImmediate.link(this);
}
void JIT::emit_op_jneq_ptr(Instruction* currentInstruction)
{
unsigned src = currentInstruction[1].u.operand;
- JSCell* ptr = currentInstruction[2].u.jsCell;
+ JSCell* ptr = currentInstruction[2].u.jsCell.get();
unsigned target = currentInstruction[3].u.operand;
emitLoad(src, regT1, regT0);
- addJump(branch32(NotEqual, regT1, Imm32(JSValue::CellTag)), target);
- addJump(branchPtr(NotEqual, regT0, ImmPtr(ptr)), target);
+ addJump(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)), target);
+ addJump(branchPtr(NotEqual, regT0, TrustedImmPtr(ptr)), target);
}
void JIT::emit_op_jsr(Instruction* currentInstruction)
{
int retAddrDst = currentInstruction[1].u.operand;
int target = currentInstruction[2].u.operand;
- DataLabelPtr storeLocation = storePtrWithPatch(ImmPtr(0), Address(callFrameRegister, sizeof(Register) * retAddrDst));
+ DataLabelPtr storeLocation = storePtrWithPatch(TrustedImmPtr(0), Address(callFrameRegister, sizeof(Register) * retAddrDst));
addJump(jump(), target);
m_jsrSites.append(JSRInfo(storeLocation, label()));
}
emitLoad2(src1, regT1, regT0, src2, regT3, regT2);
addSlowCase(branch32(NotEqual, regT1, regT3));
- addSlowCase(branch32(Equal, regT1, Imm32(JSValue::CellTag)));
- addSlowCase(branch32(Below, regT1, Imm32(JSValue::LowestTag)));
+ addSlowCase(branch32(Equal, regT1, TrustedImm32(JSValue::CellTag)));
+ addSlowCase(branch32(Below, regT1, TrustedImm32(JSValue::LowestTag)));
- set8(Equal, regT0, regT2, regT0);
- or32(Imm32(JSValue::FalseTag), regT0);
+ compare32(Equal, regT0, regT2, regT0);
emitStoreBool(dst, regT0);
}
genericCase.append(getSlowCase(iter)); // tags not equal
linkSlowCase(iter); // tags equal and JSCell
- genericCase.append(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsStringVPtr)));
- genericCase.append(branchPtr(NotEqual, Address(regT2), ImmPtr(m_globalData->jsStringVPtr)));
+ genericCase.append(branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsStringVPtr)));
+ genericCase.append(branchPtr(NotEqual, Address(regT2), TrustedImmPtr(m_globalData->jsStringVPtr)));
// String case.
JITStubCall stubCallEqStrings(this, cti_op_eq_strings);
stubCallEq.call(regT0);
storeResult.link(this);
- or32(Imm32(JSValue::FalseTag), regT0);
emitStoreBool(dst, regT0);
}
emitLoad2(src1, regT1, regT0, src2, regT3, regT2);
addSlowCase(branch32(NotEqual, regT1, regT3));
- addSlowCase(branch32(Equal, regT1, Imm32(JSValue::CellTag)));
- addSlowCase(branch32(Below, regT1, Imm32(JSValue::LowestTag)));
+ addSlowCase(branch32(Equal, regT1, TrustedImm32(JSValue::CellTag)));
+ addSlowCase(branch32(Below, regT1, TrustedImm32(JSValue::LowestTag)));
- set8(NotEqual, regT0, regT2, regT0);
- or32(Imm32(JSValue::FalseTag), regT0);
+ compare32(NotEqual, regT0, regT2, regT0);
emitStoreBool(dst, regT0);
}
genericCase.append(getSlowCase(iter)); // tags not equal
linkSlowCase(iter); // tags equal and JSCell
- genericCase.append(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsStringVPtr)));
- genericCase.append(branchPtr(NotEqual, Address(regT2), ImmPtr(m_globalData->jsStringVPtr)));
+ genericCase.append(branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsStringVPtr)));
+ genericCase.append(branchPtr(NotEqual, Address(regT2), TrustedImmPtr(m_globalData->jsStringVPtr)));
// String case.
JITStubCall stubCallEqStrings(this, cti_op_eq_strings);
stubCallEq.call(regT0);
storeResult.link(this);
- xor32(Imm32(0x1), regT0);
- or32(Imm32(JSValue::FalseTag), regT0);
+ xor32(TrustedImm32(0x1), regT0);
emitStoreBool(dst, regT0);
}
// cells and/or Int32s.
move(regT0, regT2);
and32(regT1, regT2);
- addSlowCase(branch32(Below, regT2, Imm32(JSValue::LowestTag)));
- addSlowCase(branch32(AboveOrEqual, regT2, Imm32(JSValue::CellTag)));
+ addSlowCase(branch32(Below, regT2, TrustedImm32(JSValue::LowestTag)));
+ addSlowCase(branch32(AboveOrEqual, regT2, TrustedImm32(JSValue::CellTag)));
if (type == OpStrictEq)
- set8(Equal, regT0, regT1, regT0);
+ compare32(Equal, regT0, regT1, regT0);
else
- set8(NotEqual, regT0, regT1, regT0);
-
- or32(Imm32(JSValue::FalseTag), regT0);
+ compare32(NotEqual, regT0, regT1, regT0);
emitStoreBool(dst, regT0);
}
unsigned src = currentInstruction[2].u.operand;
emitLoad(src, regT1, regT0);
- Jump isImmediate = branch32(NotEqual, regT1, Imm32(JSValue::CellTag));
+ Jump isImmediate = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag));
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT1);
- setTest8(NonZero, Address(regT1, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(MasqueradesAsUndefined), regT1);
+ loadPtr(Address(regT0, JSCell::structureOffset()), regT1);
+ test8(NonZero, Address(regT1, Structure::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined), regT1);
Jump wasNotImmediate = jump();
isImmediate.link(this);
- set8(Equal, regT1, Imm32(JSValue::NullTag), regT2);
- set8(Equal, regT1, Imm32(JSValue::UndefinedTag), regT1);
+ compare32(Equal, regT1, TrustedImm32(JSValue::NullTag), regT2);
+ compare32(Equal, regT1, TrustedImm32(JSValue::UndefinedTag), regT1);
or32(regT2, regT1);
wasNotImmediate.link(this);
- or32(Imm32(JSValue::FalseTag), regT1);
-
emitStoreBool(dst, regT1);
}
unsigned src = currentInstruction[2].u.operand;
emitLoad(src, regT1, regT0);
- Jump isImmediate = branch32(NotEqual, regT1, Imm32(JSValue::CellTag));
+ Jump isImmediate = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag));
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT1);
- setTest8(Zero, Address(regT1, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(MasqueradesAsUndefined), regT1);
+ loadPtr(Address(regT0, JSCell::structureOffset()), regT1);
+ test8(Zero, Address(regT1, Structure::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined), regT1);
Jump wasNotImmediate = jump();
isImmediate.link(this);
- set8(NotEqual, regT1, Imm32(JSValue::NullTag), regT2);
- set8(NotEqual, regT1, Imm32(JSValue::UndefinedTag), regT1);
+ compare32(NotEqual, regT1, TrustedImm32(JSValue::NullTag), regT2);
+ compare32(NotEqual, regT1, TrustedImm32(JSValue::UndefinedTag), regT1);
and32(regT2, regT1);
wasNotImmediate.link(this);
- or32(Imm32(JSValue::FalseTag), regT1);
-
emitStoreBool(dst, regT1);
}
void JIT::emit_op_resolve_with_base(Instruction* currentInstruction)
{
JITStubCall stubCall(this, cti_op_resolve_with_base);
- stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[3].u.operand)));
+ stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[3].u.operand)));
stubCall.addArgument(Imm32(currentInstruction[1].u.operand));
stubCall.call(currentInstruction[2].u.operand);
}
void JIT::emit_op_new_func_exp(Instruction* currentInstruction)
{
JITStubCall stubCall(this, cti_op_new_func_exp);
- stubCall.addArgument(ImmPtr(m_codeBlock->functionExpr(currentInstruction[2].u.operand)));
+ stubCall.addArgument(TrustedImmPtr(m_codeBlock->functionExpr(currentInstruction[2].u.operand)));
stubCall.call(currentInstruction[1].u.operand);
}
emitLoad(base, regT1, regT0);
if (!m_codeBlock->isKnownNotImmediate(base))
- isNotObject.append(branch32(NotEqual, regT1, Imm32(JSValue::CellTag)));
- if (base != m_codeBlock->thisRegister()) {
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2);
- isNotObject.append(branch8(NotEqual, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_type)), Imm32(ObjectType)));
+ isNotObject.append(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)));
+ if (base != m_codeBlock->thisRegister() || m_codeBlock->isStrictMode()) {
+ loadPtr(Address(regT0, JSCell::structureOffset()), regT2);
+ isNotObject.append(branch8(NotEqual, Address(regT2, Structure::typeInfoTypeOffset()), TrustedImm32(ObjectType)));
}
// We could inline the case where you have a valid cache, but
getPnamesStubCall.addArgument(regT0);
getPnamesStubCall.call(dst);
load32(Address(regT0, OBJECT_OFFSETOF(JSPropertyNameIterator, m_jsStringsSize)), regT3);
- store32(Imm32(0), addressFor(i));
- store32(regT3, addressFor(size));
+ store32(TrustedImm32(Int32Tag), intTagFor(i));
+ store32(TrustedImm32(0), intPayloadFor(i));
+ store32(TrustedImm32(Int32Tag), intTagFor(size));
+ store32(regT3, payloadFor(size));
Jump end = jump();
isNotObject.link(this);
- addJump(branch32(Equal, regT1, Imm32(JSValue::NullTag)), breakTarget);
- addJump(branch32(Equal, regT1, Imm32(JSValue::UndefinedTag)), breakTarget);
+ addJump(branch32(Equal, regT1, TrustedImm32(JSValue::NullTag)), breakTarget);
+ addJump(branch32(Equal, regT1, TrustedImm32(JSValue::UndefinedTag)), breakTarget);
JITStubCall toObjectStubCall(this, cti_to_object);
toObjectStubCall.addArgument(regT1, regT0);
toObjectStubCall.call(base);
JumpList callHasProperty;
Label begin(this);
- load32(addressFor(i), regT0);
- Jump end = branch32(Equal, regT0, addressFor(size));
+ load32(intPayloadFor(i), regT0);
+ Jump end = branch32(Equal, regT0, intPayloadFor(size));
// Grab key @ i
- loadPtr(addressFor(it), regT1);
+ loadPtr(payloadFor(it), regT1);
loadPtr(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_jsStrings)), regT2);
load32(BaseIndex(regT2, regT0, TimesEight), regT2);
- store32(Imm32(JSValue::CellTag), tagFor(dst));
+ store32(TrustedImm32(JSValue::CellTag), tagFor(dst));
store32(regT2, payloadFor(dst));
// Increment i
- add32(Imm32(1), regT0);
- store32(regT0, addressFor(i));
+ add32(TrustedImm32(1), regT0);
+ store32(regT0, intPayloadFor(i));
// Verify that i is valid:
- loadPtr(addressFor(base), regT0);
+ loadPtr(payloadFor(base), regT0);
// Test base's structure
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2);
+ loadPtr(Address(regT0, JSCell::structureOffset()), regT2);
callHasProperty.append(branchPtr(NotEqual, regT2, Address(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedStructure)))));
// Test base's prototype chain
addJump(branchTestPtr(Zero, Address(regT3)), target);
Label checkPrototype(this);
- callHasProperty.append(branch32(Equal, Address(regT2, OBJECT_OFFSETOF(Structure, m_prototype) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), Imm32(JSValue::NullTag)));
- loadPtr(Address(regT2, OBJECT_OFFSETOF(Structure, m_prototype) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT2);
- loadPtr(Address(regT2, OBJECT_OFFSETOF(JSCell, m_structure)), regT2);
+ callHasProperty.append(branch32(Equal, Address(regT2, Structure::prototypeOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::NullTag)));
+ loadPtr(Address(regT2, Structure::prototypeOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT2);
+ loadPtr(Address(regT2, JSCell::structureOffset()), regT2);
callHasProperty.append(branchPtr(NotEqual, regT2, Address(regT3)));
- addPtr(Imm32(sizeof(Structure*)), regT3);
+ addPtr(TrustedImm32(sizeof(Structure*)), regT3);
branchTestPtr(NonZero, Address(regT3)).linkTo(checkPrototype, this);
// Continue loop.
emitLoad(src, regT1, regT0);
- Jump isInt32 = branch32(Equal, regT1, Imm32(JSValue::Int32Tag));
- addSlowCase(branch32(AboveOrEqual, regT1, Imm32(JSValue::EmptyValueTag)));
+ Jump isInt32 = branch32(Equal, regT1, TrustedImm32(JSValue::Int32Tag));
+ addSlowCase(branch32(AboveOrEqual, regT1, TrustedImm32(JSValue::EmptyValueTag)));
isInt32.link(this);
if (src != dst)
emitStore(dst, regT1, regT0);
- map(m_bytecodeIndex + OPCODE_LENGTH(op_to_jsnumber), dst, regT1, regT0);
+ map(m_bytecodeOffset + OPCODE_LENGTH(op_to_jsnumber), dst, regT1, regT0);
}
void JIT::emitSlow_op_to_jsnumber(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
void JIT::emit_op_push_new_scope(Instruction* currentInstruction)
{
JITStubCall stubCall(this, cti_op_push_new_scope);
- stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
+ stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
stubCall.addArgument(currentInstruction[3].u.operand);
stubCall.call(currentInstruction[1].u.operand);
}
void JIT::emit_op_catch(Instruction* currentInstruction)
{
- unsigned exception = currentInstruction[1].u.operand;
-
- // This opcode only executes after a return from cti_op_throw.
-
- // cti_op_throw may have taken us to a call frame further up the stack; reload
- // the call frame pointer to adjust.
- peek(callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*));
+ // cti_op_throw returns the callFrame for the handler.
+ move(regT0, callFrameRegister);
// Now store the exception returned by cti_op_throw.
+ loadPtr(Address(stackPointerRegister, OBJECT_OFFSETOF(struct JITStackFrame, globalData)), regT3);
+ load32(Address(regT3, OBJECT_OFFSETOF(JSGlobalData, exception) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0);
+ load32(Address(regT3, OBJECT_OFFSETOF(JSGlobalData, exception) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1);
+ store32(TrustedImm32(JSValue().payload()), Address(regT3, OBJECT_OFFSETOF(JSGlobalData, exception) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
+ store32(TrustedImm32(JSValue().tag()), Address(regT3, OBJECT_OFFSETOF(JSGlobalData, exception) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
+
+ unsigned exception = currentInstruction[1].u.operand;
emitStore(exception, regT1, regT0);
- map(m_bytecodeIndex + OPCODE_LENGTH(op_catch), exception, regT1, regT0);
+ map(m_bytecodeOffset + OPCODE_LENGTH(op_catch), exception, regT1, regT0);
}
void JIT::emit_op_jmp_scopes(Instruction* currentInstruction)
// create jump table for switch destinations, track this switch statement.
SimpleJumpTable* jumpTable = &m_codeBlock->immediateSwitchJumpTable(tableIndex);
- m_switches.append(SwitchRecord(jumpTable, m_bytecodeIndex, defaultOffset, SwitchRecord::Immediate));
+ m_switches.append(SwitchRecord(jumpTable, m_bytecodeOffset, defaultOffset, SwitchRecord::Immediate));
jumpTable->ctiOffsets.grow(jumpTable->branchOffsets.size());
JITStubCall stubCall(this, cti_op_switch_imm);
// create jump table for switch destinations, track this switch statement.
SimpleJumpTable* jumpTable = &m_codeBlock->characterSwitchJumpTable(tableIndex);
- m_switches.append(SwitchRecord(jumpTable, m_bytecodeIndex, defaultOffset, SwitchRecord::Character));
+ m_switches.append(SwitchRecord(jumpTable, m_bytecodeOffset, defaultOffset, SwitchRecord::Character));
jumpTable->ctiOffsets.grow(jumpTable->branchOffsets.size());
JITStubCall stubCall(this, cti_op_switch_char);
// create jump table for switch destinations, track this switch statement.
StringJumpTable* jumpTable = &m_codeBlock->stringSwitchJumpTable(tableIndex);
- m_switches.append(SwitchRecord(jumpTable, m_bytecodeIndex, defaultOffset));
+ m_switches.append(SwitchRecord(jumpTable, m_bytecodeOffset, defaultOffset));
JITStubCall stubCall(this, cti_op_switch_string);
stubCall.addArgument(scrutinee);
jump(regT0);
}
-void JIT::emit_op_new_error(Instruction* currentInstruction)
+void JIT::emit_op_throw_reference_error(Instruction* currentInstruction)
{
- unsigned dst = currentInstruction[1].u.operand;
- unsigned type = currentInstruction[2].u.operand;
- unsigned message = currentInstruction[3].u.operand;
+ unsigned message = currentInstruction[1].u.operand;
- JITStubCall stubCall(this, cti_op_new_error);
- stubCall.addArgument(Imm32(type));
+ JITStubCall stubCall(this, cti_op_throw_reference_error);
stubCall.addArgument(m_codeBlock->getConstant(message));
- stubCall.addArgument(Imm32(m_bytecodeIndex));
- stubCall.call(dst);
+ stubCall.call();
}
void JIT::emit_op_debug(Instruction* currentInstruction)
emitStore(i, jsUndefined());
}
-void JIT::emit_op_enter_with_activation(Instruction* currentInstruction)
+void JIT::emit_op_create_activation(Instruction* currentInstruction)
{
- emit_op_enter(currentInstruction);
-
- JITStubCall(this, cti_op_push_activation).call(currentInstruction[1].u.operand);
+ unsigned activation = currentInstruction[1].u.operand;
+
+ Jump activationCreated = branch32(NotEqual, tagFor(activation), TrustedImm32(JSValue::EmptyValueTag));
+ JITStubCall(this, cti_op_push_activation).call(activation);
+ activationCreated.link(this);
}
-void JIT::emit_op_create_arguments(Instruction*)
+void JIT::emit_op_create_arguments(Instruction* currentInstruction)
{
- Jump argsCreated = branch32(NotEqual, tagFor(RegisterFile::ArgumentsRegister, callFrameRegister), Imm32(JSValue::EmptyValueTag));
+ unsigned dst = currentInstruction[1].u.operand;
+
+ Jump argsCreated = branch32(NotEqual, tagFor(dst), TrustedImm32(JSValue::EmptyValueTag));
- // If we get here the arguments pointer is a null cell - i.e. arguments need lazy creation.
if (m_codeBlock->m_numParameters == 1)
JITStubCall(this, cti_op_create_arguments_no_params).call();
else
JITStubCall(this, cti_op_create_arguments).call();
+ emitStore(dst, regT1, regT0);
+ emitStore(unmodifiedArgumentsRegister(dst), regT1, regT0);
+
argsCreated.link(this);
}
-void JIT::emit_op_init_arguments(Instruction*)
+void JIT::emit_op_init_lazy_reg(Instruction* currentInstruction)
{
- emitStore(RegisterFile::ArgumentsRegister, JSValue(), callFrameRegister);
+ unsigned dst = currentInstruction[1].u.operand;
+
+ emitStore(dst, JSValue());
+}
+
+void JIT::emit_op_get_callee(Instruction* currentInstruction)
+{
+ int dst = currentInstruction[1].u.operand;
+ emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT0);
+ emitStoreCell(dst, regT0);
+}
+
+void JIT::emit_op_create_this(Instruction* currentInstruction)
+{
+ unsigned protoRegister = currentInstruction[2].u.operand;
+ emitLoad(protoRegister, regT1, regT0);
+ JITStubCall stubCall(this, cti_op_create_this);
+ stubCall.addArgument(regT1, regT0);
+ stubCall.call(currentInstruction[1].u.operand);
}
void JIT::emit_op_convert_this(Instruction* currentInstruction)
emitLoad(thisRegister, regT1, regT0);
- addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::CellTag)));
+ addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)));
+
+ loadPtr(Address(regT0, JSCell::structureOffset()), regT2);
+ addSlowCase(branchTest8(NonZero, Address(regT2, Structure::typeInfoFlagsOffset()), TrustedImm32(NeedsThisConversion)));
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2);
- addSlowCase(branchTest8(NonZero, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(NeedsThisConversion)));
+ map(m_bytecodeOffset + OPCODE_LENGTH(op_convert_this), thisRegister, regT1, regT0);
+}
- map(m_bytecodeIndex + OPCODE_LENGTH(op_convert_this), thisRegister, regT1, regT0);
+void JIT::emit_op_convert_this_strict(Instruction* currentInstruction)
+{
+ unsigned thisRegister = currentInstruction[1].u.operand;
+
+ emitLoad(thisRegister, regT1, regT0);
+
+ Jump notNull = branch32(NotEqual, regT1, TrustedImm32(JSValue::EmptyValueTag));
+ emitStore(thisRegister, jsNull());
+ Jump setThis = jump();
+ notNull.link(this);
+ Jump isImmediate = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag));
+ loadPtr(Address(regT0, JSCell::structureOffset()), regT2);
+ Jump notAnObject = branch8(NotEqual, Address(regT2, Structure::typeInfoTypeOffset()), TrustedImm32(ObjectType));
+ addSlowCase(branchTest8(NonZero, Address(regT2, Structure::typeInfoFlagsOffset()), TrustedImm32(NeedsThisConversion)));
+ isImmediate.link(this);
+ notAnObject.link(this);
+ setThis.link(this);
+ map(m_bytecodeOffset + OPCODE_LENGTH(op_convert_this_strict), thisRegister, regT1, regT0);
}
void JIT::emitSlow_op_convert_this(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
stubCall.call(thisRegister);
}
+void JIT::emitSlow_op_convert_this_strict(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+ unsigned thisRegister = currentInstruction[1].u.operand;
+
+ linkSlowCase(iter);
+
+ JITStubCall stubCall(this, cti_op_convert_this_strict);
+ stubCall.addArgument(regT1, regT0);
+ stubCall.call(thisRegister);
+}
+
void JIT::emit_op_profile_will_call(Instruction* currentInstruction)
{
peek(regT2, OBJECT_OFFSETOF(JITStackFrame, enabledProfilerReference) / sizeof(void*));
noProfiler.link(this);
}
+void JIT::emit_op_get_arguments_length(Instruction* currentInstruction)
+{
+ int dst = currentInstruction[1].u.operand;
+ int argumentsRegister = currentInstruction[2].u.operand;
+ addSlowCase(branch32(NotEqual, tagFor(argumentsRegister), TrustedImm32(JSValue::EmptyValueTag)));
+ emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT0);
+ sub32(TrustedImm32(1), regT0);
+ emitStoreInt32(dst, regT0);
}
-#endif // ENABLE(JIT) && USE(JSVALUE32_64)
+void JIT::emitSlow_op_get_arguments_length(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+ linkSlowCase(iter);
+ int dst = currentInstruction[1].u.operand;
+ int base = currentInstruction[2].u.operand;
+ int ident = currentInstruction[3].u.operand;
+
+ JITStubCall stubCall(this, cti_op_get_by_id_generic);
+ stubCall.addArgument(base);
+ stubCall.addArgument(TrustedImmPtr(&(m_codeBlock->identifier(ident))));
+ stubCall.call(dst);
+}
+
+void JIT::emit_op_get_argument_by_val(Instruction* currentInstruction)
+{
+ int dst = currentInstruction[1].u.operand;
+ int argumentsRegister = currentInstruction[2].u.operand;
+ int property = currentInstruction[3].u.operand;
+ addSlowCase(branch32(NotEqual, tagFor(argumentsRegister), TrustedImm32(JSValue::EmptyValueTag)));
+ emitLoad(property, regT1, regT2);
+ addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)));
+ add32(TrustedImm32(1), regT2);
+ // regT2 now contains the integer index of the argument we want, including this
+ emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT3);
+ addSlowCase(branch32(AboveOrEqual, regT2, regT3));
+
+ Jump skipOutofLineParams;
+ int numArgs = m_codeBlock->m_numParameters;
+ if (numArgs) {
+ Jump notInInPlaceArgs = branch32(AboveOrEqual, regT2, Imm32(numArgs));
+ addPtr(Imm32(static_cast<unsigned>(-(RegisterFile::CallFrameHeaderSize + numArgs) * sizeof(Register))), callFrameRegister, regT1);
+ loadPtr(BaseIndex(regT1, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0);
+ loadPtr(BaseIndex(regT1, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1);
+ skipOutofLineParams = jump();
+ notInInPlaceArgs.link(this);
+ }
+
+ addPtr(Imm32(static_cast<unsigned>(-(RegisterFile::CallFrameHeaderSize + numArgs) * sizeof(Register))), callFrameRegister, regT1);
+ mul32(TrustedImm32(sizeof(Register)), regT3, regT3);
+ subPtr(regT3, regT1);
+ loadPtr(BaseIndex(regT1, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0);
+ loadPtr(BaseIndex(regT1, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1);
+ if (numArgs)
+ skipOutofLineParams.link(this);
+ emitStore(dst, regT1, regT0);
+}
+
+void JIT::emitSlow_op_get_argument_by_val(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+ unsigned dst = currentInstruction[1].u.operand;
+ unsigned arguments = currentInstruction[2].u.operand;
+ unsigned property = currentInstruction[3].u.operand;
+
+ linkSlowCase(iter);
+ Jump skipArgumentsCreation = jump();
+
+ linkSlowCase(iter);
+ linkSlowCase(iter);
+ if (m_codeBlock->m_numParameters == 1)
+ JITStubCall(this, cti_op_create_arguments_no_params).call();
+ else
+ JITStubCall(this, cti_op_create_arguments).call();
+
+ emitStore(arguments, regT1, regT0);
+ emitStore(unmodifiedArgumentsRegister(arguments), regT1, regT0);
+
+ skipArgumentsCreation.link(this);
+ JITStubCall stubCall(this, cti_op_get_by_val);
+ stubCall.addArgument(arguments);
+ stubCall.addArgument(property);
+ stubCall.call(dst);
+}
+
+#if ENABLE(JIT_USE_SOFT_MODULO)
+void JIT::softModulo()
+{
+ push(regT1);
+ push(regT3);
+ move(regT2, regT3);
+ move(regT0, regT2);
+ move(TrustedImm32(0), regT1);
+
+ // Check for negative result reminder
+ Jump positiveRegT3 = branch32(GreaterThanOrEqual, regT3, TrustedImm32(0));
+ neg32(regT3);
+ xor32(TrustedImm32(1), regT1);
+ positiveRegT3.link(this);
+
+ Jump positiveRegT2 = branch32(GreaterThanOrEqual, regT2, TrustedImm32(0));
+ neg32(regT2);
+ xor32(TrustedImm32(2), regT1);
+ positiveRegT2.link(this);
+
+ // Save the condition for negative reminder
+ push(regT1);
+
+ Jump exitBranch = branch32(LessThan, regT2, regT3);
+
+ // Power of two fast case
+ move(regT3, regT0);
+ sub32(TrustedImm32(1), regT0);
+ Jump powerOfTwo = branchTest32(NonZero, regT0, regT3);
+ and32(regT0, regT2);
+ powerOfTwo.link(this);
+
+ and32(regT3, regT0);
+
+ Jump exitBranch2 = branchTest32(Zero, regT0);
+
+ countLeadingZeros32(regT2, regT0);
+ countLeadingZeros32(regT3, regT1);
+ sub32(regT0, regT1);
+
+ Jump useFullTable = branch32(Equal, regT1, TrustedImm32(31));
+
+ neg32(regT1);
+ add32(TrustedImm32(31), regT1);
+
+ int elementSizeByShift = -1;
+#if CPU(ARM)
+ elementSizeByShift = 3;
+#else
+#error "JIT_OPTIMIZE_MOD not yet supported on this platform."
+#endif
+ relativeTableJump(regT1, elementSizeByShift);
+
+ useFullTable.link(this);
+ // Modulo table
+ for (int i = 31; i > 0; --i) {
+#if CPU(ARM_TRADITIONAL)
+ m_assembler.cmp_r(regT2, m_assembler.lsl(regT3, i));
+ m_assembler.sub_r(regT2, regT2, m_assembler.lsl(regT3, i), ARMAssembler::CS);
+#elif CPU(ARM_THUMB2)
+ ShiftTypeAndAmount shift(SRType_LSL, i);
+ m_assembler.sub_S(regT1, regT2, regT3, shift);
+ m_assembler.it(ARMv7Assembler::ConditionCS);
+ m_assembler.mov(regT2, regT1);
+#else
+#error "JIT_OPTIMIZE_MOD not yet supported on this platform."
+#endif
+ }
+
+ Jump lower = branch32(Below, regT2, regT3);
+ sub32(regT3, regT2);
+ lower.link(this);
+
+ exitBranch.link(this);
+ exitBranch2.link(this);
+
+ // Check for negative reminder
+ pop(regT1);
+ Jump positiveResult = branch32(Equal, regT1, TrustedImm32(0));
+ neg32(regT2);
+ positiveResult.link(this);
+
+ move(regT2, regT0);
+
+ pop(regT3);
+ pop(regT1);
+ ret();
+}
+#endif // ENABLE(JIT_USE_SOFT_MODULO)
+
+} // namespace JSC
+
+#endif // USE(JSVALUE32_64)
+#endif // ENABLE(JIT)
#include "config.h"
-#if !USE(JSVALUE32_64)
-
-#include "JIT.h"
-
#if ENABLE(JIT)
+#include "JIT.h"
#include "CodeBlock.h"
#include "GetterSetter.h"
using namespace std;
namespace JSC {
+#if USE(JSVALUE64)
-PassRefPtr<NativeExecutable> JIT::stringGetByValStubGenerator(JSGlobalData* globalData, ExecutablePool* pool)
+JIT::CodePtr JIT::stringGetByValStubGenerator(JSGlobalData* globalData, ExecutablePool* pool)
{
JSInterfaceJIT jit;
JumpList failures;
- failures.append(jit.branchPtr(NotEqual, Address(regT0), ImmPtr(globalData->jsStringVPtr)));
+ failures.append(jit.branchPtr(NotEqual, Address(regT0), TrustedImmPtr(globalData->jsStringVPtr)));
failures.append(jit.branchTest32(NonZero, Address(regT0, OBJECT_OFFSETOF(JSString, m_fiberCount))));
-#if USE(JSVALUE64)
- jit.zeroExtend32ToPtr(regT1, regT1);
-#else
- jit.emitFastArithImmToInt(regT1);
-#endif
- // Load string length to regT1, and start the process of loading the data pointer into regT0
+ // Load string length to regT2, and start the process of loading the data pointer into regT0
jit.load32(Address(regT0, ThunkHelpers::jsStringLengthOffset()), regT2);
jit.loadPtr(Address(regT0, ThunkHelpers::jsStringValueOffset()), regT0);
jit.loadPtr(Address(regT0, ThunkHelpers::stringImplDataOffset()), regT0);
// Load the character
jit.load16(BaseIndex(regT0, regT1, TimesTwo, 0), regT0);
- failures.append(jit.branch32(AboveOrEqual, regT0, Imm32(0x100)));
- jit.move(ImmPtr(globalData->smallStrings.singleCharacterStrings()), regT1);
+ failures.append(jit.branch32(AboveOrEqual, regT0, TrustedImm32(0x100)));
+ jit.move(TrustedImmPtr(globalData->smallStrings.singleCharacterStrings()), regT1);
jit.loadPtr(BaseIndex(regT1, regT0, ScalePtr, 0), regT0);
jit.ret();
failures.link(&jit);
- jit.move(Imm32(0), regT0);
+ jit.move(TrustedImm32(0), regT0);
jit.ret();
- LinkBuffer patchBuffer(&jit, pool, 0);
- return adoptRef(new NativeExecutable(patchBuffer.finalizeCode()));
+ LinkBuffer patchBuffer(*globalData, &jit, pool);
+ return patchBuffer.finalizeCode().m_code;
}
void JIT::emit_op_get_by_val(Instruction* currentInstruction)
emitGetVirtualRegisters(base, regT0, property, regT1);
emitJumpSlowCaseIfNotImmediateInteger(regT1);
-#if USE(JSVALUE64)
+
// This is technically incorrect - we're zero-extending an int32. On the hot path this doesn't matter.
// We check the value as if it was a uint32 against the m_vectorLength - which will always fail if
// number was signed since m_vectorLength is always less than intmax (since the total allocation
// to 64-bits is necessary since it's used in the address calculation. We zero extend rather than sign
// extending since it makes it easier to re-tag the value in the slow case.
zeroExtend32ToPtr(regT1, regT1);
-#else
- emitFastArithImmToInt(regT1);
-#endif
+
emitJumpSlowCaseIfNotJSCell(regT0, base);
- addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsArrayVPtr)));
+ addSlowCase(branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsArrayVPtr)));
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_storage)), regT2);
- addSlowCase(branch32(AboveOrEqual, regT1, Address(regT0, OBJECT_OFFSETOF(JSArray, m_vectorLength))));
+ loadPtr(Address(regT0, JSArray::storageOffset()), regT2);
+ addSlowCase(branch32(AboveOrEqual, regT1, Address(regT0, JSArray::vectorLengthOffset())));
loadPtr(BaseIndex(regT2, regT1, ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), regT0);
addSlowCase(branchTestPtr(Zero, regT0));
linkSlowCaseIfNotJSCell(iter, base); // base cell check
Jump nonCell = jump();
linkSlowCase(iter); // base array check
- Jump notString = branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsStringVPtr));
- emitNakedCall(m_globalData->getThunk(stringGetByValStubGenerator)->generatedJITCode().addressForCall());
+ Jump notString = branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsStringVPtr));
+ emitNakedCall(m_globalData->getCTIStub(stringGetByValStubGenerator));
Jump failed = branchTestPtr(Zero, regT0);
emitPutVirtualRegister(dst, regT0);
emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_get_by_val));
stubCall.call(dst);
}
-void JIT::compileGetDirectOffset(RegisterID base, RegisterID result, RegisterID structure, RegisterID offset, RegisterID scratch)
+void JIT::compileGetDirectOffset(RegisterID base, RegisterID result, RegisterID offset, RegisterID scratch)
{
- ASSERT(sizeof(((Structure*)0)->m_propertyStorageCapacity) == sizeof(int32_t));
- ASSERT(sizeof(JSObject::inlineStorageCapacity) == sizeof(int32_t));
-
- Jump notUsingInlineStorage = branch32(NotEqual, Address(structure, OBJECT_OFFSETOF(Structure, m_propertyStorageCapacity)), Imm32(JSObject::inlineStorageCapacity));
- loadPtr(BaseIndex(base, offset, ScalePtr, OBJECT_OFFSETOF(JSObject, m_inlineStorage)), result);
- Jump finishedLoad = jump();
- notUsingInlineStorage.link(this);
- loadPtr(Address(base, OBJECT_OFFSETOF(JSObject, m_externalStorage)), scratch);
+ loadPtr(Address(base, OBJECT_OFFSETOF(JSObject, m_propertyStorage)), scratch);
loadPtr(BaseIndex(scratch, offset, ScalePtr, 0), result);
- finishedLoad.link(this);
}
void JIT::emit_op_get_by_pname(Instruction* currentInstruction)
emitJumpSlowCaseIfNotJSCell(regT0, base);
// Test base's structure
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2);
+ loadPtr(Address(regT0, JSCell::structureOffset()), regT2);
addSlowCase(branchPtr(NotEqual, regT2, Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedStructure))));
load32(addressFor(i), regT3);
- sub32(Imm32(1), regT3);
+ sub32(TrustedImm32(1), regT3);
addSlowCase(branch32(AboveOrEqual, regT3, Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_numCacheableSlots))));
- compileGetDirectOffset(regT0, regT0, regT2, regT3, regT1);
+ compileGetDirectOffset(regT0, regT0, regT3, regT1);
emitPutVirtualRegister(dst, regT0);
}
emitGetVirtualRegisters(base, regT0, property, regT1);
emitJumpSlowCaseIfNotImmediateInteger(regT1);
-#if USE(JSVALUE64)
// See comment in op_get_by_val.
zeroExtend32ToPtr(regT1, regT1);
-#else
- emitFastArithImmToInt(regT1);
-#endif
emitJumpSlowCaseIfNotJSCell(regT0, base);
- addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsArrayVPtr)));
- addSlowCase(branch32(AboveOrEqual, regT1, Address(regT0, OBJECT_OFFSETOF(JSArray, m_vectorLength))));
-
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_storage)), regT2);
+ addSlowCase(branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsArrayVPtr)));
+ addSlowCase(branch32(AboveOrEqual, regT1, Address(regT0, JSArray::vectorLengthOffset())));
+ loadPtr(Address(regT0, JSArray::storageOffset()), regT2);
Jump empty = branchTestPtr(Zero, BaseIndex(regT2, regT1, ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])));
Label storeResult(this);
Jump end = jump();
empty.link(this);
- add32(Imm32(1), Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
+ add32(TrustedImm32(1), Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
branch32(Below, regT1, Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_length))).linkTo(storeResult, this);
move(regT1, regT0);
- add32(Imm32(1), regT0);
+ add32(TrustedImm32(1), regT0);
store32(regT0, Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_length)));
jump().linkTo(storeResult, this);
{
JITStubCall stubCall(this, cti_op_put_by_index);
stubCall.addArgument(currentInstruction[1].u.operand, regT2);
- stubCall.addArgument(Imm32(currentInstruction[2].u.operand));
+ stubCall.addArgument(TrustedImm32(currentInstruction[2].u.operand));
stubCall.addArgument(currentInstruction[3].u.operand, regT2);
stubCall.call();
}
{
JITStubCall stubCall(this, cti_op_put_getter);
stubCall.addArgument(currentInstruction[1].u.operand, regT2);
- stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
+ stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
stubCall.addArgument(currentInstruction[3].u.operand, regT2);
stubCall.call();
}
{
JITStubCall stubCall(this, cti_op_put_setter);
stubCall.addArgument(currentInstruction[1].u.operand, regT2);
- stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
+ stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
stubCall.addArgument(currentInstruction[3].u.operand, regT2);
stubCall.call();
}
{
JITStubCall stubCall(this, cti_op_del_by_id);
stubCall.addArgument(currentInstruction[2].u.operand, regT2);
- stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[3].u.operand)));
+ stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[3].u.operand)));
stubCall.call(currentInstruction[1].u.operand);
}
emitGetVirtualRegister(baseVReg, regT0);
JITStubCall stubCall(this, cti_op_get_by_id_generic);
stubCall.addArgument(regT0);
- stubCall.addArgument(ImmPtr(ident));
+ stubCall.addArgument(TrustedImmPtr(ident));
stubCall.call(resultVReg);
m_propertyAccessInstructionIndex++;
JITStubCall stubCall(this, direct ? cti_op_put_by_id_direct_generic, cti_op_put_by_id_generic);
stubCall.addArgument(regT0);
- stubCall.addArgument(ImmPtr(ident));
+ stubCall.addArgument(TrustedImmPtr(ident));
stubCall.addArgument(regT1);
stubCall.call();
BEGIN_UNINTERRUPTED_SEQUENCE(sequenceMethodCheck);
- Jump structureCheck = branchPtrWithPatch(NotEqual, Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), info.structureToCompare, ImmPtr(reinterpret_cast<void*>(patchGetByIdDefaultStructure)));
- DataLabelPtr protoStructureToCompare, protoObj = moveWithPatch(ImmPtr(0), regT1);
- Jump protoStructureCheck = branchPtrWithPatch(NotEqual, Address(regT1, OBJECT_OFFSETOF(JSCell, m_structure)), protoStructureToCompare, ImmPtr(reinterpret_cast<void*>(patchGetByIdDefaultStructure)));
+ Jump structureCheck = branchPtrWithPatch(NotEqual, Address(regT0, JSCell::structureOffset()), info.structureToCompare, TrustedImmPtr(reinterpret_cast<void*>(patchGetByIdDefaultStructure)));
+ DataLabelPtr protoStructureToCompare, protoObj = moveWithPatch(TrustedImmPtr(0), regT1);
+ Jump protoStructureCheck = branchPtrWithPatch(NotEqual, Address(regT1, JSCell::structureOffset()), protoStructureToCompare, TrustedImmPtr(reinterpret_cast<void*>(patchGetByIdDefaultStructure)));
// This will be relinked to load the function without doing a load.
- DataLabelPtr putFunction = moveWithPatch(ImmPtr(0), regT0);
+ DataLabelPtr putFunction = moveWithPatch(TrustedImmPtr(0), regT0);
END_UNINTERRUPTED_SEQUENCE(sequenceMethodCheck);
Jump match = jump();
- ASSERT_JIT_OFFSET(differenceBetween(info.structureToCompare, protoObj), patchOffsetMethodCheckProtoObj);
+ ASSERT_JIT_OFFSET_UNUSED(protoObj, differenceBetween(info.structureToCompare, protoObj), patchOffsetMethodCheckProtoObj);
ASSERT_JIT_OFFSET(differenceBetween(info.structureToCompare, protoStructureToCompare), patchOffsetMethodCheckProtoStruct);
- ASSERT_JIT_OFFSET(differenceBetween(info.structureToCompare, putFunction), patchOffsetMethodCheckPutFunction);
+ ASSERT_JIT_OFFSET_UNUSED(putFunction, differenceBetween(info.structureToCompare, putFunction), patchOffsetMethodCheckPutFunction);
// Link the failure cases here.
notCell.link(this);
emitPutVirtualRegister(resultVReg);
// We've already generated the following get_by_id, so make sure it's skipped over.
- m_bytecodeIndex += OPCODE_LENGTH(op_get_by_id);
+ m_bytecodeOffset += OPCODE_LENGTH(op_get_by_id);
}
void JIT::emitSlow_op_method_check(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
compileGetByIdSlowCase(resultVReg, baseVReg, ident, iter, true);
// We've already generated the following get_by_id, so make sure it's skipped over.
- m_bytecodeIndex += OPCODE_LENGTH(op_get_by_id);
+ m_bytecodeOffset += OPCODE_LENGTH(op_get_by_id);
}
#else //!ENABLE(JIT_OPTIMIZE_METHOD_CALLS)
m_propertyAccessCompilationInfo[propertyAccessInstructionIndex].hotPathBegin = hotPathBegin;
DataLabelPtr structureToCompare;
- Jump structureCheck = branchPtrWithPatch(NotEqual, Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), structureToCompare, ImmPtr(reinterpret_cast<void*>(patchGetByIdDefaultStructure)));
+ Jump structureCheck = branchPtrWithPatch(NotEqual, Address(regT0, JSCell::structureOffset()), structureToCompare, TrustedImmPtr(reinterpret_cast<void*>(patchGetByIdDefaultStructure)));
addSlowCase(structureCheck);
ASSERT_JIT_OFFSET(differenceBetween(hotPathBegin, structureToCompare), patchOffsetGetByIdStructure);
ASSERT_JIT_OFFSET(differenceBetween(hotPathBegin, structureCheck), patchOffsetGetByIdBranchToSlowCase)
- Label externalLoad = loadPtrWithPatchToLEA(Address(regT0, OBJECT_OFFSETOF(JSObject, m_externalStorage)), regT0);
- Label externalLoadComplete(this);
- ASSERT_JIT_OFFSET(differenceBetween(hotPathBegin, externalLoad), patchOffsetGetByIdExternalLoad);
- ASSERT_JIT_OFFSET(differenceBetween(externalLoad, externalLoadComplete), patchLengthGetByIdExternalLoad);
-
- DataLabel32 displacementLabel = loadPtrWithAddressOffsetPatch(Address(regT0, patchGetByIdDefaultOffset), regT0);
- ASSERT_JIT_OFFSET(differenceBetween(hotPathBegin, displacementLabel), patchOffsetGetByIdPropertyMapOffset);
+ loadPtr(Address(regT0, OBJECT_OFFSETOF(JSObject, m_propertyStorage)), regT0);
+ DataLabelCompact displacementLabel = loadPtrWithCompactAddressOffsetPatch(Address(regT0, patchGetByIdDefaultOffset), regT0);
+ ASSERT_JIT_OFFSET_UNUSED(displacementLabel, differenceBetween(hotPathBegin, displacementLabel), patchOffsetGetByIdPropertyMapOffset);
Label putResult(this);
#endif
JITStubCall stubCall(this, isMethodCheck ? cti_op_get_by_id_method_check : cti_op_get_by_id);
stubCall.addArgument(regT0);
- stubCall.addArgument(ImmPtr(ident));
+ stubCall.addArgument(TrustedImmPtr(ident));
Call call = stubCall.call(resultVReg);
END_UNINTERRUPTED_SEQUENCE(sequenceGetByIdSlowCase);
// It is important that the following instruction plants a 32bit immediate, in order that it can be patched over.
DataLabelPtr structureToCompare;
- addSlowCase(branchPtrWithPatch(NotEqual, Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), structureToCompare, ImmPtr(reinterpret_cast<void*>(patchGetByIdDefaultStructure))));
+ addSlowCase(branchPtrWithPatch(NotEqual, Address(regT0, JSCell::structureOffset()), structureToCompare, TrustedImmPtr(reinterpret_cast<void*>(patchGetByIdDefaultStructure))));
ASSERT_JIT_OFFSET(differenceBetween(hotPathBegin, structureToCompare), patchOffsetPutByIdStructure);
- // Plant a load from a bogus ofset in the object's property map; we will patch this later, if it is to be used.
- Label externalLoad = loadPtrWithPatchToLEA(Address(regT0, OBJECT_OFFSETOF(JSObject, m_externalStorage)), regT0);
- Label externalLoadComplete(this);
- ASSERT_JIT_OFFSET(differenceBetween(hotPathBegin, externalLoad), patchOffsetPutByIdExternalLoad);
- ASSERT_JIT_OFFSET(differenceBetween(externalLoad, externalLoadComplete), patchLengthPutByIdExternalLoad);
-
- DataLabel32 displacementLabel = storePtrWithAddressOffsetPatch(regT1, Address(regT0, patchGetByIdDefaultOffset));
+ loadPtr(Address(regT0, OBJECT_OFFSETOF(JSObject, m_propertyStorage)), regT0);
+ DataLabel32 displacementLabel = storePtrWithAddressOffsetPatch(regT1, Address(regT0, patchPutByIdDefaultOffset));
END_UNINTERRUPTED_SEQUENCE(sequencePutById);
- ASSERT_JIT_OFFSET(differenceBetween(hotPathBegin, displacementLabel), patchOffsetPutByIdPropertyMapOffset);
+ ASSERT_JIT_OFFSET_UNUSED(displacementLabel, differenceBetween(hotPathBegin, displacementLabel), patchOffsetPutByIdPropertyMapOffset);
}
void JIT::emitSlow_op_put_by_id(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
JITStubCall stubCall(this, direct ? cti_op_put_by_id_direct : cti_op_put_by_id);
stubCall.addArgument(regT0);
- stubCall.addArgument(ImmPtr(ident));
+ stubCall.addArgument(TrustedImmPtr(ident));
stubCall.addArgument(regT1);
Call call = stubCall.call();
{
int offset = cachedOffset * sizeof(JSValue);
if (structure->isUsingInlineStorage())
- offset += OBJECT_OFFSETOF(JSObject, m_inlineStorage);
+ offset += JSObject::offsetOfInlineStorage();
else
- loadPtr(Address(base, OBJECT_OFFSETOF(JSObject, m_externalStorage)), base);
+ loadPtr(Address(base, OBJECT_OFFSETOF(JSObject, m_propertyStorage)), base);
storePtr(value, Address(base, offset));
}
void JIT::compileGetDirectOffset(RegisterID base, RegisterID result, Structure* structure, size_t cachedOffset)
{
int offset = cachedOffset * sizeof(JSValue);
- if (structure->isUsingInlineStorage())
- offset += OBJECT_OFFSETOF(JSObject, m_inlineStorage);
- else
- loadPtr(Address(base, OBJECT_OFFSETOF(JSObject, m_externalStorage)), base);
- loadPtr(Address(base, offset), result);
-}
-
-void JIT::compileGetDirectOffset(JSObject* base, RegisterID temp, RegisterID result, size_t cachedOffset)
-{
- if (base->isUsingInlineStorage())
- loadPtr(static_cast<void*>(&base->m_inlineStorage[cachedOffset]), result);
- else {
- PropertyStorage* protoPropertyStorage = &base->m_externalStorage;
- loadPtr(static_cast<void*>(protoPropertyStorage), temp);
- loadPtr(Address(temp, cachedOffset * sizeof(JSValue)), result);
- }
+ if (structure->isUsingInlineStorage()) {
+ offset += JSObject::offsetOfInlineStorage();
+ loadPtr(Address(base, offset), result);
+ } else {
+ loadPtr(Address(base, OBJECT_OFFSETOF(JSObject, m_propertyStorage)), result);
+ loadPtr(Address(result, offset), result);
+ }
}
-void JIT::testPrototype(Structure* structure, JumpList& failureCases)
+void JIT::compileGetDirectOffset(JSObject* base, RegisterID result, size_t cachedOffset)
{
- if (structure->m_prototype.isNull())
- return;
-
- move(ImmPtr(&asCell(structure->m_prototype)->m_structure), regT2);
- move(ImmPtr(asCell(structure->m_prototype)->m_structure), regT3);
- failureCases.append(branchPtr(NotEqual, Address(regT2), regT3));
+ loadPtr(static_cast<void*>(&base->m_propertyStorage[cachedOffset]), result);
}
void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure* oldStructure, Structure* newStructure, size_t cachedOffset, StructureChain* chain, ReturnAddressPtr returnAddress, bool direct)
JumpList failureCases;
// Check eax is an object of the right Structure.
failureCases.append(emitJumpIfNotJSCell(regT0));
- failureCases.append(branchPtr(NotEqual, Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), ImmPtr(oldStructure)));
- testPrototype(oldStructure, failureCases);
+ failureCases.append(branchPtr(NotEqual, Address(regT0, JSCell::structureOffset()), TrustedImmPtr(oldStructure)));
+ testPrototype(oldStructure->storedPrototype(), failureCases);
// ecx = baseObject->m_structure
if (!direct) {
- for (RefPtr<Structure>* it = chain->head(); *it; ++it)
- testPrototype(it->get(), failureCases);
+ for (WriteBarrier<Structure>* it = chain->head(); *it; ++it)
+ testPrototype((*it)->storedPrototype(), failureCases);
}
Call callTarget;
stubCall.skipArgument(); // base
stubCall.skipArgument(); // ident
stubCall.skipArgument(); // value
- stubCall.addArgument(Imm32(oldStructure->propertyStorageCapacity()));
- stubCall.addArgument(Imm32(newStructure->propertyStorageCapacity()));
+ stubCall.addArgument(TrustedImm32(oldStructure->propertyStorageCapacity()));
+ stubCall.addArgument(TrustedImm32(newStructure->propertyStorageCapacity()));
stubCall.call(regT0);
emitGetJITStubArg(2, regT1);
restoreReturnAddressBeforeReturn(regT3);
}
- // Assumes m_refCount can be decremented easily, refcount decrement is safe as
- // codeblock should ensure oldStructure->m_refCount > 0
- sub32(Imm32(1), AbsoluteAddress(oldStructure->addressOfCount()));
- add32(Imm32(1), AbsoluteAddress(newStructure->addressOfCount()));
- storePtr(ImmPtr(newStructure), Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)));
+ storePtrWithWriteBarrier(TrustedImmPtr(newStructure), regT0, Address(regT0, JSCell::structureOffset()));
// write the value
compilePutDirectOffset(regT0, regT1, newStructure, cachedOffset);
restoreArgumentReferenceForTrampoline();
Call failureCall = tailRecursiveCall();
- LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0);
+ LinkBuffer patchBuffer(*m_globalData, this, m_codeBlock->executablePool());
patchBuffer.link(failureCall, FunctionPtr(direct ? cti_op_put_by_id_direct_fail : cti_op_put_by_id_fail));
int offset = sizeof(JSValue) * cachedOffset;
- // If we're patching to use inline storage, convert the initial load to a lea; this avoids the extra load
- // and makes the subsequent load's offset automatically correct
- if (structure->isUsingInlineStorage())
- repatchBuffer.repatchLoadPtrToLEA(stubInfo->hotPathBegin.instructionAtOffset(patchOffsetGetByIdExternalLoad));
-
// Patch the offset into the propoerty map to load from, then patch the Structure to look for.
repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabelPtrAtOffset(patchOffsetGetByIdStructure), structure);
- repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabel32AtOffset(patchOffsetGetByIdPropertyMapOffset), offset);
-}
-
-void JIT::patchMethodCallProto(CodeBlock* codeBlock, MethodCallLinkInfo& methodCallLinkInfo, JSFunction* callee, Structure* structure, JSObject* proto, ReturnAddressPtr returnAddress)
-{
- RepatchBuffer repatchBuffer(codeBlock);
-
- ASSERT(!methodCallLinkInfo.cachedStructure);
- methodCallLinkInfo.cachedStructure = structure;
- structure->ref();
-
- Structure* prototypeStructure = proto->structure();
- methodCallLinkInfo.cachedPrototypeStructure = prototypeStructure;
- prototypeStructure->ref();
-
- repatchBuffer.repatch(methodCallLinkInfo.structureLabel, structure);
- repatchBuffer.repatch(methodCallLinkInfo.structureLabel.dataLabelPtrAtOffset(patchOffsetMethodCheckProtoObj), proto);
- repatchBuffer.repatch(methodCallLinkInfo.structureLabel.dataLabelPtrAtOffset(patchOffsetMethodCheckProtoStruct), prototypeStructure);
- repatchBuffer.repatch(methodCallLinkInfo.structureLabel.dataLabelPtrAtOffset(patchOffsetMethodCheckPutFunction), callee);
-
- repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id));
+ repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabelCompactAtOffset(patchOffsetGetByIdPropertyMapOffset), offset);
}
void JIT::patchPutByIdReplace(CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, size_t cachedOffset, ReturnAddressPtr returnAddress, bool direct)
int offset = sizeof(JSValue) * cachedOffset;
- // If we're patching to use inline storage, convert the initial load to a lea; this avoids the extra load
- // and makes the subsequent load's offset automatically correct
- if (structure->isUsingInlineStorage())
- repatchBuffer.repatchLoadPtrToLEA(stubInfo->hotPathBegin.instructionAtOffset(patchOffsetPutByIdExternalLoad));
-
// Patch the offset into the propoerty map to load from, then patch the Structure to look for.
repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabelPtrAtOffset(patchOffsetPutByIdStructure), structure);
repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabel32AtOffset(patchOffsetPutByIdPropertyMapOffset), offset);
StructureStubInfo* stubInfo = &m_codeBlock->getStubInfo(returnAddress);
// Check eax is an array
- Jump failureCases1 = branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsArrayVPtr));
+ Jump failureCases1 = branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsArrayVPtr));
// Checks out okay! - get the length from the storage
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_storage)), regT2);
- load32(Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_length)), regT2);
-
- Jump failureCases2 = branch32(Above, regT2, Imm32(JSImmediate::maxImmediateInt));
+ loadPtr(Address(regT0, JSArray::storageOffset()), regT3);
+ load32(Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_length)), regT2);
+ Jump failureCases2 = branch32(LessThan, regT2, TrustedImm32(0));
emitFastArithIntToImmNoCheck(regT2, regT0);
Jump success = jump();
- LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0);
+ LinkBuffer patchBuffer(*m_globalData, this, m_codeBlock->executablePool());
// Use the patch information to link the failure cases back to the original slow case routine.
CodeLocationLabel slowCaseBegin = stubInfo->callReturnLocation.labelAtOffset(-patchOffsetGetByIdSlowCaseCall);
Jump failureCases1 = checkStructure(regT0, structure);
// Check the prototype object's Structure had not changed.
- Structure** prototypeStructureAddress = &(protoObject->m_structure);
-#if CPU(X86_64)
- move(ImmPtr(prototypeStructure), regT3);
- Jump failureCases2 = branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), regT3);
-#else
- Jump failureCases2 = branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), ImmPtr(prototypeStructure));
-#endif
+ move(TrustedImmPtr(protoObject), regT3);
+ Jump failureCases2 = branchPtr(NotEqual, Address(regT3, JSCell::structureOffset()), TrustedImmPtr(prototypeStructure));
bool needsStubLink = false;
// Checks out okay!
if (slot.cachedPropertyType() == PropertySlot::Getter) {
needsStubLink = true;
- compileGetDirectOffset(protoObject, regT1, regT1, cachedOffset);
+ compileGetDirectOffset(protoObject, regT1, cachedOffset);
JITStubCall stubCall(this, cti_op_get_by_id_getter_stub);
stubCall.addArgument(regT1);
stubCall.addArgument(regT0);
- stubCall.addArgument(ImmPtr(stubInfo->callReturnLocation.executableAddress()));
+ stubCall.addArgument(TrustedImmPtr(stubInfo->callReturnLocation.executableAddress()));
stubCall.call();
} else if (slot.cachedPropertyType() == PropertySlot::Custom) {
needsStubLink = true;
JITStubCall stubCall(this, cti_op_get_by_id_custom_stub);
- stubCall.addArgument(ImmPtr(protoObject));
- stubCall.addArgument(ImmPtr(FunctionPtr(slot.customGetter()).executableAddress()));
- stubCall.addArgument(ImmPtr(const_cast<Identifier*>(&ident)));
- stubCall.addArgument(ImmPtr(stubInfo->callReturnLocation.executableAddress()));
+ stubCall.addArgument(TrustedImmPtr(protoObject));
+ stubCall.addArgument(TrustedImmPtr(FunctionPtr(slot.customGetter()).executableAddress()));
+ stubCall.addArgument(TrustedImmPtr(const_cast<Identifier*>(&ident)));
+ stubCall.addArgument(TrustedImmPtr(stubInfo->callReturnLocation.executableAddress()));
stubCall.call();
} else
- compileGetDirectOffset(protoObject, regT1, regT0, cachedOffset);
+ compileGetDirectOffset(protoObject, regT0, cachedOffset);
Jump success = jump();
- LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0);
+ LinkBuffer patchBuffer(*m_globalData, this, m_codeBlock->executablePool());
// Use the patch information to link the failure cases back to the original slow case routine.
CodeLocationLabel slowCaseBegin = stubInfo->callReturnLocation.labelAtOffset(-patchOffsetGetByIdSlowCaseCall);
bool needsStubLink = false;
if (slot.cachedPropertyType() == PropertySlot::Getter) {
needsStubLink = true;
- if (!structure->isUsingInlineStorage()) {
- move(regT0, regT1);
- compileGetDirectOffset(regT1, regT1, structure, cachedOffset);
- } else
- compileGetDirectOffset(regT0, regT1, structure, cachedOffset);
+ compileGetDirectOffset(regT0, regT1, structure, cachedOffset);
JITStubCall stubCall(this, cti_op_get_by_id_getter_stub);
stubCall.addArgument(regT1);
stubCall.addArgument(regT0);
- stubCall.addArgument(ImmPtr(stubInfo->callReturnLocation.executableAddress()));
+ stubCall.addArgument(TrustedImmPtr(stubInfo->callReturnLocation.executableAddress()));
stubCall.call();
} else if (slot.cachedPropertyType() == PropertySlot::Custom) {
needsStubLink = true;
JITStubCall stubCall(this, cti_op_get_by_id_custom_stub);
stubCall.addArgument(regT0);
- stubCall.addArgument(ImmPtr(FunctionPtr(slot.customGetter()).executableAddress()));
- stubCall.addArgument(ImmPtr(const_cast<Identifier*>(&ident)));
- stubCall.addArgument(ImmPtr(stubInfo->callReturnLocation.executableAddress()));
+ stubCall.addArgument(TrustedImmPtr(FunctionPtr(slot.customGetter()).executableAddress()));
+ stubCall.addArgument(TrustedImmPtr(const_cast<Identifier*>(&ident)));
+ stubCall.addArgument(TrustedImmPtr(stubInfo->callReturnLocation.executableAddress()));
stubCall.call();
} else
compileGetDirectOffset(regT0, regT0, structure, cachedOffset);
Jump success = jump();
- LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0);
+ LinkBuffer patchBuffer(*m_globalData, this, m_codeBlock->executablePool());
if (needsStubLink) {
for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) {
CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum();
- structure->ref();
- polymorphicStructures->list[currentIndex].set(entryLabel, structure);
+ polymorphicStructures->list[currentIndex].set(*m_globalData, m_codeBlock->ownerExecutable(), entryLabel, structure);
// Finally patch the jump to slow case back in the hot path to jump here instead.
CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase);
Jump failureCases1 = checkStructure(regT0, structure);
// Check the prototype object's Structure had not changed.
- Structure** prototypeStructureAddress = &(protoObject->m_structure);
-#if CPU(X86_64)
- move(ImmPtr(prototypeStructure), regT3);
- Jump failureCases2 = branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), regT3);
-#else
- Jump failureCases2 = branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), ImmPtr(prototypeStructure));
-#endif
+ move(TrustedImmPtr(protoObject), regT3);
+ Jump failureCases2 = branchPtr(NotEqual, Address(regT3, JSCell::structureOffset()), TrustedImmPtr(prototypeStructure));
// Checks out okay!
bool needsStubLink = false;
if (slot.cachedPropertyType() == PropertySlot::Getter) {
needsStubLink = true;
- compileGetDirectOffset(protoObject, regT1, regT1, cachedOffset);
+ compileGetDirectOffset(protoObject, regT1, cachedOffset);
JITStubCall stubCall(this, cti_op_get_by_id_getter_stub);
stubCall.addArgument(regT1);
stubCall.addArgument(regT0);
- stubCall.addArgument(ImmPtr(stubInfo->callReturnLocation.executableAddress()));
+ stubCall.addArgument(TrustedImmPtr(stubInfo->callReturnLocation.executableAddress()));
stubCall.call();
} else if (slot.cachedPropertyType() == PropertySlot::Custom) {
needsStubLink = true;
JITStubCall stubCall(this, cti_op_get_by_id_custom_stub);
- stubCall.addArgument(ImmPtr(protoObject));
- stubCall.addArgument(ImmPtr(FunctionPtr(slot.customGetter()).executableAddress()));
- stubCall.addArgument(ImmPtr(const_cast<Identifier*>(&ident)));
- stubCall.addArgument(ImmPtr(stubInfo->callReturnLocation.executableAddress()));
+ stubCall.addArgument(TrustedImmPtr(protoObject));
+ stubCall.addArgument(TrustedImmPtr(FunctionPtr(slot.customGetter()).executableAddress()));
+ stubCall.addArgument(TrustedImmPtr(const_cast<Identifier*>(&ident)));
+ stubCall.addArgument(TrustedImmPtr(stubInfo->callReturnLocation.executableAddress()));
stubCall.call();
} else
- compileGetDirectOffset(protoObject, regT1, regT0, cachedOffset);
+ compileGetDirectOffset(protoObject, regT0, cachedOffset);
Jump success = jump();
- LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0);
+ LinkBuffer patchBuffer(*m_globalData, this, m_codeBlock->executablePool());
if (needsStubLink) {
for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) {
patchBuffer.link(success, stubInfo->hotPathBegin.labelAtOffset(patchOffsetGetByIdPutResult));
CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum();
-
- structure->ref();
- prototypeStructure->ref();
- prototypeStructures->list[currentIndex].set(entryLabel, structure, prototypeStructure);
+ prototypeStructures->list[currentIndex].set(*m_globalData, m_codeBlock->ownerExecutable(), entryLabel, structure, prototypeStructure);
// Finally patch the jump to slow case back in the hot path to jump here instead.
CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase);
bucketsOfFail.append(baseObjectCheck);
Structure* currStructure = structure;
- RefPtr<Structure>* chainEntries = chain->head();
+ WriteBarrier<Structure>* it = chain->head();
JSObject* protoObject = 0;
- for (unsigned i = 0; i < count; ++i) {
+ for (unsigned i = 0; i < count; ++i, ++it) {
protoObject = asObject(currStructure->prototypeForLookup(callFrame));
- currStructure = chainEntries[i].get();
-
- // Check the prototype object's Structure had not changed.
- Structure** prototypeStructureAddress = &(protoObject->m_structure);
-#if CPU(X86_64)
- move(ImmPtr(currStructure), regT3);
- bucketsOfFail.append(branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), regT3));
-#else
- bucketsOfFail.append(branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), ImmPtr(currStructure)));
-#endif
+ currStructure = it->get();
+ testPrototype(protoObject, bucketsOfFail);
}
ASSERT(protoObject);
bool needsStubLink = false;
if (slot.cachedPropertyType() == PropertySlot::Getter) {
needsStubLink = true;
- compileGetDirectOffset(protoObject, regT1, regT1, cachedOffset);
+ compileGetDirectOffset(protoObject, regT1, cachedOffset);
JITStubCall stubCall(this, cti_op_get_by_id_getter_stub);
stubCall.addArgument(regT1);
stubCall.addArgument(regT0);
- stubCall.addArgument(ImmPtr(stubInfo->callReturnLocation.executableAddress()));
+ stubCall.addArgument(TrustedImmPtr(stubInfo->callReturnLocation.executableAddress()));
stubCall.call();
} else if (slot.cachedPropertyType() == PropertySlot::Custom) {
needsStubLink = true;
JITStubCall stubCall(this, cti_op_get_by_id_custom_stub);
- stubCall.addArgument(ImmPtr(protoObject));
- stubCall.addArgument(ImmPtr(FunctionPtr(slot.customGetter()).executableAddress()));
- stubCall.addArgument(ImmPtr(const_cast<Identifier*>(&ident)));
- stubCall.addArgument(ImmPtr(stubInfo->callReturnLocation.executableAddress()));
+ stubCall.addArgument(TrustedImmPtr(protoObject));
+ stubCall.addArgument(TrustedImmPtr(FunctionPtr(slot.customGetter()).executableAddress()));
+ stubCall.addArgument(TrustedImmPtr(const_cast<Identifier*>(&ident)));
+ stubCall.addArgument(TrustedImmPtr(stubInfo->callReturnLocation.executableAddress()));
stubCall.call();
} else
- compileGetDirectOffset(protoObject, regT1, regT0, cachedOffset);
+ compileGetDirectOffset(protoObject, regT0, cachedOffset);
Jump success = jump();
- LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0);
+ LinkBuffer patchBuffer(*m_globalData, this, m_codeBlock->executablePool());
if (needsStubLink) {
for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) {
CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum();
// Track the stub we have created so that it will be deleted later.
- structure->ref();
- chain->ref();
- prototypeStructures->list[currentIndex].set(entryLabel, structure, chain);
+ prototypeStructures->list[currentIndex].set(callFrame->globalData(), m_codeBlock->ownerExecutable(), entryLabel, structure, chain);
// Finally patch the jump to slow case back in the hot path to jump here instead.
CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase);
bucketsOfFail.append(checkStructure(regT0, structure));
Structure* currStructure = structure;
- RefPtr<Structure>* chainEntries = chain->head();
+ WriteBarrier<Structure>* it = chain->head();
JSObject* protoObject = 0;
- for (unsigned i = 0; i < count; ++i) {
+ for (unsigned i = 0; i < count; ++i, ++it) {
protoObject = asObject(currStructure->prototypeForLookup(callFrame));
- currStructure = chainEntries[i].get();
-
- // Check the prototype object's Structure had not changed.
- Structure** prototypeStructureAddress = &(protoObject->m_structure);
-#if CPU(X86_64)
- move(ImmPtr(currStructure), regT3);
- bucketsOfFail.append(branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), regT3));
-#else
- bucketsOfFail.append(branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), ImmPtr(currStructure)));
-#endif
+ currStructure = it->get();
+ testPrototype(protoObject, bucketsOfFail);
}
ASSERT(protoObject);
bool needsStubLink = false;
if (slot.cachedPropertyType() == PropertySlot::Getter) {
needsStubLink = true;
- compileGetDirectOffset(protoObject, regT1, regT1, cachedOffset);
+ compileGetDirectOffset(protoObject, regT1, cachedOffset);
JITStubCall stubCall(this, cti_op_get_by_id_getter_stub);
stubCall.addArgument(regT1);
stubCall.addArgument(regT0);
- stubCall.addArgument(ImmPtr(stubInfo->callReturnLocation.executableAddress()));
+ stubCall.addArgument(TrustedImmPtr(stubInfo->callReturnLocation.executableAddress()));
stubCall.call();
} else if (slot.cachedPropertyType() == PropertySlot::Custom) {
needsStubLink = true;
JITStubCall stubCall(this, cti_op_get_by_id_custom_stub);
- stubCall.addArgument(ImmPtr(protoObject));
- stubCall.addArgument(ImmPtr(FunctionPtr(slot.customGetter()).executableAddress()));
- stubCall.addArgument(ImmPtr(const_cast<Identifier*>(&ident)));
- stubCall.addArgument(ImmPtr(stubInfo->callReturnLocation.executableAddress()));
+ stubCall.addArgument(TrustedImmPtr(protoObject));
+ stubCall.addArgument(TrustedImmPtr(FunctionPtr(slot.customGetter()).executableAddress()));
+ stubCall.addArgument(TrustedImmPtr(const_cast<Identifier*>(&ident)));
+ stubCall.addArgument(TrustedImmPtr(stubInfo->callReturnLocation.executableAddress()));
stubCall.call();
} else
- compileGetDirectOffset(protoObject, regT1, regT0, cachedOffset);
+ compileGetDirectOffset(protoObject, regT0, cachedOffset);
Jump success = jump();
- LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0);
+ LinkBuffer patchBuffer(*m_globalData, this, m_codeBlock->executablePool());
if (needsStubLink) {
for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) {
#endif // !ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
+#endif // USE(JSVALUE64)
+
+void JIT::testPrototype(JSValue prototype, JumpList& failureCases)
+{
+ if (prototype.isNull())
+ return;
+
+ ASSERT(prototype.isCell());
+ move(TrustedImmPtr(prototype.asCell()), regT3);
+ failureCases.append(branchPtr(NotEqual, Address(regT3, JSCell::structureOffset()), TrustedImmPtr(prototype.asCell()->structure())));
+}
+
+void JIT::patchMethodCallProto(JSGlobalData& globalData, CodeBlock* codeBlock, MethodCallLinkInfo& methodCallLinkInfo, JSObjectWithGlobalObject* callee, Structure* structure, JSObject* proto, ReturnAddressPtr returnAddress)
+{
+ RepatchBuffer repatchBuffer(codeBlock);
+
+ ASSERT(!methodCallLinkInfo.cachedStructure);
+ CodeLocationDataLabelPtr structureLocation = methodCallLinkInfo.cachedStructure.location();
+ methodCallLinkInfo.cachedStructure.set(globalData, structureLocation, codeBlock->ownerExecutable(), structure);
+
+ Structure* prototypeStructure = proto->structure();
+ methodCallLinkInfo.cachedPrototypeStructure.set(globalData, structureLocation.dataLabelPtrAtOffset(patchOffsetMethodCheckProtoStruct), codeBlock->ownerExecutable(), prototypeStructure);
+ methodCallLinkInfo.cachedPrototype.set(globalData, structureLocation.dataLabelPtrAtOffset(patchOffsetMethodCheckProtoObj), codeBlock->ownerExecutable(), proto);
+ methodCallLinkInfo.cachedFunction.set(globalData, structureLocation.dataLabelPtrAtOffset(patchOffsetMethodCheckPutFunction), codeBlock->ownerExecutable(), callee);
+ repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id));
+}
+
} // namespace JSC
#endif // ENABLE(JIT)
-
-#endif // !USE(JSVALUE32_64)
#include "config.h"
+#if ENABLE(JIT)
#if USE(JSVALUE32_64)
-
#include "JIT.h"
-#if ENABLE(JIT)
-
#include "CodeBlock.h"
#include "JITInlineMethods.h"
#include "JITStubCall.h"
JITStubCall stubCall(this, cti_op_put_getter);
stubCall.addArgument(base);
- stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(property)));
+ stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(property)));
stubCall.addArgument(function);
stubCall.call();
}
JITStubCall stubCall(this, cti_op_put_setter);
stubCall.addArgument(base);
- stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(property)));
+ stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(property)));
stubCall.addArgument(function);
stubCall.call();
}
JITStubCall stubCall(this, cti_op_del_by_id);
stubCall.addArgument(base);
- stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(property)));
+ stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(property)));
stubCall.call(dst);
}
JITStubCall stubCall(this, cti_op_get_by_id_generic);
stubCall.addArgument(base);
- stubCall.addArgument(ImmPtr(&(m_codeBlock->identifier(ident))));
+ stubCall.addArgument(TrustedImmPtr(&(m_codeBlock->identifier(ident))));
stubCall.call(dst);
m_propertyAccessInstructionIndex++;
JITStubCall stubCall(this, cti_op_put_by_id_generic);
stubCall.addArgument(base);
- stubCall.addArgument(ImmPtr(&(m_codeBlock->identifier(ident))));
+ stubCall.addArgument(TrustedImmPtr(&(m_codeBlock->identifier(ident))));
stubCall.addArgument(value);
stubCall.call();
BEGIN_UNINTERRUPTED_SEQUENCE(sequenceMethodCheck);
- Jump structureCheck = branchPtrWithPatch(NotEqual, Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), info.structureToCompare, ImmPtr(reinterpret_cast<void*>(patchGetByIdDefaultStructure)));
- DataLabelPtr protoStructureToCompare, protoObj = moveWithPatch(ImmPtr(0), regT2);
- Jump protoStructureCheck = branchPtrWithPatch(NotEqual, Address(regT2, OBJECT_OFFSETOF(JSCell, m_structure)), protoStructureToCompare, ImmPtr(reinterpret_cast<void*>(patchGetByIdDefaultStructure)));
+ Jump structureCheck = branchPtrWithPatch(NotEqual, Address(regT0, JSCell::structureOffset()), info.structureToCompare, TrustedImmPtr(reinterpret_cast<void*>(patchGetByIdDefaultStructure)));
+ DataLabelPtr protoStructureToCompare, protoObj = moveWithPatch(TrustedImmPtr(0), regT2);
+ Jump protoStructureCheck = branchPtrWithPatch(NotEqual, Address(regT2, JSCell::structureOffset()), protoStructureToCompare, TrustedImmPtr(reinterpret_cast<void*>(patchGetByIdDefaultStructure)));
// This will be relinked to load the function without doing a load.
- DataLabelPtr putFunction = moveWithPatch(ImmPtr(0), regT0);
+ DataLabelPtr putFunction = moveWithPatch(TrustedImmPtr(0), regT0);
END_UNINTERRUPTED_SEQUENCE(sequenceMethodCheck);
- move(Imm32(JSValue::CellTag), regT1);
+ move(TrustedImm32(JSValue::CellTag), regT1);
Jump match = jump();
- ASSERT(differenceBetween(info.structureToCompare, protoObj) == patchOffsetMethodCheckProtoObj);
- ASSERT(differenceBetween(info.structureToCompare, protoStructureToCompare) == patchOffsetMethodCheckProtoStruct);
- ASSERT(differenceBetween(info.structureToCompare, putFunction) == patchOffsetMethodCheckPutFunction);
+ ASSERT_JIT_OFFSET(differenceBetween(info.structureToCompare, protoObj), patchOffsetMethodCheckProtoObj);
+ ASSERT_JIT_OFFSET(differenceBetween(info.structureToCompare, protoStructureToCompare), patchOffsetMethodCheckProtoStruct);
+ ASSERT_JIT_OFFSET(differenceBetween(info.structureToCompare, putFunction), patchOffsetMethodCheckPutFunction);
// Link the failure cases here.
structureCheck.link(this);
match.link(this);
emitStore(dst, regT1, regT0);
- map(m_bytecodeIndex + OPCODE_LENGTH(op_method_check), dst, regT1, regT0);
+ map(m_bytecodeOffset + OPCODE_LENGTH(op_method_check), dst, regT1, regT0);
// We've already generated the following get_by_id, so make sure it's skipped over.
- m_bytecodeIndex += OPCODE_LENGTH(op_get_by_id);
+ m_bytecodeOffset += OPCODE_LENGTH(op_get_by_id);
}
void JIT::emitSlow_op_method_check(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
compileGetByIdSlowCase(dst, base, &(m_codeBlock->identifier(ident)), iter, true);
// We've already generated the following get_by_id, so make sure it's skipped over.
- m_bytecodeIndex += OPCODE_LENGTH(op_get_by_id);
+ m_bytecodeOffset += OPCODE_LENGTH(op_get_by_id);
}
#else //!ENABLE(JIT_OPTIMIZE_METHOD_CALLS)
#endif
-PassRefPtr<NativeExecutable> JIT::stringGetByValStubGenerator(JSGlobalData* globalData, ExecutablePool* pool)
+JIT::CodePtr JIT::stringGetByValStubGenerator(JSGlobalData* globalData, ExecutablePool* pool)
{
JSInterfaceJIT jit;
JumpList failures;
- failures.append(jit.branchPtr(NotEqual, Address(regT0), ImmPtr(globalData->jsStringVPtr)));
+ failures.append(jit.branchPtr(NotEqual, Address(regT0), TrustedImmPtr(globalData->jsStringVPtr)));
failures.append(jit.branchTest32(NonZero, Address(regT0, OBJECT_OFFSETOF(JSString, m_fiberCount))));
// Load string length to regT1, and start the process of loading the data pointer into regT0
// Load the character
jit.load16(BaseIndex(regT0, regT2, TimesTwo, 0), regT0);
- failures.append(jit.branch32(AboveOrEqual, regT0, Imm32(0x100)));
- jit.move(ImmPtr(globalData->smallStrings.singleCharacterStrings()), regT1);
+ failures.append(jit.branch32(AboveOrEqual, regT0, TrustedImm32(0x100)));
+ jit.move(TrustedImmPtr(globalData->smallStrings.singleCharacterStrings()), regT1);
jit.loadPtr(BaseIndex(regT1, regT0, ScalePtr, 0), regT0);
- jit.move(Imm32(JSValue::CellTag), regT1); // We null check regT0 on return so this is safe
+ jit.move(TrustedImm32(JSValue::CellTag), regT1); // We null check regT0 on return so this is safe
jit.ret();
failures.link(&jit);
- jit.move(Imm32(0), regT0);
+ jit.move(TrustedImm32(0), regT0);
jit.ret();
- LinkBuffer patchBuffer(&jit, pool, 0);
- return adoptRef(new NativeExecutable(patchBuffer.finalizeCode()));
+ LinkBuffer patchBuffer(*globalData, &jit, pool);
+ return patchBuffer.finalizeCode().m_code;
}
void JIT::emit_op_get_by_val(Instruction* currentInstruction)
emitLoad2(base, regT1, regT0, property, regT3, regT2);
- addSlowCase(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
+ addSlowCase(branch32(NotEqual, regT3, TrustedImm32(JSValue::Int32Tag)));
emitJumpSlowCaseIfNotJSCell(base, regT1);
- addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsArrayVPtr)));
+ addSlowCase(branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsArrayVPtr)));
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_storage)), regT3);
- addSlowCase(branch32(AboveOrEqual, regT2, Address(regT0, OBJECT_OFFSETOF(JSArray, m_vectorLength))));
+ loadPtr(Address(regT0, JSArray::storageOffset()), regT3);
+ addSlowCase(branch32(AboveOrEqual, regT2, Address(regT0, JSArray::vectorLengthOffset())));
- load32(BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + 4), regT1); // tag
- load32(BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), regT0); // payload
- addSlowCase(branch32(Equal, regT1, Imm32(JSValue::EmptyValueTag)));
+ load32(BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1); // tag
+ load32(BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0); // payload
+ addSlowCase(branch32(Equal, regT1, TrustedImm32(JSValue::EmptyValueTag)));
emitStore(dst, regT1, regT0);
- map(m_bytecodeIndex + OPCODE_LENGTH(op_get_by_val), dst, regT1, regT0);
+ map(m_bytecodeOffset + OPCODE_LENGTH(op_get_by_val), dst, regT1, regT0);
}
void JIT::emitSlow_op_get_by_val(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
Jump nonCell = jump();
linkSlowCase(iter); // base array check
- Jump notString = branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsStringVPtr));
- emitNakedCall(m_globalData->getThunk(stringGetByValStubGenerator)->generatedJITCode().addressForCall());
+ Jump notString = branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsStringVPtr));
+ emitNakedCall(m_globalData->getCTIStub(stringGetByValStubGenerator));
Jump failed = branchTestPtr(Zero, regT0);
emitStore(dst, regT1, regT0);
emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_get_by_val));
emitLoad2(base, regT1, regT0, property, regT3, regT2);
- addSlowCase(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
+ addSlowCase(branch32(NotEqual, regT3, TrustedImm32(JSValue::Int32Tag)));
emitJumpSlowCaseIfNotJSCell(base, regT1);
- addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsArrayVPtr)));
- addSlowCase(branch32(AboveOrEqual, regT2, Address(regT0, OBJECT_OFFSETOF(JSArray, m_vectorLength))));
+ addSlowCase(branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsArrayVPtr)));
+ addSlowCase(branch32(AboveOrEqual, regT2, Address(regT0, JSArray::vectorLengthOffset())));
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_storage)), regT3);
+ loadPtr(Address(regT0, JSArray::storageOffset()), regT3);
- Jump empty = branch32(Equal, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + 4), Imm32(JSValue::EmptyValueTag));
+ Jump empty = branch32(Equal, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::EmptyValueTag));
Label storeResult(this);
emitLoad(value, regT1, regT0);
- store32(regT0, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]))); // payload
- store32(regT1, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + 4)); // tag
+ store32(regT0, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload))); // payload
+ store32(regT1, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag))); // tag
Jump end = jump();
empty.link(this);
- add32(Imm32(1), Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
+ add32(TrustedImm32(1), Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
branch32(Below, regT2, Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_length))).linkTo(storeResult, this);
- add32(Imm32(1), regT2, regT0);
+ add32(TrustedImm32(1), regT2, regT0);
store32(regT0, Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_length)));
jump().linkTo(storeResult, this);
emitJumpSlowCaseIfNotJSCell(base, regT1);
compileGetByIdHotPath();
emitStore(dst, regT1, regT0);
- map(m_bytecodeIndex + OPCODE_LENGTH(op_get_by_id), dst, regT1, regT0);
+ map(m_bytecodeOffset + OPCODE_LENGTH(op_get_by_id), dst, regT1, regT0);
}
void JIT::compileGetByIdHotPath()
m_propertyAccessInstructionIndex++;
DataLabelPtr structureToCompare;
- Jump structureCheck = branchPtrWithPatch(NotEqual, Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), structureToCompare, ImmPtr(reinterpret_cast<void*>(patchGetByIdDefaultStructure)));
+ Jump structureCheck = branchPtrWithPatch(NotEqual, Address(regT0, JSCell::structureOffset()), structureToCompare, TrustedImmPtr(reinterpret_cast<void*>(patchGetByIdDefaultStructure)));
addSlowCase(structureCheck);
- ASSERT(differenceBetween(hotPathBegin, structureToCompare) == patchOffsetGetByIdStructure);
- ASSERT(differenceBetween(hotPathBegin, structureCheck) == patchOffsetGetByIdBranchToSlowCase);
+ ASSERT_JIT_OFFSET(differenceBetween(hotPathBegin, structureToCompare), patchOffsetGetByIdStructure);
+ ASSERT_JIT_OFFSET(differenceBetween(hotPathBegin, structureCheck), patchOffsetGetByIdBranchToSlowCase);
- Label externalLoad = loadPtrWithPatchToLEA(Address(regT0, OBJECT_OFFSETOF(JSObject, m_externalStorage)), regT2);
- Label externalLoadComplete(this);
- ASSERT(differenceBetween(hotPathBegin, externalLoad) == patchOffsetGetByIdExternalLoad);
- ASSERT(differenceBetween(externalLoad, externalLoadComplete) == patchLengthGetByIdExternalLoad);
-
- DataLabel32 displacementLabel1 = loadPtrWithAddressOffsetPatch(Address(regT2, patchGetByIdDefaultOffset), regT0); // payload
- ASSERT(differenceBetween(hotPathBegin, displacementLabel1) == patchOffsetGetByIdPropertyMapOffset1);
- DataLabel32 displacementLabel2 = loadPtrWithAddressOffsetPatch(Address(regT2, patchGetByIdDefaultOffset), regT1); // tag
- ASSERT(differenceBetween(hotPathBegin, displacementLabel2) == patchOffsetGetByIdPropertyMapOffset2);
+ loadPtr(Address(regT0, OBJECT_OFFSETOF(JSObject, m_propertyStorage)), regT2);
+ DataLabelCompact displacementLabel1 = loadPtrWithCompactAddressOffsetPatch(Address(regT2, patchGetByIdDefaultOffset), regT0); // payload
+ ASSERT_JIT_OFFSET(differenceBetween(hotPathBegin, displacementLabel1), patchOffsetGetByIdPropertyMapOffset1);
+ DataLabelCompact displacementLabel2 = loadPtrWithCompactAddressOffsetPatch(Address(regT2, patchGetByIdDefaultOffset), regT1); // tag
+ ASSERT_JIT_OFFSET(differenceBetween(hotPathBegin, displacementLabel2), patchOffsetGetByIdPropertyMapOffset2);
Label putResult(this);
- ASSERT(differenceBetween(hotPathBegin, putResult) == patchOffsetGetByIdPutResult);
+ ASSERT_JIT_OFFSET(differenceBetween(hotPathBegin, putResult), patchOffsetGetByIdPutResult);
END_UNINTERRUPTED_SEQUENCE(sequenceGetByIdHotPath);
}
#endif
JITStubCall stubCall(this, isMethodCheck ? cti_op_get_by_id_method_check : cti_op_get_by_id);
stubCall.addArgument(regT1, regT0);
- stubCall.addArgument(ImmPtr(ident));
+ stubCall.addArgument(TrustedImmPtr(ident));
Call call = stubCall.call(dst);
- END_UNINTERRUPTED_SEQUENCE(sequenceGetByIdSlowCase);
+ END_UNINTERRUPTED_SEQUENCE_FOR_PUT(sequenceGetByIdSlowCase, dst);
- ASSERT(differenceBetween(coldPathBegin, call) == patchOffsetGetByIdSlowCaseCall);
+ ASSERT_JIT_OFFSET(differenceBetween(coldPathBegin, call), patchOffsetGetByIdSlowCaseCall);
// Track the location of the call; this will be used to recover patch information.
m_propertyAccessCompilationInfo[m_propertyAccessInstructionIndex].callReturnLocation = call;
// It is important that the following instruction plants a 32bit immediate, in order that it can be patched over.
DataLabelPtr structureToCompare;
- addSlowCase(branchPtrWithPatch(NotEqual, Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), structureToCompare, ImmPtr(reinterpret_cast<void*>(patchGetByIdDefaultStructure))));
- ASSERT(differenceBetween(hotPathBegin, structureToCompare) == patchOffsetPutByIdStructure);
-
- // Plant a load from a bogus ofset in the object's property map; we will patch this later, if it is to be used.
- Label externalLoad = loadPtrWithPatchToLEA(Address(regT0, OBJECT_OFFSETOF(JSObject, m_externalStorage)), regT0);
- Label externalLoadComplete(this);
- ASSERT(differenceBetween(hotPathBegin, externalLoad) == patchOffsetPutByIdExternalLoad);
- ASSERT(differenceBetween(externalLoad, externalLoadComplete) == patchLengthPutByIdExternalLoad);
+ addSlowCase(branchPtrWithPatch(NotEqual, Address(regT0, JSCell::structureOffset()), structureToCompare, TrustedImmPtr(reinterpret_cast<void*>(patchGetByIdDefaultStructure))));
+ ASSERT_JIT_OFFSET(differenceBetween(hotPathBegin, structureToCompare), patchOffsetPutByIdStructure);
- DataLabel32 displacementLabel1 = storePtrWithAddressOffsetPatch(regT2, Address(regT0, patchGetByIdDefaultOffset)); // payload
- DataLabel32 displacementLabel2 = storePtrWithAddressOffsetPatch(regT3, Address(regT0, patchGetByIdDefaultOffset)); // tag
+ loadPtr(Address(regT0, OBJECT_OFFSETOF(JSObject, m_propertyStorage)), regT0);
+ DataLabel32 displacementLabel1 = storePtrWithAddressOffsetPatch(regT2, Address(regT0, patchPutByIdDefaultOffset)); // payload
+ DataLabel32 displacementLabel2 = storePtrWithAddressOffsetPatch(regT3, Address(regT0, patchPutByIdDefaultOffset)); // tag
END_UNINTERRUPTED_SEQUENCE(sequencePutById);
- ASSERT(differenceBetween(hotPathBegin, displacementLabel1) == patchOffsetPutByIdPropertyMapOffset1);
- ASSERT(differenceBetween(hotPathBegin, displacementLabel2) == patchOffsetPutByIdPropertyMapOffset2);
+ ASSERT_JIT_OFFSET(differenceBetween(hotPathBegin, displacementLabel1), patchOffsetPutByIdPropertyMapOffset1);
+ ASSERT_JIT_OFFSET(differenceBetween(hotPathBegin, displacementLabel2), patchOffsetPutByIdPropertyMapOffset2);
}
void JIT::emitSlow_op_put_by_id(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
JITStubCall stubCall(this, direct ? cti_op_put_by_id_direct : cti_op_put_by_id);
stubCall.addArgument(regT1, regT0);
- stubCall.addArgument(ImmPtr(&(m_codeBlock->identifier(ident))));
+ stubCall.addArgument(TrustedImmPtr(&(m_codeBlock->identifier(ident))));
stubCall.addArgument(regT3, regT2);
Call call = stubCall.call();
{
int offset = cachedOffset;
if (structure->isUsingInlineStorage())
- offset += OBJECT_OFFSETOF(JSObject, m_inlineStorage) / sizeof(Register);
+ offset += JSObject::offsetOfInlineStorage() / sizeof(Register);
else
- loadPtr(Address(base, OBJECT_OFFSETOF(JSObject, m_externalStorage)), base);
+ loadPtr(Address(base, OBJECT_OFFSETOF(JSObject, m_propertyStorage)), base);
emitStore(offset, valueTag, valuePayload, base);
}
void JIT::compileGetDirectOffset(RegisterID base, RegisterID resultTag, RegisterID resultPayload, Structure* structure, size_t cachedOffset)
{
int offset = cachedOffset;
- if (structure->isUsingInlineStorage())
- offset += OBJECT_OFFSETOF(JSObject, m_inlineStorage) / sizeof(Register);
- else
- loadPtr(Address(base, OBJECT_OFFSETOF(JSObject, m_externalStorage)), base);
- emitLoad(offset, resultTag, resultPayload, base);
-}
-
-void JIT::compileGetDirectOffset(JSObject* base, RegisterID temp, RegisterID resultTag, RegisterID resultPayload, size_t cachedOffset)
-{
- if (base->isUsingInlineStorage()) {
- load32(reinterpret_cast<char*>(&base->m_inlineStorage[cachedOffset]), resultPayload);
- load32(reinterpret_cast<char*>(&base->m_inlineStorage[cachedOffset]) + 4, resultTag);
- return;
+ if (structure->isUsingInlineStorage()) {
+ offset += JSObject::offsetOfInlineStorage() / sizeof(Register);
+ emitLoad(offset, resultTag, resultPayload, base);
+ } else {
+ RegisterID temp = resultPayload;
+ loadPtr(Address(base, OBJECT_OFFSETOF(JSObject, m_propertyStorage)), temp);
+ emitLoad(offset, resultTag, resultPayload, temp);
}
-
- size_t offset = cachedOffset * sizeof(JSValue);
-
- PropertyStorage* protoPropertyStorage = &base->m_externalStorage;
- loadPtr(static_cast<void*>(protoPropertyStorage), temp);
- load32(Address(temp, offset), resultPayload);
- load32(Address(temp, offset + 4), resultTag);
}
-void JIT::testPrototype(Structure* structure, JumpList& failureCases)
+void JIT::compileGetDirectOffset(JSObject* base, RegisterID resultTag, RegisterID resultPayload, size_t cachedOffset)
{
- if (structure->m_prototype.isNull())
- return;
-
- failureCases.append(branchPtr(NotEqual, AbsoluteAddress(&asCell(structure->m_prototype)->m_structure), ImmPtr(asCell(structure->m_prototype)->m_structure)));
+ load32(reinterpret_cast<char*>(&base->m_propertyStorage[cachedOffset]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload), resultPayload);
+ load32(reinterpret_cast<char*>(&base->m_propertyStorage[cachedOffset]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag), resultTag);
}
void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure* oldStructure, Structure* newStructure, size_t cachedOffset, StructureChain* chain, ReturnAddressPtr returnAddress, bool direct)
{
- // It is assumed that regT0 contains the basePayload and regT1 contains the baseTag. The value can be found on the stack.
-
+ // The code below assumes that regT0 contains the basePayload and regT1 contains the baseTag. Restore them from the stack.
+#if CPU(MIPS) || CPU(SH4) || CPU(ARM)
+ // For MIPS, we don't add sizeof(void*) to the stack offset.
+ load32(Address(stackPointerRegister, OBJECT_OFFSETOF(JITStackFrame, args[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0);
+ // For MIPS, we don't add sizeof(void*) to the stack offset.
+ load32(Address(stackPointerRegister, OBJECT_OFFSETOF(JITStackFrame, args[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1);
+#else
+ load32(Address(stackPointerRegister, OBJECT_OFFSETOF(JITStackFrame, args[0]) + sizeof(void*) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0);
+ load32(Address(stackPointerRegister, OBJECT_OFFSETOF(JITStackFrame, args[0]) + sizeof(void*) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1);
+#endif
+
JumpList failureCases;
- failureCases.append(branch32(NotEqual, regT1, Imm32(JSValue::CellTag)));
- failureCases.append(branchPtr(NotEqual, Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), ImmPtr(oldStructure)));
- testPrototype(oldStructure, failureCases);
+ failureCases.append(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)));
+ failureCases.append(branchPtr(NotEqual, Address(regT0, JSCell::structureOffset()), TrustedImmPtr(oldStructure)));
+ testPrototype(oldStructure->storedPrototype(), failureCases);
if (!direct) {
// Verify that nothing in the prototype chain has a setter for this property.
- for (RefPtr<Structure>* it = chain->head(); *it; ++it)
- testPrototype(it->get(), failureCases);
+ for (WriteBarrier<Structure>* it = chain->head(); *it; ++it)
+ testPrototype((*it)->storedPrototype(), failureCases);
}
// Reallocate property storage if needed.
stubCall.skipArgument(); // base
stubCall.skipArgument(); // ident
stubCall.skipArgument(); // value
- stubCall.addArgument(Imm32(oldStructure->propertyStorageCapacity()));
- stubCall.addArgument(Imm32(newStructure->propertyStorageCapacity()));
+ stubCall.addArgument(TrustedImm32(oldStructure->propertyStorageCapacity()));
+ stubCall.addArgument(TrustedImm32(newStructure->propertyStorageCapacity()));
stubCall.call(regT0);
restoreReturnAddressBeforeReturn(regT3);
+
+#if CPU(MIPS) || CPU(SH4) || CPU(ARM)
+ // For MIPS, we don't add sizeof(void*) to the stack offset.
+ load32(Address(stackPointerRegister, OBJECT_OFFSETOF(JITStackFrame, args[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0);
+ // For MIPS, we don't add sizeof(void*) to the stack offset.
+ load32(Address(stackPointerRegister, OBJECT_OFFSETOF(JITStackFrame, args[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1);
+#else
+ load32(Address(stackPointerRegister, OBJECT_OFFSETOF(JITStackFrame, args[0]) + sizeof(void*) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0);
+ load32(Address(stackPointerRegister, OBJECT_OFFSETOF(JITStackFrame, args[0]) + sizeof(void*) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1);
+#endif
}
+
+ storePtrWithWriteBarrier(TrustedImmPtr(newStructure), regT0, Address(regT0, JSCell::structureOffset()));
- sub32(Imm32(1), AbsoluteAddress(oldStructure->addressOfCount()));
- add32(Imm32(1), AbsoluteAddress(newStructure->addressOfCount()));
- storePtr(ImmPtr(newStructure), Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)));
-
- load32(Address(stackPointerRegister, OBJECT_OFFSETOF(struct JITStackFrame, args[2]) + sizeof(void*)), regT3);
- load32(Address(stackPointerRegister, OBJECT_OFFSETOF(struct JITStackFrame, args[2]) + sizeof(void*) + 4), regT2);
-
+#if CPU(MIPS) || CPU(SH4) || CPU(ARM)
+ // For MIPS, we don't add sizeof(void*) to the stack offset.
+ load32(Address(stackPointerRegister, OBJECT_OFFSETOF(JITStackFrame, args[2]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT3);
+ load32(Address(stackPointerRegister, OBJECT_OFFSETOF(JITStackFrame, args[2]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT2);
+#else
+ load32(Address(stackPointerRegister, OBJECT_OFFSETOF(JITStackFrame, args[2]) + sizeof(void*) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT3);
+ load32(Address(stackPointerRegister, OBJECT_OFFSETOF(JITStackFrame, args[2]) + sizeof(void*) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT2);
+#endif
+
// Write the value
compilePutDirectOffset(regT0, regT2, regT3, newStructure, cachedOffset);
-
+
ret();
ASSERT(!failureCases.empty());
restoreArgumentReferenceForTrampoline();
Call failureCall = tailRecursiveCall();
- LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0);
+ LinkBuffer patchBuffer(*m_globalData, this, m_codeBlock->executablePool());
patchBuffer.link(failureCall, FunctionPtr(direct ? cti_op_put_by_id_direct_fail : cti_op_put_by_id_fail));
repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id_self_fail));
int offset = sizeof(JSValue) * cachedOffset;
-
- // If we're patching to use inline storage, convert the initial load to a lea; this avoids the extra load
- // and makes the subsequent load's offset automatically correct
- if (structure->isUsingInlineStorage())
- repatchBuffer.repatchLoadPtrToLEA(stubInfo->hotPathBegin.instructionAtOffset(patchOffsetGetByIdExternalLoad));
-
+
// Patch the offset into the propoerty map to load from, then patch the Structure to look for.
repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabelPtrAtOffset(patchOffsetGetByIdStructure), structure);
- repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabel32AtOffset(patchOffsetGetByIdPropertyMapOffset1), offset); // payload
- repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabel32AtOffset(patchOffsetGetByIdPropertyMapOffset2), offset + 4); // tag
-}
-
-void JIT::patchMethodCallProto(CodeBlock* codeBlock, MethodCallLinkInfo& methodCallLinkInfo, JSFunction* callee, Structure* structure, JSObject* proto, ReturnAddressPtr returnAddress)
-{
- RepatchBuffer repatchBuffer(codeBlock);
-
- ASSERT(!methodCallLinkInfo.cachedStructure);
- methodCallLinkInfo.cachedStructure = structure;
- structure->ref();
-
- Structure* prototypeStructure = proto->structure();
- methodCallLinkInfo.cachedPrototypeStructure = prototypeStructure;
- prototypeStructure->ref();
-
- repatchBuffer.repatch(methodCallLinkInfo.structureLabel, structure);
- repatchBuffer.repatch(methodCallLinkInfo.structureLabel.dataLabelPtrAtOffset(patchOffsetMethodCheckProtoObj), proto);
- repatchBuffer.repatch(methodCallLinkInfo.structureLabel.dataLabelPtrAtOffset(patchOffsetMethodCheckProtoStruct), prototypeStructure);
- repatchBuffer.repatch(methodCallLinkInfo.structureLabel.dataLabelPtrAtOffset(patchOffsetMethodCheckPutFunction), callee);
-
- repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id));
+ repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabelCompactAtOffset(patchOffsetGetByIdPropertyMapOffset1), offset + OBJECT_OFFSETOF(JSValue, u.asBits.payload)); // payload
+ repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabelCompactAtOffset(patchOffsetGetByIdPropertyMapOffset2), offset + OBJECT_OFFSETOF(JSValue, u.asBits.tag)); // tag
}
void JIT::patchPutByIdReplace(CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, size_t cachedOffset, ReturnAddressPtr returnAddress, bool direct)
repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic));
int offset = sizeof(JSValue) * cachedOffset;
-
- // If we're patching to use inline storage, convert the initial load to a lea; this avoids the extra load
- // and makes the subsequent load's offset automatically correct
- if (structure->isUsingInlineStorage())
- repatchBuffer.repatchLoadPtrToLEA(stubInfo->hotPathBegin.instructionAtOffset(patchOffsetPutByIdExternalLoad));
-
+
// Patch the offset into the propoerty map to load from, then patch the Structure to look for.
repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabelPtrAtOffset(patchOffsetPutByIdStructure), structure);
- repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabel32AtOffset(patchOffsetPutByIdPropertyMapOffset1), offset); // payload
- repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabel32AtOffset(patchOffsetPutByIdPropertyMapOffset2), offset + 4); // tag
+ repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabel32AtOffset(patchOffsetPutByIdPropertyMapOffset1), offset + OBJECT_OFFSETOF(JSValue, u.asBits.payload)); // payload
+ repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabel32AtOffset(patchOffsetPutByIdPropertyMapOffset2), offset + OBJECT_OFFSETOF(JSValue, u.asBits.tag)); // tag
}
void JIT::privateCompilePatchGetArrayLength(ReturnAddressPtr returnAddress)
// regT0 holds a JSCell*
// Check for array
- Jump failureCases1 = branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsArrayVPtr));
+ Jump failureCases1 = branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsArrayVPtr));
// Checks out okay! - get the length from the storage
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_storage)), regT2);
+ loadPtr(Address(regT0, JSArray::storageOffset()), regT2);
load32(Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_length)), regT2);
- Jump failureCases2 = branch32(Above, regT2, Imm32(INT_MAX));
+ Jump failureCases2 = branch32(Above, regT2, TrustedImm32(INT_MAX));
move(regT2, regT0);
- move(Imm32(JSValue::Int32Tag), regT1);
+ move(TrustedImm32(JSValue::Int32Tag), regT1);
Jump success = jump();
- LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0);
+ LinkBuffer patchBuffer(*m_globalData, this, m_codeBlock->executablePool());
// Use the patch information to link the failure cases back to the original slow case routine.
CodeLocationLabel slowCaseBegin = stubInfo->callReturnLocation.labelAtOffset(-patchOffsetGetByIdSlowCaseCall);
Jump failureCases1 = checkStructure(regT0, structure);
// Check the prototype object's Structure had not changed.
- Structure** prototypeStructureAddress = &(protoObject->m_structure);
-#if CPU(X86_64)
- move(ImmPtr(prototypeStructure), regT3);
- Jump failureCases2 = branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), regT3);
-#else
- Jump failureCases2 = branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), ImmPtr(prototypeStructure));
-#endif
+ move(TrustedImmPtr(protoObject), regT3);
+ Jump failureCases2 = branchPtr(NotEqual, Address(regT3, JSCell::structureOffset()), TrustedImmPtr(prototypeStructure));
+
bool needsStubLink = false;
// Checks out okay!
if (slot.cachedPropertyType() == PropertySlot::Getter) {
needsStubLink = true;
- compileGetDirectOffset(protoObject, regT2, regT2, regT1, cachedOffset);
+ compileGetDirectOffset(protoObject, regT2, regT1, cachedOffset);
JITStubCall stubCall(this, cti_op_get_by_id_getter_stub);
stubCall.addArgument(regT1);
stubCall.addArgument(regT0);
- stubCall.addArgument(ImmPtr(stubInfo->callReturnLocation.executableAddress()));
+ stubCall.addArgument(TrustedImmPtr(stubInfo->callReturnLocation.executableAddress()));
stubCall.call();
} else if (slot.cachedPropertyType() == PropertySlot::Custom) {
needsStubLink = true;
JITStubCall stubCall(this, cti_op_get_by_id_custom_stub);
- stubCall.addArgument(ImmPtr(protoObject));
- stubCall.addArgument(ImmPtr(FunctionPtr(slot.customGetter()).executableAddress()));
- stubCall.addArgument(ImmPtr(const_cast<Identifier*>(&ident)));
- stubCall.addArgument(ImmPtr(stubInfo->callReturnLocation.executableAddress()));
+ stubCall.addArgument(TrustedImmPtr(protoObject));
+ stubCall.addArgument(TrustedImmPtr(FunctionPtr(slot.customGetter()).executableAddress()));
+ stubCall.addArgument(TrustedImmPtr(const_cast<Identifier*>(&ident)));
+ stubCall.addArgument(TrustedImmPtr(stubInfo->callReturnLocation.executableAddress()));
stubCall.call();
} else
- compileGetDirectOffset(protoObject, regT2, regT1, regT0, cachedOffset);
+ compileGetDirectOffset(protoObject, regT1, regT0, cachedOffset);
Jump success = jump();
- LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0);
+ LinkBuffer patchBuffer(*m_globalData, this, m_codeBlock->executablePool());
// Use the patch information to link the failure cases back to the original slow case routine.
CodeLocationLabel slowCaseBegin = stubInfo->callReturnLocation.labelAtOffset(-patchOffsetGetByIdSlowCaseCall);
bool needsStubLink = false;
if (slot.cachedPropertyType() == PropertySlot::Getter) {
needsStubLink = true;
- if (!structure->isUsingInlineStorage()) {
- move(regT0, regT1);
- compileGetDirectOffset(regT1, regT2, regT1, structure, cachedOffset);
- } else
- compileGetDirectOffset(regT0, regT2, regT1, structure, cachedOffset);
+ compileGetDirectOffset(regT0, regT2, regT1, structure, cachedOffset);
JITStubCall stubCall(this, cti_op_get_by_id_getter_stub);
stubCall.addArgument(regT1);
stubCall.addArgument(regT0);
- stubCall.addArgument(ImmPtr(stubInfo->callReturnLocation.executableAddress()));
+ stubCall.addArgument(TrustedImmPtr(stubInfo->callReturnLocation.executableAddress()));
stubCall.call();
} else if (slot.cachedPropertyType() == PropertySlot::Custom) {
needsStubLink = true;
JITStubCall stubCall(this, cti_op_get_by_id_custom_stub);
stubCall.addArgument(regT0);
- stubCall.addArgument(ImmPtr(FunctionPtr(slot.customGetter()).executableAddress()));
- stubCall.addArgument(ImmPtr(const_cast<Identifier*>(&ident)));
- stubCall.addArgument(ImmPtr(stubInfo->callReturnLocation.executableAddress()));
+ stubCall.addArgument(TrustedImmPtr(FunctionPtr(slot.customGetter()).executableAddress()));
+ stubCall.addArgument(TrustedImmPtr(const_cast<Identifier*>(&ident)));
+ stubCall.addArgument(TrustedImmPtr(stubInfo->callReturnLocation.executableAddress()));
stubCall.call();
} else
compileGetDirectOffset(regT0, regT1, regT0, structure, cachedOffset);
Jump success = jump();
- LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0);
+ LinkBuffer patchBuffer(*m_globalData, this, m_codeBlock->executablePool());
if (needsStubLink) {
for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) {
if (iter->to)
patchBuffer.link(success, stubInfo->hotPathBegin.labelAtOffset(patchOffsetGetByIdPutResult));
CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum();
-
- structure->ref();
- polymorphicStructures->list[currentIndex].set(entryLabel, structure);
+
+ polymorphicStructures->list[currentIndex].set(*m_globalData, m_codeBlock->ownerExecutable(), entryLabel, structure);
// Finally patch the jump to slow case back in the hot path to jump here instead.
CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase);
Jump failureCases1 = checkStructure(regT0, structure);
// Check the prototype object's Structure had not changed.
- Structure** prototypeStructureAddress = &(protoObject->m_structure);
-#if CPU(X86_64)
- move(ImmPtr(prototypeStructure), regT3);
- Jump failureCases2 = branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), regT3);
-#else
- Jump failureCases2 = branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), ImmPtr(prototypeStructure));
-#endif
+ move(TrustedImmPtr(protoObject), regT3);
+ Jump failureCases2 = branchPtr(NotEqual, Address(regT3, JSCell::structureOffset()), TrustedImmPtr(prototypeStructure));
bool needsStubLink = false;
if (slot.cachedPropertyType() == PropertySlot::Getter) {
needsStubLink = true;
- compileGetDirectOffset(protoObject, regT2, regT2, regT1, cachedOffset);
+ compileGetDirectOffset(protoObject, regT2, regT1, cachedOffset);
JITStubCall stubCall(this, cti_op_get_by_id_getter_stub);
stubCall.addArgument(regT1);
stubCall.addArgument(regT0);
- stubCall.addArgument(ImmPtr(stubInfo->callReturnLocation.executableAddress()));
+ stubCall.addArgument(TrustedImmPtr(stubInfo->callReturnLocation.executableAddress()));
stubCall.call();
} else if (slot.cachedPropertyType() == PropertySlot::Custom) {
needsStubLink = true;
JITStubCall stubCall(this, cti_op_get_by_id_custom_stub);
- stubCall.addArgument(ImmPtr(protoObject));
- stubCall.addArgument(ImmPtr(FunctionPtr(slot.customGetter()).executableAddress()));
- stubCall.addArgument(ImmPtr(const_cast<Identifier*>(&ident)));
- stubCall.addArgument(ImmPtr(stubInfo->callReturnLocation.executableAddress()));
+ stubCall.addArgument(TrustedImmPtr(protoObject));
+ stubCall.addArgument(TrustedImmPtr(FunctionPtr(slot.customGetter()).executableAddress()));
+ stubCall.addArgument(TrustedImmPtr(const_cast<Identifier*>(&ident)));
+ stubCall.addArgument(TrustedImmPtr(stubInfo->callReturnLocation.executableAddress()));
stubCall.call();
} else
- compileGetDirectOffset(protoObject, regT2, regT1, regT0, cachedOffset);
+ compileGetDirectOffset(protoObject, regT1, regT0, cachedOffset);
Jump success = jump();
- LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0);
+ LinkBuffer patchBuffer(*m_globalData, this, m_codeBlock->executablePool());
if (needsStubLink) {
for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) {
if (iter->to)
patchBuffer.link(success, stubInfo->hotPathBegin.labelAtOffset(patchOffsetGetByIdPutResult));
CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum();
-
- structure->ref();
- prototypeStructure->ref();
- prototypeStructures->list[currentIndex].set(entryLabel, structure, prototypeStructure);
+
+ prototypeStructures->list[currentIndex].set(callFrame->globalData(), m_codeBlock->ownerExecutable(), entryLabel, structure, prototypeStructure);
// Finally patch the jump to slow case back in the hot path to jump here instead.
CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase);
bucketsOfFail.append(checkStructure(regT0, structure));
Structure* currStructure = structure;
- RefPtr<Structure>* chainEntries = chain->head();
+ WriteBarrier<Structure>* it = chain->head();
JSObject* protoObject = 0;
- for (unsigned i = 0; i < count; ++i) {
+ for (unsigned i = 0; i < count; ++i, ++it) {
protoObject = asObject(currStructure->prototypeForLookup(callFrame));
- currStructure = chainEntries[i].get();
-
- // Check the prototype object's Structure had not changed.
- Structure** prototypeStructureAddress = &(protoObject->m_structure);
-#if CPU(X86_64)
- move(ImmPtr(currStructure), regT3);
- bucketsOfFail.append(branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), regT3));
-#else
- bucketsOfFail.append(branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), ImmPtr(currStructure)));
-#endif
+ currStructure = it->get();
+ testPrototype(protoObject, bucketsOfFail);
}
ASSERT(protoObject);
bool needsStubLink = false;
if (slot.cachedPropertyType() == PropertySlot::Getter) {
needsStubLink = true;
- compileGetDirectOffset(protoObject, regT2, regT2, regT1, cachedOffset);
+ compileGetDirectOffset(protoObject, regT2, regT1, cachedOffset);
JITStubCall stubCall(this, cti_op_get_by_id_getter_stub);
stubCall.addArgument(regT1);
stubCall.addArgument(regT0);
- stubCall.addArgument(ImmPtr(stubInfo->callReturnLocation.executableAddress()));
+ stubCall.addArgument(TrustedImmPtr(stubInfo->callReturnLocation.executableAddress()));
stubCall.call();
} else if (slot.cachedPropertyType() == PropertySlot::Custom) {
needsStubLink = true;
JITStubCall stubCall(this, cti_op_get_by_id_custom_stub);
- stubCall.addArgument(ImmPtr(protoObject));
- stubCall.addArgument(ImmPtr(FunctionPtr(slot.customGetter()).executableAddress()));
- stubCall.addArgument(ImmPtr(const_cast<Identifier*>(&ident)));
- stubCall.addArgument(ImmPtr(stubInfo->callReturnLocation.executableAddress()));
+ stubCall.addArgument(TrustedImmPtr(protoObject));
+ stubCall.addArgument(TrustedImmPtr(FunctionPtr(slot.customGetter()).executableAddress()));
+ stubCall.addArgument(TrustedImmPtr(const_cast<Identifier*>(&ident)));
+ stubCall.addArgument(TrustedImmPtr(stubInfo->callReturnLocation.executableAddress()));
stubCall.call();
} else
- compileGetDirectOffset(protoObject, regT2, regT1, regT0, cachedOffset);
+ compileGetDirectOffset(protoObject, regT1, regT0, cachedOffset);
Jump success = jump();
- LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0);
+ LinkBuffer patchBuffer(*m_globalData, this, m_codeBlock->executablePool());
if (needsStubLink) {
for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) {
if (iter->to)
CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum();
// Track the stub we have created so that it will be deleted later.
- structure->ref();
- chain->ref();
- prototypeStructures->list[currentIndex].set(entryLabel, structure, chain);
+ prototypeStructures->list[currentIndex].set(callFrame->globalData(), m_codeBlock->ownerExecutable(), entryLabel, structure, chain);
// Finally patch the jump to slow case back in the hot path to jump here instead.
CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase);
bucketsOfFail.append(checkStructure(regT0, structure));
Structure* currStructure = structure;
- RefPtr<Structure>* chainEntries = chain->head();
+ WriteBarrier<Structure>* it = chain->head();
JSObject* protoObject = 0;
- for (unsigned i = 0; i < count; ++i) {
+ for (unsigned i = 0; i < count; ++i, ++it) {
protoObject = asObject(currStructure->prototypeForLookup(callFrame));
- currStructure = chainEntries[i].get();
-
- // Check the prototype object's Structure had not changed.
- Structure** prototypeStructureAddress = &(protoObject->m_structure);
-#if CPU(X86_64)
- move(ImmPtr(currStructure), regT3);
- bucketsOfFail.append(branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), regT3));
-#else
- bucketsOfFail.append(branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), ImmPtr(currStructure)));
-#endif
+ currStructure = it->get();
+ testPrototype(protoObject, bucketsOfFail);
}
ASSERT(protoObject);
bool needsStubLink = false;
if (slot.cachedPropertyType() == PropertySlot::Getter) {
needsStubLink = true;
- compileGetDirectOffset(protoObject, regT2, regT2, regT1, cachedOffset);
+ compileGetDirectOffset(protoObject, regT2, regT1, cachedOffset);
JITStubCall stubCall(this, cti_op_get_by_id_getter_stub);
stubCall.addArgument(regT1);
stubCall.addArgument(regT0);
- stubCall.addArgument(ImmPtr(stubInfo->callReturnLocation.executableAddress()));
+ stubCall.addArgument(TrustedImmPtr(stubInfo->callReturnLocation.executableAddress()));
stubCall.call();
} else if (slot.cachedPropertyType() == PropertySlot::Custom) {
needsStubLink = true;
JITStubCall stubCall(this, cti_op_get_by_id_custom_stub);
- stubCall.addArgument(ImmPtr(protoObject));
- stubCall.addArgument(ImmPtr(FunctionPtr(slot.customGetter()).executableAddress()));
- stubCall.addArgument(ImmPtr(const_cast<Identifier*>(&ident)));
- stubCall.addArgument(ImmPtr(stubInfo->callReturnLocation.executableAddress()));
+ stubCall.addArgument(TrustedImmPtr(protoObject));
+ stubCall.addArgument(TrustedImmPtr(FunctionPtr(slot.customGetter()).executableAddress()));
+ stubCall.addArgument(TrustedImmPtr(const_cast<Identifier*>(&ident)));
+ stubCall.addArgument(TrustedImmPtr(stubInfo->callReturnLocation.executableAddress()));
stubCall.call();
} else
- compileGetDirectOffset(protoObject, regT2, regT1, regT0, cachedOffset);
+ compileGetDirectOffset(protoObject, regT1, regT0, cachedOffset);
Jump success = jump();
- LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0);
+ LinkBuffer patchBuffer(*m_globalData, this, m_codeBlock->executablePool());
if (needsStubLink) {
for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) {
if (iter->to)
#endif // !ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
-void JIT::compileGetDirectOffset(RegisterID base, RegisterID resultTag, RegisterID resultPayload, RegisterID structure, RegisterID offset)
+void JIT::compileGetDirectOffset(RegisterID base, RegisterID resultTag, RegisterID resultPayload, RegisterID offset)
{
- ASSERT(sizeof(((Structure*)0)->m_propertyStorageCapacity) == sizeof(int32_t));
- ASSERT(sizeof(JSObject::inlineStorageCapacity) == sizeof(int32_t));
ASSERT(sizeof(JSValue) == 8);
- Jump notUsingInlineStorage = branch32(NotEqual, Address(structure, OBJECT_OFFSETOF(Structure, m_propertyStorageCapacity)), Imm32(JSObject::inlineStorageCapacity));
- loadPtr(BaseIndex(base, offset, TimesEight, OBJECT_OFFSETOF(JSObject, m_inlineStorage)+OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload);
- loadPtr(BaseIndex(base, offset, TimesEight, OBJECT_OFFSETOF(JSObject, m_inlineStorage)+OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTag);
- Jump finishedLoad = jump();
- notUsingInlineStorage.link(this);
- loadPtr(Address(base, OBJECT_OFFSETOF(JSObject, m_externalStorage)), base);
+ loadPtr(Address(base, OBJECT_OFFSETOF(JSObject, m_propertyStorage)), base);
loadPtr(BaseIndex(base, offset, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload);
loadPtr(BaseIndex(base, offset, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTag);
- finishedLoad.link(this);
}
void JIT::emit_op_get_by_pname(Instruction* currentInstruction)
emitLoadPayload(iter, regT1);
// Test base's structure
- loadPtr(Address(regT2, OBJECT_OFFSETOF(JSCell, m_structure)), regT0);
+ loadPtr(Address(regT2, JSCell::structureOffset()), regT0);
addSlowCase(branchPtr(NotEqual, regT0, Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedStructure))));
load32(addressFor(i), regT3);
- sub32(Imm32(1), regT3);
+ sub32(TrustedImm32(1), regT3);
addSlowCase(branch32(AboveOrEqual, regT3, Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_numCacheableSlots))));
- compileGetDirectOffset(regT2, regT1, regT0, regT0, regT3);
+ compileGetDirectOffset(regT2, regT1, regT0, regT3);
emitStore(dst, regT1, regT0);
- map(m_bytecodeIndex + OPCODE_LENGTH(op_get_by_pname), dst, regT1, regT0);
+ map(m_bytecodeOffset + OPCODE_LENGTH(op_get_by_pname), dst, regT1, regT0);
}
void JIT::emitSlow_op_get_by_pname(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
} // namespace JSC
+#endif // USE(JSVALUE32_64)
#endif // ENABLE(JIT)
-
-#endif // ENABLE(JSVALUE32_64)
-
m_stackIndex += stackIndexStep;
}
- void addArgument(JIT::Imm32 argument)
+ void addArgument(JIT::TrustedImm32 argument)
{
m_jit->poke(argument, m_stackIndex);
m_stackIndex += stackIndexStep;
}
- void addArgument(JIT::ImmPtr argument)
+ void addArgument(JIT::TrustedImmPtr argument)
{
m_jit->poke(argument, m_stackIndex);
m_stackIndex += stackIndexStep;
JIT::Call call()
{
#if ENABLE(OPCODE_SAMPLING)
- if (m_jit->m_bytecodeIndex != (unsigned)-1)
- m_jit->sampleInstruction(m_jit->m_codeBlock->instructions().begin() + m_jit->m_bytecodeIndex, true);
+ if (m_jit->m_bytecodeOffset != (unsigned)-1)
+ m_jit->sampleInstruction(m_jit->m_codeBlock->instructions().begin() + m_jit->m_bytecodeOffset, true);
#endif
m_jit->restoreArgumentReference();
JIT::Call call = m_jit->call();
- m_jit->m_calls.append(CallRecord(call, m_jit->m_bytecodeIndex, m_stub.value()));
+ m_jit->m_calls.append(CallRecord(call, m_jit->m_bytecodeOffset, m_stub.value()));
#if ENABLE(OPCODE_SAMPLING)
- if (m_jit->m_bytecodeIndex != (unsigned)-1)
- m_jit->sampleInstruction(m_jit->m_codeBlock->instructions().begin() + m_jit->m_bytecodeIndex, false);
+ if (m_jit->m_bytecodeOffset != (unsigned)-1)
+ m_jit->sampleInstruction(m_jit->m_codeBlock->instructions().begin() + m_jit->m_bytecodeOffset, false);
#endif
#if USE(JSVALUE32_64)
/*
* Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
* Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
+ * Copyright (C) Research In Motion Limited 2010, 2011. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
*/
#include "config.h"
-#include "JITStubs.h"
#if ENABLE(JIT)
+#include "JITStubs.h"
#include "Arguments.h"
#include "CallFrame.h"
#include "CodeBlock.h"
-#include "Collector.h"
+#include "Heap.h"
#include "Debugger.h"
#include "ExceptionHelpers.h"
#include "GetterSetter.h"
-#include "GlobalEvalFunction.h"
+#include "Strong.h"
#include "JIT.h"
#include "JSActivation.h"
#include "JSArray.h"
#include "JSByteArray.h"
#include "JSFunction.h"
+#include "JSGlobalObjectFunctions.h"
#include "JSNotAnObject.h"
#include "JSPropertyNameIterator.h"
#include "JSStaticScopeObject.h"
namespace JSC {
-#if OS(DARWIN) || OS(WINDOWS)
+#if OS(DARWIN) || (OS(WINDOWS) && CPU(X86))
#define SYMBOL_STRING(name) "_" #name
#else
#define SYMBOL_STRING(name) #name
#endif
-#if OS(IPHONE_OS)
+#if OS(IOS)
#define THUMB_FUNC_PARAM(name) SYMBOL_STRING(name)
#else
#define THUMB_FUNC_PARAM(name)
#endif
-#if OS(LINUX) && CPU(X86_64)
+#if (OS(LINUX) || OS(FREEBSD)) && CPU(X86_64)
#define SYMBOL_STRING_RELOCATION(name) #name "@plt"
+#elif OS(DARWIN) || (CPU(X86_64) && COMPILER(MINGW) && !GCC_VERSION_AT_LEAST(4, 5, 0))
+#define SYMBOL_STRING_RELOCATION(name) "_" #name
+#elif CPU(X86) && COMPILER(MINGW)
+#define SYMBOL_STRING_RELOCATION(name) "@" #name "@4"
#else
-#define SYMBOL_STRING_RELOCATION(name) SYMBOL_STRING(name)
+#define SYMBOL_STRING_RELOCATION(name) #name
#endif
#if OS(DARWIN)
COMPILE_ASSERT(offsetof(struct JITStackFrame, callFrame) == 0x58, JITStackFrame_callFrame_offset_matches_ctiTrampoline);
COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x50, JITStackFrame_code_offset_matches_ctiTrampoline);
-asm volatile (
+asm (
".text\n"
".globl " SYMBOL_STRING(ctiTrampoline) "\n"
HIDE_SYMBOL(ctiTrampoline) "\n"
"ret" "\n"
);
-asm volatile (
+asm (
".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n"
HIDE_SYMBOL(ctiVMThrowTrampoline) "\n"
SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n"
-#if !USE(JIT_STUB_ARGUMENT_VA_LIST)
"movl %esp, %ecx" "\n"
-#endif
"call " SYMBOL_STRING_RELOCATION(cti_vm_throw) "\n"
- "addl $0x3c, %esp" "\n"
- "popl %ebx" "\n"
- "popl %edi" "\n"
- "popl %esi" "\n"
- "popl %ebp" "\n"
- "ret" "\n"
+ "int3" "\n"
);
-asm volatile (
+asm (
".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n"
HIDE_SYMBOL(ctiOpThrowNotCaught) "\n"
SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n"
#elif COMPILER(GCC) && CPU(X86_64)
-#if USE(JIT_STUB_ARGUMENT_VA_LIST)
-#error "JIT_STUB_ARGUMENT_VA_LIST not supported on x86-64."
-#endif
-
// These ASSERTs remind you that, if you change the layout of JITStackFrame, you
// need to change the assembly trampolines below to match.
COMPILE_ASSERT(offsetof(struct JITStackFrame, code) % 32 == 0x0, JITStackFrame_maintains_32byte_stack_alignment);
COMPILE_ASSERT(offsetof(struct JITStackFrame, callFrame) == 0x90, JITStackFrame_callFrame_offset_matches_ctiTrampoline);
COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x80, JITStackFrame_code_offset_matches_ctiTrampoline);
-asm volatile (
+asm (
".globl " SYMBOL_STRING(ctiTrampoline) "\n"
HIDE_SYMBOL(ctiTrampoline) "\n"
SYMBOL_STRING(ctiTrampoline) ":" "\n"
"ret" "\n"
);
-asm volatile (
+asm (
".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n"
HIDE_SYMBOL(ctiVMThrowTrampoline) "\n"
SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n"
"movq %rsp, %rdi" "\n"
"call " SYMBOL_STRING_RELOCATION(cti_vm_throw) "\n"
- "addq $0x48, %rsp" "\n"
- "popq %rbx" "\n"
- "popq %r15" "\n"
- "popq %r14" "\n"
- "popq %r13" "\n"
- "popq %r12" "\n"
- "popq %rbp" "\n"
- "ret" "\n"
+ "int3" "\n"
);
-asm volatile (
+asm (
".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n"
HIDE_SYMBOL(ctiOpThrowNotCaught) "\n"
SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n"
"ret" "\n"
);
-#elif COMPILER(GCC) && CPU(ARM_THUMB2)
-
-#if USE(JIT_STUB_ARGUMENT_VA_LIST)
-#error "JIT_STUB_ARGUMENT_VA_LIST not supported on ARMv7."
-#endif
+#elif (COMPILER(GCC) || COMPILER(RVCT)) && CPU(ARM_THUMB2)
-#define THUNK_RETURN_ADDRESS_OFFSET 0x3C
-#define PRESERVED_RETURN_ADDRESS_OFFSET 0x40
-#define PRESERVED_R4_OFFSET 0x44
-#define PRESERVED_R5_OFFSET 0x48
-#define PRESERVED_R6_OFFSET 0x4C
-#define REGISTER_FILE_OFFSET 0x50
-#define CALLFRAME_OFFSET 0x54
-#define EXCEPTION_OFFSET 0x58
-#define ENABLE_PROFILER_REFERENCE_OFFSET 0x60
+#define THUNK_RETURN_ADDRESS_OFFSET 0x38
+#define PRESERVED_RETURN_ADDRESS_OFFSET 0x3C
+#define PRESERVED_R4_OFFSET 0x40
+#define PRESERVED_R5_OFFSET 0x44
+#define PRESERVED_R6_OFFSET 0x48
+#define REGISTER_FILE_OFFSET 0x4C
+#define CALLFRAME_OFFSET 0x50
+#define EXCEPTION_OFFSET 0x54
+#define ENABLE_PROFILER_REFERENCE_OFFSET 0x58
-#elif COMPILER(GCC) && CPU(ARM_TRADITIONAL)
+#elif (COMPILER(GCC) || COMPILER(MSVC) || COMPILER(RVCT)) && CPU(ARM_TRADITIONAL)
+// Also update the MSVC section (defined at DEFINE_STUB_FUNCTION)
+// when changing one of the following values.
#define THUNK_RETURN_ADDRESS_OFFSET 64
#define PRESERVEDR4_OFFSET 68
#elif COMPILER(MSVC) && CPU(X86)
-#if USE(JIT_STUB_ARGUMENT_VA_LIST)
-#error "JIT_STUB_ARGUMENT_VA_LIST configuration not supported on MSVC."
-#endif
-
// These ASSERTs remind you that, if you change the layout of JITStackFrame, you
// need to change the assembly trampolines below to match.
COMPILE_ASSERT(offsetof(struct JITStackFrame, code) % 16 == 0x0, JITStackFrame_maintains_16byte_stack_alignment);
extern "C" {
- __declspec(naked) EncodedJSValue ctiTrampoline(void* code, RegisterFile*, CallFrame*, JSValue* exception, Profiler**, JSGlobalData*)
+ __declspec(naked) EncodedJSValue ctiTrampoline(void* code, RegisterFile*, CallFrame*, void* /*unused1*/, Profiler**, JSGlobalData*)
{
__asm {
push ebp;
}
}
-#else
- #error "JIT not supported on this platform."
-#endif
-
-#else // USE(JSVALUE32_64)
-
-#if COMPILER(GCC) && CPU(X86)
+#elif CPU(MIPS)
-// These ASSERTs remind you that, if you change the layout of JITStackFrame, you
-// need to change the assembly trampolines below to match.
-COMPILE_ASSERT(offsetof(struct JITStackFrame, callFrame) == 0x38, JITStackFrame_callFrame_offset_matches_ctiTrampoline);
-COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x30, JITStackFrame_code_offset_matches_ctiTrampoline);
-COMPILE_ASSERT(offsetof(struct JITStackFrame, savedEBX) == 0x1c, JITStackFrame_stub_argument_space_matches_ctiTrampoline);
+#define PRESERVED_GP_OFFSET 60
+#define PRESERVED_S0_OFFSET 64
+#define PRESERVED_S1_OFFSET 68
+#define PRESERVED_S2_OFFSET 72
+#define PRESERVED_RETURN_ADDRESS_OFFSET 76
+#define THUNK_RETURN_ADDRESS_OFFSET 80
+#define REGISTER_FILE_OFFSET 84
+#define CALLFRAME_OFFSET 88
+#define EXCEPTION_OFFSET 92
+#define ENABLE_PROFILER_REFERENCE_OFFSET 96
+#define GLOBAL_DATA_OFFSET 100
+#define STACK_LENGTH 104
+#elif CPU(SH4)
+#define SYMBOL_STRING(name) #name
+/* code (r4), RegisterFile* (r5), CallFrame* (r6), JSValue* exception (r7), Profiler**(sp), JSGlobalData (sp)*/
asm volatile (
".text\n"
".globl " SYMBOL_STRING(ctiTrampoline) "\n"
HIDE_SYMBOL(ctiTrampoline) "\n"
SYMBOL_STRING(ctiTrampoline) ":" "\n"
- "pushl %ebp" "\n"
- "movl %esp, %ebp" "\n"
- "pushl %esi" "\n"
- "pushl %edi" "\n"
- "pushl %ebx" "\n"
- "subl $0x1c, %esp" "\n"
- "movl $512, %esi" "\n"
- "movl 0x38(%esp), %edi" "\n"
- "call *0x30(%esp)" "\n"
- "addl $0x1c, %esp" "\n"
- "popl %ebx" "\n"
- "popl %edi" "\n"
- "popl %esi" "\n"
- "popl %ebp" "\n"
- "ret" "\n"
+ "mov.l r7, @-r15" "\n"
+ "mov.l r6, @-r15" "\n"
+ "mov.l r5, @-r15" "\n"
+ "mov.l r8, @-r15" "\n"
+ "mov #127, r8" "\n"
+ "mov.l r14, @-r15" "\n"
+ "sts.l pr, @-r15" "\n"
+ "mov.l r13, @-r15" "\n"
+ "mov.l r11, @-r15" "\n"
+ "mov.l r10, @-r15" "\n"
+ "add #-60, r15" "\n"
+ "mov r6, r14" "\n"
+ "jsr @r4" "\n"
+ "nop" "\n"
+ "add #60, r15" "\n"
+ "mov.l @r15+,r10" "\n"
+ "mov.l @r15+,r11" "\n"
+ "mov.l @r15+,r13" "\n"
+ "lds.l @r15+,pr" "\n"
+ "mov.l @r15+,r14" "\n"
+ "mov.l @r15+,r8" "\n"
+ "add #12, r15" "\n"
+ "rts" "\n"
+ "nop" "\n"
);
asm volatile (
".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n"
HIDE_SYMBOL(ctiVMThrowTrampoline) "\n"
SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n"
-#if !USE(JIT_STUB_ARGUMENT_VA_LIST)
- "movl %esp, %ecx" "\n"
-#endif
- "call " SYMBOL_STRING_RELOCATION(cti_vm_throw) "\n"
- "addl $0x1c, %esp" "\n"
- "popl %ebx" "\n"
- "popl %edi" "\n"
- "popl %esi" "\n"
- "popl %ebp" "\n"
- "ret" "\n"
+ "mov.l .L2"SYMBOL_STRING(cti_vm_throw)",r0" "\n"
+ "mov r15, r4" "\n"
+ "mov.l @(r0,r12),r11" "\n"
+ "jsr @r11" "\n"
+ "nop" "\n"
+ "add #60, r15" "\n"
+ "mov.l @r15+,r10" "\n"
+ "mov.l @r15+,r11" "\n"
+ "mov.l @r15+,r13" "\n"
+ "lds.l @r15+,pr" "\n"
+ "mov.l @r15+,r14" "\n"
+ "mov.l @r15+,r8" "\n"
+ "add #12, r15" "\n"
+ "rts" "\n"
+ "nop" "\n"
+ ".align 2" "\n"
+ ".L2"SYMBOL_STRING(cti_vm_throw)":.long " SYMBOL_STRING(cti_vm_throw)"@GOT \n"
);
-
+
asm volatile (
".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n"
HIDE_SYMBOL(ctiOpThrowNotCaught) "\n"
SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n"
- "addl $0x1c, %esp" "\n"
- "popl %ebx" "\n"
- "popl %edi" "\n"
- "popl %esi" "\n"
- "popl %ebp" "\n"
- "ret" "\n"
+ "add #60, r15" "\n"
+ "mov.l @r15+,r10" "\n"
+ "mov.l @r15+,r11" "\n"
+ "mov.l @r15+,r13" "\n"
+ "lds.l @r15+,pr" "\n"
+ "mov.l @r15+,r14" "\n"
+ "mov.l @r15+,r8" "\n"
+ "add #12, r15" "\n"
+ "rts" "\n"
+ "nop" "\n"
);
-
-#elif COMPILER(GCC) && CPU(X86_64)
-
-#if USE(JIT_STUB_ARGUMENT_VA_LIST)
-#error "JIT_STUB_ARGUMENT_VA_LIST not supported on x86-64."
+#else
+ #error "JIT not supported on this platform."
#endif
+#else // USE(JSVALUE32_64)
+
+#if COMPILER(GCC) && CPU(X86_64)
+
// These ASSERTs remind you that, if you change the layout of JITStackFrame, you
// need to change the assembly trampolines below to match.
COMPILE_ASSERT(offsetof(struct JITStackFrame, callFrame) == 0x58, JITStackFrame_callFrame_offset_matches_ctiTrampoline);
COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x48, JITStackFrame_code_offset_matches_ctiTrampoline);
COMPILE_ASSERT(offsetof(struct JITStackFrame, savedRBX) == 0x78, JITStackFrame_stub_argument_space_matches_ctiTrampoline);
-asm volatile (
+asm (
".text\n"
".globl " SYMBOL_STRING(ctiTrampoline) "\n"
HIDE_SYMBOL(ctiTrampoline) "\n"
"ret" "\n"
);
-asm volatile (
+asm (
".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n"
HIDE_SYMBOL(ctiVMThrowTrampoline) "\n"
SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n"
"movq %rsp, %rdi" "\n"
"call " SYMBOL_STRING_RELOCATION(cti_vm_throw) "\n"
- "addq $0x78, %rsp" "\n"
- "popq %rbx" "\n"
- "popq %r15" "\n"
- "popq %r14" "\n"
- "popq %r13" "\n"
- "popq %r12" "\n"
- "popq %rbp" "\n"
- "ret" "\n"
+ "int3" "\n"
);
-asm volatile (
+asm (
".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n"
HIDE_SYMBOL(ctiOpThrowNotCaught) "\n"
SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n"
"ret" "\n"
);
-#elif COMPILER(GCC) && CPU(ARM_THUMB2)
-
-#if USE(JIT_STUB_ARGUMENT_VA_LIST)
-#error "JIT_STUB_ARGUMENT_VA_LIST not supported on ARMv7."
+#else
+ #error "JIT not supported on this platform."
#endif
-#define THUNK_RETURN_ADDRESS_OFFSET 0x1C
-#define PRESERVED_RETURN_ADDRESS_OFFSET 0x20
-#define PRESERVED_R4_OFFSET 0x24
-#define PRESERVED_R5_OFFSET 0x28
-#define PRESERVED_R6_OFFSET 0x2C
-#define REGISTER_FILE_OFFSET 0x30
-#define CALLFRAME_OFFSET 0x34
-#define EXCEPTION_OFFSET 0x38
-#define ENABLE_PROFILER_REFERENCE_OFFSET 0x40
-
-#elif COMPILER(GCC) && CPU(ARM_TRADITIONAL)
-
-#define THUNK_RETURN_ADDRESS_OFFSET 32
-#define PRESERVEDR4_OFFSET 36
-
-#elif CPU(MIPS)
-
-#if USE(JIT_STUB_ARGUMENT_VA_LIST)
-#error "JIT_STUB_ARGUMENT_VA_LIST not supported on MIPS."
-#endif
+#endif // USE(JSVALUE32_64)
-asm volatile(
+#if CPU(MIPS)
+asm (
".text" "\n"
".align 2" "\n"
".set noreorder" "\n"
".globl " SYMBOL_STRING(ctiTrampoline) "\n"
".ent " SYMBOL_STRING(ctiTrampoline) "\n"
SYMBOL_STRING(ctiTrampoline) ":" "\n"
- "addiu $29,$29,-72" "\n"
- "sw $31,44($29)" "\n"
- "sw $18,40($29)" "\n"
- "sw $17,36($29)" "\n"
- "sw $16,32($29)" "\n"
+ "addiu $29,$29,-" STRINGIZE_VALUE_OF(STACK_LENGTH) "\n"
+ "sw $31," STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "($29)" "\n"
+ "sw $18," STRINGIZE_VALUE_OF(PRESERVED_S2_OFFSET) "($29)" "\n"
+ "sw $17," STRINGIZE_VALUE_OF(PRESERVED_S1_OFFSET) "($29)" "\n"
+ "sw $16," STRINGIZE_VALUE_OF(PRESERVED_S0_OFFSET) "($29)" "\n"
#if WTF_MIPS_PIC
- "sw $28,28($29)" "\n"
+ "sw $28," STRINGIZE_VALUE_OF(PRESERVED_GP_OFFSET) "($29)" "\n"
#endif
"move $16,$6 # set callFrameRegister" "\n"
"li $17,512 # set timeoutCheckRegister" "\n"
"move $25,$4 # move executableAddress to t9" "\n"
- "sw $5,52($29) # store registerFile to current stack" "\n"
- "sw $6,56($29) # store callFrame to curent stack" "\n"
- "sw $7,60($29) # store exception to current stack" "\n"
- "lw $8,88($29) # load enableProfilerReference from previous stack" "\n"
- "lw $9,92($29) # load globalData from previous stack" "\n"
- "sw $8,64($29) # store enableProfilerReference to current stack" "\n"
+ "sw $5," STRINGIZE_VALUE_OF(REGISTER_FILE_OFFSET) "($29) # store registerFile to current stack" "\n"
+ "sw $6," STRINGIZE_VALUE_OF(CALLFRAME_OFFSET) "($29) # store callFrame to curent stack" "\n"
+ "sw $7," STRINGIZE_VALUE_OF(EXCEPTION_OFFSET) "($29) # store exception to current stack" "\n"
+ "lw $8," STRINGIZE_VALUE_OF(STACK_LENGTH + 16) "($29) # load enableProfilerReference from previous stack" "\n"
+ "lw $9," STRINGIZE_VALUE_OF(STACK_LENGTH + 20) "($29) # load globalData from previous stack" "\n"
+ "sw $8," STRINGIZE_VALUE_OF(ENABLE_PROFILER_REFERENCE_OFFSET) "($29) # store enableProfilerReference to current stack" "\n"
"jalr $25" "\n"
- "sw $9,68($29) # store globalData to current stack" "\n"
- "lw $16,32($29)" "\n"
- "lw $17,36($29)" "\n"
- "lw $18,40($29)" "\n"
- "lw $31,44($29)" "\n"
+ "sw $9," STRINGIZE_VALUE_OF(GLOBAL_DATA_OFFSET) "($29) # store globalData to current stack" "\n"
+ "lw $16," STRINGIZE_VALUE_OF(PRESERVED_S0_OFFSET) "($29)" "\n"
+ "lw $17," STRINGIZE_VALUE_OF(PRESERVED_S1_OFFSET) "($29)" "\n"
+ "lw $18," STRINGIZE_VALUE_OF(PRESERVED_S2_OFFSET) "($29)" "\n"
+ "lw $31," STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "($29)" "\n"
"jr $31" "\n"
- "addiu $29,$29,72" "\n"
+ "addiu $29,$29," STRINGIZE_VALUE_OF(STACK_LENGTH) "\n"
".set reorder" "\n"
".set macro" "\n"
".end " SYMBOL_STRING(ctiTrampoline) "\n"
);
-asm volatile(
+asm (
".text" "\n"
".align 2" "\n"
".set noreorder" "\n"
".ent " SYMBOL_STRING(ctiVMThrowTrampoline) "\n"
SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n"
#if WTF_MIPS_PIC
- "lw $28,28($29)" "\n"
+ "lw $28," STRINGIZE_VALUE_OF(PRESERVED_GP_OFFSET) "($29)" "\n"
".set macro" "\n"
"la $25," SYMBOL_STRING(cti_vm_throw) "\n"
".set nomacro" "\n"
"jal " SYMBOL_STRING(cti_vm_throw) "\n"
"move $4,$29" "\n"
#endif
- "lw $16,32($29)" "\n"
- "lw $17,36($29)" "\n"
- "lw $18,40($29)" "\n"
- "lw $31,44($29)" "\n"
+ "lw $16," STRINGIZE_VALUE_OF(PRESERVED_S0_OFFSET) "($29)" "\n"
+ "lw $17," STRINGIZE_VALUE_OF(PRESERVED_S1_OFFSET) "($29)" "\n"
+ "lw $18," STRINGIZE_VALUE_OF(PRESERVED_S2_OFFSET) "($29)" "\n"
+ "lw $31," STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "($29)" "\n"
"jr $31" "\n"
- "addiu $29,$29,72" "\n"
+ "addiu $29,$29," STRINGIZE_VALUE_OF(STACK_LENGTH) "\n"
".set reorder" "\n"
".set macro" "\n"
".end " SYMBOL_STRING(ctiVMThrowTrampoline) "\n"
);
-asm volatile(
+asm (
".text" "\n"
".align 2" "\n"
".set noreorder" "\n"
".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n"
".ent " SYMBOL_STRING(ctiOpThrowNotCaught) "\n"
SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n"
- "lw $16,32($29)" "\n"
- "lw $17,36($29)" "\n"
- "lw $18,40($29)" "\n"
- "lw $31,44($29)" "\n"
+ "lw $16," STRINGIZE_VALUE_OF(PRESERVED_S0_OFFSET) "($29)" "\n"
+ "lw $17," STRINGIZE_VALUE_OF(PRESERVED_S1_OFFSET) "($29)" "\n"
+ "lw $18," STRINGIZE_VALUE_OF(PRESERVED_S2_OFFSET) "($29)" "\n"
+ "lw $31," STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "($29)" "\n"
"jr $31" "\n"
- "addiu $29,$29,72" "\n"
+ "addiu $29,$29," STRINGIZE_VALUE_OF(STACK_LENGTH) "\n"
".set reorder" "\n"
".set macro" "\n"
".end " SYMBOL_STRING(ctiOpThrowNotCaught) "\n"
);
-
-#elif COMPILER(RVCT) && CPU(ARM_TRADITIONAL)
-
-#define THUNK_RETURN_ADDRESS_OFFSET 32
-#define PRESERVEDR4_OFFSET 36
-
-__asm EncodedJSValue ctiTrampoline(void*, RegisterFile*, CallFrame*, JSValue*, Profiler**, JSGlobalData*)
-{
- ARM
- stmdb sp!, {r1-r3}
- stmdb sp!, {r4-r8, lr}
- sub sp, sp, #36
- mov r4, r2
- mov r5, #512
- mov lr, pc
- bx r0
- add sp, sp, #36
- ldmia sp!, {r4-r8, lr}
- add sp, sp, #12
- bx lr
-}
-
-__asm void ctiVMThrowTrampoline()
-{
- ARM
- PRESERVE8
- mov r0, sp
- bl cti_vm_throw
- add sp, sp, #36
- ldmia sp!, {r4-r8, lr}
- add sp, sp, #12
- bx lr
-}
-
-__asm void ctiOpThrowNotCaught()
-{
- ARM
- add sp, sp, #36
- ldmia sp!, {r4-r8, lr}
- add sp, sp, #12
- bx lr
-}
-
-#elif COMPILER(MSVC) && CPU(X86)
-
-#if USE(JIT_STUB_ARGUMENT_VA_LIST)
-#error "JIT_STUB_ARGUMENT_VA_LIST configuration not supported on MSVC."
-#endif
-
-// These ASSERTs remind you that, if you change the layout of JITStackFrame, you
-// need to change the assembly trampolines below to match.
-COMPILE_ASSERT(offsetof(struct JITStackFrame, callFrame) == 0x38, JITStackFrame_callFrame_offset_matches_ctiTrampoline);
-COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x30, JITStackFrame_code_offset_matches_ctiTrampoline);
-COMPILE_ASSERT(offsetof(struct JITStackFrame, savedEBX) == 0x1c, JITStackFrame_stub_argument_space_matches_ctiTrampoline);
-
-extern "C" {
-
- __declspec(naked) EncodedJSValue ctiTrampoline(void* code, RegisterFile*, CallFrame*, JSValue* exception, Profiler**, JSGlobalData*)
- {
- __asm {
- push ebp;
- mov ebp, esp;
- push esi;
- push edi;
- push ebx;
- sub esp, 0x1c;
- mov esi, 512;
- mov ecx, esp;
- mov edi, [esp + 0x38];
- call [esp + 0x30];
- add esp, 0x1c;
- pop ebx;
- pop edi;
- pop esi;
- pop ebp;
- ret;
- }
- }
-
- __declspec(naked) void ctiVMThrowTrampoline()
- {
- __asm {
- mov ecx, esp;
- call cti_vm_throw;
- add esp, 0x1c;
- pop ebx;
- pop edi;
- pop esi;
- pop ebp;
- ret;
- }
- }
-
- __declspec(naked) void ctiOpThrowNotCaught()
- {
- __asm {
- add esp, 0x1c;
- pop ebx;
- pop edi;
- pop esi;
- pop ebp;
- ret;
- }
- }
-}
-
-#else
- #error "JIT not supported on this platform."
#endif
-#endif // USE(JSVALUE32_64)
-
#if COMPILER(GCC) && CPU(ARM_THUMB2)
-asm volatile(
+asm (
".text" "\n"
".align 2" "\n"
".globl " SYMBOL_STRING(ctiTrampoline) "\n"
"bx lr" "\n"
);
-asm volatile(
+asm (
".text" "\n"
".align 2" "\n"
".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n"
"bx lr" "\n"
);
-asm volatile(
+asm (
".text" "\n"
".align 2" "\n"
".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n"
#elif COMPILER(GCC) && CPU(ARM_TRADITIONAL)
-asm volatile(
+asm (
".globl " SYMBOL_STRING(ctiTrampoline) "\n"
HIDE_SYMBOL(ctiTrampoline) "\n"
SYMBOL_STRING(ctiTrampoline) ":" "\n"
"mov pc, lr" "\n"
);
-asm volatile(
+asm (
".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n"
HIDE_SYMBOL(ctiVMThrowTrampoline) "\n"
SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n"
"mov pc, lr" "\n"
);
+#elif COMPILER(RVCT) && CPU(ARM_THUMB2)
+
+__asm EncodedJSValue ctiTrampoline(void*, RegisterFile*, CallFrame*, JSValue*, Profiler**, JSGlobalData*)
+{
+ PRESERVE8
+ sub sp, sp, # ENABLE_PROFILER_REFERENCE_OFFSET
+ str lr, [sp, # PRESERVED_RETURN_ADDRESS_OFFSET ]
+ str r4, [sp, # PRESERVED_R4_OFFSET ]
+ str r5, [sp, # PRESERVED_R5_OFFSET ]
+ str r6, [sp, # PRESERVED_R6_OFFSET ]
+ str r1, [sp, # REGISTER_FILE_OFFSET ]
+ str r2, [sp, # CALLFRAME_OFFSET ]
+ str r3, [sp, # EXCEPTION_OFFSET ]
+ cpy r5, r2
+ mov r6, #512
+ blx r0
+ ldr r6, [sp, # PRESERVED_R6_OFFSET ]
+ ldr r5, [sp, # PRESERVED_R5_OFFSET ]
+ ldr r4, [sp, # PRESERVED_R4_OFFSET ]
+ ldr lr, [sp, # PRESERVED_RETURN_ADDRESS_OFFSET ]
+ add sp, sp, # ENABLE_PROFILER_REFERENCE_OFFSET
+ bx lr
+}
+
+__asm void ctiVMThrowTrampoline()
+{
+ PRESERVE8
+ cpy r0, sp
+ bl cti_vm_throw
+ ldr r6, [sp, # PRESERVED_R6_OFFSET ]
+ ldr r5, [sp, # PRESERVED_R5_OFFSET ]
+ ldr r4, [sp, # PRESERVED_R4_OFFSET ]
+ ldr lr, [sp, # PRESERVED_RETURN_ADDRESS_OFFSET ]
+ add sp, sp, # ENABLE_PROFILER_REFERENCE_OFFSET
+ bx lr
+}
+
+__asm void ctiOpThrowNotCaught()
+{
+ PRESERVE8
+ ldr r6, [sp, # PRESERVED_R6_OFFSET ]
+ ldr r5, [sp, # PRESERVED_R5_OFFSET ]
+ ldr r4, [sp, # PRESERVED_R4_OFFSET ]
+ ldr lr, [sp, # PRESERVED_RETURN_ADDRESS_OFFSET ]
+ add sp, sp, # ENABLE_PROFILER_REFERENCE_OFFSET
+ bx lr
+}
+
+#elif COMPILER(RVCT) && CPU(ARM_TRADITIONAL)
+
+__asm EncodedJSValue ctiTrampoline(void*, RegisterFile*, CallFrame*, void* /*unused1*/, Profiler**, JSGlobalData*)
+{
+ ARM
+ stmdb sp!, {r1-r3}
+ stmdb sp!, {r4-r8, lr}
+ sub sp, sp, # PRESERVEDR4_OFFSET
+ mov r4, r2
+ mov r5, #512
+ mov lr, pc
+ bx r0
+ add sp, sp, # PRESERVEDR4_OFFSET
+ ldmia sp!, {r4-r8, lr}
+ add sp, sp, #12
+ bx lr
+}
+
+__asm void ctiVMThrowTrampoline()
+{
+ ARM
+ PRESERVE8
+ mov r0, sp
+ bl cti_vm_throw
+ add sp, sp, # PRESERVEDR4_OFFSET
+ ldmia sp!, {r4-r8, lr}
+ add sp, sp, #12
+ bx lr
+}
+
+__asm void ctiOpThrowNotCaught()
+{
+ ARM
+ add sp, sp, # PRESERVEDR4_OFFSET
+ ldmia sp!, {r4-r8, lr}
+ add sp, sp, #12
+ bx lr
+}
#endif
#if ENABLE(OPCODE_SAMPLING)
#endif
JITThunks::JITThunks(JSGlobalData* globalData)
+ : m_hostFunctionStubMap(adoptPtr(new HostFunctionStubMap))
{
- JIT::compileCTIMachineTrampolines(globalData, &m_executablePool, &m_trampolineStructure);
+ if (!globalData->executableAllocator.isValid())
+ return;
+ JIT::compileCTIMachineTrampolines(globalData, &m_executablePool, &m_trampolineStructure);
+ ASSERT(m_executablePool);
#if CPU(ARM_THUMB2)
// Unfortunate the arm compiler does not like the use of offsetof on JITStackFrame (since it contains non POD types),
// and the OBJECT_OFFSETOF macro does not appear constantish enough for it to be happy with its use in COMPILE_ASSERT
ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, registerFile) == REGISTER_FILE_OFFSET);
ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, callFrame) == CALLFRAME_OFFSET);
- ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, exception) == EXCEPTION_OFFSET);
// The fifth argument is the first item already on the stack.
ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, enabledProfilerReference) == ENABLE_PROFILER_REFERENCE_OFFSET);
#elif CPU(MIPS)
- ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedGP) == 28);
- ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedS0) == 32);
- ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedS1) == 36);
- ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedS2) == 40);
- ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedReturnAddress) == 44);
- ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, thunkReturnAddress) == 48);
- ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, registerFile) == 52);
- ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, callFrame) == 56);
- ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, exception) == 60);
- ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, enabledProfilerReference) == 64);
- ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, globalData) == 68);
+ ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedGP) == PRESERVED_GP_OFFSET);
+ ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedS0) == PRESERVED_S0_OFFSET);
+ ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedS1) == PRESERVED_S1_OFFSET);
+ ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedS2) == PRESERVED_S2_OFFSET);
+ ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedReturnAddress) == PRESERVED_RETURN_ADDRESS_OFFSET);
+ ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, thunkReturnAddress) == THUNK_RETURN_ADDRESS_OFFSET);
+ ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, registerFile) == REGISTER_FILE_OFFSET);
+ ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, callFrame) == CALLFRAME_OFFSET);
+ ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, unused1) == EXCEPTION_OFFSET);
+ ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, enabledProfilerReference) == ENABLE_PROFILER_REFERENCE_OFFSET);
+ ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, globalData) == GLOBAL_DATA_OFFSET);
#endif
}
return;
}
- JSCell* baseCell = asCell(baseValue);
+ JSCell* baseCell = baseValue.asCell();
Structure* structure = baseCell->structure();
- if (structure->isUncacheableDictionary()) {
+ if (structure->isUncacheableDictionary() || structure->typeInfo().prohibitsPropertyCaching()) {
ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic));
return;
}
normalizePrototypeChain(callFrame, baseCell);
StructureChain* prototypeChain = structure->prototypeChain(callFrame);
- stubInfo->initPutByIdTransition(structure->previousID(), structure, prototypeChain);
+ stubInfo->initPutByIdTransition(callFrame->globalData(), codeBlock->ownerExecutable(), structure->previousID(), structure, prototypeChain);
JIT::compilePutByIdTransition(callFrame->scopeChain()->globalData, codeBlock, stubInfo, structure->previousID(), structure, slot.cachedOffset(), prototypeChain, returnAddress, direct);
return;
}
- stubInfo->initPutByIdReplace(structure);
+ stubInfo->initPutByIdReplace(callFrame->globalData(), codeBlock->ownerExecutable(), structure);
JIT::patchPutByIdReplace(codeBlock, stubInfo, structure, slot.cachedOffset(), returnAddress, direct);
}
return;
}
- JSCell* baseCell = asCell(baseValue);
+ JSCell* baseCell = baseValue.asCell();
Structure* structure = baseCell->structure();
- if (structure->isUncacheableDictionary()) {
+ if (structure->isUncacheableDictionary() || structure->typeInfo().prohibitsPropertyCaching()) {
ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic));
return;
}
if (slot.slotBase() == baseValue) {
// set this up, so derefStructures can do it's job.
- stubInfo->initGetByIdSelf(structure);
- if (slot.cachedPropertyType() != PropertySlot::Value)
+ stubInfo->initGetByIdSelf(callFrame->globalData(), codeBlock->ownerExecutable(), structure);
+ if ((slot.cachedPropertyType() != PropertySlot::Value) || ((slot.cachedOffset() * sizeof(JSValue)) > (unsigned)MacroAssembler::MaximumCompactPtrAlignedAddressOffset))
ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_self_fail));
else
JIT::patchGetByIdSelf(codeBlock, stubInfo, structure, slot.cachedOffset(), returnAddress);
// Since we're accessing a prototype in a loop, it's a good bet that it
// should not be treated as a dictionary.
if (slotBaseObject->structure()->isDictionary()) {
- slotBaseObject->flattenDictionaryObject();
- offset = slotBaseObject->structure()->get(propertyName);
+ slotBaseObject->flattenDictionaryObject(callFrame->globalData());
+ offset = slotBaseObject->structure()->get(callFrame->globalData(), propertyName);
}
- stubInfo->initGetByIdProto(structure, slotBaseObject->structure());
+ stubInfo->initGetByIdProto(callFrame->globalData(), codeBlock->ownerExecutable(), structure, slotBaseObject->structure());
ASSERT(!structure->isDictionary());
ASSERT(!slotBaseObject->structure()->isDictionary());
}
StructureChain* prototypeChain = structure->prototypeChain(callFrame);
- stubInfo->initGetByIdChain(structure, prototypeChain);
+ stubInfo->initGetByIdChain(callFrame->globalData(), codeBlock->ownerExecutable(), structure, prototypeChain);
JIT::compileGetByIdChain(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, prototypeChain, count, propertyName, slot, offset, returnAddress);
}
#endif // ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
-#if USE(JIT_STUB_ARGUMENT_VA_LIST)
-#define SETUP_VA_LISTL_ARGS va_list vl_args; va_start(vl_args, args)
-#else
-#define SETUP_VA_LISTL_ARGS
-#endif
-
#ifndef NDEBUG
extern "C" {
ReturnAddressPtr savedReturnAddress;
};
-#define STUB_INIT_STACK_FRAME(stackFrame) SETUP_VA_LISTL_ARGS; JITStackFrame& stackFrame = *reinterpret_cast<JITStackFrame*>(STUB_ARGS); StackHack stackHack(stackFrame)
+#define STUB_INIT_STACK_FRAME(stackFrame) JITStackFrame& stackFrame = *reinterpret_cast_ptr<JITStackFrame*>(STUB_ARGS); StackHack stackHack(stackFrame)
#define STUB_SET_RETURN_ADDRESS(returnAddress) stackHack.savedReturnAddress = ReturnAddressPtr(returnAddress)
#define STUB_RETURN_ADDRESS stackHack.savedReturnAddress
#else
-#define STUB_INIT_STACK_FRAME(stackFrame) SETUP_VA_LISTL_ARGS; JITStackFrame& stackFrame = *reinterpret_cast<JITStackFrame*>(STUB_ARGS)
+#define STUB_INIT_STACK_FRAME(stackFrame) JITStackFrame& stackFrame = *reinterpret_cast_ptr<JITStackFrame*>(STUB_ARGS)
#define STUB_SET_RETURN_ADDRESS(returnAddress) *stackFrame.returnAddressSlot() = ReturnAddressPtr(returnAddress)
#define STUB_RETURN_ADDRESS *stackFrame.returnAddressSlot()
return 0; \
} while (0)
#define VM_THROW_EXCEPTION_AT_END() \
- returnToThrowTrampoline(stackFrame.globalData, STUB_RETURN_ADDRESS, STUB_RETURN_ADDRESS)
+ do {\
+ returnToThrowTrampoline(stackFrame.globalData, STUB_RETURN_ADDRESS, STUB_RETURN_ADDRESS);\
+ } while (0)
#define CHECK_FOR_EXCEPTION() \
do { \
} \
} while (0)
-#if CPU(ARM_THUMB2)
+struct ExceptionHandler {
+ void* catchRoutine;
+ CallFrame* callFrame;
+};
+static ExceptionHandler jitThrow(JSGlobalData* globalData, CallFrame* callFrame, JSValue exceptionValue, ReturnAddressPtr faultLocation)
+{
+ ASSERT(exceptionValue);
+
+ unsigned vPCIndex = callFrame->codeBlock()->bytecodeOffset(faultLocation);
+ globalData->exception = JSValue();
+ HandlerInfo* handler = globalData->interpreter->throwException(callFrame, exceptionValue, vPCIndex); // This may update callFrame & exceptionValue!
+ globalData->exception = exceptionValue;
+
+ void* catchRoutine = handler ? handler->nativeCode.executableAddress() : FunctionPtr(ctiOpThrowNotCaught).value();
+ ASSERT(catchRoutine);
+ ExceptionHandler exceptionHandler = { catchRoutine, callFrame };
+ return exceptionHandler;
+}
+
+#if CPU(ARM_THUMB2) && COMPILER(GCC)
#define DEFINE_STUB_FUNCTION(rtype, op) \
extern "C" { \
rtype JITStubThunked_##op(STUB_ARGS_DECLARATION); \
}; \
- asm volatile ( \
+ asm ( \
".text" "\n" \
".align 2" "\n" \
".globl " SYMBOL_STRING(cti_##op) "\n" \
extern "C" { \
rtype JITStubThunked_##op(STUB_ARGS_DECLARATION); \
}; \
- asm volatile( \
+ asm ( \
".text" "\n" \
".align 2" "\n" \
".set noreorder" "\n" \
".globl " SYMBOL_STRING(cti_##op) "\n" \
".ent " SYMBOL_STRING(cti_##op) "\n" \
SYMBOL_STRING(cti_##op) ":" "\n" \
- "lw $28,28($29)" "\n" \
- "sw $31,48($29)" "\n" \
+ "lw $28," STRINGIZE_VALUE_OF(PRESERVED_GP_OFFSET) "($29)" "\n" \
+ "sw $31," STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "($29)" "\n" \
".set macro" "\n" \
"la $25," SYMBOL_STRING(JITStubThunked_##op) "\n" \
".set nomacro" "\n" \
"bal " SYMBOL_STRING(JITStubThunked_##op) "\n" \
"nop" "\n" \
- "lw $31,48($29)" "\n" \
+ "lw $31," STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "($29)" "\n" \
"jr $31" "\n" \
"nop" "\n" \
".set reorder" "\n" \
extern "C" { \
rtype JITStubThunked_##op(STUB_ARGS_DECLARATION); \
}; \
- asm volatile( \
+ asm ( \
".text" "\n" \
".align 2" "\n" \
".set noreorder" "\n" \
".globl " SYMBOL_STRING(cti_##op) "\n" \
".ent " SYMBOL_STRING(cti_##op) "\n" \
SYMBOL_STRING(cti_##op) ":" "\n" \
- "sw $31,48($29)" "\n" \
+ "sw $31," STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "($29)" "\n" \
"jal " SYMBOL_STRING(JITStubThunked_##op) "\n" \
"nop" "\n" \
- "lw $31,48($29)" "\n" \
+ "lw $31," STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "($29)" "\n" \
"jr $31" "\n" \
"nop" "\n" \
".set reorder" "\n" \
extern "C" { \
rtype JITStubThunked_##op(STUB_ARGS_DECLARATION); \
}; \
- asm volatile ( \
+ asm ( \
".globl " SYMBOL_STRING(cti_##op) "\n" \
SYMBOL_STRING(cti_##op) ":" "\n" \
"str lr, [sp, #" STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "]" "\n" \
); \
rtype JITStubThunked_##op(STUB_ARGS_DECLARATION)
-#elif CPU(ARM_TRADITIONAL) && COMPILER(RVCT)
+#elif (CPU(ARM_THUMB2) || CPU(ARM_TRADITIONAL)) && COMPILER(RVCT)
#define DEFINE_STUB_FUNCTION(rtype, op) rtype JITStubThunked_##op(STUB_ARGS_DECLARATION)
RVCT(extern "C" #rtype# JITStubThunked_#op#(STUB_ARGS_DECLARATION);)
RVCT(__asm #rtype# cti_#op#(STUB_ARGS_DECLARATION))
RVCT({)
-RVCT( ARM)
+RVCT( PRESERVE8)
RVCT( IMPORT JITStubThunked_#op#)
-RVCT( str lr, [sp, ##offset#])
+RVCT( str lr, [sp, # THUNK_RETURN_ADDRESS_OFFSET])
RVCT( bl JITStubThunked_#op#)
-RVCT( ldr lr, [sp, ##offset#])
+RVCT( ldr lr, [sp, # THUNK_RETURN_ADDRESS_OFFSET])
RVCT( bx lr)
RVCT(})
RVCT()
/* Include the generated file */
#include "GeneratedJITStubs_RVCT.h"
+#elif CPU(ARM_TRADITIONAL) && COMPILER(MSVC)
+
+#define DEFINE_STUB_FUNCTION(rtype, op) extern "C" rtype JITStubThunked_##op(STUB_ARGS_DECLARATION)
+
+/* The following is a workaround for MSVC toolchain; inline assembler is not supported */
+
+/* The following section is a template to generate code for GeneratedJITStubs_MSVC.asm */
+/* The pattern "#xxx#" will be replaced with "xxx" */
+
+/*
+MSVC_BEGIN( AREA Trampoline, CODE)
+MSVC_BEGIN()
+MSVC_BEGIN( EXPORT ctiTrampoline)
+MSVC_BEGIN( EXPORT ctiVMThrowTrampoline)
+MSVC_BEGIN( EXPORT ctiOpThrowNotCaught)
+MSVC_BEGIN()
+MSVC_BEGIN(ctiTrampoline PROC)
+MSVC_BEGIN( stmdb sp!, {r1-r3})
+MSVC_BEGIN( stmdb sp!, {r4-r8, lr})
+MSVC_BEGIN( sub sp, sp, #68 ; sync with PRESERVEDR4_OFFSET)
+MSVC_BEGIN( mov r4, r2)
+MSVC_BEGIN( mov r5, #512)
+MSVC_BEGIN( ; r0 contains the code)
+MSVC_BEGIN( mov lr, pc)
+MSVC_BEGIN( bx r0)
+MSVC_BEGIN( add sp, sp, #68 ; sync with PRESERVEDR4_OFFSET)
+MSVC_BEGIN( ldmia sp!, {r4-r8, lr})
+MSVC_BEGIN( add sp, sp, #12)
+MSVC_BEGIN( bx lr)
+MSVC_BEGIN(ctiTrampoline ENDP)
+MSVC_BEGIN()
+MSVC_BEGIN(ctiVMThrowTrampoline PROC)
+MSVC_BEGIN( mov r0, sp)
+MSVC_BEGIN( mov lr, pc)
+MSVC_BEGIN( bl cti_vm_throw)
+MSVC_BEGIN(ctiOpThrowNotCaught)
+MSVC_BEGIN( add sp, sp, #68 ; sync with PRESERVEDR4_OFFSET)
+MSVC_BEGIN( ldmia sp!, {r4-r8, lr})
+MSVC_BEGIN( add sp, sp, #12)
+MSVC_BEGIN( bx lr)
+MSVC_BEGIN(ctiVMThrowTrampoline ENDP)
+MSVC_BEGIN()
+
+MSVC( EXPORT cti_#op#)
+MSVC( IMPORT JITStubThunked_#op#)
+MSVC(cti_#op# PROC)
+MSVC( str lr, [sp, #64] ; sync with THUNK_RETURN_ADDRESS_OFFSET)
+MSVC( bl JITStubThunked_#op#)
+MSVC( ldr lr, [sp, #64] ; sync with THUNK_RETURN_ADDRESS_OFFSET)
+MSVC( bx lr)
+MSVC(cti_#op# ENDP)
+MSVC()
+
+MSVC_END( END)
+*/
+
+#elif CPU(SH4)
+#define DEFINE_STUB_FUNCTION(rtype, op) \
+ extern "C" { \
+ rtype JITStubThunked_##op(STUB_ARGS_DECLARATION); \
+ }; \
+ asm volatile( \
+ ".align 2" "\n" \
+ ".globl " SYMBOL_STRING(cti_##op) "\n" \
+ SYMBOL_STRING(cti_##op) ":" "\n" \
+ "sts pr, r11" "\n" \
+ "mov.l r11, @(0x38, r15)" "\n" \
+ "mov.l .L2"SYMBOL_STRING(JITStubThunked_##op)",r0" "\n" \
+ "mov.l @(r0,r12),r11" "\n" \
+ "jsr @r11" "\n" \
+ "nop" "\n" \
+ "mov.l @(0x38, r15), r11 " "\n" \
+ "lds r11, pr " "\n" \
+ "rts" "\n" \
+ "nop" "\n" \
+ ".align 2" "\n" \
+ ".L2"SYMBOL_STRING(JITStubThunked_##op)":.long " SYMBOL_STRING(JITStubThunked_##op)"@GOT \n" \
+ ); \
+ rtype JITStubThunked_##op(STUB_ARGS_DECLARATION)
#else
#define DEFINE_STUB_FUNCTION(rtype, op) rtype JIT_STUB cti_##op(STUB_ARGS_DECLARATION)
#endif
+DEFINE_STUB_FUNCTION(EncodedJSValue, op_create_this)
+{
+ STUB_INIT_STACK_FRAME(stackFrame);
+ CallFrame* callFrame = stackFrame.callFrame;
+
+ JSFunction* constructor = asFunction(callFrame->callee());
+#if !ASSERT_DISABLED
+ ConstructData constructData;
+ ASSERT(constructor->getConstructData(constructData) == ConstructTypeJS);
+#endif
+
+ Structure* structure;
+ JSValue proto = stackFrame.args[0].jsValue();
+ if (proto.isObject())
+ structure = asObject(proto)->inheritorID(*stackFrame.globalData);
+ else
+ structure = constructor->scope()->globalObject->emptyObjectStructure();
+ JSValue result = constructEmptyObject(callFrame, structure);
+
+ return JSValue::encode(result);
+}
+
DEFINE_STUB_FUNCTION(EncodedJSValue, op_convert_this)
{
STUB_INIT_STACK_FRAME(stackFrame);
return JSValue::encode(result);
}
-DEFINE_STUB_FUNCTION(void, op_end)
+DEFINE_STUB_FUNCTION(EncodedJSValue, op_convert_this_strict)
{
STUB_INIT_STACK_FRAME(stackFrame);
-
- ScopeChainNode* scopeChain = stackFrame.callFrame->scopeChain();
- ASSERT(scopeChain->refCount > 1);
- scopeChain->deref();
+
+ JSValue v1 = stackFrame.args[0].jsValue();
+ CallFrame* callFrame = stackFrame.callFrame;
+ ASSERT(v1.asCell()->structure()->typeInfo().needsThisConversion());
+ JSValue result = v1.toStrictThisObject(callFrame);
+ CHECK_FOR_EXCEPTION_AT_END();
+ return JSValue::encode(result);
}
DEFINE_STUB_FUNCTION(EncodedJSValue, op_add)
double left = 0.0, right;
if (v1.getNumber(left) && v2.getNumber(right))
- return JSValue::encode(jsNumber(stackFrame.globalData, left + right));
+ return JSValue::encode(jsNumber(left + right));
// All other cases are pretty uncommon
JSValue result = jsAddSlowCase(callFrame, v1, v2);
JSValue v = stackFrame.args[0].jsValue();
CallFrame* callFrame = stackFrame.callFrame;
- JSValue result = jsNumber(stackFrame.globalData, v.toNumber(callFrame) + 1);
+ JSValue result = jsNumber(v.toNumber(callFrame) + 1);
CHECK_FOR_EXCEPTION_AT_END();
return JSValue::encode(result);
}
return timeoutChecker.ticksUntilNextCheck();
}
-DEFINE_STUB_FUNCTION(void, register_file_check)
+DEFINE_STUB_FUNCTION(void*, register_file_check)
{
STUB_INIT_STACK_FRAME(stackFrame);
+ CallFrame* callFrame = stackFrame.callFrame;
- if (LIKELY(stackFrame.registerFile->grow(&stackFrame.callFrame->registers()[stackFrame.callFrame->codeBlock()->m_numCalleeRegisters])))
- return;
+ if (UNLIKELY(!stackFrame.registerFile->grow(&callFrame->registers()[callFrame->codeBlock()->m_numCalleeRegisters]))) {
+ // Rewind to the previous call frame because op_call already optimistically
+ // moved the call frame forward.
+ CallFrame* oldCallFrame = callFrame->callerFrame();
+ ExceptionHandler handler = jitThrow(stackFrame.globalData, oldCallFrame, createStackOverflowError(oldCallFrame), ReturnAddressPtr(callFrame->returnPC()));
+ STUB_SET_RETURN_ADDRESS(handler.catchRoutine);
+ callFrame = handler.callFrame;
+ }
- // Rewind to the previous call frame because op_call already optimistically
- // moved the call frame forward.
- CallFrame* oldCallFrame = stackFrame.callFrame->callerFrame();
- stackFrame.callFrame = oldCallFrame;
- throwStackOverflowError(oldCallFrame, stackFrame.globalData, ReturnAddressPtr(oldCallFrame->returnPC()), STUB_RETURN_ADDRESS);
+ return callFrame;
}
DEFINE_STUB_FUNCTION(int, op_loop_if_lesseq)
{
STUB_INIT_STACK_FRAME(stackFrame);
- PutPropertySlot slot;
+ PutPropertySlot slot(stackFrame.callFrame->codeBlock()->isStrictMode());
stackFrame.args[0].jsValue().put(stackFrame.callFrame, stackFrame.args[1].identifier(), stackFrame.args[2].jsValue(), slot);
CHECK_FOR_EXCEPTION_AT_END();
}
{
STUB_INIT_STACK_FRAME(stackFrame);
- PutPropertySlot slot;
+ PutPropertySlot slot(stackFrame.callFrame->codeBlock()->isStrictMode());
stackFrame.args[0].jsValue().putDirect(stackFrame.callFrame, stackFrame.args[1].identifier(), stackFrame.args[2].jsValue(), slot);
CHECK_FOR_EXCEPTION_AT_END();
}
CallFrame* callFrame = stackFrame.callFrame;
Identifier& ident = stackFrame.args[1].identifier();
- PutPropertySlot slot;
+ PutPropertySlot slot(callFrame->codeBlock()->isStrictMode());
stackFrame.args[0].jsValue().put(callFrame, ident, stackFrame.args[2].jsValue(), slot);
CodeBlock* codeBlock = stackFrame.callFrame->codeBlock();
CallFrame* callFrame = stackFrame.callFrame;
Identifier& ident = stackFrame.args[1].identifier();
- PutPropertySlot slot;
+ PutPropertySlot slot(callFrame->codeBlock()->isStrictMode());
stackFrame.args[0].jsValue().putDirect(callFrame, ident, stackFrame.args[2].jsValue(), slot);
CodeBlock* codeBlock = stackFrame.callFrame->codeBlock();
CallFrame* callFrame = stackFrame.callFrame;
Identifier& ident = stackFrame.args[1].identifier();
-
- PutPropertySlot slot;
+
+ PutPropertySlot slot(callFrame->codeBlock()->isStrictMode());
stackFrame.args[0].jsValue().put(callFrame, ident, stackFrame.args[2].jsValue(), slot);
CHECK_FOR_EXCEPTION_AT_END();
CallFrame* callFrame = stackFrame.callFrame;
Identifier& ident = stackFrame.args[1].identifier();
- PutPropertySlot slot;
+ PutPropertySlot slot(callFrame->codeBlock()->isStrictMode());
stackFrame.args[0].jsValue().putDirect(callFrame, ident, stackFrame.args[2].jsValue(), slot);
CHECK_FOR_EXCEPTION_AT_END();
JSObject* slotBaseObject;
if (baseValue.isCell()
&& slot.isCacheableValue()
- && !(structure = asCell(baseValue)->structure())->isUncacheableDictionary()
+ && !(structure = baseValue.asCell()->structure())->isUncacheableDictionary()
&& (slotBaseObject = asObject(slot.slotBase()))->getPropertySpecificValue(callFrame, ident, specific)
&& specific
) {
- JSFunction* callee = (JSFunction*)specific;
+ JSObjectWithGlobalObject* callee = (JSObjectWithGlobalObject*)specific;
// Since we're accessing a prototype in a loop, it's a good bet that it
// should not be treated as a dictionary.
if (slotBaseObject->structure()->isDictionary())
- slotBaseObject->flattenDictionaryObject();
+ slotBaseObject->flattenDictionaryObject(callFrame->globalData());
// The result fetched should always be the callee!
ASSERT(result == JSValue(callee));
// Check to see if the function is on the object's prototype. Patch up the code to optimize.
if (slot.slotBase() == structure->prototypeForLookup(callFrame)) {
- JIT::patchMethodCallProto(codeBlock, methodCallLinkInfo, callee, structure, slotBaseObject, STUB_RETURN_ADDRESS);
+ JIT::patchMethodCallProto(callFrame->globalData(), codeBlock, methodCallLinkInfo, callee, structure, slotBaseObject, STUB_RETURN_ADDRESS);
return JSValue::encode(result);
}
// for now. For now it performs a check on a special object on the global object only used for this
// purpose. The object is in no way exposed, and as such the check will always pass.
if (slot.slotBase() == baseValue) {
- JIT::patchMethodCallProto(codeBlock, methodCallLinkInfo, callee, structure, callFrame->scopeChain()->globalObject->methodCallDummy(), STUB_RETURN_ADDRESS);
+ JIT::patchMethodCallProto(callFrame->globalData(), codeBlock, methodCallLinkInfo, callee, structure, callFrame->scopeChain()->globalObject->methodCallDummy(), STUB_RETURN_ADDRESS);
return JSValue::encode(result);
}
}
if (baseValue.isCell()
&& slot.isCacheable()
- && !asCell(baseValue)->structure()->isUncacheableDictionary()
+ && !baseValue.asCell()->structure()->isUncacheableDictionary()
&& slot.slotBase() == baseValue) {
CodeBlock* codeBlock = callFrame->codeBlock();
if (stubInfo->accessType == access_get_by_id_self) {
ASSERT(!stubInfo->stubRoutine);
- polymorphicStructureList = new PolymorphicAccessStructureList(CodeLocationLabel(), stubInfo->u.getByIdSelf.baseObjectStructure);
+ polymorphicStructureList = new PolymorphicAccessStructureList(callFrame->globalData(), codeBlock->ownerExecutable(), CodeLocationLabel(), stubInfo->u.getByIdSelf.baseObjectStructure.get());
stubInfo->initGetByIdSelfList(polymorphicStructureList, 1);
} else {
polymorphicStructureList = stubInfo->u.getByIdSelfList.structureList;
}
if (listIndex < POLYMORPHIC_LIST_CACHE_SIZE) {
stubInfo->u.getByIdSelfList.listSize++;
- JIT::compileGetByIdSelfList(callFrame->scopeChain()->globalData, codeBlock, stubInfo, polymorphicStructureList, listIndex, asCell(baseValue)->structure(), ident, slot, slot.cachedOffset());
+ JIT::compileGetByIdSelfList(callFrame->scopeChain()->globalData, codeBlock, stubInfo, polymorphicStructureList, listIndex, baseValue.asCell()->structure(), ident, slot, slot.cachedOffset());
if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1))
ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_generic));
return JSValue::encode(result);
}
-static PolymorphicAccessStructureList* getPolymorphicAccessStructureListSlot(StructureStubInfo* stubInfo, int& listIndex)
+static PolymorphicAccessStructureList* getPolymorphicAccessStructureListSlot(JSGlobalData& globalData, ScriptExecutable* owner, StructureStubInfo* stubInfo, int& listIndex)
{
PolymorphicAccessStructureList* prototypeStructureList = 0;
listIndex = 1;
switch (stubInfo->accessType) {
case access_get_by_id_proto:
- prototypeStructureList = new PolymorphicAccessStructureList(stubInfo->stubRoutine, stubInfo->u.getByIdProto.baseObjectStructure, stubInfo->u.getByIdProto.prototypeStructure);
+ prototypeStructureList = new PolymorphicAccessStructureList(globalData, owner, stubInfo->stubRoutine, stubInfo->u.getByIdProto.baseObjectStructure.get(), stubInfo->u.getByIdProto.prototypeStructure.get());
stubInfo->stubRoutine = CodeLocationLabel();
stubInfo->initGetByIdProtoList(prototypeStructureList, 2);
break;
case access_get_by_id_chain:
- prototypeStructureList = new PolymorphicAccessStructureList(stubInfo->stubRoutine, stubInfo->u.getByIdChain.baseObjectStructure, stubInfo->u.getByIdChain.chain);
+ prototypeStructureList = new PolymorphicAccessStructureList(globalData, owner, stubInfo->stubRoutine, stubInfo->u.getByIdChain.baseObjectStructure.get(), stubInfo->u.getByIdChain.chain.get());
stubInfo->stubRoutine = CodeLocationLabel();
stubInfo->initGetByIdProtoList(prototypeStructureList, 2);
break;
CHECK_FOR_EXCEPTION();
- if (!baseValue.isCell() || !slot.isCacheable() || asCell(baseValue)->structure()->isDictionary()) {
+ if (!baseValue.isCell() || !slot.isCacheable() || baseValue.asCell()->structure()->isDictionary() || baseValue.asCell()->structure()->typeInfo().prohibitsPropertyCaching()) {
ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail));
return JSValue::encode(result);
}
- Structure* structure = asCell(baseValue)->structure();
+ Structure* structure = baseValue.asCell()->structure();
CodeBlock* codeBlock = callFrame->codeBlock();
StructureStubInfo* stubInfo = &codeBlock->getStubInfo(STUB_RETURN_ADDRESS);
if (slot.slotBase() == baseValue)
ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail));
- else if (slot.slotBase() == asCell(baseValue)->structure()->prototypeForLookup(callFrame)) {
- ASSERT(!asCell(baseValue)->structure()->isDictionary());
+ else if (slot.slotBase() == baseValue.asCell()->structure()->prototypeForLookup(callFrame)) {
+ ASSERT(!baseValue.asCell()->structure()->isDictionary());
// Since we're accessing a prototype in a loop, it's a good bet that it
// should not be treated as a dictionary.
if (slotBaseObject->structure()->isDictionary()) {
- slotBaseObject->flattenDictionaryObject();
- offset = slotBaseObject->structure()->get(propertyName);
+ slotBaseObject->flattenDictionaryObject(callFrame->globalData());
+ offset = slotBaseObject->structure()->get(callFrame->globalData(), propertyName);
}
int listIndex;
- PolymorphicAccessStructureList* prototypeStructureList = getPolymorphicAccessStructureListSlot(stubInfo, listIndex);
+ PolymorphicAccessStructureList* prototypeStructureList = getPolymorphicAccessStructureListSlot(callFrame->globalData(), codeBlock->ownerExecutable(), stubInfo, listIndex);
if (listIndex < POLYMORPHIC_LIST_CACHE_SIZE) {
JIT::compileGetByIdProtoList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, prototypeStructureList, listIndex, structure, slotBaseObject->structure(), propertyName, slot, offset);
ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_list_full));
}
} else if (size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase(), propertyName, offset)) {
- ASSERT(!asCell(baseValue)->structure()->isDictionary());
+ ASSERT(!baseValue.asCell()->structure()->isDictionary());
int listIndex;
- PolymorphicAccessStructureList* prototypeStructureList = getPolymorphicAccessStructureListSlot(stubInfo, listIndex);
+ PolymorphicAccessStructureList* prototypeStructureList = getPolymorphicAccessStructureListSlot(callFrame->globalData(), codeBlock->ownerExecutable(), stubInfo, listIndex);
if (listIndex < POLYMORPHIC_LIST_CACHE_SIZE) {
StructureChain* protoChain = structure->prototypeChain(callFrame);
#endif // ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
+DEFINE_STUB_FUNCTION(void, op_check_has_instance)
+{
+ STUB_INIT_STACK_FRAME(stackFrame);
+
+ CallFrame* callFrame = stackFrame.callFrame;
+ JSValue baseVal = stackFrame.args[0].jsValue();
+
+ // ECMA-262 15.3.5.3:
+ // Throw an exception either if baseVal is not an object, or if it does not implement 'HasInstance' (i.e. is a function).
+#ifndef NDEBUG
+ TypeInfo typeInfo(UnspecifiedType);
+ ASSERT(!baseVal.isObject() || !(typeInfo = asObject(baseVal)->structure()->typeInfo()).implementsHasInstance());
+#endif
+ stackFrame.globalData->exception = createInvalidParamError(callFrame, "instanceof", baseVal);
+ VM_THROW_EXCEPTION_AT_END();
+}
+
DEFINE_STUB_FUNCTION(EncodedJSValue, op_instanceof)
{
STUB_INIT_STACK_FRAME(stackFrame);
// Throw an exception either if baseVal is not an object, or if it does not implement 'HasInstance' (i.e. is a function).
TypeInfo typeInfo(UnspecifiedType);
if (!baseVal.isObject() || !(typeInfo = asObject(baseVal)->structure()->typeInfo()).implementsHasInstance()) {
- CallFrame* callFrame = stackFrame.callFrame;
- CodeBlock* codeBlock = callFrame->codeBlock();
- unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
- stackFrame.globalData->exception = createInvalidParamError(callFrame, "instanceof", baseVal, vPCIndex, codeBlock);
+ stackFrame.globalData->exception = createInvalidParamError(stackFrame.callFrame, "instanceof", baseVal);
VM_THROW_EXCEPTION();
}
ASSERT(typeInfo.type() != UnspecifiedType);
return JSValue::encode(jsBoolean(false));
if (!proto.isObject()) {
- throwError(callFrame, TypeError, "instanceof called on an object with an invalid prototype property.");
+ throwError(callFrame, createTypeError(callFrame, "instanceof called on an object with an invalid prototype property."));
VM_THROW_EXCEPTION();
}
}
JSObject* baseObj = stackFrame.args[0].jsValue().toObject(callFrame);
- JSValue result = jsBoolean(baseObj->deleteProperty(callFrame, stackFrame.args[1].identifier()));
+ bool couldDelete = baseObj->deleteProperty(callFrame, stackFrame.args[1].identifier());
+ JSValue result = jsBoolean(couldDelete);
+ if (!couldDelete && callFrame->codeBlock()->isStrictMode())
+ stackFrame.globalData->exception = createTypeError(stackFrame.callFrame, "Unable to delete property.");
+
CHECK_FOR_EXCEPTION_AT_END();
return JSValue::encode(result);
}
double left;
double right;
if (src1.getNumber(left) && src2.getNumber(right))
- return JSValue::encode(jsNumber(stackFrame.globalData, left * right));
+ return JSValue::encode(jsNumber(left * right));
CallFrame* callFrame = stackFrame.callFrame;
- JSValue result = jsNumber(stackFrame.globalData, src1.toNumber(callFrame) * src2.toNumber(callFrame));
+ JSValue result = jsNumber(src1.toNumber(callFrame) * src2.toNumber(callFrame));
CHECK_FOR_EXCEPTION_AT_END();
return JSValue::encode(result);
}
DEFINE_STUB_FUNCTION(JSObject*, op_new_func)
{
STUB_INIT_STACK_FRAME(stackFrame);
-
+
+ ASSERT(stackFrame.callFrame->codeBlock()->codeType() != FunctionCode || !stackFrame.callFrame->codeBlock()->needsFullScopeChain() || stackFrame.callFrame->uncheckedR(stackFrame.callFrame->codeBlock()->activationRegister()).jsValue());
return stackFrame.args[0].function()->make(stackFrame.callFrame, stackFrame.callFrame->scopeChain());
}
-DEFINE_STUB_FUNCTION(void*, op_call_JSFunction)
+DEFINE_STUB_FUNCTION(void*, op_call_jitCompile)
{
STUB_INIT_STACK_FRAME(stackFrame);
#if !ASSERT_DISABLED
CallData callData;
- ASSERT(stackFrame.args[0].jsValue().getCallData(callData) == CallTypeJS);
+ ASSERT(stackFrame.callFrame->callee()->getCallData(callData) == CallTypeJS);
#endif
- JSFunction* function = asFunction(stackFrame.args[0].jsValue());
+ JSFunction* function = asFunction(stackFrame.callFrame->callee());
ASSERT(!function->isHostFunction());
FunctionExecutable* executable = function->jsExecutable();
- ScopeChainNode* callDataScopeChain = function->scope().node();
- executable->jitCode(stackFrame.callFrame, callDataScopeChain);
+ ScopeChainNode* callDataScopeChain = function->scope();
+ JSObject* error = executable->compileForCall(stackFrame.callFrame, callDataScopeChain);
+ if (error) {
+ stackFrame.callFrame->globalData().exception = error;
+ return 0;
+ }
+ return function;
+}
+
+DEFINE_STUB_FUNCTION(void*, op_construct_jitCompile)
+{
+ STUB_INIT_STACK_FRAME(stackFrame);
+
+#if !ASSERT_DISABLED
+ ConstructData constructData;
+ ASSERT(asFunction(stackFrame.callFrame->callee())->getConstructData(constructData) == ConstructTypeJS);
+#endif
+ JSFunction* function = asFunction(stackFrame.callFrame->callee());
+ ASSERT(!function->isHostFunction());
+ FunctionExecutable* executable = function->jsExecutable();
+ ScopeChainNode* callDataScopeChain = function->scope();
+ JSObject* error = executable->compileForConstruct(stackFrame.callFrame, callDataScopeChain);
+ if (error) {
+ stackFrame.callFrame->globalData().exception = error;
+ return 0;
+ }
return function;
}
-DEFINE_STUB_FUNCTION(VoidPtrPair, op_call_arityCheck)
+DEFINE_STUB_FUNCTION(void*, op_call_arityCheck)
{
STUB_INIT_STACK_FRAME(stackFrame);
CallFrame* callFrame = stackFrame.callFrame;
- JSFunction* callee = asFunction(stackFrame.args[0].jsValue());
+ JSFunction* callee = asFunction(callFrame->callee());
ASSERT(!callee->isHostFunction());
- CodeBlock* newCodeBlock = &callee->jsExecutable()->generatedBytecode();
- int argCount = stackFrame.args[2].int32();
+ CodeBlock* newCodeBlock = &callee->jsExecutable()->generatedBytecodeForCall();
+ int argCount = callFrame->argumentCountIncludingThis();
+ ReturnAddressPtr pc = callFrame->returnPC();
ASSERT(argCount != newCodeBlock->m_numParameters);
CallFrame* oldCallFrame = callFrame->callerFrame();
+ Register* r;
if (argCount > newCodeBlock->m_numParameters) {
size_t numParameters = newCodeBlock->m_numParameters;
- Register* r = callFrame->registers() + numParameters;
+ r = callFrame->registers() + numParameters;
Register* newEnd = r + newCodeBlock->m_numCalleeRegisters;
if (!stackFrame.registerFile->grow(newEnd)) {
// Rewind to the previous call frame because op_call already optimistically
// moved the call frame forward.
- stackFrame.callFrame = oldCallFrame;
- throwStackOverflowError(oldCallFrame, stackFrame.globalData, stackFrame.args[1].returnAddress(), STUB_RETURN_ADDRESS);
- RETURN_POINTER_PAIR(0, 0);
+ ExceptionHandler handler = jitThrow(stackFrame.globalData, oldCallFrame, createStackOverflowError(oldCallFrame), pc);
+ STUB_SET_RETURN_ADDRESS(handler.catchRoutine);
+ return handler.callFrame;
}
Register* argv = r - RegisterFile::CallFrameHeaderSize - numParameters - argCount;
for (size_t i = 0; i < numParameters; ++i)
argv[i + argCount] = argv[i];
-
- callFrame = CallFrame::create(r);
- callFrame->setCallerFrame(oldCallFrame);
} else {
size_t omittedArgCount = newCodeBlock->m_numParameters - argCount;
- Register* r = callFrame->registers() + omittedArgCount;
+ r = callFrame->registers() + omittedArgCount;
Register* newEnd = r + newCodeBlock->m_numCalleeRegisters;
if (!stackFrame.registerFile->grow(newEnd)) {
// Rewind to the previous call frame because op_call already optimistically
// moved the call frame forward.
- stackFrame.callFrame = oldCallFrame;
- throwStackOverflowError(oldCallFrame, stackFrame.globalData, stackFrame.args[1].returnAddress(), STUB_RETURN_ADDRESS);
- RETURN_POINTER_PAIR(0, 0);
+ ExceptionHandler handler = jitThrow(stackFrame.globalData, oldCallFrame, createStackOverflowError(oldCallFrame), pc);
+ STUB_SET_RETURN_ADDRESS(handler.catchRoutine);
+ return handler.callFrame;
}
Register* argv = r - RegisterFile::CallFrameHeaderSize - omittedArgCount;
for (size_t i = 0; i < omittedArgCount; ++i)
argv[i] = jsUndefined();
+ }
+
+ callFrame = CallFrame::create(r);
+ callFrame->setCallerFrame(oldCallFrame);
+ callFrame->setArgumentCountIncludingThis(argCount);
+ callFrame->setCallee(callee);
+ callFrame->setScopeChain(callee->scope());
+ callFrame->setReturnPC(pc.value());
+
+ ASSERT((void*)callFrame <= stackFrame.registerFile->end());
+ return callFrame;
+}
+
+DEFINE_STUB_FUNCTION(void*, op_construct_arityCheck)
+{
+ STUB_INIT_STACK_FRAME(stackFrame);
+
+ CallFrame* callFrame = stackFrame.callFrame;
+ JSFunction* callee = asFunction(callFrame->callee());
+ ASSERT(!callee->isHostFunction());
+ CodeBlock* newCodeBlock = &callee->jsExecutable()->generatedBytecodeForConstruct();
+ int argCount = callFrame->argumentCountIncludingThis();
+ ReturnAddressPtr pc = callFrame->returnPC();
+
+ ASSERT(argCount != newCodeBlock->m_numParameters);
+
+ CallFrame* oldCallFrame = callFrame->callerFrame();
+
+ Register* r;
+ if (argCount > newCodeBlock->m_numParameters) {
+ size_t numParameters = newCodeBlock->m_numParameters;
+ r = callFrame->registers() + numParameters;
+ Register* newEnd = r + newCodeBlock->m_numCalleeRegisters;
+ if (!stackFrame.registerFile->grow(newEnd)) {
+ // Rewind to the previous call frame because op_call already optimistically
+ // moved the call frame forward.
+ ExceptionHandler handler = jitThrow(stackFrame.globalData, oldCallFrame, createStackOverflowError(oldCallFrame), pc);
+ STUB_SET_RETURN_ADDRESS(handler.catchRoutine);
+ return handler.callFrame;
+ }
+
+ Register* argv = r - RegisterFile::CallFrameHeaderSize - numParameters - argCount;
+ for (size_t i = 0; i < numParameters; ++i)
+ argv[i + argCount] = argv[i];
+ } else {
+ size_t omittedArgCount = newCodeBlock->m_numParameters - argCount;
+ r = callFrame->registers() + omittedArgCount;
+ Register* newEnd = r + newCodeBlock->m_numCalleeRegisters;
+ if (!stackFrame.registerFile->grow(newEnd)) {
+ // Rewind to the previous call frame because op_call already optimistically
+ // moved the call frame forward.
+ ExceptionHandler handler = jitThrow(stackFrame.globalData, oldCallFrame, createStackOverflowError(oldCallFrame), pc);
+ STUB_SET_RETURN_ADDRESS(handler.catchRoutine);
+ return handler.callFrame;
+ }
- callFrame = CallFrame::create(r);
- callFrame->setCallerFrame(oldCallFrame);
+ Register* argv = r - RegisterFile::CallFrameHeaderSize - omittedArgCount;
+ for (size_t i = 0; i < omittedArgCount; ++i)
+ argv[i] = jsUndefined();
}
ASSERT((void*)callFrame <= stackFrame.registerFile->end());
- RETURN_POINTER_PAIR(callee, callFrame);
+ callFrame = CallFrame::create(r);
+ callFrame->setCallerFrame(oldCallFrame);
+ callFrame->setArgumentCountIncludingThis(argCount);
+ callFrame->setCallee(callee);
+ callFrame->setScopeChain(callee->scope());
+ callFrame->setReturnPC(pc.value());
+
+ ASSERT((void*)callFrame <= stackFrame.registerFile->end());
+ return callFrame;
}
#if ENABLE(JIT_OPTIMIZE_CALL)
DEFINE_STUB_FUNCTION(void*, vm_lazyLinkCall)
{
STUB_INIT_STACK_FRAME(stackFrame);
- JSFunction* callee = asFunction(stackFrame.args[0].jsValue());
+ CallFrame* callFrame = stackFrame.callFrame;
+ JSFunction* callee = asFunction(callFrame->callee());
ExecutableBase* executable = callee->executable();
- JITCode& jitCode = executable->generatedJITCode();
-
+
+ MacroAssemblerCodePtr codePtr;
+ CodeBlock* codeBlock = 0;
+ if (executable->isHostFunction())
+ codePtr = executable->generatedJITCodeForCall().addressForCall();
+ else {
+ FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable);
+ JSObject* error = functionExecutable->compileForCall(callFrame, callee->scope());
+ if (error) {
+ callFrame->globalData().exception = createStackOverflowError(callFrame);
+ return 0;
+ }
+ codeBlock = &functionExecutable->generatedBytecodeForCall();
+ if (callFrame->argumentCountIncludingThis() == static_cast<size_t>(codeBlock->m_numParameters))
+ codePtr = functionExecutable->generatedJITCodeForCall().addressForCall();
+ else
+ codePtr = functionExecutable->generatedJITCodeForCallWithArityCheck();
+ }
+ CallLinkInfo* callLinkInfo = &stackFrame.callFrame->callerFrame()->codeBlock()->getCallLinkInfo(callFrame->returnPC());
+
+ if (!callLinkInfo->seenOnce())
+ callLinkInfo->setSeen();
+ else
+ JIT::linkCall(callee, stackFrame.callFrame->callerFrame()->codeBlock(), codeBlock, codePtr, callLinkInfo, callFrame->argumentCountIncludingThis(), stackFrame.globalData);
+
+ return codePtr.executableAddress();
+}
+
+DEFINE_STUB_FUNCTION(void*, vm_lazyLinkConstruct)
+{
+ STUB_INIT_STACK_FRAME(stackFrame);
+ CallFrame* callFrame = stackFrame.callFrame;
+ JSFunction* callee = asFunction(callFrame->callee());
+ ExecutableBase* executable = callee->executable();
+
+ MacroAssemblerCodePtr codePtr;
CodeBlock* codeBlock = 0;
- if (!executable->isHostFunction())
- codeBlock = &static_cast<FunctionExecutable*>(executable)->bytecode(stackFrame.callFrame, callee->scope().node());
- CallLinkInfo* callLinkInfo = &stackFrame.callFrame->callerFrame()->codeBlock()->getCallLinkInfo(stackFrame.args[1].returnAddress());
+ if (executable->isHostFunction())
+ codePtr = executable->generatedJITCodeForConstruct().addressForCall();
+ else {
+ FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable);
+ JSObject* error = functionExecutable->compileForConstruct(callFrame, callee->scope());
+ if (error) {
+ throwStackOverflowError(callFrame, stackFrame.globalData, ReturnAddressPtr(callFrame->returnPC()), STUB_RETURN_ADDRESS);
+ return 0;
+ }
+ codeBlock = &functionExecutable->generatedBytecodeForConstruct();
+ if (callFrame->argumentCountIncludingThis() == static_cast<size_t>(codeBlock->m_numParameters))
+ codePtr = functionExecutable->generatedJITCodeForConstruct().addressForCall();
+ else
+ codePtr = functionExecutable->generatedJITCodeForConstructWithArityCheck();
+ }
+ CallLinkInfo* callLinkInfo = &stackFrame.callFrame->callerFrame()->codeBlock()->getCallLinkInfo(callFrame->returnPC());
if (!callLinkInfo->seenOnce())
callLinkInfo->setSeen();
else
- JIT::linkCall(callee, stackFrame.callFrame->callerFrame()->codeBlock(), codeBlock, jitCode, callLinkInfo, stackFrame.args[2].int32(), stackFrame.globalData);
+ JIT::linkConstruct(callee, stackFrame.callFrame->callerFrame()->codeBlock(), codeBlock, codePtr, callLinkInfo, callFrame->argumentCountIncludingThis(), stackFrame.globalData);
- return jitCode.addressForCall().executableAddress();
+ return codePtr.executableAddress();
}
#endif // !ENABLE(JIT_OPTIMIZE_CALL)
STUB_INIT_STACK_FRAME(stackFrame);
JSActivation* activation = new (stackFrame.globalData) JSActivation(stackFrame.callFrame, static_cast<FunctionExecutable*>(stackFrame.callFrame->codeBlock()->ownerExecutable()));
- stackFrame.callFrame->setScopeChain(stackFrame.callFrame->scopeChain()->copy()->push(activation));
+ stackFrame.callFrame->setScopeChain(stackFrame.callFrame->scopeChain()->push(activation));
return activation;
}
JSValue funcVal = stackFrame.args[0].jsValue();
CallData callData;
- CallType callType = funcVal.getCallData(callData);
+ CallType callType = getCallData(funcVal, callData);
ASSERT(callType != CallTypeJS);
int argCount = stackFrame.args[2].int32();
CallFrame* previousCallFrame = stackFrame.callFrame;
CallFrame* callFrame = CallFrame::create(previousCallFrame->registers() + registerOffset);
+ if (!stackFrame.registerFile->grow(callFrame->registers())) {
+ throwStackOverflowError(previousCallFrame, stackFrame.globalData, callFrame->returnPC(), STUB_RETURN_ADDRESS);
+ VM_THROW_EXCEPTION();
+ }
- callFrame->init(0, static_cast<Instruction*>((STUB_RETURN_ADDRESS).value()), previousCallFrame->scopeChain(), previousCallFrame, 0, argCount, 0);
- stackFrame.callFrame = callFrame;
-
- Register* argv = stackFrame.callFrame->registers() - RegisterFile::CallFrameHeaderSize - argCount;
- ArgList argList(argv + 1, argCount - 1);
+ callFrame->init(0, static_cast<Instruction*>((STUB_RETURN_ADDRESS).value()), previousCallFrame->scopeChain(), previousCallFrame, argCount, asObject(funcVal));
- JSValue returnValue;
+ EncodedJSValue returnValue;
{
SamplingTool::HostCallRecord callRecord(CTI_SAMPLER);
-
- // FIXME: All host methods should be calling toThisObject, but this is not presently the case.
- JSValue thisValue = argv[0].jsValue();
- if (thisValue == jsNull())
- thisValue = callFrame->globalThisValue();
-
- returnValue = callData.native.function(callFrame, asObject(funcVal), thisValue, argList);
+ returnValue = callData.native.function(callFrame);
}
- stackFrame.callFrame = previousCallFrame;
- CHECK_FOR_EXCEPTION();
- return JSValue::encode(returnValue);
+ CHECK_FOR_EXCEPTION_AT_END();
+ return returnValue;
}
ASSERT(callType == CallTypeNone);
- CallFrame* callFrame = stackFrame.callFrame;
- CodeBlock* codeBlock = callFrame->codeBlock();
- unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
- stackFrame.globalData->exception = createNotAFunctionError(stackFrame.callFrame, funcVal, vPCIndex, codeBlock);
+ stackFrame.globalData->exception = createNotAFunctionError(stackFrame.callFrame, funcVal);
VM_THROW_EXCEPTION();
}
-DEFINE_STUB_FUNCTION(void, op_create_arguments)
+DEFINE_STUB_FUNCTION(EncodedJSValue, op_create_arguments)
{
STUB_INIT_STACK_FRAME(stackFrame);
Arguments* arguments = new (stackFrame.globalData) Arguments(stackFrame.callFrame);
- stackFrame.callFrame->setCalleeArguments(arguments);
- stackFrame.callFrame[RegisterFile::ArgumentsRegister] = JSValue(arguments);
+ return JSValue::encode(JSValue(arguments));
}
-DEFINE_STUB_FUNCTION(void, op_create_arguments_no_params)
+DEFINE_STUB_FUNCTION(EncodedJSValue, op_create_arguments_no_params)
{
STUB_INIT_STACK_FRAME(stackFrame);
Arguments* arguments = new (stackFrame.globalData) Arguments(stackFrame.callFrame, Arguments::NoParameters);
- stackFrame.callFrame->setCalleeArguments(arguments);
- stackFrame.callFrame[RegisterFile::ArgumentsRegister] = JSValue(arguments);
+ return JSValue::encode(JSValue(arguments));
}
DEFINE_STUB_FUNCTION(void, op_tear_off_activation)
STUB_INIT_STACK_FRAME(stackFrame);
ASSERT(stackFrame.callFrame->codeBlock()->needsFullScopeChain());
- asActivation(stackFrame.args[0].jsValue())->copyRegisters(stackFrame.callFrame->optionalCalleeArguments());
+ JSValue activationValue = stackFrame.args[0].jsValue();
+ if (!activationValue) {
+ if (JSValue v = stackFrame.args[1].jsValue()) {
+ if (!stackFrame.callFrame->codeBlock()->isStrictMode())
+ asArguments(v)->copyRegisters(*stackFrame.globalData);
+ }
+ return;
+ }
+ JSActivation* activation = asActivation(stackFrame.args[0].jsValue());
+ activation->copyRegisters(*stackFrame.globalData);
+ if (JSValue v = stackFrame.args[1].jsValue()) {
+ if (!stackFrame.callFrame->codeBlock()->isStrictMode())
+ asArguments(v)->setActivation(*stackFrame.globalData, activation);
+ }
}
DEFINE_STUB_FUNCTION(void, op_tear_off_arguments)
STUB_INIT_STACK_FRAME(stackFrame);
ASSERT(stackFrame.callFrame->codeBlock()->usesArguments() && !stackFrame.callFrame->codeBlock()->needsFullScopeChain());
- if (stackFrame.callFrame->optionalCalleeArguments())
- stackFrame.callFrame->optionalCalleeArguments()->copyRegisters();
+ asArguments(stackFrame.args[0].jsValue())->copyRegisters(*stackFrame.globalData);
}
DEFINE_STUB_FUNCTION(void, op_profile_will_call)
(*stackFrame.enabledProfilerReference)->didExecute(stackFrame.callFrame, stackFrame.args[0].jsValue());
}
-DEFINE_STUB_FUNCTION(void, op_ret_scopeChain)
+DEFINE_STUB_FUNCTION(JSObject*, op_new_array)
{
STUB_INIT_STACK_FRAME(stackFrame);
- ASSERT(stackFrame.callFrame->codeBlock()->needsFullScopeChain());
- stackFrame.callFrame->scopeChain()->deref();
+ ArgList argList(&stackFrame.callFrame->registers()[stackFrame.args[0].int32()], stackFrame.args[1].int32());
+ return constructArray(stackFrame.callFrame, argList);
}
-DEFINE_STUB_FUNCTION(JSObject*, op_new_array)
+DEFINE_STUB_FUNCTION(JSObject*, op_new_array_buffer)
{
STUB_INIT_STACK_FRAME(stackFrame);
-
- ArgList argList(&stackFrame.callFrame->registers()[stackFrame.args[0].int32()], stackFrame.args[1].int32());
+
+ ArgList argList(stackFrame.callFrame->codeBlock()->constantBuffer(stackFrame.args[0].int32()), stackFrame.args[1].int32());
return constructArray(stackFrame.callFrame, argList);
}
Identifier& ident = stackFrame.args[0].identifier();
do {
- JSObject* o = *iter;
+ JSObject* o = iter->get();
PropertySlot slot(o);
if (o->getPropertySlot(callFrame, ident, slot)) {
JSValue result = slot.getValue(callFrame, ident);
}
} while (++iter != end);
- CodeBlock* codeBlock = callFrame->codeBlock();
- unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
- stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident, vPCIndex, codeBlock);
+ stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident);
VM_THROW_EXCEPTION();
}
-DEFINE_STUB_FUNCTION(JSObject*, op_construct_JSConstruct)
-{
- STUB_INIT_STACK_FRAME(stackFrame);
-
- JSFunction* constructor = asFunction(stackFrame.args[0].jsValue());
- if (constructor->isHostFunction()) {
- CallFrame* callFrame = stackFrame.callFrame;
- CodeBlock* codeBlock = callFrame->codeBlock();
- unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
- stackFrame.globalData->exception = createNotAConstructorError(callFrame, constructor, vPCIndex, codeBlock);
- VM_THROW_EXCEPTION();
- }
-
-#if !ASSERT_DISABLED
- ConstructData constructData;
- ASSERT(constructor->getConstructData(constructData) == ConstructTypeJS);
-#endif
-
- Structure* structure;
- if (stackFrame.args[3].jsValue().isObject())
- structure = asObject(stackFrame.args[3].jsValue())->inheritorID();
- else
- structure = constructor->scope().node()->globalObject->emptyObjectStructure();
- return new (stackFrame.globalData) JSObject(structure);
-}
-
DEFINE_STUB_FUNCTION(EncodedJSValue, op_construct_NotJSConstruct)
{
STUB_INIT_STACK_FRAME(stackFrame);
- CallFrame* callFrame = stackFrame.callFrame;
-
JSValue constrVal = stackFrame.args[0].jsValue();
- int argCount = stackFrame.args[2].int32();
- int thisRegister = stackFrame.args[4].int32();
ConstructData constructData;
- ConstructType constructType = constrVal.getConstructData(constructData);
+ ConstructType constructType = getConstructData(constrVal, constructData);
+
+ ASSERT(constructType != ConstructTypeJS);
if (constructType == ConstructTypeHost) {
- ArgList argList(callFrame->registers() + thisRegister + 1, argCount - 1);
+ int registerOffset = stackFrame.args[1].int32();
+ int argCount = stackFrame.args[2].int32();
+ CallFrame* previousCallFrame = stackFrame.callFrame;
+ CallFrame* callFrame = CallFrame::create(previousCallFrame->registers() + registerOffset);
+ if (!stackFrame.registerFile->grow(callFrame->registers())) {
+ throwStackOverflowError(previousCallFrame, stackFrame.globalData, callFrame->returnPC(), STUB_RETURN_ADDRESS);
+ VM_THROW_EXCEPTION();
+ }
- JSValue returnValue;
+ callFrame->init(0, static_cast<Instruction*>((STUB_RETURN_ADDRESS).value()), previousCallFrame->scopeChain(), previousCallFrame, argCount, asObject(constrVal));
+
+ EncodedJSValue returnValue;
{
SamplingTool::HostCallRecord callRecord(CTI_SAMPLER);
- returnValue = constructData.native.function(callFrame, asObject(constrVal), argList);
+ returnValue = constructData.native.function(callFrame);
}
- CHECK_FOR_EXCEPTION();
- return JSValue::encode(returnValue);
+ CHECK_FOR_EXCEPTION_AT_END();
+ return returnValue;
}
ASSERT(constructType == ConstructTypeNone);
- CodeBlock* codeBlock = callFrame->codeBlock();
- unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
- stackFrame.globalData->exception = createNotAConstructorError(callFrame, constrVal, vPCIndex, codeBlock);
+ stackFrame.globalData->exception = createNotAConstructorError(stackFrame.callFrame, constrVal);
VM_THROW_EXCEPTION();
}
if (LIKELY(baseValue.isCell() && subscript.isString())) {
Identifier propertyName(callFrame, asString(subscript)->value(callFrame));
- PropertySlot slot(asCell(baseValue));
+ PropertySlot slot(baseValue.asCell());
// JSString::value may have thrown, but we shouldn't find a property with a null identifier,
// so we should miss this case and wind up in the CHECK_FOR_EXCEPTION_AT_END, below.
- if (asCell(baseValue)->fastGetOwnPropertySlot(callFrame, propertyName, slot)) {
+ if (baseValue.asCell()->fastGetOwnPropertySlot(callFrame, propertyName, slot)) {
JSValue result = slot.getValue(callFrame, propertyName);
CHECK_FOR_EXCEPTION();
return JSValue::encode(result);
double left;
double right;
if (src1.getNumber(left) && src2.getNumber(right))
- return JSValue::encode(jsNumber(stackFrame.globalData, left - right));
+ return JSValue::encode(jsNumber(left - right));
CallFrame* callFrame = stackFrame.callFrame;
- JSValue result = jsNumber(stackFrame.globalData, src1.toNumber(callFrame) - src2.toNumber(callFrame));
+ JSValue result = jsNumber(src1.toNumber(callFrame) - src2.toNumber(callFrame));
CHECK_FOR_EXCEPTION_AT_END();
return JSValue::encode(result);
}
if (isJSArray(globalData, baseValue)) {
JSArray* jsArray = asArray(baseValue);
if (jsArray->canSetIndex(i))
- jsArray->setIndex(i, value);
+ jsArray->setIndex(*globalData, i, value);
else
jsArray->JSArray::put(callFrame, i, value);
} else if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) {
} else {
Identifier property(callFrame, subscript.toString(callFrame));
if (!stackFrame.globalData->exception) { // Don't put to an object if toString threw an exception.
- PutPropertySlot slot;
+ PutPropertySlot slot(callFrame->codeBlock()->isStrictMode());
baseValue.put(callFrame, property, value, slot);
}
}
} else {
Identifier property(callFrame, subscript.toString(callFrame));
if (!stackFrame.globalData->exception) { // Don't put to an object if toString threw an exception.
- PutPropertySlot slot;
+ PutPropertySlot slot(callFrame->codeBlock()->isStrictMode());
baseValue.put(callFrame, property, value, slot);
}
}
stackFrame.globalData->exception = createStackOverflowError(callFrame);
VM_THROW_EXCEPTION();
}
- int32_t expectedParams = callFrame->callee()->jsExecutable()->parameterCount();
+ int32_t expectedParams = asFunction(callFrame->callee())->jsExecutable()->parameterCount();
int32_t inplaceArgs = min(providedParams, expectedParams);
Register* inplaceArgsDst = callFrame->registers() + argsOffset;
} else if (!arguments.isUndefinedOrNull()) {
if (!arguments.isObject()) {
- CodeBlock* codeBlock = callFrame->codeBlock();
- unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
- stackFrame.globalData->exception = createInvalidParamError(callFrame, "Function.prototype.apply", arguments, vPCIndex, codeBlock);
+ stackFrame.globalData->exception = createInvalidParamError(callFrame, "Function.prototype.apply", arguments);
VM_THROW_EXCEPTION();
}
- if (asObject(arguments)->classInfo() == &Arguments::info) {
+ if (asObject(arguments)->classInfo() == &Arguments::s_info) {
Arguments* argsObject = asArguments(arguments);
argCount = argsObject->numProvidedArguments(callFrame);
argCount = min(argCount, static_cast<uint32_t>(Arguments::MaxArguments));
VM_THROW_EXCEPTION();
}
array->copyToRegisters(callFrame, callFrame->registers() + argsOffset, argCount);
- } else if (asObject(arguments)->inherits(&JSArray::info)) {
+ } else if (asObject(arguments)->inherits(&JSArray::s_info)) {
JSObject* argObject = asObject(arguments);
argCount = argObject->get(callFrame, callFrame->propertyNames().length).toUInt32(callFrame);
argCount = min(argCount, static_cast<uint32_t>(Arguments::MaxArguments));
CHECK_FOR_EXCEPTION();
}
} else {
- CodeBlock* codeBlock = callFrame->codeBlock();
- unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
- stackFrame.globalData->exception = createInvalidParamError(callFrame, "Function.prototype.apply", arguments, vPCIndex, codeBlock);
+ stackFrame.globalData->exception = createInvalidParamError(callFrame, "Function.prototype.apply", arguments);
VM_THROW_EXCEPTION();
}
}
double v;
if (src.getNumber(v))
- return JSValue::encode(jsNumber(stackFrame.globalData, -v));
+ return JSValue::encode(jsNumber(-v));
CallFrame* callFrame = stackFrame.callFrame;
- JSValue result = jsNumber(stackFrame.globalData, -src.toNumber(callFrame));
+ JSValue result = jsNumber(-src.toNumber(callFrame));
CHECK_FOR_EXCEPTION_AT_END();
return JSValue::encode(result);
}
{
STUB_INIT_STACK_FRAME(stackFrame);
- return JSValue::encode(JSC::resolveBase(stackFrame.callFrame, stackFrame.args[0].identifier(), stackFrame.callFrame->scopeChain()));
+ return JSValue::encode(JSC::resolveBase(stackFrame.callFrame, stackFrame.args[0].identifier(), stackFrame.callFrame->scopeChain(), false));
+}
+
+DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_base_strict_put)
+{
+ STUB_INIT_STACK_FRAME(stackFrame);
+ JSValue base = JSC::resolveBase(stackFrame.callFrame, stackFrame.args[0].identifier(), stackFrame.callFrame->scopeChain(), true);
+ if (!base) {
+ stackFrame.globalData->exception = createErrorForInvalidGlobalAssignment(stackFrame.callFrame, stackFrame.args[0].identifier().ustring());
+ VM_THROW_EXCEPTION();
+ }
+ return JSValue::encode(base);
}
+DEFINE_STUB_FUNCTION(EncodedJSValue, op_ensure_property_exists)
+{
+ STUB_INIT_STACK_FRAME(stackFrame);
+ JSValue base = stackFrame.callFrame->r(stackFrame.args[0].int32()).jsValue();
+ JSObject* object = asObject(base);
+ PropertySlot slot(object);
+ ASSERT(stackFrame.callFrame->codeBlock()->isStrictMode());
+ if (!object->getPropertySlot(stackFrame.callFrame, stackFrame.args[1].identifier(), slot)) {
+ stackFrame.globalData->exception = createErrorForInvalidGlobalAssignment(stackFrame.callFrame, stackFrame.args[1].identifier().ustring());
+ VM_THROW_EXCEPTION();
+ }
+
+ return JSValue::encode(base);
+}
+
DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_skip)
{
STUB_INIT_STACK_FRAME(stackFrame);
ScopeChainIterator iter = scopeChain->begin();
ScopeChainIterator end = scopeChain->end();
ASSERT(iter != end);
+ CodeBlock* codeBlock = callFrame->codeBlock();
+ bool checkTopLevel = codeBlock->codeType() == FunctionCode && codeBlock->needsFullScopeChain();
+ ASSERT(skip || !checkTopLevel);
+ if (checkTopLevel && skip--) {
+ if (callFrame->uncheckedR(codeBlock->activationRegister()).jsValue())
+ ++iter;
+ }
while (skip--) {
++iter;
ASSERT(iter != end);
}
Identifier& ident = stackFrame.args[0].identifier();
do {
- JSObject* o = *iter;
+ JSObject* o = iter->get();
PropertySlot slot(o);
if (o->getPropertySlot(callFrame, ident, slot)) {
JSValue result = slot.getValue(callFrame, ident);
}
} while (++iter != end);
- CodeBlock* codeBlock = callFrame->codeBlock();
- unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
- stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident, vPCIndex, codeBlock);
+ stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident);
VM_THROW_EXCEPTION();
}
STUB_INIT_STACK_FRAME(stackFrame);
CallFrame* callFrame = stackFrame.callFrame;
- JSGlobalObject* globalObject = stackFrame.args[0].globalObject();
- Identifier& ident = stackFrame.args[1].identifier();
- unsigned globalResolveInfoIndex = stackFrame.args[2].int32();
+ CodeBlock* codeBlock = callFrame->codeBlock();
+ JSGlobalObject* globalObject = codeBlock->globalObject();
+ Identifier& ident = stackFrame.args[0].identifier();
+ unsigned globalResolveInfoIndex = stackFrame.args[1].int32();
ASSERT(globalObject->isGlobalObject());
PropertySlot slot(globalObject);
if (globalObject->getPropertySlot(callFrame, ident, slot)) {
JSValue result = slot.getValue(callFrame, ident);
if (slot.isCacheableValue() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) {
- GlobalResolveInfo& globalResolveInfo = callFrame->codeBlock()->globalResolveInfo(globalResolveInfoIndex);
- if (globalResolveInfo.structure)
- globalResolveInfo.structure->deref();
- globalObject->structure()->ref();
- globalResolveInfo.structure = globalObject->structure();
+ GlobalResolveInfo& globalResolveInfo = codeBlock->globalResolveInfo(globalResolveInfoIndex);
+ globalResolveInfo.structure.set(callFrame->globalData(), codeBlock->ownerExecutable(), globalObject->structure());
globalResolveInfo.offset = slot.cachedOffset();
return JSValue::encode(result);
}
return JSValue::encode(result);
}
- unsigned vPCIndex = callFrame->codeBlock()->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
- stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident, vPCIndex, callFrame->codeBlock());
+ stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident);
VM_THROW_EXCEPTION();
}
double left;
double right;
if (src1.getNumber(left) && src2.getNumber(right))
- return JSValue::encode(jsNumber(stackFrame.globalData, left / right));
+ return JSValue::encode(jsNumber(left / right));
CallFrame* callFrame = stackFrame.callFrame;
- JSValue result = jsNumber(stackFrame.globalData, src1.toNumber(callFrame) / src2.toNumber(callFrame));
+ JSValue result = jsNumber(src1.toNumber(callFrame) / src2.toNumber(callFrame));
CHECK_FOR_EXCEPTION_AT_END();
return JSValue::encode(result);
}
JSValue v = stackFrame.args[0].jsValue();
CallFrame* callFrame = stackFrame.callFrame;
- JSValue result = jsNumber(stackFrame.globalData, v.toNumber(callFrame) - 1);
+ JSValue result = jsNumber(v.toNumber(callFrame) - 1);
CHECK_FOR_EXCEPTION_AT_END();
return JSValue::encode(result);
}
JSValue number = v.toJSNumber(callFrame);
CHECK_FOR_EXCEPTION_AT_END();
- callFrame->registers()[stackFrame.args[1].int32()] = jsNumber(stackFrame.globalData, number.uncheckedGetNumber() + 1);
+ callFrame->registers()[stackFrame.args[1].int32()] = jsNumber(number.uncheckedGetNumber() + 1);
return JSValue::encode(number);
}
start:
if (src2.isUndefined()) {
return src1.isNull() ||
- (src1.isCell() && asCell(src1)->structure()->typeInfo().masqueradesAsUndefined()) ||
- src1.isUndefined();
+ (src1.isCell() && src1.asCell()->structure()->typeInfo().masqueradesAsUndefined())
+ || src1.isUndefined();
}
if (src2.isNull()) {
return src1.isUndefined() ||
- (src1.isCell() && asCell(src1)->structure()->typeInfo().masqueradesAsUndefined()) ||
- src1.isNull();
+ (src1.isCell() && src1.asCell()->structure()->typeInfo().masqueradesAsUndefined())
+ || src1.isNull();
}
if (src1.isInt32()) {
}
if (src1.isUndefined())
- return src2.isCell() && asCell(src2)->structure()->typeInfo().masqueradesAsUndefined();
+ return src2.isCell() && src2.asCell()->structure()->typeInfo().masqueradesAsUndefined();
if (src1.isNull())
- return src2.isCell() && asCell(src2)->structure()->typeInfo().masqueradesAsUndefined();
+ return src2.isCell() && src2.asCell()->structure()->typeInfo().masqueradesAsUndefined();
- JSCell* cell1 = asCell(src1);
+ JSCell* cell1 = src1.asCell();
if (cell1->isString()) {
if (src2.isInt32())
- return static_cast<JSString*>(cell1)->value(stackFrame.callFrame).toDouble() == src2.asInt32();
+ return jsToNumber(static_cast<JSString*>(cell1)->value(stackFrame.callFrame)) == src2.asInt32();
if (src2.isDouble())
- return static_cast<JSString*>(cell1)->value(stackFrame.callFrame).toDouble() == src2.asDouble();
+ return jsToNumber(static_cast<JSString*>(cell1)->value(stackFrame.callFrame)) == src2.asDouble();
if (src2.isTrue())
- return static_cast<JSString*>(cell1)->value(stackFrame.callFrame).toDouble() == 1.0;
+ return jsToNumber(static_cast<JSString*>(cell1)->value(stackFrame.callFrame)) == 1.0;
if (src2.isFalse())
- return static_cast<JSString*>(cell1)->value(stackFrame.callFrame).toDouble() == 0.0;
+ return jsToNumber(static_cast<JSString*>(cell1)->value(stackFrame.callFrame)) == 0.0;
- JSCell* cell2 = asCell(src2);
+ JSCell* cell2 = src2.asCell();
if (cell2->isString())
return static_cast<JSString*>(cell1)->value(stackFrame.callFrame) == static_cast<JSString*>(cell2)->value(stackFrame.callFrame);
JSValue shift = stackFrame.args[1].jsValue();
CallFrame* callFrame = stackFrame.callFrame;
- JSValue result = jsNumber(stackFrame.globalData, (val.toInt32(callFrame)) << (shift.toUInt32(callFrame) & 0x1f));
+ JSValue result = jsNumber((val.toInt32(callFrame)) << (shift.toUInt32(callFrame) & 0x1f));
CHECK_FOR_EXCEPTION_AT_END();
return JSValue::encode(result);
}
ASSERT(!src1.isInt32() || !src2.isInt32());
CallFrame* callFrame = stackFrame.callFrame;
- JSValue result = jsNumber(stackFrame.globalData, src1.toInt32(callFrame) & src2.toInt32(callFrame));
+ JSValue result = jsNumber(src1.toInt32(callFrame) & src2.toInt32(callFrame));
CHECK_FOR_EXCEPTION_AT_END();
return JSValue::encode(result);
}
JSValue shift = stackFrame.args[1].jsValue();
CallFrame* callFrame = stackFrame.callFrame;
- JSValue result = jsNumber(stackFrame.globalData, (val.toInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f));
+ JSValue result = jsNumber((val.toInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f));
CHECK_FOR_EXCEPTION_AT_END();
return JSValue::encode(result);
ASSERT(!src.isInt32());
CallFrame* callFrame = stackFrame.callFrame;
- JSValue result = jsNumber(stackFrame.globalData, ~src.toInt32(callFrame));
+ JSValue result = jsNumber(~src.toInt32(callFrame));
CHECK_FOR_EXCEPTION_AT_END();
return JSValue::encode(result);
}
Identifier& ident = stackFrame.args[0].identifier();
JSObject* base;
do {
- base = *iter;
+ base = iter->get();
PropertySlot slot(base);
if (base->getPropertySlot(callFrame, ident, slot)) {
JSValue result = slot.getValue(callFrame, ident);
++iter;
} while (iter != end);
- CodeBlock* codeBlock = callFrame->codeBlock();
- unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
- stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident, vPCIndex, codeBlock);
+ stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident);
VM_THROW_EXCEPTION_AT_END();
return JSValue::encode(JSValue());
}
FunctionExecutable* function = stackFrame.args[0].function();
JSFunction* func = function->make(callFrame, callFrame->scopeChain());
+ ASSERT(callFrame->codeBlock()->codeType() != FunctionCode || !callFrame->codeBlock()->needsFullScopeChain() || callFrame->uncheckedR(callFrame->codeBlock()->activationRegister()).jsValue());
/*
The Identifier in a FunctionExpression can be referenced from inside
*/
if (!function->name().isNull()) {
JSStaticScopeObject* functionScopeObject = new (callFrame) JSStaticScopeObject(callFrame, function->name(), func, ReadOnly | DontDelete);
- func->scope().push(functionScopeObject);
+ func->setScope(callFrame->globalData(), func->scope()->push(functionScopeObject));
}
return func;
CallFrame* callFrame = stackFrame.callFrame;
double d = dividendValue.toNumber(callFrame);
- JSValue result = jsNumber(stackFrame.globalData, fmod(d, divisorValue.toNumber(callFrame)));
+ JSValue result = jsNumber(fmod(d, divisorValue.toNumber(callFrame)));
CHECK_FOR_EXCEPTION_AT_END();
return JSValue::encode(result);
}
JSValue number = v.toJSNumber(callFrame);
CHECK_FOR_EXCEPTION_AT_END();
- callFrame->registers()[stackFrame.args[1].int32()] = jsNumber(stackFrame.globalData, number.uncheckedGetNumber() - 1);
+ callFrame->registers()[stackFrame.args[1].int32()] = jsNumber(number.uncheckedGetNumber() - 1);
return JSValue::encode(number);
}
JSValue shift = stackFrame.args[1].jsValue();
CallFrame* callFrame = stackFrame.callFrame;
- JSValue result = jsNumber(stackFrame.globalData, (val.toUInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f));
+ JSValue result = jsNumber((val.toUInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f));
CHECK_FOR_EXCEPTION_AT_END();
return JSValue::encode(result);
}
CallFrame* callFrame = stackFrame.callFrame;
- JSValue result = jsNumber(stackFrame.globalData, src1.toInt32(callFrame) ^ src2.toInt32(callFrame));
+ JSValue result = jsNumber(src1.toInt32(callFrame) ^ src2.toInt32(callFrame));
CHECK_FOR_EXCEPTION_AT_END();
return JSValue::encode(result);
}
{
STUB_INIT_STACK_FRAME(stackFrame);
- return new (stackFrame.globalData) RegExpObject(stackFrame.callFrame->lexicalGlobalObject()->regExpStructure(), stackFrame.args[0].regExp());
+ CallFrame* callFrame = stackFrame.callFrame;
+
+ RegExp* regExp = stackFrame.args[0].regExp();
+ if (!regExp->isValid()) {
+ stackFrame.globalData->exception = createSyntaxError(callFrame, "Invalid flags supplied to RegExp constructor.");
+ VM_THROW_EXCEPTION();
+ }
+
+ return new (stackFrame.globalData) RegExpObject(stackFrame.callFrame->lexicalGlobalObject(), stackFrame.callFrame->lexicalGlobalObject()->regExpStructure(), regExp);
}
DEFINE_STUB_FUNCTION(EncodedJSValue, op_bitor)
CallFrame* callFrame = stackFrame.callFrame;
- JSValue result = jsNumber(stackFrame.globalData, src1.toInt32(callFrame) | src2.toInt32(callFrame));
+ JSValue result = jsNumber(src1.toInt32(callFrame) | src2.toInt32(callFrame));
CHECK_FOR_EXCEPTION_AT_END();
return JSValue::encode(result);
}
DEFINE_STUB_FUNCTION(EncodedJSValue, op_call_eval)
{
STUB_INIT_STACK_FRAME(stackFrame);
+ ASSERT(stackFrame.callFrame->codeBlock()->codeType() != FunctionCode || !stackFrame.callFrame->codeBlock()->needsFullScopeChain() || stackFrame.callFrame->uncheckedR(stackFrame.callFrame->codeBlock()->activationRegister()).jsValue());
CallFrame* callFrame = stackFrame.callFrame;
RegisterFile* registerFile = stackFrame.registerFile;
Register* newCallFrame = callFrame->registers() + registerOffset;
Register* argv = newCallFrame - RegisterFile::CallFrameHeaderSize - argCount;
- JSValue thisValue = argv[0].jsValue();
- JSGlobalObject* globalObject = callFrame->scopeChain()->globalObject;
-
- if (thisValue == globalObject && funcVal == globalObject->evalFunction()) {
- JSValue exceptionValue;
- JSValue result = interpreter->callEval(callFrame, registerFile, argv, argCount, registerOffset, exceptionValue);
- if (UNLIKELY(exceptionValue)) {
- stackFrame.globalData->exception = exceptionValue;
- VM_THROW_EXCEPTION_AT_END();
- }
+ JSValue baseValue = argv[0].jsValue();
+ JSGlobalObject* globalObject = callFrame->scopeChain()->globalObject.get();
+
+ if (baseValue == globalObject && funcVal == globalObject->evalFunction()) {
+ JSValue result = interpreter->callEval(callFrame, registerFile, argv, argCount, registerOffset);
+ CHECK_FOR_EXCEPTION_AT_END();
return JSValue::encode(result);
}
return JSValue::encode(JSValue());
}
-DEFINE_STUB_FUNCTION(EncodedJSValue, op_throw)
+DEFINE_STUB_FUNCTION(void*, op_throw)
{
STUB_INIT_STACK_FRAME(stackFrame);
-
- CallFrame* callFrame = stackFrame.callFrame;
- CodeBlock* codeBlock = callFrame->codeBlock();
-
- unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
-
- JSValue exceptionValue = stackFrame.args[0].jsValue();
- ASSERT(exceptionValue);
-
- HandlerInfo* handler = stackFrame.globalData->interpreter->throwException(callFrame, exceptionValue, vPCIndex, true);
-
- if (!handler) {
- *stackFrame.exception = exceptionValue;
- STUB_SET_RETURN_ADDRESS(FunctionPtr(ctiOpThrowNotCaught).value());
- return JSValue::encode(jsNull());
- }
-
- stackFrame.callFrame = callFrame;
- void* catchRoutine = handler->nativeCode.executableAddress();
- ASSERT(catchRoutine);
- STUB_SET_RETURN_ADDRESS(catchRoutine);
- return JSValue::encode(exceptionValue);
+ ExceptionHandler handler = jitThrow(stackFrame.globalData, stackFrame.callFrame, stackFrame.args[0].jsValue(), STUB_RETURN_ADDRESS);
+ STUB_SET_RETURN_ADDRESS(handler.catchRoutine);
+ return handler.callFrame;
}
DEFINE_STUB_FUNCTION(JSPropertyNameIterator*, op_get_pnames)
JSValue baseVal = stackFrame.args[1].jsValue();
if (!baseVal.isObject()) {
- CallFrame* callFrame = stackFrame.callFrame;
- CodeBlock* codeBlock = callFrame->codeBlock();
- unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
- stackFrame.globalData->exception = createInvalidParamError(callFrame, "in", baseVal, vPCIndex, codeBlock);
+ stackFrame.globalData->exception = createInvalidParamError(stackFrame.callFrame, "in", baseVal);
VM_THROW_EXCEPTION();
}
void* result = codeBlock->characterSwitchJumpTable(tableIndex).ctiDefault.executableAddress();
if (scrutinee.isString()) {
- UString::Rep* value = asString(scrutinee)->value(callFrame).rep();
+ StringImpl* value = asString(scrutinee)->value(callFrame).impl();
if (value->length() == 1)
result = codeBlock->characterSwitchJumpTable(tableIndex).ctiForValue(value->characters()[0]).executableAddress();
}
void* result = codeBlock->stringSwitchJumpTable(tableIndex).ctiDefault.executableAddress();
if (scrutinee.isString()) {
- UString::Rep* value = asString(scrutinee)->value(callFrame).rep();
+ StringImpl* value = asString(scrutinee)->value(callFrame).impl();
result = codeBlock->stringSwitchJumpTable(tableIndex).ctiForValue(value).executableAddress();
}
JSObject* baseObj = baseValue.toObject(callFrame); // may throw
JSValue subscript = stackFrame.args[1].jsValue();
- JSValue result;
+ bool result;
uint32_t i;
if (subscript.getUInt32(i))
- result = jsBoolean(baseObj->deleteProperty(callFrame, i));
+ result = baseObj->deleteProperty(callFrame, i);
else {
CHECK_FOR_EXCEPTION();
Identifier property(callFrame, subscript.toString(callFrame));
CHECK_FOR_EXCEPTION();
- result = jsBoolean(baseObj->deleteProperty(callFrame, property));
+ result = baseObj->deleteProperty(callFrame, property);
}
+ if (!result && callFrame->codeBlock()->isStrictMode())
+ stackFrame.globalData->exception = createTypeError(stackFrame.callFrame, "Unable to delete property.");
+
CHECK_FOR_EXCEPTION_AT_END();
- return JSValue::encode(result);
+ return JSValue::encode(jsBoolean(result));
}
DEFINE_STUB_FUNCTION(void, op_put_getter)
baseObj->defineSetter(callFrame, stackFrame.args[1].identifier(), asObject(stackFrame.args[2].jsValue()));
}
-DEFINE_STUB_FUNCTION(JSObject*, op_new_error)
+DEFINE_STUB_FUNCTION(void, op_throw_reference_error)
{
STUB_INIT_STACK_FRAME(stackFrame);
CallFrame* callFrame = stackFrame.callFrame;
- CodeBlock* codeBlock = callFrame->codeBlock();
- unsigned type = stackFrame.args[0].int32();
- JSValue message = stackFrame.args[1].jsValue();
- unsigned bytecodeOffset = stackFrame.args[2].int32();
-
- unsigned lineNumber = codeBlock->lineNumberForBytecodeOffset(callFrame, bytecodeOffset);
- return Error::create(callFrame, static_cast<ErrorType>(type), message.toString(callFrame), lineNumber, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->sourceURL());
+ UString message = stackFrame.args[0].jsValue().toString(callFrame);
+ stackFrame.globalData->exception = createReferenceError(callFrame, message);
+ VM_THROW_EXCEPTION_AT_END();
}
DEFINE_STUB_FUNCTION(void, op_debug)
stackFrame.globalData->interpreter->debug(callFrame, static_cast<DebugHookID>(debugHookID), firstLine, lastLine);
}
-DEFINE_STUB_FUNCTION(EncodedJSValue, vm_throw)
+DEFINE_STUB_FUNCTION(void*, vm_throw)
{
STUB_INIT_STACK_FRAME(stackFrame);
-
- CallFrame* callFrame = stackFrame.callFrame;
- CodeBlock* codeBlock = callFrame->codeBlock();
JSGlobalData* globalData = stackFrame.globalData;
-
- unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, globalData->exceptionLocation);
-
- JSValue exceptionValue = globalData->exception;
- ASSERT(exceptionValue);
- globalData->exception = JSValue();
-
- HandlerInfo* handler = globalData->interpreter->throwException(callFrame, exceptionValue, vPCIndex, false);
-
- if (!handler) {
- *stackFrame.exception = exceptionValue;
- return JSValue::encode(jsNull());
- }
-
- stackFrame.callFrame = callFrame;
- void* catchRoutine = handler->nativeCode.executableAddress();
- ASSERT(catchRoutine);
- STUB_SET_RETURN_ADDRESS(catchRoutine);
- return JSValue::encode(exceptionValue);
+ ExceptionHandler handler = jitThrow(globalData, stackFrame.callFrame, globalData->exception, globalData->exceptionLocation);
+ STUB_SET_RETURN_ADDRESS(handler.catchRoutine);
+ return handler.callFrame;
}
DEFINE_STUB_FUNCTION(EncodedJSValue, to_object)
return JSValue::encode(stackFrame.args[0].jsValue().toObject(callFrame));
}
-NativeExecutable* JITThunks::specializedThunk(JSGlobalData* globalData, ThunkGenerator generator)
+MacroAssemblerCodePtr JITThunks::ctiStub(JSGlobalData* globalData, ThunkGenerator generator)
+{
+ std::pair<CTIStubMap::iterator, bool> entry = m_ctiStubMap.add(generator, MacroAssemblerCodePtr());
+ if (entry.second)
+ entry.first->second = generator(globalData, m_executablePool.get());
+ return entry.first->second;
+}
+
+NativeExecutable* JITThunks::hostFunctionStub(JSGlobalData* globalData, NativeFunction function)
{
- std::pair<ThunkMap::iterator, bool> entry = m_thunkMap.add(generator, 0);
- if (!entry.second)
- return entry.first->second.get();
- entry.first->second = generator(globalData, m_executablePool.get());
+ std::pair<HostFunctionStubMap::iterator, bool> entry = m_hostFunctionStubMap->add(function, Weak<NativeExecutable>());
+ if (!*entry.first->second)
+ entry.first->second.set(*globalData, NativeExecutable::create(*globalData, JIT::compileCTINativeCall(globalData, m_executablePool, function), function, ctiNativeConstruct(), callHostFunctionAsConstructor));
return entry.first->second.get();
}
+NativeExecutable* JITThunks::hostFunctionStub(JSGlobalData* globalData, NativeFunction function, ThunkGenerator generator)
+{
+ std::pair<HostFunctionStubMap::iterator, bool> entry = m_hostFunctionStubMap->add(function, Weak<NativeExecutable>());
+ if (!*entry.first->second) {
+ MacroAssemblerCodePtr code = globalData->canUseJIT() ? generator(globalData, m_executablePool.get()) : MacroAssemblerCodePtr();
+ entry.first->second.set(*globalData, NativeExecutable::create(*globalData, code, function, ctiNativeConstruct(), callHostFunctionAsConstructor));
+ }
+ return entry.first->second.get();
+}
+
+void JITThunks::clearHostFunctionStubs()
+{
+ m_hostFunctionStubMap.clear();
+}
+
} // namespace JSC
#endif // ENABLE(JIT)
/*
* Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) Research In Motion Limited 2010. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
#ifndef JITStubs_h
#define JITStubs_h
+#include "CallData.h"
#include "MacroAssemblerCodeRef.h"
#include "Register.h"
#include "ThunkGenerators.h"
class RegisterFile;
class RegExp;
+ template <typename T> class Weak;
+
union JITStubArg {
void* asPointer;
EncodedJSValue asEncodedJSValue;
struct TrampolineStructure {
MacroAssemblerCodePtr ctiStringLengthTrampoline;
MacroAssemblerCodePtr ctiVirtualCallLink;
+ MacroAssemblerCodePtr ctiVirtualConstructLink;
MacroAssemblerCodePtr ctiVirtualCall;
- RefPtr<NativeExecutable> ctiNativeCallThunk;
+ MacroAssemblerCodePtr ctiVirtualConstruct;
+ MacroAssemblerCodePtr ctiNativeCall;
+ MacroAssemblerCodePtr ctiNativeConstruct;
MacroAssemblerCodePtr ctiSoftModulo;
};
void* code;
RegisterFile* registerFile;
CallFrame* callFrame;
- JSValue* exception;
+ void* unused1;
Profiler** enabledProfilerReference;
JSGlobalData* globalData;
void* code;
RegisterFile* registerFile;
CallFrame* callFrame;
- JSValue* exception;
+ void* unused1;
Profiler** enabledProfilerReference;
JSGlobalData* globalData;
#endif // COMPILER(MSVC) || (OS(WINDOWS) && COMPILER(GCC))
#elif CPU(ARM_THUMB2)
struct JITStackFrame {
- void* reserved; // Unused
+ JITStubArg reserved; // Unused
JITStubArg args[6];
-#if USE(JSVALUE32_64)
- void* padding[2]; // Maintain 16-byte stack alignment.
+#if USE(JSVALUE64)
+ void* padding; // Maintain 16-byte stack alignment.
#endif
ReturnAddressPtr thunkReturnAddress;
// These arguments passed in r1..r3 (r0 contained the entry code pointed, which is not preserved)
RegisterFile* registerFile;
CallFrame* callFrame;
- JSValue* exception;
-
- void* padding2;
+ void* unused1;
// These arguments passed on the stack.
Profiler** enabledProfilerReference;
ReturnAddressPtr* returnAddressSlot() { return &thunkReturnAddress; }
};
#elif CPU(ARM_TRADITIONAL)
+#if COMPILER(MSVC)
+#pragma pack(push)
+#pragma pack(4)
+#endif // COMPILER(MSVC)
struct JITStackFrame {
JITStubArg padding; // Unused
JITStubArg args[7];
RegisterFile* registerFile;
CallFrame* callFrame;
- JSValue* exception;
+ void* unused1;
// These arguments passed on the stack.
Profiler** enabledProfilerReference;
// When JIT code makes a call, it pushes its return address just below the rest of the stack.
ReturnAddressPtr* returnAddressSlot() { return &thunkReturnAddress; }
};
+#if COMPILER(MSVC)
+#pragma pack(pop)
+#endif // COMPILER(MSVC)
#elif CPU(MIPS)
struct JITStackFrame {
- void* reserved; // Unused
+ JITStubArg reserved; // Unused
JITStubArg args[6];
+#if USE(JSVALUE32_64)
+ void* padding; // Make the overall stack length 8-byte aligned.
+#endif
+
void* preservedGP; // store GP when using PIC code
void* preservedS0;
void* preservedS1;
// These arguments passed in a1..a3 (a0 contained the entry code pointed, which is not preserved)
RegisterFile* registerFile;
CallFrame* callFrame;
- JSValue* exception;
+ void* unused1;
// These arguments passed on the stack.
Profiler** enabledProfilerReference;
JSGlobalData* globalData;
+ ReturnAddressPtr* returnAddressSlot() { return &thunkReturnAddress; }
+ };
+#elif CPU(SH4)
+ struct JITStackFrame {
+ JITStubArg padding; // Unused
+ JITStubArg args[6];
+
+ ReturnAddressPtr thunkReturnAddress;
+ void* savedR10;
+ void* savedR11;
+ void* savedR13;
+ void* savedRPR;
+ void* savedR14;
+ void* savedTimeoutReg;
+
+ RegisterFile* registerFile;
+ CallFrame* callFrame;
+ JSValue* exception;
+ Profiler** enabledProfilerReference;
+ JSGlobalData* globalData;
+
ReturnAddressPtr* returnAddressSlot() { return &thunkReturnAddress; }
};
#else
#define JITSTACKFRAME_ARGS_INDEX (OBJECT_OFFSETOF(JITStackFrame, args) / sizeof(void*))
-#if USE(JIT_STUB_ARGUMENT_VA_LIST)
- #define STUB_ARGS_DECLARATION void* args, ...
- #define STUB_ARGS (reinterpret_cast<void**>(vl_args) - 1)
+#define STUB_ARGS_DECLARATION void** args
+#define STUB_ARGS (args)
+#if CPU(X86)
#if COMPILER(MSVC)
- #define JIT_STUB __cdecl
- #else
- #define JIT_STUB
- #endif
-#else
- #define STUB_ARGS_DECLARATION void** args
- #define STUB_ARGS (args)
-
- #if CPU(X86) && COMPILER(MSVC)
#define JIT_STUB __fastcall
- #elif CPU(X86) && COMPILER(GCC)
+ #elif COMPILER(GCC)
#define JIT_STUB __attribute__ ((fastcall))
#else
- #define JIT_STUB
+ #error "JIT_STUB function calls require fastcall conventions on x86, add appropriate directive/attribute here for your compiler!"
#endif
-#endif
-
-#if CPU(X86_64)
- struct VoidPtrPair {
- void* first;
- void* second;
- };
- #define RETURN_POINTER_PAIR(a,b) VoidPtrPair pair = { a, b }; return pair
#else
- // MSVC doesn't support returning a two-value struct in two registers, so
- // we cast the struct to int64_t instead.
- typedef uint64_t VoidPtrPair;
- union VoidPtrPairUnion {
- struct { void* first; void* second; } s;
- VoidPtrPair i;
- };
- #define RETURN_POINTER_PAIR(a,b) VoidPtrPairUnion pair = {{ a, b }}; return pair.i
+ #define JIT_STUB
#endif
extern "C" void ctiVMThrowTrampoline();
extern "C" void ctiOpThrowNotCaught();
- extern "C" EncodedJSValue ctiTrampoline(void* code, RegisterFile*, CallFrame*, JSValue* exception, Profiler**, JSGlobalData*);
+ extern "C" EncodedJSValue ctiTrampoline(void* code, RegisterFile*, CallFrame*, void* /*unused1*/, Profiler**, JSGlobalData*);
class JITThunks {
public:
MacroAssemblerCodePtr ctiStringLengthTrampoline() { return m_trampolineStructure.ctiStringLengthTrampoline; }
MacroAssemblerCodePtr ctiVirtualCallLink() { return m_trampolineStructure.ctiVirtualCallLink; }
+ MacroAssemblerCodePtr ctiVirtualConstructLink() { return m_trampolineStructure.ctiVirtualConstructLink; }
MacroAssemblerCodePtr ctiVirtualCall() { return m_trampolineStructure.ctiVirtualCall; }
- NativeExecutable* ctiNativeCallThunk() { return m_trampolineStructure.ctiNativeCallThunk.get(); }
+ MacroAssemblerCodePtr ctiVirtualConstruct() { return m_trampolineStructure.ctiVirtualConstruct; }
+ MacroAssemblerCodePtr ctiNativeCall() { return m_trampolineStructure.ctiNativeCall; }
+ MacroAssemblerCodePtr ctiNativeConstruct() { return m_trampolineStructure.ctiNativeConstruct; }
MacroAssemblerCodePtr ctiSoftModulo() { return m_trampolineStructure.ctiSoftModulo; }
- NativeExecutable* specializedThunk(JSGlobalData* globalData, ThunkGenerator generator);
+ MacroAssemblerCodePtr ctiStub(JSGlobalData* globalData, ThunkGenerator generator);
+
+ NativeExecutable* hostFunctionStub(JSGlobalData*, NativeFunction);
+ NativeExecutable* hostFunctionStub(JSGlobalData*, NativeFunction, ThunkGenerator);
+
+ void clearHostFunctionStubs();
+
private:
- typedef HashMap<ThunkGenerator, RefPtr<NativeExecutable> > ThunkMap;
- ThunkMap m_thunkMap;
+ typedef HashMap<ThunkGenerator, MacroAssemblerCodePtr> CTIStubMap;
+ CTIStubMap m_ctiStubMap;
+ typedef HashMap<NativeFunction, Weak<NativeExecutable> > HostFunctionStubMap;
+ OwnPtr<HostFunctionStubMap> m_hostFunctionStubMap;
RefPtr<ExecutablePool> m_executablePool;
TrampolineStructure m_trampolineStructure;
EncodedJSValue JIT_STUB cti_op_call_NotJSFunction(STUB_ARGS_DECLARATION);
EncodedJSValue JIT_STUB cti_op_call_eval(STUB_ARGS_DECLARATION);
EncodedJSValue JIT_STUB cti_op_construct_NotJSConstruct(STUB_ARGS_DECLARATION);
+ EncodedJSValue JIT_STUB cti_op_create_this(STUB_ARGS_DECLARATION);
EncodedJSValue JIT_STUB cti_op_convert_this(STUB_ARGS_DECLARATION);
+ EncodedJSValue JIT_STUB cti_op_convert_this_strict(STUB_ARGS_DECLARATION);
+ EncodedJSValue JIT_STUB cti_op_create_arguments(STUB_ARGS_DECLARATION);
+ EncodedJSValue JIT_STUB cti_op_create_arguments_no_params(STUB_ARGS_DECLARATION);
EncodedJSValue JIT_STUB cti_op_del_by_id(STUB_ARGS_DECLARATION);
EncodedJSValue JIT_STUB cti_op_del_by_val(STUB_ARGS_DECLARATION);
EncodedJSValue JIT_STUB cti_op_div(STUB_ARGS_DECLARATION);
EncodedJSValue JIT_STUB cti_op_get_by_id(STUB_ARGS_DECLARATION);
EncodedJSValue JIT_STUB cti_op_get_by_id_array_fail(STUB_ARGS_DECLARATION);
+ EncodedJSValue JIT_STUB cti_op_get_by_id_custom_stub(STUB_ARGS_DECLARATION);
EncodedJSValue JIT_STUB cti_op_get_by_id_generic(STUB_ARGS_DECLARATION);
- EncodedJSValue JIT_STUB cti_op_get_by_id_method_check(STUB_ARGS_DECLARATION);
EncodedJSValue JIT_STUB cti_op_get_by_id_getter_stub(STUB_ARGS_DECLARATION);
- EncodedJSValue JIT_STUB cti_op_get_by_id_custom_stub(STUB_ARGS_DECLARATION);
+ EncodedJSValue JIT_STUB cti_op_get_by_id_method_check(STUB_ARGS_DECLARATION);
EncodedJSValue JIT_STUB cti_op_get_by_id_proto_fail(STUB_ARGS_DECLARATION);
EncodedJSValue JIT_STUB cti_op_get_by_id_proto_list(STUB_ARGS_DECLARATION);
EncodedJSValue JIT_STUB cti_op_get_by_id_proto_list_full(STUB_ARGS_DECLARATION);
EncodedJSValue JIT_STUB cti_op_pre_inc(STUB_ARGS_DECLARATION);
EncodedJSValue JIT_STUB cti_op_resolve(STUB_ARGS_DECLARATION);
EncodedJSValue JIT_STUB cti_op_resolve_base(STUB_ARGS_DECLARATION);
+ EncodedJSValue JIT_STUB cti_op_resolve_base_strict_put(STUB_ARGS_DECLARATION);
+ EncodedJSValue JIT_STUB cti_op_ensure_property_exists(STUB_ARGS_DECLARATION);
EncodedJSValue JIT_STUB cti_op_resolve_global(STUB_ARGS_DECLARATION);
EncodedJSValue JIT_STUB cti_op_resolve_global_dynamic(STUB_ARGS_DECLARATION);
EncodedJSValue JIT_STUB cti_op_resolve_skip(STUB_ARGS_DECLARATION);
EncodedJSValue JIT_STUB cti_op_strcat(STUB_ARGS_DECLARATION);
EncodedJSValue JIT_STUB cti_op_stricteq(STUB_ARGS_DECLARATION);
EncodedJSValue JIT_STUB cti_op_sub(STUB_ARGS_DECLARATION);
- EncodedJSValue JIT_STUB cti_op_throw(STUB_ARGS_DECLARATION);
EncodedJSValue JIT_STUB cti_op_to_jsnumber(STUB_ARGS_DECLARATION);
EncodedJSValue JIT_STUB cti_op_to_primitive(STUB_ARGS_DECLARATION);
EncodedJSValue JIT_STUB cti_op_typeof(STUB_ARGS_DECLARATION);
EncodedJSValue JIT_STUB cti_op_urshift(STUB_ARGS_DECLARATION);
- EncodedJSValue JIT_STUB cti_vm_throw(STUB_ARGS_DECLARATION);
EncodedJSValue JIT_STUB cti_to_object(STUB_ARGS_DECLARATION);
- JSObject* JIT_STUB cti_op_construct_JSConstruct(STUB_ARGS_DECLARATION);
JSObject* JIT_STUB cti_op_new_array(STUB_ARGS_DECLARATION);
- JSObject* JIT_STUB cti_op_new_error(STUB_ARGS_DECLARATION);
+ JSObject* JIT_STUB cti_op_new_array_buffer(STUB_ARGS_DECLARATION);
JSObject* JIT_STUB cti_op_new_func(STUB_ARGS_DECLARATION);
JSObject* JIT_STUB cti_op_new_func_exp(STUB_ARGS_DECLARATION);
JSObject* JIT_STUB cti_op_new_object(STUB_ARGS_DECLARATION);
JSObject* JIT_STUB cti_op_push_scope(STUB_ARGS_DECLARATION);
JSObject* JIT_STUB cti_op_put_by_id_transition_realloc(STUB_ARGS_DECLARATION);
JSPropertyNameIterator* JIT_STUB cti_op_get_pnames(STUB_ARGS_DECLARATION);
- VoidPtrPair JIT_STUB cti_op_call_arityCheck(STUB_ARGS_DECLARATION);
int JIT_STUB cti_op_eq(STUB_ARGS_DECLARATION);
int JIT_STUB cti_op_eq_strings(STUB_ARGS_DECLARATION);
int JIT_STUB cti_op_jless(STUB_ARGS_DECLARATION);
int JIT_STUB cti_op_loop_if_lesseq(STUB_ARGS_DECLARATION);
int JIT_STUB cti_timeout_check(STUB_ARGS_DECLARATION);
int JIT_STUB cti_has_property(STUB_ARGS_DECLARATION);
- void JIT_STUB cti_op_create_arguments(STUB_ARGS_DECLARATION);
- void JIT_STUB cti_op_create_arguments_no_params(STUB_ARGS_DECLARATION);
+ void JIT_STUB cti_op_check_has_instance(STUB_ARGS_DECLARATION);
void JIT_STUB cti_op_debug(STUB_ARGS_DECLARATION);
void JIT_STUB cti_op_end(STUB_ARGS_DECLARATION);
void JIT_STUB cti_op_jmp_scopes(STUB_ARGS_DECLARATION);
void JIT_STUB cti_op_put_by_val_byte_array(STUB_ARGS_DECLARATION);
void JIT_STUB cti_op_put_getter(STUB_ARGS_DECLARATION);
void JIT_STUB cti_op_put_setter(STUB_ARGS_DECLARATION);
- void JIT_STUB cti_op_ret_scopeChain(STUB_ARGS_DECLARATION);
void JIT_STUB cti_op_tear_off_activation(STUB_ARGS_DECLARATION);
void JIT_STUB cti_op_tear_off_arguments(STUB_ARGS_DECLARATION);
- void JIT_STUB cti_register_file_check(STUB_ARGS_DECLARATION);
- void* JIT_STUB cti_op_call_JSFunction(STUB_ARGS_DECLARATION);
+ void JIT_STUB cti_op_throw_reference_error(STUB_ARGS_DECLARATION);
+ void* JIT_STUB cti_op_call_arityCheck(STUB_ARGS_DECLARATION);
+ void* JIT_STUB cti_op_construct_arityCheck(STUB_ARGS_DECLARATION);
+ void* JIT_STUB cti_op_call_jitCompile(STUB_ARGS_DECLARATION);
+ void* JIT_STUB cti_op_construct_jitCompile(STUB_ARGS_DECLARATION);
void* JIT_STUB cti_op_switch_char(STUB_ARGS_DECLARATION);
void* JIT_STUB cti_op_switch_imm(STUB_ARGS_DECLARATION);
void* JIT_STUB cti_op_switch_string(STUB_ARGS_DECLARATION);
+ void* JIT_STUB cti_op_throw(STUB_ARGS_DECLARATION);
+ void* JIT_STUB cti_register_file_check(STUB_ARGS_DECLARATION);
void* JIT_STUB cti_vm_lazyLinkCall(STUB_ARGS_DECLARATION);
+ void* JIT_STUB cti_vm_lazyLinkConstruct(STUB_ARGS_DECLARATION);
+ void* JIT_STUB cti_vm_throw(STUB_ARGS_DECLARATION);
} // extern "C"
} // namespace JSC
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef JITWriteBarrier_h
+#define JITWriteBarrier_h
+
+#if ENABLE(JIT)
+
+#include "MacroAssembler.h"
+#include "MarkStack.h"
+#include "WriteBarrier.h"
+
+namespace JSC {
+
+class JSCell;
+class JSGlobalData;
+
+// Needs to be even to appease some of the backends.
+#define JITWriteBarrierFlag ((void*)2)
+class JITWriteBarrierBase {
+public:
+ typedef void* (JITWriteBarrierBase::*UnspecifiedBoolType);
+ operator UnspecifiedBoolType*() const { return get() ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; }
+ bool operator!() const { return !get(); }
+
+ void setFlagOnBarrier()
+ {
+ ASSERT(!m_location);
+ m_location = CodeLocationDataLabelPtr(JITWriteBarrierFlag);
+ }
+
+ bool isFlagged() const
+ {
+ return !!m_location;
+ }
+
+ void setLocation(CodeLocationDataLabelPtr location)
+ {
+ ASSERT(!m_location);
+ m_location = location;
+ }
+
+ CodeLocationDataLabelPtr location() const
+ {
+ ASSERT((!!m_location) && m_location.executableAddress() != JITWriteBarrierFlag);
+ return m_location;
+ }
+
+ void clear() { clear(0); }
+
+protected:
+ JITWriteBarrierBase()
+ {
+ }
+
+ void set(JSGlobalData&, CodeLocationDataLabelPtr location, JSCell* owner, JSCell* value)
+ {
+ Heap::writeBarrier(owner, value);
+ m_location = location;
+ ASSERT(((!!m_location) && m_location.executableAddress() != JITWriteBarrierFlag) || (location.executableAddress() == m_location.executableAddress()));
+ MacroAssembler::repatchPointer(m_location, value);
+ ASSERT(get() == value);
+ }
+
+ JSCell* get() const
+ {
+ if (!m_location || m_location.executableAddress() == JITWriteBarrierFlag)
+ return 0;
+ void* result = static_cast<JSCell*>(MacroAssembler::readPointer(m_location));
+ // We use -1 to indicate a "safe" empty value in the instruction stream
+ if (result == (void*)-1)
+ return 0;
+ return static_cast<JSCell*>(result);
+ }
+
+private:
+ void clear(void* clearedValue)
+ {
+ if (!m_location)
+ return;
+ if (m_location.executableAddress() != JITWriteBarrierFlag)
+ MacroAssembler::repatchPointer(m_location, clearedValue);
+ }
+
+ CodeLocationDataLabelPtr m_location;
+};
+
+#undef JITWriteBarrierFlag
+
+template <typename T> class JITWriteBarrier : public JITWriteBarrierBase {
+public:
+ JITWriteBarrier()
+ {
+ }
+
+ void set(JSGlobalData& globalData, CodeLocationDataLabelPtr location, JSCell* owner, T* value)
+ {
+ validateCell(owner);
+ validateCell(value);
+ JITWriteBarrierBase::set(globalData, location, owner, value);
+ }
+ T* get() const
+ {
+ T* result = static_cast<T*>(JITWriteBarrierBase::get());
+ if (result)
+ validateCell(result);
+ return result;
+ }
+};
+
+template<typename T> inline void MarkStack::append(JITWriteBarrier<T>* slot)
+{
+ internalAppend(slot->get());
+}
+
+}
+
+#endif // ENABLE(JIT)
+
+#endif
#include "JITCode.h"
#include "JITStubs.h"
-#include "JSImmediate.h"
+#include "JSValue.h"
#include "MacroAssembler.h"
#include "RegisterFile.h"
#include <wtf/AlwaysInline.h>
static const FPRegisterID fpRegT0 = MIPSRegisters::f4;
static const FPRegisterID fpRegT1 = MIPSRegisters::f6;
static const FPRegisterID fpRegT2 = MIPSRegisters::f8;
- static const FPRegisterID fpRegT2 = MIPSRegisters::f10;
+ static const FPRegisterID fpRegT3 = MIPSRegisters::f10;
+#elif CPU(SH4)
+ static const RegisterID timeoutCheckRegister = SH4Registers::r8;
+ static const RegisterID callFrameRegister = SH4Registers::fp;
+
+ static const RegisterID regT0 = SH4Registers::r0;
+ static const RegisterID regT1 = SH4Registers::r1;
+ static const RegisterID regT2 = SH4Registers::r2;
+ static const RegisterID regT3 = SH4Registers::r10;
+ static const RegisterID regT4 = SH4Registers::r4;
+ static const RegisterID regT5 = SH4Registers::r5;
+ static const RegisterID regT6 = SH4Registers::r6;
+ static const RegisterID regT7 = SH4Registers::r7;
+ static const RegisterID firstArgumentRegister =regT4;
+
+ static const RegisterID returnValueRegister = SH4Registers::r0;
+ static const RegisterID cachedResultRegister = SH4Registers::r0;
+
+ static const FPRegisterID fpRegT0 = SH4Registers::fr0;
+ static const FPRegisterID fpRegT1 = SH4Registers::fr2;
+ static const FPRegisterID fpRegT2 = SH4Registers::fr4;
+ static const FPRegisterID fpRegT3 = SH4Registers::fr6;
+ static const FPRegisterID fpRegT4 = SH4Registers::fr8;
+ static const FPRegisterID fpRegT5 = SH4Registers::fr10;
+ static const FPRegisterID fpRegT6 = SH4Registers::fr12;
+ static const FPRegisterID fpRegT7 = SH4Registers::fr14;
#else
#error "JIT not supported on this platform."
#endif
+#if USE(JSVALUE32_64)
+ // Can't just propogate JSValue::Int32Tag as visual studio doesn't like it
+ static const unsigned Int32Tag = 0xffffffff;
+ COMPILE_ASSERT(Int32Tag == JSValue::Int32Tag, Int32Tag_out_of_sync);
+#else
+ static const unsigned Int32Tag = TagTypeNumber >> 32;
+#endif
inline Jump emitLoadJSCell(unsigned virtualRegisterIndex, RegisterID payload);
inline Jump emitLoadInt32(unsigned virtualRegisterIndex, RegisterID dst);
inline Jump emitLoadDouble(unsigned virtualRegisterIndex, FPRegisterID dst, RegisterID scratch);
+ inline void storePtrWithWriteBarrier(TrustedImmPtr ptr, RegisterID /* owner */, Address dest)
+ {
+ storePtr(ptr, dest);
+ }
+
#if USE(JSVALUE32_64)
inline Jump emitJumpIfNotJSCell(unsigned virtualRegisterIndex);
- inline Address tagFor(unsigned index, RegisterID base = callFrameRegister);
+ inline Address tagFor(int index, RegisterID base = callFrameRegister);
#endif
-#if USE(JSVALUE32) || USE(JSVALUE64)
+#if USE(JSVALUE64)
Jump emitJumpIfImmediateNumber(RegisterID reg);
Jump emitJumpIfNotImmediateNumber(RegisterID reg);
void emitFastArithImmToInt(RegisterID reg);
#endif
- inline Address payloadFor(unsigned index, RegisterID base = callFrameRegister);
- inline Address addressFor(unsigned index, RegisterID base = callFrameRegister);
+ inline Address payloadFor(int index, RegisterID base = callFrameRegister);
+ inline Address intPayloadFor(int index, RegisterID base = callFrameRegister);
+ inline Address intTagFor(int index, RegisterID base = callFrameRegister);
+ inline Address addressFor(int index, RegisterID base = callFrameRegister);
};
struct ThunkHelpers {
- static unsigned stringImplDataOffset() { return WebCore::StringImpl::dataOffset(); }
+ static unsigned stringImplDataOffset() { return StringImpl::dataOffset(); }
static unsigned jsStringLengthOffset() { return OBJECT_OFFSETOF(JSString, m_length); }
static unsigned jsStringValueOffset() { return OBJECT_OFFSETOF(JSString, m_value); }
};
inline JSInterfaceJIT::Jump JSInterfaceJIT::emitJumpIfNotJSCell(unsigned virtualRegisterIndex)
{
ASSERT(static_cast<int>(virtualRegisterIndex) < FirstConstantRegisterIndex);
- return branch32(NotEqual, tagFor(virtualRegisterIndex), Imm32(JSValue::CellTag));
+ return branch32(NotEqual, tagFor(virtualRegisterIndex), TrustedImm32(JSValue::CellTag));
}
inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadInt32(unsigned virtualRegisterIndex, RegisterID dst)
{
ASSERT(static_cast<int>(virtualRegisterIndex) < FirstConstantRegisterIndex);
loadPtr(payloadFor(virtualRegisterIndex), dst);
- return branch32(NotEqual, tagFor(virtualRegisterIndex), Imm32(JSValue::Int32Tag));
+ return branch32(NotEqual, tagFor(static_cast<int>(virtualRegisterIndex)), TrustedImm32(JSValue::Int32Tag));
}
- inline JSInterfaceJIT::Address JSInterfaceJIT::tagFor(unsigned virtualRegisterIndex, RegisterID base)
+ inline JSInterfaceJIT::Address JSInterfaceJIT::tagFor(int virtualRegisterIndex, RegisterID base)
{
- ASSERT(static_cast<int>(virtualRegisterIndex) < FirstConstantRegisterIndex);
- return Address(base, (virtualRegisterIndex * sizeof(Register)) + OBJECT_OFFSETOF(JSValue, u.asBits.tag));
+ ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex);
+ return Address(base, (static_cast<unsigned>(virtualRegisterIndex) * sizeof(Register)) + OBJECT_OFFSETOF(JSValue, u.asBits.tag));
}
- inline JSInterfaceJIT::Address JSInterfaceJIT::payloadFor(unsigned virtualRegisterIndex, RegisterID base)
+ inline JSInterfaceJIT::Address JSInterfaceJIT::payloadFor(int virtualRegisterIndex, RegisterID base)
{
- ASSERT(static_cast<int>(virtualRegisterIndex) < FirstConstantRegisterIndex);
- return Address(base, (virtualRegisterIndex * sizeof(Register)) + OBJECT_OFFSETOF(JSValue, u.asBits.payload));
+ ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex);
+ return Address(base, (static_cast<unsigned>(virtualRegisterIndex) * sizeof(Register)) + OBJECT_OFFSETOF(JSValue, u.asBits.payload));
+ }
+
+ inline JSInterfaceJIT::Address JSInterfaceJIT::intPayloadFor(int virtualRegisterIndex, RegisterID base)
+ {
+ return payloadFor(virtualRegisterIndex, base);
+ }
+
+ inline JSInterfaceJIT::Address JSInterfaceJIT::intTagFor(int virtualRegisterIndex, RegisterID base)
+ {
+ return tagFor(virtualRegisterIndex, base);
}
inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadDouble(unsigned virtualRegisterIndex, FPRegisterID dst, RegisterID scratch)
{
ASSERT(static_cast<int>(virtualRegisterIndex) < FirstConstantRegisterIndex);
loadPtr(tagFor(virtualRegisterIndex), scratch);
- Jump isDouble = branch32(Below, scratch, Imm32(JSValue::LowestTag));
- Jump notInt = branch32(NotEqual, scratch, Imm32(JSValue::Int32Tag));
+ Jump isDouble = branch32(Below, scratch, TrustedImm32(JSValue::LowestTag));
+ Jump notInt = branch32(NotEqual, scratch, TrustedImm32(JSValue::Int32Tag));
loadPtr(payloadFor(virtualRegisterIndex), scratch);
convertInt32ToDouble(scratch, dst);
Jump done = jump();
#endif
-#if USE(JSVALUE32)
- inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadJSCell(unsigned virtualRegisterIndex, RegisterID dst)
- {
- loadPtr(addressFor(virtualRegisterIndex), dst);
- return branchTest32(NonZero, dst, Imm32(JSImmediate::TagMask));
- }
-
- inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadInt32(unsigned virtualRegisterIndex, RegisterID dst)
+#if USE(JSVALUE64)
+ inline JSInterfaceJIT::Address JSInterfaceJIT::payloadFor(int virtualRegisterIndex, RegisterID base)
{
- loadPtr(addressFor(virtualRegisterIndex), dst);
- Jump result = branchTest32(Zero, dst, Imm32(JSImmediate::TagTypeNumber));
- rshift32(Imm32(JSImmediate::IntegerPayloadShift), dst);
- return result;
+ ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex);
+ return addressFor(virtualRegisterIndex, base);
}
- inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadDouble(unsigned, FPRegisterID, RegisterID)
+ inline JSInterfaceJIT::Address JSInterfaceJIT::intPayloadFor(int virtualRegisterIndex, RegisterID base)
{
- ASSERT_NOT_REACHED();
- return jump();
+ ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex);
+ return Address(base, (static_cast<unsigned>(virtualRegisterIndex) * sizeof(Register)) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
}
-
- ALWAYS_INLINE void JSInterfaceJIT::emitFastArithImmToInt(RegisterID reg)
+ inline JSInterfaceJIT::Address JSInterfaceJIT::intTagFor(int virtualRegisterIndex, RegisterID base)
{
- rshift32(Imm32(JSImmediate::IntegerPayloadShift), reg);
- }
-
-#endif
-
-#if !USE(JSVALUE32_64)
- inline JSInterfaceJIT::Address JSInterfaceJIT::payloadFor(unsigned virtualRegisterIndex, RegisterID base)
- {
- ASSERT(static_cast<int>(virtualRegisterIndex) < FirstConstantRegisterIndex);
- return addressFor(virtualRegisterIndex, base);
+ ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex);
+ return Address(base, (static_cast<unsigned>(virtualRegisterIndex) * sizeof(Register)) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
}
#endif
- inline JSInterfaceJIT::Address JSInterfaceJIT::addressFor(unsigned virtualRegisterIndex, RegisterID base)
+ inline JSInterfaceJIT::Address JSInterfaceJIT::addressFor(int virtualRegisterIndex, RegisterID base)
{
- ASSERT(static_cast<int>(virtualRegisterIndex) < FirstConstantRegisterIndex);
- return Address(base, (virtualRegisterIndex * sizeof(Register)));
+ ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex);
+ return Address(base, (static_cast<unsigned>(virtualRegisterIndex) * sizeof(Register)));
}
}
, m_pool(pool)
{
// Check that we have the expected number of arguments
- m_failures.append(branch32(NotEqual, Address(callFrameRegister, RegisterFile::ArgumentCount * (int)sizeof(Register)), Imm32(expectedArgCount + 1)));
+ m_failures.append(branch32(NotEqual, Address(callFrameRegister, RegisterFile::ArgumentCount * (int)sizeof(Register)), TrustedImm32(expectedArgCount + 1)));
}
void loadDoubleArgument(int argument, FPRegisterID dst, RegisterID scratch)
void loadJSStringArgument(int argument, RegisterID dst)
{
loadCellArgument(argument, dst);
- m_failures.append(branchPtr(NotEqual, Address(dst, 0), ImmPtr(m_globalData->jsStringVPtr)));
+ m_failures.append(branchPtr(NotEqual, Address(dst, 0), TrustedImmPtr(m_globalData->jsStringVPtr)));
m_failures.append(branchTest32(NonZero, Address(dst, OBJECT_OFFSETOF(JSString, m_fiberCount))));
}
{
if (src != regT0)
move(src, regT0);
- loadPtr(Address(callFrameRegister, RegisterFile::CallerFrame * (int)sizeof(Register)), callFrameRegister);
+ loadPtr(payloadFor(RegisterFile::CallerFrame, callFrameRegister), callFrameRegister);
ret();
}
#if USE(JSVALUE64)
moveDoubleToPtr(src, regT0);
subPtr(tagTypeNumberRegister, regT0);
-#elif USE(JSVALUE32_64)
+#else
storeDouble(src, Address(stackPointerRegister, -(int)sizeof(double)));
loadPtr(Address(stackPointerRegister, OBJECT_OFFSETOF(JSValue, u.asBits.tag) - sizeof(double)), regT1);
loadPtr(Address(stackPointerRegister, OBJECT_OFFSETOF(JSValue, u.asBits.payload) - sizeof(double)), regT0);
-#else
- UNUSED_PARAM(src);
- ASSERT_NOT_REACHED();
- m_failures.append(jump());
#endif
- loadPtr(Address(callFrameRegister, RegisterFile::CallerFrame * (int)sizeof(Register)), callFrameRegister);
+ loadPtr(payloadFor(RegisterFile::CallerFrame, callFrameRegister), callFrameRegister);
ret();
}
if (src != regT0)
move(src, regT0);
tagReturnAsInt32();
- loadPtr(Address(callFrameRegister, RegisterFile::CallerFrame * (int)sizeof(Register)), callFrameRegister);
+ loadPtr(payloadFor(RegisterFile::CallerFrame, callFrameRegister), callFrameRegister);
ret();
}
if (src != regT0)
move(src, regT0);
tagReturnAsJSCell();
- loadPtr(Address(callFrameRegister, RegisterFile::CallerFrame * (int)sizeof(Register)), callFrameRegister);
+ loadPtr(payloadFor(RegisterFile::CallerFrame, callFrameRegister), callFrameRegister);
ret();
}
- PassRefPtr<NativeExecutable> finalize()
+ MacroAssemblerCodePtr finalize(JSGlobalData& globalData, MacroAssemblerCodePtr fallback)
{
- LinkBuffer patchBuffer(this, m_pool.get(), 0);
- patchBuffer.link(m_failures, CodeLocationLabel(m_globalData->jitStubs->ctiNativeCallThunk()->generatedJITCode().addressForCall()));
- return adoptRef(new NativeExecutable(patchBuffer.finalizeCode()));
+ LinkBuffer patchBuffer(globalData, this, m_pool.get());
+ patchBuffer.link(m_failures, CodeLocationLabel(fallback));
+ return patchBuffer.finalizeCode().m_code;
}
private:
{
#if USE(JSVALUE64)
orPtr(tagTypeNumberRegister, regT0);
-#elif USE(JSVALUE32_64)
- move(Imm32(JSValue::Int32Tag), regT1);
#else
- signExtend32ToPtr(regT0, regT0);
- // If we can't tag the result, give up and jump to the slow case
- m_failures.append(branchAddPtr(Overflow, regT0, regT0));
- addPtr(Imm32(JSImmediate::TagTypeNumber), regT0);
+ move(TrustedImm32(JSValue::Int32Tag), regT1);
#endif
}
void tagReturnAsJSCell()
{
#if USE(JSVALUE32_64)
- move(Imm32(JSValue::CellTag), regT1);
+ move(TrustedImm32(JSValue::CellTag), regT1);
#endif
}
static void charToString(SpecializedThunkJIT& jit, JSGlobalData* globalData, MacroAssembler::RegisterID src, MacroAssembler::RegisterID dst, MacroAssembler::RegisterID scratch)
{
- jit.appendFailure(jit.branch32(MacroAssembler::AboveOrEqual, src, MacroAssembler::Imm32(0x100)));
- jit.move(MacroAssembler::ImmPtr(globalData->smallStrings.singleCharacterStrings()), scratch);
+ jit.appendFailure(jit.branch32(MacroAssembler::AboveOrEqual, src, MacroAssembler::TrustedImm32(0x100)));
+ jit.move(MacroAssembler::TrustedImmPtr(globalData->smallStrings.singleCharacterStrings()), scratch);
jit.loadPtr(MacroAssembler::BaseIndex(scratch, src, MacroAssembler::ScalePtr, 0), dst);
jit.appendFailure(jit.branchTestPtr(MacroAssembler::Zero, dst));
}
-PassRefPtr<NativeExecutable> charCodeAtThunkGenerator(JSGlobalData* globalData, ExecutablePool* pool)
+MacroAssemblerCodePtr charCodeAtThunkGenerator(JSGlobalData* globalData, ExecutablePool* pool)
{
SpecializedThunkJIT jit(1, globalData, pool);
stringCharLoad(jit);
jit.returnInt32(SpecializedThunkJIT::regT0);
- return jit.finalize();
+ return jit.finalize(*globalData, globalData->jitStubs->ctiNativeCall());
}
-PassRefPtr<NativeExecutable> charAtThunkGenerator(JSGlobalData* globalData, ExecutablePool* pool)
+MacroAssemblerCodePtr charAtThunkGenerator(JSGlobalData* globalData, ExecutablePool* pool)
{
SpecializedThunkJIT jit(1, globalData, pool);
stringCharLoad(jit);
charToString(jit, globalData, SpecializedThunkJIT::regT0, SpecializedThunkJIT::regT0, SpecializedThunkJIT::regT1);
jit.returnJSCell(SpecializedThunkJIT::regT0);
- return jit.finalize();
+ return jit.finalize(*globalData, globalData->jitStubs->ctiNativeCall());
}
-PassRefPtr<NativeExecutable> fromCharCodeThunkGenerator(JSGlobalData* globalData, ExecutablePool* pool)
+MacroAssemblerCodePtr fromCharCodeThunkGenerator(JSGlobalData* globalData, ExecutablePool* pool)
{
SpecializedThunkJIT jit(1, globalData, pool);
// load char code
jit.loadInt32Argument(0, SpecializedThunkJIT::regT0);
charToString(jit, globalData, SpecializedThunkJIT::regT0, SpecializedThunkJIT::regT0, SpecializedThunkJIT::regT1);
jit.returnJSCell(SpecializedThunkJIT::regT0);
- return jit.finalize();
+ return jit.finalize(*globalData, globalData->jitStubs->ctiNativeCall());
}
-PassRefPtr<NativeExecutable> sqrtThunkGenerator(JSGlobalData* globalData, ExecutablePool* pool)
+MacroAssemblerCodePtr sqrtThunkGenerator(JSGlobalData* globalData, ExecutablePool* pool)
{
-#if USE(JSVALUE64) || USE(JSVALUE32_64)
SpecializedThunkJIT jit(1, globalData, pool);
if (!jit.supportsFloatingPointSqrt())
- return globalData->jitStubs->ctiNativeCallThunk();
+ return globalData->jitStubs->ctiNativeCall();
jit.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0);
jit.sqrtDouble(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT0);
jit.returnDouble(SpecializedThunkJIT::fpRegT0);
- return jit.finalize();
-#else
- UNUSED_PARAM(pool);
- return globalData->jitStubs.ctiNativeCallThunk();
-#endif
+ return jit.finalize(*globalData, globalData->jitStubs->ctiNativeCall());
}
static const double oneConstant = 1.0;
static const double negativeHalfConstant = -0.5;
-PassRefPtr<NativeExecutable> powThunkGenerator(JSGlobalData* globalData, ExecutablePool* pool)
+MacroAssemblerCodePtr powThunkGenerator(JSGlobalData* globalData, ExecutablePool* pool)
{
-#if USE(JSVALUE64) || USE(JSVALUE32_64)
SpecializedThunkJIT jit(2, globalData, pool);
if (!jit.supportsFloatingPoint())
- return globalData->jitStubs->ctiNativeCallThunk();
+ return globalData->jitStubs->ctiNativeCall();
jit.loadDouble(&oneConstant, SpecializedThunkJIT::fpRegT1);
jit.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0);
MacroAssembler::Jump nonIntExponent;
jit.loadInt32Argument(1, SpecializedThunkJIT::regT0, nonIntExponent);
- jit.appendFailure(jit.branch32(MacroAssembler::LessThan, SpecializedThunkJIT::regT0, MacroAssembler::Imm32(0)));
+ jit.appendFailure(jit.branch32(MacroAssembler::LessThan, SpecializedThunkJIT::regT0, MacroAssembler::TrustedImm32(0)));
MacroAssembler::Jump exponentIsZero = jit.branchTest32(MacroAssembler::Zero, SpecializedThunkJIT::regT0);
MacroAssembler::Label startLoop(jit.label());
- MacroAssembler::Jump exponentIsEven = jit.branchTest32(MacroAssembler::Zero, SpecializedThunkJIT::regT0, MacroAssembler::Imm32(1));
+ MacroAssembler::Jump exponentIsEven = jit.branchTest32(MacroAssembler::Zero, SpecializedThunkJIT::regT0, MacroAssembler::TrustedImm32(1));
jit.mulDouble(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT1);
exponentIsEven.link(&jit);
jit.mulDouble(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT0);
- jit.rshift32(MacroAssembler::Imm32(1), SpecializedThunkJIT::regT0);
+ jit.rshift32(MacroAssembler::TrustedImm32(1), SpecializedThunkJIT::regT0);
jit.branchTest32(MacroAssembler::NonZero, SpecializedThunkJIT::regT0).linkTo(startLoop, &jit);
exponentIsZero.link(&jit);
- jit.returnDouble(SpecializedThunkJIT::fpRegT1);
+
+ {
+ SpecializedThunkJIT::JumpList doubleResult;
+ jit.branchConvertDoubleToInt32(SpecializedThunkJIT::fpRegT1, SpecializedThunkJIT::regT0, doubleResult, SpecializedThunkJIT::fpRegT0);
+ jit.returnInt32(SpecializedThunkJIT::regT0);
+ doubleResult.link(&jit);
+ jit.returnDouble(SpecializedThunkJIT::fpRegT1);
+ }
if (jit.supportsFloatingPointSqrt()) {
nonIntExponent.link(&jit);
jit.appendFailure(jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, SpecializedThunkJIT::fpRegT2, SpecializedThunkJIT::fpRegT3));
jit.sqrtDouble(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT0);
jit.divDouble(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT1);
+
+ SpecializedThunkJIT::JumpList doubleResult;
+ jit.branchConvertDoubleToInt32(SpecializedThunkJIT::fpRegT1, SpecializedThunkJIT::regT0, doubleResult, SpecializedThunkJIT::fpRegT0);
+ jit.returnInt32(SpecializedThunkJIT::regT0);
+ doubleResult.link(&jit);
jit.returnDouble(SpecializedThunkJIT::fpRegT1);
} else
jit.appendFailure(nonIntExponent);
- return jit.finalize();
-#else
- UNUSED_PARAM(pool);
- return globalData->jitStubs.ctiNativeCallThunk();
-#endif
+ return jit.finalize(*globalData, globalData->jitStubs->ctiNativeCall());
}
}
#define ThunkGenerators_h
#if ENABLE(JIT)
-#include <wtf/PassRefPtr.h>
-
namespace JSC {
class ExecutablePool;
class JSGlobalData;
class NativeExecutable;
+ class MacroAssemblerCodePtr;
- typedef PassRefPtr<NativeExecutable> (*ThunkGenerator)(JSGlobalData*, ExecutablePool*);
- PassRefPtr<NativeExecutable> charCodeAtThunkGenerator(JSGlobalData*, ExecutablePool*);
- PassRefPtr<NativeExecutable> charAtThunkGenerator(JSGlobalData*, ExecutablePool*);
- PassRefPtr<NativeExecutable> fromCharCodeThunkGenerator(JSGlobalData*, ExecutablePool*);
- PassRefPtr<NativeExecutable> sqrtThunkGenerator(JSGlobalData*, ExecutablePool*);
- PassRefPtr<NativeExecutable> powThunkGenerator(JSGlobalData*, ExecutablePool*);
+ typedef MacroAssemblerCodePtr (*ThunkGenerator)(JSGlobalData*, ExecutablePool*);
+ MacroAssemblerCodePtr charCodeAtThunkGenerator(JSGlobalData*, ExecutablePool*);
+ MacroAssemblerCodePtr charAtThunkGenerator(JSGlobalData*, ExecutablePool*);
+ MacroAssemblerCodePtr fromCharCodeThunkGenerator(JSGlobalData*, ExecutablePool*);
+ MacroAssemblerCodePtr sqrtThunkGenerator(JSGlobalData*, ExecutablePool*);
+ MacroAssemblerCodePtr powThunkGenerator(JSGlobalData*, ExecutablePool*);
}
#endif
#include "BytecodeGenerator.h"
#include "Completion.h"
#include "CurrentTime.h"
+#include "ExceptionHelpers.h"
#include "InitializeThreading.h"
#include "JSArray.h"
#include "JSFunction.h"
#include "JSLock.h"
#include "JSString.h"
-#include "PrototypeFunction.h"
#include "SamplingTool.h"
#include <math.h>
#include <stdio.h>
static void cleanupGlobalData(JSGlobalData*);
static bool fillBufferWithContentsOfFile(const UString& fileName, Vector<char>& buffer);
-static JSValue JSC_HOST_CALL functionPrint(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL functionDebug(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL functionGC(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL functionVersion(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL functionRun(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL functionLoad(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL functionCheckSyntax(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL functionReadline(ExecState*, JSObject*, JSValue, const ArgList&);
-static NO_RETURN_WITH_VALUE JSValue JSC_HOST_CALL functionQuit(ExecState*, JSObject*, JSValue, const ArgList&);
+static EncodedJSValue JSC_HOST_CALL functionPrint(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionDebug(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionGC(ExecState*);
+#ifndef NDEBUG
+static EncodedJSValue JSC_HOST_CALL functionReleaseExecutableMemory(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 functionCheckSyntax(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionReadline(ExecState*);
+static NO_RETURN_WITH_VALUE EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*);
#if ENABLE(SAMPLING_FLAGS)
-static JSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState*, JSObject*, JSValue, const ArgList&);
+static EncodedJSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState*);
#endif
struct Script {
class GlobalObject : public JSGlobalObject {
public:
- GlobalObject(const Vector<UString>& arguments);
+ GlobalObject(JSGlobalData&, Structure*, const Vector<UString>& arguments);
virtual UString className() const { return "global"; }
};
COMPILE_ASSERT(!IsInteger<GlobalObject>::value, WTF_IsInteger_GlobalObject_false);
ASSERT_CLASS_FITS_IN_CELL(GlobalObject);
-GlobalObject::GlobalObject(const Vector<UString>& arguments)
- : JSGlobalObject()
+GlobalObject::GlobalObject(JSGlobalData& globalData, Structure* structure, const Vector<UString>& arguments)
+ : JSGlobalObject(globalData, structure)
{
- putDirectFunction(globalExec(), new (globalExec()) NativeFunctionWrapper(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "debug"), functionDebug));
- putDirectFunction(globalExec(), new (globalExec()) NativeFunctionWrapper(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "print"), functionPrint));
- putDirectFunction(globalExec(), new (globalExec()) NativeFunctionWrapper(globalExec(), prototypeFunctionStructure(), 0, Identifier(globalExec(), "quit"), functionQuit));
- putDirectFunction(globalExec(), new (globalExec()) NativeFunctionWrapper(globalExec(), prototypeFunctionStructure(), 0, Identifier(globalExec(), "gc"), functionGC));
- putDirectFunction(globalExec(), new (globalExec()) NativeFunctionWrapper(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "version"), functionVersion));
- putDirectFunction(globalExec(), new (globalExec()) NativeFunctionWrapper(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "run"), functionRun));
- putDirectFunction(globalExec(), new (globalExec()) NativeFunctionWrapper(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "load"), functionLoad));
- putDirectFunction(globalExec(), new (globalExec()) NativeFunctionWrapper(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "checkSyntax"), functionCheckSyntax));
- putDirectFunction(globalExec(), new (globalExec()) NativeFunctionWrapper(globalExec(), prototypeFunctionStructure(), 0, Identifier(globalExec(), "readline"), functionReadline));
+ putDirectFunction(globalExec(), new (globalExec()) JSFunction(globalExec(), this, functionStructure(), 1, Identifier(globalExec(), "debug"), functionDebug));
+ putDirectFunction(globalExec(), new (globalExec()) JSFunction(globalExec(), this, functionStructure(), 1, Identifier(globalExec(), "print"), functionPrint));
+ putDirectFunction(globalExec(), new (globalExec()) JSFunction(globalExec(), this, functionStructure(), 0, Identifier(globalExec(), "quit"), functionQuit));
+ putDirectFunction(globalExec(), new (globalExec()) JSFunction(globalExec(), this, functionStructure(), 0, Identifier(globalExec(), "gc"), functionGC));
+#ifndef NDEBUG
+ putDirectFunction(globalExec(), new (globalExec()) JSFunction(globalExec(), this, functionStructure(), 0, Identifier(globalExec(), "releaseExecutableMemory"), functionReleaseExecutableMemory));
+#endif
+ putDirectFunction(globalExec(), new (globalExec()) JSFunction(globalExec(), this, functionStructure(), 1, Identifier(globalExec(), "version"), functionVersion));
+ putDirectFunction(globalExec(), new (globalExec()) JSFunction(globalExec(), this, functionStructure(), 1, Identifier(globalExec(), "run"), functionRun));
+ putDirectFunction(globalExec(), new (globalExec()) JSFunction(globalExec(), this, functionStructure(), 1, Identifier(globalExec(), "load"), functionLoad));
+ putDirectFunction(globalExec(), new (globalExec()) JSFunction(globalExec(), this, functionStructure(), 1, Identifier(globalExec(), "checkSyntax"), functionCheckSyntax));
+ putDirectFunction(globalExec(), new (globalExec()) JSFunction(globalExec(), this, functionStructure(), 0, Identifier(globalExec(), "readline"), functionReadline));
#if ENABLE(SAMPLING_FLAGS)
- putDirectFunction(globalExec(), new (globalExec()) NativeFunctionWrapper(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "setSamplingFlags"), functionSetSamplingFlags));
- putDirectFunction(globalExec(), new (globalExec()) NativeFunctionWrapper(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "clearSamplingFlags"), functionClearSamplingFlags));
+ putDirectFunction(globalExec(), new (globalExec()) JSFunction(globalExec(), this, functionStructure(), 1, Identifier(globalExec(), "setSamplingFlags"), functionSetSamplingFlags));
+ putDirectFunction(globalExec(), new (globalExec()) JSFunction(globalExec(), this, functionStructure(), 1, Identifier(globalExec(), "clearSamplingFlags"), functionClearSamplingFlags));
#endif
JSObject* array = constructEmptyArray(globalExec());
for (size_t i = 0; i < arguments.size(); ++i)
array->put(globalExec(), i, jsString(globalExec(), arguments[i]));
- putDirect(Identifier(globalExec(), "arguments"), array);
+ putDirect(globalExec()->globalData(), Identifier(globalExec(), "arguments"), array);
}
-JSValue JSC_HOST_CALL functionPrint(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL functionPrint(ExecState* exec)
{
- for (unsigned i = 0; i < args.size(); ++i) {
+ for (unsigned i = 0; i < exec->argumentCount(); ++i) {
if (i)
putchar(' ');
- printf("%s", args.at(i).toString(exec).UTF8String().data());
+ printf("%s", exec->argument(i).toString(exec).utf8().data());
}
putchar('\n');
fflush(stdout);
- return jsUndefined();
+ return JSValue::encode(jsUndefined());
}
-JSValue JSC_HOST_CALL functionDebug(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL functionDebug(ExecState* exec)
{
- fprintf(stderr, "--> %s\n", args.at(0).toString(exec).UTF8String().data());
- return jsUndefined();
+ fprintf(stderr, "--> %s\n", exec->argument(0).toString(exec).utf8().data());
+ return JSValue::encode(jsUndefined());
}
-JSValue JSC_HOST_CALL functionGC(ExecState* exec, JSObject*, JSValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL functionGC(ExecState* exec)
{
JSLock lock(SilenceAssertionsOnly);
exec->heap()->collectAllGarbage();
- return jsUndefined();
+ return JSValue::encode(jsUndefined());
+}
+
+#ifndef NDEBUG
+EncodedJSValue JSC_HOST_CALL functionReleaseExecutableMemory(ExecState* exec)
+{
+ JSLock lock(SilenceAssertionsOnly);
+ exec->globalData().releaseExecutableMemory();
+ return JSValue::encode(jsUndefined());
}
+#endif
-JSValue JSC_HOST_CALL functionVersion(ExecState*, JSObject*, JSValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*)
{
// We need this function for compatibility with the Mozilla JS tests but for now
// we don't actually do any version-specific handling
- return jsUndefined();
+ return JSValue::encode(jsUndefined());
}
-JSValue JSC_HOST_CALL functionRun(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL functionRun(ExecState* exec)
{
- StopWatch stopWatch;
- UString fileName = args.at(0).toString(exec);
+ UString fileName = exec->argument(0).toString(exec);
Vector<char> script;
if (!fillBufferWithContentsOfFile(fileName, script))
- return throwError(exec, GeneralError, "Could not open file.");
+ return JSValue::encode(throwError(exec, createError(exec, "Could not open file.")));
- JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+ GlobalObject* globalObject = new (&exec->globalData()) GlobalObject(exec->globalData(), GlobalObject::createStructure(exec->globalData(), jsNull()), Vector<UString>());
+ StopWatch stopWatch;
stopWatch.start();
evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), makeSource(script.data(), fileName));
stopWatch.stop();
- return jsNumber(globalObject->globalExec(), stopWatch.getElapsedMS());
+ return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
}
-JSValue JSC_HOST_CALL functionLoad(ExecState* exec, JSObject* o, JSValue v, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL functionLoad(ExecState* exec)
{
- UNUSED_PARAM(o);
- UNUSED_PARAM(v);
- UString fileName = args.at(0).toString(exec);
+ UString fileName = exec->argument(0).toString(exec);
Vector<char> script;
if (!fillBufferWithContentsOfFile(fileName, script))
- return throwError(exec, GeneralError, "Could not open file.");
+ return JSValue::encode(throwError(exec, createError(exec, "Could not open file.")));
JSGlobalObject* globalObject = exec->lexicalGlobalObject();
Completion result = evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), makeSource(script.data(), fileName));
if (result.complType() == Throw)
- exec->setException(result.value());
- return result.value();
+ throwError(exec, result.value());
+ return JSValue::encode(result.value());
}
-JSValue JSC_HOST_CALL functionCheckSyntax(ExecState* exec, JSObject* o, JSValue v, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState* exec)
{
- UNUSED_PARAM(o);
- UNUSED_PARAM(v);
- UString fileName = args.at(0).toString(exec);
+ UString fileName = exec->argument(0).toString(exec);
Vector<char> script;
if (!fillBufferWithContentsOfFile(fileName, script))
- return throwError(exec, GeneralError, "Could not open file.");
+ return JSValue::encode(throwError(exec, createError(exec, "Could not open file.")));
JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+
+ StopWatch stopWatch;
+ stopWatch.start();
Completion result = checkSyntax(globalObject->globalExec(), makeSource(script.data(), fileName));
+ stopWatch.stop();
+
if (result.complType() == Throw)
- exec->setException(result.value());
- return result.value();
+ throwError(exec, result.value());
+ return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
}
#if ENABLE(SAMPLING_FLAGS)
-JSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState* exec)
{
- for (unsigned i = 0; i < args.size(); ++i) {
- unsigned flag = static_cast<unsigned>(args.at(i).toNumber(exec));
+ for (unsigned i = 0; i < exec->argumentCount(); ++i) {
+ unsigned flag = static_cast<unsigned>(exec->argument(i).toNumber(exec));
if ((flag >= 1) && (flag <= 32))
SamplingFlags::setFlag(flag);
}
- return jsNull();
+ return JSValue::encode(jsNull());
}
-JSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState* exec)
{
- for (unsigned i = 0; i < args.size(); ++i) {
- unsigned flag = static_cast<unsigned>(args.at(i).toNumber(exec));
+ for (unsigned i = 0; i < exec->argumentCount(); ++i) {
+ unsigned flag = static_cast<unsigned>(exec->argument(i).toNumber(exec));
if ((flag >= 1) && (flag <= 32))
SamplingFlags::clearFlag(flag);
}
- return jsNull();
+ return JSValue::encode(jsNull());
}
#endif
-JSValue JSC_HOST_CALL functionReadline(ExecState* exec, JSObject*, JSValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL functionReadline(ExecState* exec)
{
Vector<char, 256> line;
int c;
line.append(c);
}
line.append('\0');
- return jsString(exec, line.data());
+ return JSValue::encode(jsString(exec, line.data()));
}
-JSValue JSC_HOST_CALL functionQuit(ExecState* exec, JSObject*, JSValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL functionQuit(ExecState* exec)
{
// Technically, destroying the heap in the middle of JS execution is a no-no,
// but we want to maintain compatibility with the Mozilla test suite, so
#if COMPILER(MSVC) && OS(WINCE)
// Without this, Visual Studio will complain that this method does not return a value.
- return jsUndefined();
+ return JSValue::encode(jsUndefined());
#endif
}
// be in a separate main function because the jscmain function requires object
// unwinding.
-#if COMPILER(MSVC) && !defined(_DEBUG)
+#if COMPILER(MSVC) && !defined(_DEBUG) && !OS(WINCE)
#define TRY __try {
#define EXCEPT(x) } __except (EXCEPTION_EXECUTE_HANDLER) { x; }
#else
int main(int argc, char** argv)
{
-#if defined(_DEBUG) && OS(WINDOWS)
+#if OS(WINDOWS)
+#if !OS(WINCE)
+ // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for
+ // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the
+ // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>.
+ ::SetErrorMode(0);
+#endif
+
+#if defined(_DEBUG)
_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
#endif
-#if COMPILER(MSVC) && !OS(WINCE)
timeBeginPeriod(1);
#endif
// We can't use destructors in the following code because it uses Windows
// Structured Exception Handling
int res = 0;
- JSGlobalData* globalData = JSGlobalData::create(ThreadStackTypeLarge).releaseRef();
+ JSGlobalData* globalData = JSGlobalData::create(ThreadStackTypeLarge).leakRef();
TRY
res = jscmain(argc, argv, globalData);
EXCEPT(res = 3)
static void cleanupGlobalData(JSGlobalData* globalData)
{
JSLock lock(SilenceAssertionsOnly);
+ globalData->clearBuiltinStructures();
globalData->heap.destroy();
globalData->deref();
}
if (dump)
BytecodeGenerator::setDumpsGeneratedCode(true);
- JSGlobalData* globalData = globalObject->globalData();
+ JSGlobalData& globalData = globalObject->globalData();
#if ENABLE(SAMPLING_FLAGS)
SamplingFlags::start();
fileName = "[Command Line]";
}
- globalData->startSampling();
+ globalData.startSampling();
Completion completion = evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), makeSource(script, fileName));
success = success && completion.complType() != Throw;
if (dump) {
if (completion.complType() == Throw)
- printf("Exception: %s\n", completion.value().toString(globalObject->globalExec()).ascii());
+ printf("Exception: %s\n", completion.value().toString(globalObject->globalExec()).utf8().data());
else
- printf("End: %s\n", completion.value().toString(globalObject->globalExec()).ascii());
+ printf("End: %s\n", completion.value().toString(globalObject->globalExec()).utf8().data());
}
- globalData->stopSampling();
+ globalData.stopSampling();
globalObject->globalExec()->clearException();
}
#if ENABLE(SAMPLING_FLAGS)
SamplingFlags::stop();
#endif
- globalData->dumpSampleData(globalObject->globalExec());
+ globalData.dumpSampleData(globalObject->globalExec());
#if ENABLE(SAMPLING_COUNTERS)
AbstractSamplingCounter::dump();
+#endif
+#if ENABLE(REGEXP_TRACING)
+ globalData.dumpRegExpTrace();
#endif
return success;
}
Completion completion = evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), makeSource(line.data(), interpreterName));
#endif
if (completion.complType() == Throw)
- printf("Exception: %s\n", completion.value().toString(globalObject->globalExec()).ascii());
+ printf("Exception: %s\n", completion.value().toString(globalObject->globalExec()).utf8().data());
else
- printf("%s\n", completion.value().toString(globalObject->globalExec()).UTF8String().data());
+ printf("%s\n", completion.value().toString(globalObject->globalExec()).utf8().data());
globalObject->globalExec()->clearException();
}
Options options;
parseArguments(argc, argv, options, globalData);
- GlobalObject* globalObject = new (globalData) GlobalObject(options.arguments);
+ GlobalObject* globalObject = new (globalData) GlobalObject(*globalData, GlobalObject::createStructure(*globalData, jsNull()), options.arguments);
bool success = runWithScripts(globalObject, options.scripts, options.dump);
if (options.interactive && success)
runInteractive(globalObject);
static bool fillBufferWithContentsOfFile(const UString& fileName, Vector<char>& buffer)
{
- FILE* f = fopen(fileName.UTF8String().data(), "r");
+ FILE* f = fopen(fileName.utf8().data(), "r");
if (!f) {
- fprintf(stderr, "Could not open file: %s\n", fileName.UTF8String().data());
+ fprintf(stderr, "Could not open file: %s\n", fileName.utf8().data());
return false;
}
fclose(f);
buffer[bufferSize] = '\0';
+ if (buffer[0] == '#' && buffer[1] == '!')
+ buffer[0] = buffer[1] = '/';
+
return true;
}
isEmpty(OUTPUT_DIR): OUTPUT_DIR= ..
include($$PWD/../WebKit.pri)
-CONFIG += link_pkgconfig
+unix:!mac:!symbian:CONFIG += link_pkgconfig
QMAKE_RPATHDIR += $$OUTPUT_DIR/lib
-CONFIG(debug, debug|release) {
- OBJECTS_DIR = obj/debug
-} else { # Release
- OBJECTS_DIR = obj/release
-}
OBJECTS_DIR_WTR = $$OBJECTS_DIR$${QMAKE_DIR_SEP}
include($$PWD/JavaScriptCore.pri)
-addJavaScriptCoreLib(.)
+prependJavaScriptCoreLib(.)
symbian {
TARGET.CAPABILITY = ReadUserData WriteUserData NetworkServices
mac {
LIBS_PRIVATE += -framework AppKit
-}
\ No newline at end of file
+}
+
+win* {
+ LIBS += -ladvapi32
+}
+
+wince* {
+ LIBS += mmtimer.lib
+}
+
+# Prevent warnings about difference in visibility on Mac OS X
+contains(QT_CONFIG, reduce_exports):CONFIG += hide_symbols
+unix:contains(QT_CONFIG, reduce_relocations):CONFIG += bsymbolic_functions
export WebCore=$PWD
export CREATE_HASH_TABLE="$SRCROOT/create_hash_table"
export CREATE_REGEXP_TABLES="$SRCROOT/create_regex_tables"
+export CREATE_KEYWORD_LOOKUP="$SRCROOT/KeywordLookupGenerator.py"
mkdir -p DerivedSources/JavaScriptCore
cd DerivedSources/JavaScriptCore
--- /dev/null
+// ISO C9x compliant inttypes.h for Microsoft Visual Studio
+// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
+//
+// Copyright (c) 2006 Alexander Chemeris
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// 3. The name of the author may be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef INTTYPES_WIN32_H
+#define INTTYPES_WIN32_H
+
+#include <wtf/Platform.h>
+
+#if !COMPILER(MSVC)
+#error "This inttypes.h file should only be compiled with MSVC"
+#endif
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+#include "stdint.h"
+
+// 7.8.1 Macros for format specifiers
+
+#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS)
+
+// The fprintf macros for signed integers are:
+#define PRId8 "d"
+#define PRIi8 "i"
+#define PRIdLEAST8 "d"
+#define PRIiLEAST8 "i"
+#define PRIdFAST8 "d"
+#define PRIiFAST8 "i"
+
+#define PRId16 "hd"
+#define PRIi16 "hi"
+#define PRIdLEAST16 "hd"
+#define PRIiLEAST16 "hi"
+#define PRIdFAST16 "hd"
+#define PRIiFAST16 "hi"
+
+#define PRId32 "I32d"
+#define PRIi32 "I32i"
+#define PRIdLEAST32 "I32d"
+#define PRIiLEAST32 "I32i"
+#define PRIdFAST32 "I32d"
+#define PRIiFAST32 "I32i"
+
+#define PRId64 "I64d"
+#define PRIi64 "I64i"
+#define PRIdLEAST64 "I64d"
+#define PRIiLEAST64 "I64i"
+#define PRIdFAST64 "I64d"
+#define PRIiFAST64 "I64i"
+
+#define PRIdMAX "I64d"
+#define PRIiMAX "I64i"
+
+#define PRIdPTR "Id"
+#define PRIiPTR "Ii"
+
+// The fprintf macros for unsigned integers are:
+#define PRIo8 "o"
+#define PRIu8 "u"
+#define PRIx8 "x"
+#define PRIX8 "X"
+#define PRIoLEAST8 "o"
+#define PRIuLEAST8 "u"
+#define PRIxLEAST8 "x"
+#define PRIXLEAST8 "X"
+#define PRIoFAST8 "o"
+#define PRIuFAST8 "u"
+#define PRIxFAST8 "x"
+#define PRIXFAST8 "X"
+
+#define PRIo16 "ho"
+#define PRIu16 "hu"
+#define PRIx16 "hx"
+#define PRIX16 "hX"
+#define PRIoLEAST16 "ho"
+#define PRIuLEAST16 "hu"
+#define PRIxLEAST16 "hx"
+#define PRIXLEAST16 "hX"
+#define PRIoFAST16 "ho"
+#define PRIuFAST16 "hu"
+#define PRIxFAST16 "hx"
+#define PRIXFAST16 "hX"
+
+#define PRIo32 "I32o"
+#define PRIu32 "I32u"
+#define PRIx32 "I32x"
+#define PRIX32 "I32X"
+#define PRIoLEAST32 "I32o"
+#define PRIuLEAST32 "I32u"
+#define PRIxLEAST32 "I32x"
+#define PRIXLEAST32 "I32X"
+#define PRIoFAST32 "I32o"
+#define PRIuFAST32 "I32u"
+#define PRIxFAST32 "I32x"
+#define PRIXFAST32 "I32X"
+
+#define PRIo64 "I64o"
+#define PRIu64 "I64u"
+#define PRIx64 "I64x"
+#define PRIX64 "I64X"
+#define PRIoLEAST64 "I64o"
+#define PRIuLEAST64 "I64u"
+#define PRIxLEAST64 "I64x"
+#define PRIXLEAST64 "I64X"
+#define PRIoFAST64 "I64o"
+#define PRIuFAST64 "I64u"
+#define PRIxFAST64 "I64x"
+#define PRIXFAST64 "I64X"
+
+#define PRIoMAX "I64o"
+#define PRIuMAX "I64u"
+#define PRIxMAX "I64x"
+#define PRIXMAX "I64X"
+
+#define PRIoPTR "Io"
+#define PRIuPTR "Iu"
+#define PRIxPTR "Ix"
+#define PRIXPTR "IX"
+
+// The fscanf macros for signed integers are:
+#define SCNd8 "d"
+#define SCNi8 "i"
+#define SCNdLEAST8 "d"
+#define SCNiLEAST8 "i"
+#define SCNdFAST8 "d"
+#define SCNiFAST8 "i"
+
+#define SCNd16 "hd"
+#define SCNi16 "hi"
+#define SCNdLEAST16 "hd"
+#define SCNiLEAST16 "hi"
+#define SCNdFAST16 "hd"
+#define SCNiFAST16 "hi"
+
+#define SCNd32 "ld"
+#define SCNi32 "li"
+#define SCNdLEAST32 "ld"
+#define SCNiLEAST32 "li"
+#define SCNdFAST32 "ld"
+#define SCNiFAST32 "li"
+
+#define SCNd64 "I64d"
+#define SCNi64 "I64i"
+#define SCNdLEAST64 "I64d"
+#define SCNiLEAST64 "I64i"
+#define SCNdFAST64 "I64d"
+#define SCNiFAST64 "I64i"
+
+#define SCNdMAX "I64d"
+#define SCNiMAX "I64i"
+
+#ifdef _WIN64
+# define SCNdPTR "I64d"
+# define SCNiPTR "I64i"
+#else
+# define SCNdPTR "ld"
+# define SCNiPTR "li"
+#endif
+
+// The fscanf macros for unsigned integers are:
+#define SCNo8 "o"
+#define SCNu8 "u"
+#define SCNx8 "x"
+#define SCNX8 "X"
+#define SCNoLEAST8 "o"
+#define SCNuLEAST8 "u"
+#define SCNxLEAST8 "x"
+#define SCNXLEAST8 "X"
+#define SCNoFAST8 "o"
+#define SCNuFAST8 "u"
+#define SCNxFAST8 "x"
+#define SCNXFAST8 "X"
+
+#define SCNo16 "ho"
+#define SCNu16 "hu"
+#define SCNx16 "hx"
+#define SCNX16 "hX"
+#define SCNoLEAST16 "ho"
+#define SCNuLEAST16 "hu"
+#define SCNxLEAST16 "hx"
+#define SCNXLEAST16 "hX"
+#define SCNoFAST16 "ho"
+#define SCNuFAST16 "hu"
+#define SCNxFAST16 "hx"
+#define SCNXFAST16 "hX"
+
+#define SCNo32 "lo"
+#define SCNu32 "lu"
+#define SCNx32 "lx"
+#define SCNX32 "lX"
+#define SCNoLEAST32 "lo"
+#define SCNuLEAST32 "lu"
+#define SCNxLEAST32 "lx"
+#define SCNXLEAST32 "lX"
+#define SCNoFAST32 "lo"
+#define SCNuFAST32 "lu"
+#define SCNxFAST32 "lx"
+#define SCNXFAST32 "lX"
+
+#define SCNo64 "I64o"
+#define SCNu64 "I64u"
+#define SCNx64 "I64x"
+#define SCNX64 "I64X"
+#define SCNoLEAST64 "I64o"
+#define SCNuLEAST64 "I64u"
+#define SCNxLEAST64 "I64x"
+#define SCNXLEAST64 "I64X"
+#define SCNoFAST64 "I64o"
+#define SCNuFAST64 "I64u"
+#define SCNxFAST64 "I64x"
+#define SCNXFAST64 "I64X"
+
+#define SCNoMAX "I64o"
+#define SCNuMAX "I64u"
+#define SCNxMAX "I64x"
+#define SCNXMAX "I64X"
+
+#ifdef _WIN64
+# define SCNoPTR "I64o"
+# define SCNuPTR "I64u"
+# define SCNxPTR "I64x"
+# define SCNXPTR "I64X"
+#else
+# define SCNoPTR "lo"
+# define SCNuPTR "lu"
+# define SCNxPTR "lx"
+# define SCNXPTR "lX"
+#endif
+
+#endif
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ASTBuilder_h
+#define ASTBuilder_h
+
+#include "NodeConstructors.h"
+#include "SyntaxChecker.h"
+#include <utility>
+
+namespace JSC {
+
+class ASTBuilder {
+ struct BinaryOpInfo {
+ BinaryOpInfo() {}
+ BinaryOpInfo(int s, int d, int e, bool r)
+ : start(s)
+ , divot(d)
+ , end(e)
+ , hasAssignment(r)
+ {
+ }
+ BinaryOpInfo(const BinaryOpInfo& lhs, const BinaryOpInfo& rhs)
+ : start(lhs.start)
+ , divot(rhs.start)
+ , end(rhs.end)
+ , hasAssignment(lhs.hasAssignment || rhs.hasAssignment)
+ {
+ }
+ int start;
+ int divot;
+ int end;
+ bool hasAssignment;
+ };
+
+
+ struct AssignmentInfo {
+ AssignmentInfo() {}
+ AssignmentInfo(ExpressionNode* node, int start, int divot, int initAssignments, Operator op)
+ : m_node(node)
+ , m_start(start)
+ , m_divot(divot)
+ , m_initAssignments(initAssignments)
+ , m_op(op)
+ {
+ }
+ ExpressionNode* m_node;
+ int m_start;
+ int m_divot;
+ int m_initAssignments;
+ Operator m_op;
+ };
+public:
+ ASTBuilder(JSGlobalData* globalData, Lexer* lexer)
+ : m_globalData(globalData)
+ , m_lexer(lexer)
+ , m_scope(globalData)
+ , m_evalCount(0)
+ {
+ }
+
+ struct BinaryExprContext {
+ BinaryExprContext(ASTBuilder&) {}
+ };
+ struct UnaryExprContext {
+ UnaryExprContext(ASTBuilder&) {}
+ };
+
+ typedef SyntaxChecker FunctionBodyBuilder;
+
+ typedef ExpressionNode* Expression;
+ typedef JSC::SourceElements* SourceElements;
+ typedef ArgumentsNode* Arguments;
+ typedef CommaNode* Comma;
+ typedef PropertyNode* Property;
+ typedef PropertyListNode* PropertyList;
+ typedef ElementNode* ElementList;
+ typedef ArgumentListNode* ArgumentsList;
+ typedef ParameterNode* FormalParameterList;
+ typedef FunctionBodyNode* FunctionBody;
+ typedef StatementNode* Statement;
+ typedef ClauseListNode* ClauseList;
+ typedef CaseClauseNode* Clause;
+ typedef ConstDeclNode* ConstDeclList;
+ typedef std::pair<ExpressionNode*, BinaryOpInfo> BinaryOperand;
+
+ static const bool CreatesAST = true;
+ static const bool NeedsFreeVariableInfo = true;
+ static const bool CanUseFunctionCache = true;
+ static const int DontBuildKeywords = 0;
+ static const int DontBuildStrings = 0;
+
+ ExpressionNode* makeBinaryNode(int token, std::pair<ExpressionNode*, BinaryOpInfo>, std::pair<ExpressionNode*, BinaryOpInfo>);
+ ExpressionNode* makeFunctionCallNode(ExpressionNode* func, ArgumentsNode* args, int start, int divot, int end);
+
+ JSC::SourceElements* createSourceElements() { return new (m_globalData) JSC::SourceElements(m_globalData); }
+
+ ParserArenaData<DeclarationStacks::VarStack>* varDeclarations() { return m_scope.m_varDeclarations; }
+ ParserArenaData<DeclarationStacks::FunctionStack>* funcDeclarations() { return m_scope.m_funcDeclarations; }
+ int features() const { return m_scope.m_features; }
+ int numConstants() const { return m_scope.m_numConstants; }
+
+ void appendToComma(CommaNode* commaNode, ExpressionNode* expr) { commaNode->append(expr); }
+
+ CommaNode* createCommaExpr(ExpressionNode* lhs, ExpressionNode* rhs) { return new (m_globalData) CommaNode(m_globalData, lhs, rhs); }
+
+ ExpressionNode* makeAssignNode(ExpressionNode* left, Operator, ExpressionNode* right, bool leftHasAssignments, bool rightHasAssignments, int start, int divot, int end);
+ ExpressionNode* makePrefixNode(ExpressionNode*, Operator, int start, int divot, int end);
+ ExpressionNode* makePostfixNode(ExpressionNode*, Operator, int start, int divot, int end);
+ ExpressionNode* makeTypeOfNode(ExpressionNode*);
+ ExpressionNode* makeDeleteNode(ExpressionNode*, int start, int divot, int end);
+ ExpressionNode* makeNegateNode(ExpressionNode*);
+ ExpressionNode* makeBitwiseNotNode(ExpressionNode*);
+ ExpressionNode* makeMultNode(ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+ ExpressionNode* makeDivNode(ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+ ExpressionNode* makeModNode(ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+ ExpressionNode* makeAddNode(ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+ ExpressionNode* makeSubNode(ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+ ExpressionNode* makeBitXOrNode(ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+ ExpressionNode* makeBitAndNode(ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+ ExpressionNode* makeBitOrNode(ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+ ExpressionNode* makeLeftShiftNode(ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+ ExpressionNode* makeRightShiftNode(ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+ ExpressionNode* makeURightShiftNode(ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+
+ ExpressionNode* createLogicalNot(ExpressionNode* expr) { return new (m_globalData) LogicalNotNode(m_globalData, expr); }
+ ExpressionNode* createUnaryPlus(ExpressionNode* expr) { return new (m_globalData) UnaryPlusNode(m_globalData, expr); }
+ ExpressionNode* createVoid(ExpressionNode* expr)
+ {
+ incConstants();
+ return new (m_globalData) VoidNode(m_globalData, expr);
+ }
+ ExpressionNode* thisExpr()
+ {
+ usesThis();
+ return new (m_globalData) ThisNode(m_globalData);
+ }
+ ExpressionNode* createResolve(const Identifier* ident, int start)
+ {
+ if (m_globalData->propertyNames->arguments == *ident)
+ usesArguments();
+ return new (m_globalData) ResolveNode(m_globalData, *ident, start);
+ }
+ ExpressionNode* createObjectLiteral() { return new (m_globalData) ObjectLiteralNode(m_globalData); }
+ ExpressionNode* createObjectLiteral(PropertyListNode* properties) { return new (m_globalData) ObjectLiteralNode(m_globalData, properties); }
+
+ ExpressionNode* createArray(int elisions)
+ {
+ if (elisions)
+ incConstants();
+ return new (m_globalData) ArrayNode(m_globalData, elisions);
+ }
+
+ ExpressionNode* createArray(ElementNode* elems) { return new (m_globalData) ArrayNode(m_globalData, elems); }
+ ExpressionNode* createArray(int elisions, ElementNode* elems)
+ {
+ if (elisions)
+ incConstants();
+ return new (m_globalData) ArrayNode(m_globalData, elisions, elems);
+ }
+ ExpressionNode* createNumberExpr(double d)
+ {
+ incConstants();
+ return new (m_globalData) NumberNode(m_globalData, d);
+ }
+
+ ExpressionNode* createString(const Identifier* string)
+ {
+ incConstants();
+ return new (m_globalData) StringNode(m_globalData, *string);
+ }
+
+ ExpressionNode* createBoolean(bool b)
+ {
+ incConstants();
+ return new (m_globalData) BooleanNode(m_globalData, b);
+ }
+
+ ExpressionNode* createNull()
+ {
+ incConstants();
+ return new (m_globalData) NullNode(m_globalData);
+ }
+
+ ExpressionNode* createBracketAccess(ExpressionNode* base, ExpressionNode* property, bool propertyHasAssignments, int start, int divot, int end)
+ {
+ BracketAccessorNode* node = new (m_globalData) BracketAccessorNode(m_globalData, base, property, propertyHasAssignments);
+ setExceptionLocation(node, start, divot, end);
+ return node;
+ }
+
+ ExpressionNode* createDotAccess(ExpressionNode* base, const Identifier* property, int start, int divot, int end)
+ {
+ DotAccessorNode* node = new (m_globalData) DotAccessorNode(m_globalData, base, *property);
+ setExceptionLocation(node, start, divot, end);
+ return node;
+ }
+
+ ExpressionNode* createRegExp(const Identifier& pattern, const Identifier& flags, int start)
+ {
+ if (Yarr::checkSyntax(pattern.ustring()))
+ return 0;
+ RegExpNode* node = new (m_globalData) RegExpNode(m_globalData, pattern, flags);
+ int size = pattern.length() + 2; // + 2 for the two /'s
+ setExceptionLocation(node, start, start + size, start + size);
+ return node;
+ }
+
+ ExpressionNode* createNewExpr(ExpressionNode* expr, ArgumentsNode* arguments, int start, int divot, int end)
+ {
+ NewExprNode* node = new (m_globalData) NewExprNode(m_globalData, expr, arguments);
+ setExceptionLocation(node, start, divot, end);
+ return node;
+ }
+
+ ExpressionNode* createNewExpr(ExpressionNode* expr, int start, int end)
+ {
+ NewExprNode* node = new (m_globalData) NewExprNode(m_globalData, expr);
+ setExceptionLocation(node, start, end, end);
+ return node;
+ }
+
+ ExpressionNode* createConditionalExpr(ExpressionNode* condition, ExpressionNode* lhs, ExpressionNode* rhs)
+ {
+ return new (m_globalData) ConditionalNode(m_globalData, condition, lhs, rhs);
+ }
+
+ ExpressionNode* createAssignResolve(const Identifier& ident, ExpressionNode* rhs, bool rhsHasAssignment, int start, int divot, int end)
+ {
+ AssignResolveNode* node = new (m_globalData) AssignResolveNode(m_globalData, ident, rhs, rhsHasAssignment);
+ setExceptionLocation(node, start, divot, end);
+ return node;
+ }
+
+ ExpressionNode* createFunctionExpr(const Identifier* name, FunctionBodyNode* body, ParameterNode* parameters, int openBracePos, int closeBracePos, int bodyStartLine, int bodyEndLine)
+ {
+ FuncExprNode* result = new (m_globalData) FuncExprNode(m_globalData, *name, body, m_lexer->sourceCode(openBracePos, closeBracePos, bodyStartLine), parameters);
+ body->setLoc(bodyStartLine, bodyEndLine);
+ return result;
+ }
+
+ FunctionBodyNode* createFunctionBody(bool inStrictContext)
+ {
+ usesClosures();
+ return FunctionBodyNode::create(m_globalData, inStrictContext);
+ }
+
+ template <bool> PropertyNode* createGetterOrSetterProperty(PropertyNode::Type type, const Identifier* name, ParameterNode* params, FunctionBodyNode* body, int openBracePos, int closeBracePos, int bodyStartLine, int bodyEndLine)
+ {
+ ASSERT(name);
+ body->setLoc(bodyStartLine, bodyEndLine);
+ return new (m_globalData) PropertyNode(m_globalData, *name, new (m_globalData) FuncExprNode(m_globalData, m_globalData->propertyNames->nullIdentifier, body, m_lexer->sourceCode(openBracePos, closeBracePos, bodyStartLine), params), type);
+ }
+
+
+ ArgumentsNode* createArguments() { return new (m_globalData) ArgumentsNode(m_globalData); }
+ ArgumentsNode* createArguments(ArgumentListNode* args) { return new (m_globalData) ArgumentsNode(m_globalData, args); }
+ ArgumentListNode* createArgumentsList(ExpressionNode* arg) { return new (m_globalData) ArgumentListNode(m_globalData, arg); }
+ ArgumentListNode* createArgumentsList(ArgumentListNode* args, ExpressionNode* arg) { return new (m_globalData) ArgumentListNode(m_globalData, args, arg); }
+
+ template <bool> PropertyNode* createProperty(const Identifier* propertyName, ExpressionNode* node, PropertyNode::Type type) { return new (m_globalData) PropertyNode(m_globalData, *propertyName, node, type); }
+ template <bool> PropertyNode* createProperty(JSGlobalData*, double propertyName, ExpressionNode* node, PropertyNode::Type type) { return new (m_globalData) PropertyNode(m_globalData, propertyName, node, type); }
+ PropertyListNode* createPropertyList(PropertyNode* property) { return new (m_globalData) PropertyListNode(m_globalData, property); }
+ PropertyListNode* createPropertyList(PropertyNode* property, PropertyListNode* tail) { return new (m_globalData) PropertyListNode(m_globalData, property, tail); }
+
+ ElementNode* createElementList(int elisions, ExpressionNode* expr) { return new (m_globalData) ElementNode(m_globalData, elisions, expr); }
+ ElementNode* createElementList(ElementNode* elems, int elisions, ExpressionNode* expr) { return new (m_globalData) ElementNode(m_globalData, elems, elisions, expr); }
+
+ ParameterNode* createFormalParameterList(const Identifier& ident) { return new (m_globalData) ParameterNode(m_globalData, ident); }
+ ParameterNode* createFormalParameterList(ParameterNode* list, const Identifier& ident) { return new (m_globalData) ParameterNode(m_globalData, list, ident); }
+
+ CaseClauseNode* createClause(ExpressionNode* expr, JSC::SourceElements* statements) { return new (m_globalData) CaseClauseNode(m_globalData, expr, statements); }
+ ClauseListNode* createClauseList(CaseClauseNode* clause) { return new (m_globalData) ClauseListNode(m_globalData, clause); }
+ ClauseListNode* createClauseList(ClauseListNode* tail, CaseClauseNode* clause) { return new (m_globalData) ClauseListNode(m_globalData, tail, clause); }
+
+ void setUsesArguments(FunctionBodyNode* node) { node->setUsesArguments(); }
+
+ StatementNode* createFuncDeclStatement(const Identifier* name, FunctionBodyNode* body, ParameterNode* parameters, int openBracePos, int closeBracePos, int bodyStartLine, int bodyEndLine)
+ {
+ FuncDeclNode* decl = new (m_globalData) FuncDeclNode(m_globalData, *name, body, m_lexer->sourceCode(openBracePos, closeBracePos, bodyStartLine), parameters);
+ if (*name == m_globalData->propertyNames->arguments)
+ usesArguments();
+ m_scope.m_funcDeclarations->data.append(decl->body());
+ body->setLoc(bodyStartLine, bodyEndLine);
+ return decl;
+ }
+
+ StatementNode* createBlockStatement(JSC::SourceElements* elements, int startLine, int endLine)
+ {
+ BlockNode* block = new (m_globalData) BlockNode(m_globalData, elements);
+ block->setLoc(startLine, endLine);
+ return block;
+ }
+
+ StatementNode* createExprStatement(ExpressionNode* expr, int start, int end)
+ {
+ ExprStatementNode* result = new (m_globalData) ExprStatementNode(m_globalData, expr);
+ result->setLoc(start, end);
+ return result;
+ }
+
+ StatementNode* createIfStatement(ExpressionNode* condition, StatementNode* trueBlock, int start, int end)
+ {
+ IfNode* result = new (m_globalData) IfNode(m_globalData, condition, trueBlock);
+ result->setLoc(start, end);
+ return result;
+ }
+
+ StatementNode* createIfStatement(ExpressionNode* condition, StatementNode* trueBlock, StatementNode* falseBlock, int start, int end)
+ {
+ IfNode* result = new (m_globalData) IfElseNode(m_globalData, condition, trueBlock, falseBlock);
+ result->setLoc(start, end);
+ return result;
+ }
+
+ StatementNode* createForLoop(ExpressionNode* initializer, ExpressionNode* condition, ExpressionNode* iter, StatementNode* statements, bool b, int start, int end)
+ {
+ ForNode* result = new (m_globalData) ForNode(m_globalData, initializer, condition, iter, statements, b);
+ result->setLoc(start, end);
+ return result;
+ }
+
+ StatementNode* createForInLoop(const Identifier* ident, ExpressionNode* initializer, ExpressionNode* iter, StatementNode* statements, int start, int divot, int end, int initStart, int initEnd, int startLine, int endLine)
+ {
+ ForInNode* result = new (m_globalData) ForInNode(m_globalData, *ident, initializer, iter, statements, initStart, initStart - start, initEnd - initStart);
+ result->setLoc(startLine, endLine);
+ setExceptionLocation(result, start, divot + 1, end);
+ return result;
+ }
+
+ StatementNode* createForInLoop(ExpressionNode* lhs, ExpressionNode* iter, StatementNode* statements, int eStart, int eDivot, int eEnd, int start, int end)
+ {
+ ForInNode* result = new (m_globalData) ForInNode(m_globalData, lhs, iter, statements);
+ result->setLoc(start, end);
+ setExceptionLocation(result, eStart, eDivot, eEnd);
+ return result;
+ }
+
+ StatementNode* createEmptyStatement() { return new (m_globalData) EmptyStatementNode(m_globalData); }
+
+ StatementNode* createVarStatement(ExpressionNode* expr, int start, int end)
+ {
+ StatementNode* result;
+ if (!expr)
+ result = new (m_globalData) EmptyStatementNode(m_globalData);
+ else
+ result = new (m_globalData) VarStatementNode(m_globalData, expr);
+ result->setLoc(start, end);
+ return result;
+ }
+
+ StatementNode* createReturnStatement(ExpressionNode* expression, int eStart, int eEnd, int startLine, int endLine)
+ {
+ ReturnNode* result = new (m_globalData) ReturnNode(m_globalData, expression);
+ setExceptionLocation(result, eStart, eEnd, eEnd);
+ result->setLoc(startLine, endLine);
+ return result;
+ }
+
+ StatementNode* createBreakStatement(int eStart, int eEnd, int startLine, int endLine)
+ {
+ BreakNode* result = new (m_globalData) BreakNode(m_globalData);
+ setExceptionLocation(result, eStart, eEnd, eEnd);
+ result->setLoc(startLine, endLine);
+ return result;
+ }
+
+ StatementNode* createBreakStatement(const Identifier* ident, int eStart, int eEnd, int startLine, int endLine)
+ {
+ BreakNode* result = new (m_globalData) BreakNode(m_globalData, *ident);
+ setExceptionLocation(result, eStart, eEnd, eEnd);
+ result->setLoc(startLine, endLine);
+ return result;
+ }
+
+ StatementNode* createContinueStatement(int eStart, int eEnd, int startLine, int endLine)
+ {
+ ContinueNode* result = new (m_globalData) ContinueNode(m_globalData);
+ setExceptionLocation(result, eStart, eEnd, eEnd);
+ result->setLoc(startLine, endLine);
+ return result;
+ }
+
+ StatementNode* createContinueStatement(const Identifier* ident, int eStart, int eEnd, int startLine, int endLine)
+ {
+ ContinueNode* result = new (m_globalData) ContinueNode(m_globalData, *ident);
+ setExceptionLocation(result, eStart, eEnd, eEnd);
+ result->setLoc(startLine, endLine);
+ return result;
+ }
+
+ StatementNode* createTryStatement(StatementNode* tryBlock, const Identifier* ident, bool catchHasEval, StatementNode* catchBlock, StatementNode* finallyBlock, int startLine, int endLine)
+ {
+ TryNode* result = new (m_globalData) TryNode(m_globalData, tryBlock, *ident, catchHasEval, catchBlock, finallyBlock);
+ if (catchBlock)
+ usesCatch();
+ result->setLoc(startLine, endLine);
+ return result;
+ }
+
+ StatementNode* createSwitchStatement(ExpressionNode* expr, ClauseListNode* firstClauses, CaseClauseNode* defaultClause, ClauseListNode* secondClauses, int startLine, int endLine)
+ {
+ CaseBlockNode* cases = new (m_globalData) CaseBlockNode(m_globalData, firstClauses, defaultClause, secondClauses);
+ SwitchNode* result = new (m_globalData) SwitchNode(m_globalData, expr, cases);
+ result->setLoc(startLine, endLine);
+ return result;
+ }
+
+ StatementNode* createWhileStatement(ExpressionNode* expr, StatementNode* statement, int startLine, int endLine)
+ {
+ WhileNode* result = new (m_globalData) WhileNode(m_globalData, expr, statement);
+ result->setLoc(startLine, endLine);
+ return result;
+ }
+
+ StatementNode* createDoWhileStatement(StatementNode* statement, ExpressionNode* expr, int startLine, int endLine)
+ {
+ DoWhileNode* result = new (m_globalData) DoWhileNode(m_globalData, statement, expr);
+ result->setLoc(startLine, endLine);
+ return result;
+ }
+
+ StatementNode* createLabelStatement(const Identifier* ident, StatementNode* statement, int start, int end)
+ {
+ LabelNode* result = new (m_globalData) LabelNode(m_globalData, *ident, statement);
+ setExceptionLocation(result, start, end, end);
+ return result;
+ }
+
+ StatementNode* createWithStatement(ExpressionNode* expr, StatementNode* statement, int start, int end, int startLine, int endLine)
+ {
+ usesWith();
+ WithNode* result = new (m_globalData) WithNode(m_globalData, expr, statement, end, end - start);
+ result->setLoc(startLine, endLine);
+ return result;
+ }
+
+ StatementNode* createThrowStatement(ExpressionNode* expr, int start, int end, int startLine, int endLine)
+ {
+ ThrowNode* result = new (m_globalData) ThrowNode(m_globalData, expr);
+ result->setLoc(startLine, endLine);
+ setExceptionLocation(result, start, end, end);
+ return result;
+ }
+
+ StatementNode* createDebugger(int startLine, int endLine)
+ {
+ DebuggerStatementNode* result = new (m_globalData) DebuggerStatementNode(m_globalData);
+ result->setLoc(startLine, endLine);
+ return result;
+ }
+
+ StatementNode* createConstStatement(ConstDeclNode* decls, int startLine, int endLine)
+ {
+ ConstStatementNode* result = new (m_globalData) ConstStatementNode(m_globalData, decls);
+ result->setLoc(startLine, endLine);
+ return result;
+ }
+
+ ConstDeclNode* appendConstDecl(ConstDeclNode* tail, const Identifier* name, ExpressionNode* initializer)
+ {
+ ConstDeclNode* result = new (m_globalData) ConstDeclNode(m_globalData, *name, initializer);
+ if (tail)
+ tail->m_next = result;
+ return result;
+ }
+
+ void appendStatement(JSC::SourceElements* elements, JSC::StatementNode* statement)
+ {
+ elements->append(statement);
+ }
+
+ void addVar(const Identifier* ident, int attrs)
+ {
+ if (m_globalData->propertyNames->arguments == *ident)
+ usesArguments();
+ m_scope.m_varDeclarations->data.append(std::make_pair(ident, attrs));
+ }
+
+ ExpressionNode* combineCommaNodes(ExpressionNode* list, ExpressionNode* init)
+ {
+ if (!list)
+ return init;
+ if (list->isCommaNode()) {
+ static_cast<CommaNode*>(list)->append(init);
+ return list;
+ }
+ return new (m_globalData) CommaNode(m_globalData, list, init);
+ }
+
+ int evalCount() const { return m_evalCount; }
+
+ void appendBinaryExpressionInfo(int& operandStackDepth, ExpressionNode* current, int exprStart, int lhs, int rhs, bool hasAssignments)
+ {
+ operandStackDepth++;
+ m_binaryOperandStack.append(std::make_pair(current, BinaryOpInfo(exprStart, lhs, rhs, hasAssignments)));
+ }
+
+ // Logic to handle datastructures used during parsing of binary expressions
+ void operatorStackPop(int& operatorStackDepth)
+ {
+ operatorStackDepth--;
+ m_binaryOperatorStack.removeLast();
+ }
+ bool operatorStackHasHigherPrecedence(int&, int precedence)
+ {
+ return precedence <= m_binaryOperatorStack.last().second;
+ }
+ const BinaryOperand& getFromOperandStack(int i) { return m_binaryOperandStack[m_binaryOperandStack.size() + i]; }
+ void shrinkOperandStackBy(int& operandStackDepth, int amount)
+ {
+ operandStackDepth -= amount;
+ ASSERT(operandStackDepth >= 0);
+ m_binaryOperandStack.resize(m_binaryOperandStack.size() - amount);
+ }
+ void appendBinaryOperation(int& operandStackDepth, int&, const BinaryOperand& lhs, const BinaryOperand& rhs)
+ {
+ operandStackDepth++;
+ m_binaryOperandStack.append(std::make_pair(makeBinaryNode(m_binaryOperatorStack.last().first, lhs, rhs), BinaryOpInfo(lhs.second, rhs.second)));
+ }
+ void operatorStackAppend(int& operatorStackDepth, int op, int precedence)
+ {
+ operatorStackDepth++;
+ m_binaryOperatorStack.append(std::make_pair(op, precedence));
+ }
+ ExpressionNode* popOperandStack(int&)
+ {
+ ExpressionNode* result = m_binaryOperandStack.last().first;
+ m_binaryOperandStack.removeLast();
+ return result;
+ }
+
+ void appendUnaryToken(int& tokenStackDepth, int type, int start)
+ {
+ tokenStackDepth++;
+ m_unaryTokenStack.append(std::make_pair(type, start));
+ }
+
+ int unaryTokenStackLastType(int&)
+ {
+ return m_unaryTokenStack.last().first;
+ }
+
+ int unaryTokenStackLastStart(int&)
+ {
+ return m_unaryTokenStack.last().second;
+ }
+
+ void unaryTokenStackRemoveLast(int& tokenStackDepth)
+ {
+ tokenStackDepth--;
+ m_unaryTokenStack.removeLast();
+ }
+
+ void assignmentStackAppend(int& assignmentStackDepth, ExpressionNode* node, int start, int divot, int assignmentCount, Operator op)
+ {
+ assignmentStackDepth++;
+ m_assignmentInfoStack.append(AssignmentInfo(node, start, divot, assignmentCount, op));
+ }
+
+ ExpressionNode* createAssignment(int& assignmentStackDepth, ExpressionNode* rhs, int initialAssignmentCount, int currentAssignmentCount, int lastTokenEnd)
+ {
+ ExpressionNode* result = makeAssignNode(m_assignmentInfoStack.last().m_node, m_assignmentInfoStack.last().m_op, rhs, m_assignmentInfoStack.last().m_initAssignments != initialAssignmentCount, m_assignmentInfoStack.last().m_initAssignments != currentAssignmentCount, m_assignmentInfoStack.last().m_start, m_assignmentInfoStack.last().m_divot + 1, lastTokenEnd);
+ m_assignmentInfoStack.removeLast();
+ assignmentStackDepth--;
+ return result;
+ }
+
+ const Identifier& getName(Property property) const { return property->name(); }
+ PropertyNode::Type getType(Property property) const { return property->type(); }
+
+ bool isResolve(ExpressionNode* expr) const { return expr->isResolveNode(); }
+
+private:
+ struct Scope {
+ Scope(JSGlobalData* globalData)
+ : m_varDeclarations(new (globalData) ParserArenaData<DeclarationStacks::VarStack>)
+ , m_funcDeclarations(new (globalData) ParserArenaData<DeclarationStacks::FunctionStack>)
+ , m_features(0)
+ , m_numConstants(0)
+ {
+ }
+ ParserArenaData<DeclarationStacks::VarStack>* m_varDeclarations;
+ ParserArenaData<DeclarationStacks::FunctionStack>* m_funcDeclarations;
+ int m_features;
+ int m_numConstants;
+ };
+
+ static void setExceptionLocation(ThrowableExpressionData* node, unsigned start, unsigned divot, unsigned end)
+ {
+ node->setExceptionSourceCode(divot, divot - start, end - divot);
+ }
+
+ void incConstants() { m_scope.m_numConstants++; }
+ void usesThis() { m_scope.m_features |= ThisFeature; }
+ void usesCatch() { m_scope.m_features |= CatchFeature; }
+ void usesClosures() { m_scope.m_features |= ClosureFeature; }
+ void usesArguments() { m_scope.m_features |= ArgumentsFeature; }
+ void usesAssignment() { m_scope.m_features |= AssignFeature; }
+ void usesWith() { m_scope.m_features |= WithFeature; }
+ void usesEval()
+ {
+ m_evalCount++;
+ m_scope.m_features |= EvalFeature;
+ }
+ ExpressionNode* createNumber(double d)
+ {
+ return new (m_globalData) NumberNode(m_globalData, d);
+ }
+
+ JSGlobalData* m_globalData;
+ Lexer* m_lexer;
+ Scope m_scope;
+ Vector<BinaryOperand, 10> m_binaryOperandStack;
+ Vector<AssignmentInfo, 10> m_assignmentInfoStack;
+ Vector<pair<int, int>, 10> m_binaryOperatorStack;
+ Vector<pair<int, int>, 10> m_unaryTokenStack;
+ int m_evalCount;
+};
+
+ExpressionNode* ASTBuilder::makeTypeOfNode(ExpressionNode* expr)
+{
+ if (expr->isResolveNode()) {
+ ResolveNode* resolve = static_cast<ResolveNode*>(expr);
+ return new (m_globalData) TypeOfResolveNode(m_globalData, resolve->identifier());
+ }
+ return new (m_globalData) TypeOfValueNode(m_globalData, expr);
+}
+
+ExpressionNode* ASTBuilder::makeDeleteNode(ExpressionNode* expr, int start, int divot, int end)
+{
+ if (!expr->isLocation())
+ return new (m_globalData) DeleteValueNode(m_globalData, expr);
+ if (expr->isResolveNode()) {
+ ResolveNode* resolve = static_cast<ResolveNode*>(expr);
+ return new (m_globalData) DeleteResolveNode(m_globalData, resolve->identifier(), divot, divot - start, end - divot);
+ }
+ if (expr->isBracketAccessorNode()) {
+ BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(expr);
+ return new (m_globalData) DeleteBracketNode(m_globalData, bracket->base(), bracket->subscript(), divot, divot - start, end - divot);
+ }
+ ASSERT(expr->isDotAccessorNode());
+ DotAccessorNode* dot = static_cast<DotAccessorNode*>(expr);
+ return new (m_globalData) DeleteDotNode(m_globalData, dot->base(), dot->identifier(), divot, divot - start, end - divot);
+}
+
+ExpressionNode* ASTBuilder::makeNegateNode(ExpressionNode* n)
+{
+ if (n->isNumber()) {
+ NumberNode* numberNode = static_cast<NumberNode*>(n);
+ numberNode->setValue(-numberNode->value());
+ return numberNode;
+ }
+
+ return new (m_globalData) NegateNode(m_globalData, n);
+}
+
+ExpressionNode* ASTBuilder::makeBitwiseNotNode(ExpressionNode* expr)
+{
+ if (expr->isNumber())
+ return createNumber(~toInt32(static_cast<NumberNode*>(expr)->value()));
+ return new (m_globalData) BitwiseNotNode(m_globalData, expr);
+}
+
+ExpressionNode* ASTBuilder::makeMultNode(ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ expr1 = expr1->stripUnaryPlus();
+ expr2 = expr2->stripUnaryPlus();
+
+ if (expr1->isNumber() && expr2->isNumber())
+ return createNumber(static_cast<NumberNode*>(expr1)->value() * static_cast<NumberNode*>(expr2)->value());
+
+ if (expr1->isNumber() && static_cast<NumberNode*>(expr1)->value() == 1)
+ return new (m_globalData) UnaryPlusNode(m_globalData, expr2);
+
+ if (expr2->isNumber() && static_cast<NumberNode*>(expr2)->value() == 1)
+ return new (m_globalData) UnaryPlusNode(m_globalData, expr1);
+
+ return new (m_globalData) MultNode(m_globalData, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeDivNode(ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ expr1 = expr1->stripUnaryPlus();
+ expr2 = expr2->stripUnaryPlus();
+
+ if (expr1->isNumber() && expr2->isNumber())
+ return createNumber(static_cast<NumberNode*>(expr1)->value() / static_cast<NumberNode*>(expr2)->value());
+ return new (m_globalData) DivNode(m_globalData, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeModNode(ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ expr1 = expr1->stripUnaryPlus();
+ expr2 = expr2->stripUnaryPlus();
+
+ if (expr1->isNumber() && expr2->isNumber())
+ return createNumber(fmod(static_cast<NumberNode*>(expr1)->value(), static_cast<NumberNode*>(expr2)->value()));
+ return new (m_globalData) ModNode(m_globalData, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeAddNode(ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ if (expr1->isNumber() && expr2->isNumber())
+ return createNumber(static_cast<NumberNode*>(expr1)->value() + static_cast<NumberNode*>(expr2)->value());
+ return new (m_globalData) AddNode(m_globalData, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeSubNode(ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ expr1 = expr1->stripUnaryPlus();
+ expr2 = expr2->stripUnaryPlus();
+
+ if (expr1->isNumber() && expr2->isNumber())
+ return createNumber(static_cast<NumberNode*>(expr1)->value() - static_cast<NumberNode*>(expr2)->value());
+ return new (m_globalData) SubNode(m_globalData, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeLeftShiftNode(ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ if (expr1->isNumber() && expr2->isNumber())
+ return createNumber(toInt32(static_cast<NumberNode*>(expr1)->value()) << (toUInt32(static_cast<NumberNode*>(expr2)->value()) & 0x1f));
+ return new (m_globalData) LeftShiftNode(m_globalData, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeRightShiftNode(ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ if (expr1->isNumber() && expr2->isNumber())
+ return createNumber(toInt32(static_cast<NumberNode*>(expr1)->value()) >> (toUInt32(static_cast<NumberNode*>(expr2)->value()) & 0x1f));
+ return new (m_globalData) RightShiftNode(m_globalData, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeURightShiftNode(ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ if (expr1->isNumber() && expr2->isNumber())
+ return createNumber(toUInt32(static_cast<NumberNode*>(expr1)->value()) >> (toUInt32(static_cast<NumberNode*>(expr2)->value()) & 0x1f));
+ return new (m_globalData) UnsignedRightShiftNode(m_globalData, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeBitOrNode(ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ if (expr1->isNumber() && expr2->isNumber())
+ return createNumber(toInt32(static_cast<NumberNode*>(expr1)->value()) | toInt32(static_cast<NumberNode*>(expr2)->value()));
+ return new (m_globalData) BitOrNode(m_globalData, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeBitAndNode(ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ if (expr1->isNumber() && expr2->isNumber())
+ return createNumber(toInt32(static_cast<NumberNode*>(expr1)->value()) & toInt32(static_cast<NumberNode*>(expr2)->value()));
+ return new (m_globalData) BitAndNode(m_globalData, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeBitXOrNode(ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ if (expr1->isNumber() && expr2->isNumber())
+ return createNumber(toInt32(static_cast<NumberNode*>(expr1)->value()) ^ toInt32(static_cast<NumberNode*>(expr2)->value()));
+ return new (m_globalData) BitXOrNode(m_globalData, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeFunctionCallNode(ExpressionNode* func, ArgumentsNode* args, int start, int divot, int end)
+{
+ if (!func->isLocation())
+ return new (m_globalData) FunctionCallValueNode(m_globalData, func, args, divot, divot - start, end - divot);
+ if (func->isResolveNode()) {
+ ResolveNode* resolve = static_cast<ResolveNode*>(func);
+ const Identifier& identifier = resolve->identifier();
+ if (identifier == m_globalData->propertyNames->eval) {
+ usesEval();
+ return new (m_globalData) EvalFunctionCallNode(m_globalData, args, divot, divot - start, end - divot);
+ }
+ return new (m_globalData) FunctionCallResolveNode(m_globalData, identifier, args, divot, divot - start, end - divot);
+ }
+ if (func->isBracketAccessorNode()) {
+ BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(func);
+ FunctionCallBracketNode* node = new (m_globalData) FunctionCallBracketNode(m_globalData, bracket->base(), bracket->subscript(), args, divot, divot - start, end - divot);
+ node->setSubexpressionInfo(bracket->divot(), bracket->endOffset());
+ return node;
+ }
+ ASSERT(func->isDotAccessorNode());
+ DotAccessorNode* dot = static_cast<DotAccessorNode*>(func);
+ FunctionCallDotNode* node;
+ if (dot->identifier() == m_globalData->propertyNames->call)
+ node = new (m_globalData) CallFunctionCallDotNode(m_globalData, dot->base(), dot->identifier(), args, divot, divot - start, end - divot);
+ else if (dot->identifier() == m_globalData->propertyNames->apply)
+ node = new (m_globalData) ApplyFunctionCallDotNode(m_globalData, dot->base(), dot->identifier(), args, divot, divot - start, end - divot);
+ else
+ node = new (m_globalData) FunctionCallDotNode(m_globalData, dot->base(), dot->identifier(), args, divot, divot - start, end - divot);
+ node->setSubexpressionInfo(dot->divot(), dot->endOffset());
+ return node;
+}
+
+ExpressionNode* ASTBuilder::makeBinaryNode(int token, pair<ExpressionNode*, BinaryOpInfo> lhs, pair<ExpressionNode*, BinaryOpInfo> rhs)
+{
+ switch (token) {
+ case OR:
+ return new (m_globalData) LogicalOpNode(m_globalData, lhs.first, rhs.first, OpLogicalOr);
+
+ case AND:
+ return new (m_globalData) LogicalOpNode(m_globalData, lhs.first, rhs.first, OpLogicalAnd);
+
+ case BITOR:
+ return makeBitOrNode(lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case BITXOR:
+ return makeBitXOrNode(lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case BITAND:
+ return makeBitAndNode(lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case EQEQ:
+ return new (m_globalData) EqualNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case NE:
+ return new (m_globalData) NotEqualNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case STREQ:
+ return new (m_globalData) StrictEqualNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case STRNEQ:
+ return new (m_globalData) NotStrictEqualNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case LT:
+ return new (m_globalData) LessNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case GT:
+ return new (m_globalData) GreaterNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case LE:
+ return new (m_globalData) LessEqNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case GE:
+ return new (m_globalData) GreaterEqNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case INSTANCEOF: {
+ InstanceOfNode* node = new (m_globalData) InstanceOfNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment);
+ setExceptionLocation(node, lhs.second.start, rhs.second.start, rhs.second.end);
+ return node;
+ }
+
+ case INTOKEN: {
+ InNode* node = new (m_globalData) InNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment);
+ setExceptionLocation(node, lhs.second.start, rhs.second.start, rhs.second.end);
+ return node;
+ }
+
+ case LSHIFT:
+ return makeLeftShiftNode(lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case RSHIFT:
+ return makeRightShiftNode(lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case URSHIFT:
+ return makeURightShiftNode(lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case PLUS:
+ return makeAddNode(lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case MINUS:
+ return makeSubNode(lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case TIMES:
+ return makeMultNode(lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case DIVIDE:
+ return makeDivNode(lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case MOD:
+ return makeModNode(lhs.first, rhs.first, rhs.second.hasAssignment);
+ }
+ CRASH();
+ return 0;
+}
+
+ExpressionNode* ASTBuilder::makeAssignNode(ExpressionNode* loc, Operator op, ExpressionNode* expr, bool locHasAssignments, bool exprHasAssignments, int start, int divot, int end)
+{
+ usesAssignment();
+ if (!loc->isLocation())
+ return new (m_globalData) AssignErrorNode(m_globalData, loc, op, expr, divot, divot - start, end - divot);
+
+ if (loc->isResolveNode()) {
+ ResolveNode* resolve = static_cast<ResolveNode*>(loc);
+ if (op == OpEqual) {
+ AssignResolveNode* node = new (m_globalData) AssignResolveNode(m_globalData, resolve->identifier(), expr, exprHasAssignments);
+ setExceptionLocation(node, start, divot, end);
+ return node;
+ }
+ return new (m_globalData) ReadModifyResolveNode(m_globalData, resolve->identifier(), op, expr, exprHasAssignments, divot, divot - start, end - divot);
+ }
+ if (loc->isBracketAccessorNode()) {
+ BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(loc);
+ if (op == OpEqual)
+ return new (m_globalData) AssignBracketNode(m_globalData, bracket->base(), bracket->subscript(), expr, locHasAssignments, exprHasAssignments, bracket->divot(), bracket->divot() - start, end - bracket->divot());
+ ReadModifyBracketNode* node = new (m_globalData) ReadModifyBracketNode(m_globalData, bracket->base(), bracket->subscript(), op, expr, locHasAssignments, exprHasAssignments, divot, divot - start, end - divot);
+ node->setSubexpressionInfo(bracket->divot(), bracket->endOffset());
+ return node;
+ }
+ ASSERT(loc->isDotAccessorNode());
+ DotAccessorNode* dot = static_cast<DotAccessorNode*>(loc);
+ if (op == OpEqual)
+ return new (m_globalData) AssignDotNode(m_globalData, dot->base(), dot->identifier(), expr, exprHasAssignments, dot->divot(), dot->divot() - start, end - dot->divot());
+
+ ReadModifyDotNode* node = new (m_globalData) ReadModifyDotNode(m_globalData, dot->base(), dot->identifier(), op, expr, exprHasAssignments, divot, divot - start, end - divot);
+ node->setSubexpressionInfo(dot->divot(), dot->endOffset());
+ return node;
+}
+
+ExpressionNode* ASTBuilder::makePrefixNode(ExpressionNode* expr, Operator op, int start, int divot, int end)
+{
+ usesAssignment();
+ if (!expr->isLocation())
+ return new (m_globalData) PrefixErrorNode(m_globalData, expr, op, divot, divot - start, end - divot);
+
+ if (expr->isResolveNode()) {
+ ResolveNode* resolve = static_cast<ResolveNode*>(expr);
+ return new (m_globalData) PrefixResolveNode(m_globalData, resolve->identifier(), op, divot, divot - start, end - divot);
+ }
+ if (expr->isBracketAccessorNode()) {
+ BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(expr);
+ PrefixBracketNode* node = new (m_globalData) PrefixBracketNode(m_globalData, bracket->base(), bracket->subscript(), op, divot, divot - start, end - divot);
+ node->setSubexpressionInfo(bracket->divot(), bracket->startOffset());
+ return node;
+ }
+ ASSERT(expr->isDotAccessorNode());
+ DotAccessorNode* dot = static_cast<DotAccessorNode*>(expr);
+ PrefixDotNode* node = new (m_globalData) PrefixDotNode(m_globalData, dot->base(), dot->identifier(), op, divot, divot - start, end - divot);
+ node->setSubexpressionInfo(dot->divot(), dot->startOffset());
+ return node;
+}
+
+ExpressionNode* ASTBuilder::makePostfixNode(ExpressionNode* expr, Operator op, int start, int divot, int end)
+{
+ usesAssignment();
+ if (!expr->isLocation())
+ return new (m_globalData) PostfixErrorNode(m_globalData, expr, op, divot, divot - start, end - divot);
+
+ if (expr->isResolveNode()) {
+ ResolveNode* resolve = static_cast<ResolveNode*>(expr);
+ return new (m_globalData) PostfixResolveNode(m_globalData, resolve->identifier(), op, divot, divot - start, end - divot);
+ }
+ if (expr->isBracketAccessorNode()) {
+ BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(expr);
+ PostfixBracketNode* node = new (m_globalData) PostfixBracketNode(m_globalData, bracket->base(), bracket->subscript(), op, divot, divot - start, end - divot);
+ node->setSubexpressionInfo(bracket->divot(), bracket->endOffset());
+ return node;
+
+ }
+ ASSERT(expr->isDotAccessorNode());
+ DotAccessorNode* dot = static_cast<DotAccessorNode*>(expr);
+ PostfixDotNode* node = new (m_globalData) PostfixDotNode(m_globalData, dot->base(), dot->identifier(), op, divot, divot - start, end - divot);
+ node->setSubexpressionInfo(dot->divot(), dot->endOffset());
+ return node;
+}
+
+}
+
+#endif
+++ /dev/null
-%pure_parser
-
-%{
-
-/*
- * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
- * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#include "config.h"
-
-#include "JSObject.h"
-#include "JSString.h"
-#include "Lexer.h"
-#include "NodeConstructors.h"
-#include "NodeInfo.h"
-#include <stdlib.h>
-#include <string.h>
-#include <wtf/MathExtras.h>
-
-#define YYMALLOC fastMalloc
-#define YYFREE fastFree
-
-#define YYMAXDEPTH 10000
-#define YYENABLE_NLS 0
-
-// Default values for bison.
-#define YYDEBUG 0 // Set to 1 to debug a parse error.
-#define jscyydebug 0 // Set to 1 to debug a parse error.
-#if !OS(DARWIN)
-// Avoid triggering warnings in older bison by not setting this on the Darwin platform.
-// FIXME: Is this still needed?
-#define YYERROR_VERBOSE
-#endif
-
-int jscyyerror(const char*);
-
-static inline bool allowAutomaticSemicolon(JSC::Lexer&, int);
-
-#define GLOBAL_DATA static_cast<JSGlobalData*>(globalPtr)
-#define AUTO_SEMICOLON do { if (!allowAutomaticSemicolon(*GLOBAL_DATA->lexer, yychar)) YYABORT; } while (0)
-
-using namespace JSC;
-using namespace std;
-
-static ExpressionNode* makeAssignNode(JSGlobalData*, ExpressionNode* left, Operator, ExpressionNode* right, bool leftHasAssignments, bool rightHasAssignments, int start, int divot, int end);
-static ExpressionNode* makePrefixNode(JSGlobalData*, ExpressionNode*, Operator, int start, int divot, int end);
-static ExpressionNode* makePostfixNode(JSGlobalData*, ExpressionNode*, Operator, int start, int divot, int end);
-static PropertyNode* makeGetterOrSetterPropertyNode(JSGlobalData*, const Identifier& getOrSet, const Identifier& name, ParameterNode*, FunctionBodyNode*, const SourceCode&);
-static ExpressionNodeInfo makeFunctionCallNode(JSGlobalData*, ExpressionNodeInfo function, ArgumentsNodeInfo, int start, int divot, int end);
-static ExpressionNode* makeTypeOfNode(JSGlobalData*, ExpressionNode*);
-static ExpressionNode* makeDeleteNode(JSGlobalData*, ExpressionNode*, int start, int divot, int end);
-static ExpressionNode* makeNegateNode(JSGlobalData*, ExpressionNode*);
-static NumberNode* makeNumberNode(JSGlobalData*, double);
-static ExpressionNode* makeBitwiseNotNode(JSGlobalData*, ExpressionNode*);
-static ExpressionNode* makeMultNode(JSGlobalData*, ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
-static ExpressionNode* makeDivNode(JSGlobalData*, ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
-static ExpressionNode* makeAddNode(JSGlobalData*, ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
-static ExpressionNode* makeSubNode(JSGlobalData*, ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
-static ExpressionNode* makeLeftShiftNode(JSGlobalData*, ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
-static ExpressionNode* makeRightShiftNode(JSGlobalData*, ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
-static StatementNode* makeVarStatementNode(JSGlobalData*, ExpressionNode*);
-static ExpressionNode* combineCommaNodes(JSGlobalData*, ExpressionNode* list, ExpressionNode* init);
-
-#if COMPILER(MSVC)
-
-#pragma warning(disable: 4065)
-#pragma warning(disable: 4244)
-#pragma warning(disable: 4702)
-
-#endif
-
-#define YYPARSE_PARAM globalPtr
-#define YYLEX_PARAM globalPtr
-
-template <typename T> inline NodeDeclarationInfo<T> createNodeDeclarationInfo(T node,
- ParserArenaData<DeclarationStacks::VarStack>* varDecls,
- ParserArenaData<DeclarationStacks::FunctionStack>* funcDecls,
- CodeFeatures info, int numConstants)
-{
- ASSERT((info & ~AllFeatures) == 0);
- NodeDeclarationInfo<T> result = { node, varDecls, funcDecls, info, numConstants };
- return result;
-}
-
-template <typename T> inline NodeInfo<T> createNodeInfo(T node, CodeFeatures info, int numConstants)
-{
- ASSERT((info & ~AllFeatures) == 0);
- NodeInfo<T> result = { node, info, numConstants };
- return result;
-}
-
-template <typename T> inline T mergeDeclarationLists(T decls1, T decls2)
-{
- // decls1 or both are null
- if (!decls1)
- return decls2;
- // only decls1 is non-null
- if (!decls2)
- return decls1;
-
- // Both are non-null
- decls1->data.append(decls2->data);
-
- // Manually release as much as possible from the now-defunct declaration lists
- // to avoid accumulating so many unused heap allocated vectors.
- decls2->data.clear();
-
- return decls1;
-}
-
-static inline void appendToVarDeclarationList(JSGlobalData* globalData, ParserArenaData<DeclarationStacks::VarStack>*& varDecls, const Identifier& ident, unsigned attrs)
-{
- if (!varDecls)
- varDecls = new (globalData) ParserArenaData<DeclarationStacks::VarStack>;
-
- varDecls->data.append(make_pair(&ident, attrs));
-}
-
-static inline void appendToVarDeclarationList(JSGlobalData* globalData, ParserArenaData<DeclarationStacks::VarStack>*& varDecls, ConstDeclNode* decl)
-{
- unsigned attrs = DeclarationStacks::IsConstant;
- if (decl->hasInitializer())
- attrs |= DeclarationStacks::HasInitializer;
- appendToVarDeclarationList(globalData, varDecls, decl->ident(), attrs);
-}
-
-%}
-
-%union {
- int intValue;
- double doubleValue;
- const Identifier* ident;
-
- // expression subtrees
- ExpressionNodeInfo expressionNode;
- FuncDeclNodeInfo funcDeclNode;
- PropertyNodeInfo propertyNode;
- ArgumentsNodeInfo argumentsNode;
- ConstDeclNodeInfo constDeclNode;
- CaseBlockNodeInfo caseBlockNode;
- CaseClauseNodeInfo caseClauseNode;
- FuncExprNodeInfo funcExprNode;
-
- // statement nodes
- StatementNodeInfo statementNode;
- FunctionBodyNode* functionBodyNode;
- ProgramNode* programNode;
-
- SourceElementsInfo sourceElements;
- PropertyListInfo propertyList;
- ArgumentListInfo argumentList;
- VarDeclListInfo varDeclList;
- ConstDeclListInfo constDeclList;
- ClauseListInfo clauseList;
- ElementListInfo elementList;
- ParameterListInfo parameterList;
-
- Operator op;
-}
-
-%{
-
-template <typename T> inline void setStatementLocation(StatementNode* statement, const T& start, const T& end)
-{
- statement->setLoc(start.first_line, end.last_line);
-}
-
-static inline void setExceptionLocation(ThrowableExpressionData* node, unsigned start, unsigned divot, unsigned end)
-{
- node->setExceptionSourceCode(divot, divot - start, end - divot);
-}
-
-%}
-
-%start Program
-
-/* literals */
-%token NULLTOKEN TRUETOKEN FALSETOKEN
-
-/* keywords */
-%token BREAK CASE DEFAULT FOR NEW VAR CONSTTOKEN CONTINUE
-%token FUNCTION RETURN VOIDTOKEN DELETETOKEN
-%token IF THISTOKEN DO WHILE INTOKEN INSTANCEOF TYPEOF
-%token SWITCH WITH RESERVED
-%token THROW TRY CATCH FINALLY
-%token DEBUGGER
-
-/* give an if without an else higher precedence than an else to resolve the ambiguity */
-%nonassoc IF_WITHOUT_ELSE
-%nonassoc ELSE
-
-/* punctuators */
-%token EQEQ NE /* == and != */
-%token STREQ STRNEQ /* === and !== */
-%token LE GE /* < and > */
-%token OR AND /* || and && */
-%token PLUSPLUS MINUSMINUS /* ++ and -- */
-%token LSHIFT /* << */
-%token RSHIFT URSHIFT /* >> and >>> */
-%token PLUSEQUAL MINUSEQUAL /* += and -= */
-%token MULTEQUAL DIVEQUAL /* *= and /= */
-%token LSHIFTEQUAL /* <<= */
-%token RSHIFTEQUAL URSHIFTEQUAL /* >>= and >>>= */
-%token ANDEQUAL MODEQUAL /* &= and %= */
-%token XOREQUAL OREQUAL /* ^= and |= */
-%token <intValue> OPENBRACE /* { (with char offset) */
-%token <intValue> CLOSEBRACE /* } (with char offset) */
-
-/* terminal types */
-%token <doubleValue> NUMBER
-%token <ident> IDENT STRING
-
-/* automatically inserted semicolon */
-%token AUTOPLUSPLUS AUTOMINUSMINUS
-
-/* non-terminal types */
-%type <expressionNode> Literal ArrayLiteral
-
-%type <expressionNode> PrimaryExpr PrimaryExprNoBrace
-%type <expressionNode> MemberExpr MemberExprNoBF /* BF => brace or function */
-%type <expressionNode> NewExpr NewExprNoBF
-%type <expressionNode> CallExpr CallExprNoBF
-%type <expressionNode> LeftHandSideExpr LeftHandSideExprNoBF
-%type <expressionNode> PostfixExpr PostfixExprNoBF
-%type <expressionNode> UnaryExpr UnaryExprNoBF UnaryExprCommon
-%type <expressionNode> MultiplicativeExpr MultiplicativeExprNoBF
-%type <expressionNode> AdditiveExpr AdditiveExprNoBF
-%type <expressionNode> ShiftExpr ShiftExprNoBF
-%type <expressionNode> RelationalExpr RelationalExprNoIn RelationalExprNoBF
-%type <expressionNode> EqualityExpr EqualityExprNoIn EqualityExprNoBF
-%type <expressionNode> BitwiseANDExpr BitwiseANDExprNoIn BitwiseANDExprNoBF
-%type <expressionNode> BitwiseXORExpr BitwiseXORExprNoIn BitwiseXORExprNoBF
-%type <expressionNode> BitwiseORExpr BitwiseORExprNoIn BitwiseORExprNoBF
-%type <expressionNode> LogicalANDExpr LogicalANDExprNoIn LogicalANDExprNoBF
-%type <expressionNode> LogicalORExpr LogicalORExprNoIn LogicalORExprNoBF
-%type <expressionNode> ConditionalExpr ConditionalExprNoIn ConditionalExprNoBF
-%type <expressionNode> AssignmentExpr AssignmentExprNoIn AssignmentExprNoBF
-%type <expressionNode> Expr ExprNoIn ExprNoBF
-
-%type <expressionNode> ExprOpt ExprNoInOpt
-
-%type <statementNode> Statement Block
-%type <statementNode> VariableStatement ConstStatement EmptyStatement ExprStatement
-%type <statementNode> IfStatement IterationStatement ContinueStatement
-%type <statementNode> BreakStatement ReturnStatement WithStatement
-%type <statementNode> SwitchStatement LabelledStatement
-%type <statementNode> ThrowStatement TryStatement
-%type <statementNode> DebuggerStatement
-
-%type <expressionNode> Initializer InitializerNoIn
-%type <statementNode> FunctionDeclaration
-%type <funcExprNode> FunctionExpr
-%type <functionBodyNode> FunctionBody
-%type <sourceElements> SourceElements
-%type <parameterList> FormalParameterList
-%type <op> AssignmentOperator
-%type <argumentsNode> Arguments
-%type <argumentList> ArgumentList
-%type <varDeclList> VariableDeclarationList VariableDeclarationListNoIn
-%type <constDeclList> ConstDeclarationList
-%type <constDeclNode> ConstDeclaration
-%type <caseBlockNode> CaseBlock
-%type <caseClauseNode> CaseClause DefaultClause
-%type <clauseList> CaseClauses CaseClausesOpt
-%type <intValue> Elision ElisionOpt
-%type <elementList> ElementList
-%type <propertyNode> Property
-%type <propertyList> PropertyList
-%%
-
-// FIXME: There are currently two versions of the grammar in this file, the normal one, and the NoNodes version used for
-// lazy recompilation of FunctionBodyNodes. We should move to generating the two versions from a script to avoid bugs.
-// In the mean time, make sure to make any changes to the grammar in both versions.
-
-Literal:
- NULLTOKEN { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) NullNode(GLOBAL_DATA), 0, 1); }
- | TRUETOKEN { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) BooleanNode(GLOBAL_DATA, true), 0, 1); }
- | FALSETOKEN { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) BooleanNode(GLOBAL_DATA, false), 0, 1); }
- | NUMBER { $$ = createNodeInfo<ExpressionNode*>(makeNumberNode(GLOBAL_DATA, $1), 0, 1); }
- | STRING { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) StringNode(GLOBAL_DATA, *$1), 0, 1); }
- | '/' /* regexp */ {
- Lexer& l = *GLOBAL_DATA->lexer;
- const Identifier* pattern;
- const Identifier* flags;
- if (!l.scanRegExp(pattern, flags))
- YYABORT;
- RegExpNode* node = new (GLOBAL_DATA) RegExpNode(GLOBAL_DATA, *pattern, *flags);
- int size = pattern->size() + 2; // + 2 for the two /'s
- setExceptionLocation(node, @1.first_column, @1.first_column + size, @1.first_column + size);
- $$ = createNodeInfo<ExpressionNode*>(node, 0, 0);
- }
- | DIVEQUAL /* regexp with /= */ {
- Lexer& l = *GLOBAL_DATA->lexer;
- const Identifier* pattern;
- const Identifier* flags;
- if (!l.scanRegExp(pattern, flags, '='))
- YYABORT;
- RegExpNode* node = new (GLOBAL_DATA) RegExpNode(GLOBAL_DATA, *pattern, *flags);
- int size = pattern->size() + 2; // + 2 for the two /'s
- setExceptionLocation(node, @1.first_column, @1.first_column + size, @1.first_column + size);
- $$ = createNodeInfo<ExpressionNode*>(node, 0, 0);
- }
-;
-
-Property:
- IDENT ':' AssignmentExpr { $$ = createNodeInfo<PropertyNode*>(new (GLOBAL_DATA) PropertyNode(GLOBAL_DATA, *$1, $3.m_node, PropertyNode::Constant), $3.m_features, $3.m_numConstants); }
- | STRING ':' AssignmentExpr { $$ = createNodeInfo<PropertyNode*>(new (GLOBAL_DATA) PropertyNode(GLOBAL_DATA, *$1, $3.m_node, PropertyNode::Constant), $3.m_features, $3.m_numConstants); }
- | NUMBER ':' AssignmentExpr { $$ = createNodeInfo<PropertyNode*>(new (GLOBAL_DATA) PropertyNode(GLOBAL_DATA, $1, $3.m_node, PropertyNode::Constant), $3.m_features, $3.m_numConstants); }
- | IDENT IDENT '(' ')' OPENBRACE FunctionBody CLOSEBRACE { $$ = createNodeInfo<PropertyNode*>(makeGetterOrSetterPropertyNode(GLOBAL_DATA, *$1, *$2, 0, $6, GLOBAL_DATA->lexer->sourceCode($5, $7, @5.first_line)), ClosureFeature, 0); setStatementLocation($6, @5, @7); if (!$$.m_node) YYABORT; }
- | IDENT IDENT '(' FormalParameterList ')' OPENBRACE FunctionBody CLOSEBRACE
- {
- $$ = createNodeInfo<PropertyNode*>(makeGetterOrSetterPropertyNode(GLOBAL_DATA, *$1, *$2, $4.m_node.head, $7, GLOBAL_DATA->lexer->sourceCode($6, $8, @6.first_line)), $4.m_features | ClosureFeature, 0);
- if ($4.m_features & ArgumentsFeature)
- $7->setUsesArguments();
- setStatementLocation($7, @6, @8);
- if (!$$.m_node)
- YYABORT;
- }
-;
-
-PropertyList:
- Property { $$.m_node.head = new (GLOBAL_DATA) PropertyListNode(GLOBAL_DATA, $1.m_node);
- $$.m_node.tail = $$.m_node.head;
- $$.m_features = $1.m_features;
- $$.m_numConstants = $1.m_numConstants; }
- | PropertyList ',' Property { $$.m_node.head = $1.m_node.head;
- $$.m_node.tail = new (GLOBAL_DATA) PropertyListNode(GLOBAL_DATA, $3.m_node, $1.m_node.tail);
- $$.m_features = $1.m_features | $3.m_features;
- $$.m_numConstants = $1.m_numConstants + $3.m_numConstants; }
-;
-
-PrimaryExpr:
- PrimaryExprNoBrace
- | OPENBRACE CLOSEBRACE { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) ObjectLiteralNode(GLOBAL_DATA), 0, 0); }
- | OPENBRACE PropertyList CLOSEBRACE { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) ObjectLiteralNode(GLOBAL_DATA, $2.m_node.head), $2.m_features, $2.m_numConstants); }
- /* allow extra comma, see http://bugs.webkit.org/show_bug.cgi?id=5939 */
- | OPENBRACE PropertyList ',' CLOSEBRACE { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) ObjectLiteralNode(GLOBAL_DATA, $2.m_node.head), $2.m_features, $2.m_numConstants); }
-;
-
-PrimaryExprNoBrace:
- THISTOKEN { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) ThisNode(GLOBAL_DATA), ThisFeature, 0); }
- | Literal
- | ArrayLiteral
- | IDENT { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) ResolveNode(GLOBAL_DATA, *$1, @1.first_column), (*$1 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0, 0); }
- | '(' Expr ')' { $$ = $2; }
-;
-
-ArrayLiteral:
- '[' ElisionOpt ']' { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) ArrayNode(GLOBAL_DATA, $2), 0, $2 ? 1 : 0); }
- | '[' ElementList ']' { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) ArrayNode(GLOBAL_DATA, $2.m_node.head), $2.m_features, $2.m_numConstants); }
- | '[' ElementList ',' ElisionOpt ']' { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) ArrayNode(GLOBAL_DATA, $4, $2.m_node.head), $2.m_features, $4 ? $2.m_numConstants + 1 : $2.m_numConstants); }
-;
-
-ElementList:
- ElisionOpt AssignmentExpr { $$.m_node.head = new (GLOBAL_DATA) ElementNode(GLOBAL_DATA, $1, $2.m_node);
- $$.m_node.tail = $$.m_node.head;
- $$.m_features = $2.m_features;
- $$.m_numConstants = $2.m_numConstants; }
- | ElementList ',' ElisionOpt AssignmentExpr
- { $$.m_node.head = $1.m_node.head;
- $$.m_node.tail = new (GLOBAL_DATA) ElementNode(GLOBAL_DATA, $1.m_node.tail, $3, $4.m_node);
- $$.m_features = $1.m_features | $4.m_features;
- $$.m_numConstants = $1.m_numConstants + $4.m_numConstants; }
-;
-
-ElisionOpt:
- /* nothing */ { $$ = 0; }
- | Elision
-;
-
-Elision:
- ',' { $$ = 1; }
- | Elision ',' { $$ = $1 + 1; }
-;
-
-MemberExpr:
- PrimaryExpr
- | FunctionExpr { $$ = createNodeInfo<ExpressionNode*>($1.m_node, $1.m_features, $1.m_numConstants); }
- | MemberExpr '[' Expr ']' { BracketAccessorNode* node = new (GLOBAL_DATA) BracketAccessorNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature);
- setExceptionLocation(node, @1.first_column, @1.last_column, @4.last_column);
- $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants);
- }
- | MemberExpr '.' IDENT { DotAccessorNode* node = new (GLOBAL_DATA) DotAccessorNode(GLOBAL_DATA, $1.m_node, *$3);
- setExceptionLocation(node, @1.first_column, @1.last_column, @3.last_column);
- $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features, $1.m_numConstants);
- }
- | NEW MemberExpr Arguments { NewExprNode* node = new (GLOBAL_DATA) NewExprNode(GLOBAL_DATA, $2.m_node, $3.m_node);
- setExceptionLocation(node, @1.first_column, @2.last_column, @3.last_column);
- $$ = createNodeInfo<ExpressionNode*>(node, $2.m_features | $3.m_features, $2.m_numConstants + $3.m_numConstants);
- }
-;
-
-MemberExprNoBF:
- PrimaryExprNoBrace
- | MemberExprNoBF '[' Expr ']' { BracketAccessorNode* node = new (GLOBAL_DATA) BracketAccessorNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature);
- setExceptionLocation(node, @1.first_column, @1.last_column, @4.last_column);
- $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants);
- }
- | MemberExprNoBF '.' IDENT { DotAccessorNode* node = new (GLOBAL_DATA) DotAccessorNode(GLOBAL_DATA, $1.m_node, *$3);
- setExceptionLocation(node, @1.first_column, @1.last_column, @3.last_column);
- $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features, $1.m_numConstants);
- }
- | NEW MemberExpr Arguments { NewExprNode* node = new (GLOBAL_DATA) NewExprNode(GLOBAL_DATA, $2.m_node, $3.m_node);
- setExceptionLocation(node, @1.first_column, @2.last_column, @3.last_column);
- $$ = createNodeInfo<ExpressionNode*>(node, $2.m_features | $3.m_features, $2.m_numConstants + $3.m_numConstants);
- }
-;
-
-NewExpr:
- MemberExpr
- | NEW NewExpr { NewExprNode* node = new (GLOBAL_DATA) NewExprNode(GLOBAL_DATA, $2.m_node);
- setExceptionLocation(node, @1.first_column, @2.last_column, @2.last_column);
- $$ = createNodeInfo<ExpressionNode*>(node, $2.m_features, $2.m_numConstants);
- }
-;
-
-NewExprNoBF:
- MemberExprNoBF
- | NEW NewExpr { NewExprNode* node = new (GLOBAL_DATA) NewExprNode(GLOBAL_DATA, $2.m_node);
- setExceptionLocation(node, @1.first_column, @2.last_column, @2.last_column);
- $$ = createNodeInfo<ExpressionNode*>(node, $2.m_features, $2.m_numConstants);
- }
-;
-
-CallExpr:
- MemberExpr Arguments { $$ = makeFunctionCallNode(GLOBAL_DATA, $1, $2, @1.first_column, @1.last_column, @2.last_column); }
- | CallExpr Arguments { $$ = makeFunctionCallNode(GLOBAL_DATA, $1, $2, @1.first_column, @1.last_column, @2.last_column); }
- | CallExpr '[' Expr ']' { BracketAccessorNode* node = new (GLOBAL_DATA) BracketAccessorNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature);
- setExceptionLocation(node, @1.first_column, @1.last_column, @4.last_column);
- $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants);
- }
- | CallExpr '.' IDENT { DotAccessorNode* node = new (GLOBAL_DATA) DotAccessorNode(GLOBAL_DATA, $1.m_node, *$3);
- setExceptionLocation(node, @1.first_column, @1.last_column, @3.last_column);
- $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features, $1.m_numConstants); }
-;
-
-CallExprNoBF:
- MemberExprNoBF Arguments { $$ = makeFunctionCallNode(GLOBAL_DATA, $1, $2, @1.first_column, @1.last_column, @2.last_column); }
- | CallExprNoBF Arguments { $$ = makeFunctionCallNode(GLOBAL_DATA, $1, $2, @1.first_column, @1.last_column, @2.last_column); }
- | CallExprNoBF '[' Expr ']' { BracketAccessorNode* node = new (GLOBAL_DATA) BracketAccessorNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature);
- setExceptionLocation(node, @1.first_column, @1.last_column, @4.last_column);
- $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants);
- }
- | CallExprNoBF '.' IDENT { DotAccessorNode* node = new (GLOBAL_DATA) DotAccessorNode(GLOBAL_DATA, $1.m_node, *$3);
- setExceptionLocation(node, @1.first_column, @1.last_column, @3.last_column);
- $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features, $1.m_numConstants);
- }
-;
-
-Arguments:
- '(' ')' { $$ = createNodeInfo<ArgumentsNode*>(new (GLOBAL_DATA) ArgumentsNode(GLOBAL_DATA), 0, 0); }
- | '(' ArgumentList ')' { $$ = createNodeInfo<ArgumentsNode*>(new (GLOBAL_DATA) ArgumentsNode(GLOBAL_DATA, $2.m_node.head), $2.m_features, $2.m_numConstants); }
-;
-
-ArgumentList:
- AssignmentExpr { $$.m_node.head = new (GLOBAL_DATA) ArgumentListNode(GLOBAL_DATA, $1.m_node);
- $$.m_node.tail = $$.m_node.head;
- $$.m_features = $1.m_features;
- $$.m_numConstants = $1.m_numConstants; }
- | ArgumentList ',' AssignmentExpr { $$.m_node.head = $1.m_node.head;
- $$.m_node.tail = new (GLOBAL_DATA) ArgumentListNode(GLOBAL_DATA, $1.m_node.tail, $3.m_node);
- $$.m_features = $1.m_features | $3.m_features;
- $$.m_numConstants = $1.m_numConstants + $3.m_numConstants; }
-;
-
-LeftHandSideExpr:
- NewExpr
- | CallExpr
-;
-
-LeftHandSideExprNoBF:
- NewExprNoBF
- | CallExprNoBF
-;
-
-PostfixExpr:
- LeftHandSideExpr
- | LeftHandSideExpr PLUSPLUS { $$ = createNodeInfo<ExpressionNode*>(makePostfixNode(GLOBAL_DATA, $1.m_node, OpPlusPlus, @1.first_column, @1.last_column, @2.last_column), $1.m_features | AssignFeature, $1.m_numConstants); }
- | LeftHandSideExpr MINUSMINUS { $$ = createNodeInfo<ExpressionNode*>(makePostfixNode(GLOBAL_DATA, $1.m_node, OpMinusMinus, @1.first_column, @1.last_column, @2.last_column), $1.m_features | AssignFeature, $1.m_numConstants); }
-;
-
-PostfixExprNoBF:
- LeftHandSideExprNoBF
- | LeftHandSideExprNoBF PLUSPLUS { $$ = createNodeInfo<ExpressionNode*>(makePostfixNode(GLOBAL_DATA, $1.m_node, OpPlusPlus, @1.first_column, @1.last_column, @2.last_column), $1.m_features | AssignFeature, $1.m_numConstants); }
- | LeftHandSideExprNoBF MINUSMINUS { $$ = createNodeInfo<ExpressionNode*>(makePostfixNode(GLOBAL_DATA, $1.m_node, OpMinusMinus, @1.first_column, @1.last_column, @2.last_column), $1.m_features | AssignFeature, $1.m_numConstants); }
-;
-
-UnaryExprCommon:
- DELETETOKEN UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(makeDeleteNode(GLOBAL_DATA, $2.m_node, @1.first_column, @2.last_column, @2.last_column), $2.m_features, $2.m_numConstants); }
- | VOIDTOKEN UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) VoidNode(GLOBAL_DATA, $2.m_node), $2.m_features, $2.m_numConstants + 1); }
- | TYPEOF UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(makeTypeOfNode(GLOBAL_DATA, $2.m_node), $2.m_features, $2.m_numConstants); }
- | PLUSPLUS UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(makePrefixNode(GLOBAL_DATA, $2.m_node, OpPlusPlus, @1.first_column, @2.first_column + 1, @2.last_column), $2.m_features | AssignFeature, $2.m_numConstants); }
- | AUTOPLUSPLUS UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(makePrefixNode(GLOBAL_DATA, $2.m_node, OpPlusPlus, @1.first_column, @2.first_column + 1, @2.last_column), $2.m_features | AssignFeature, $2.m_numConstants); }
- | MINUSMINUS UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(makePrefixNode(GLOBAL_DATA, $2.m_node, OpMinusMinus, @1.first_column, @2.first_column + 1, @2.last_column), $2.m_features | AssignFeature, $2.m_numConstants); }
- | AUTOMINUSMINUS UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(makePrefixNode(GLOBAL_DATA, $2.m_node, OpMinusMinus, @1.first_column, @2.first_column + 1, @2.last_column), $2.m_features | AssignFeature, $2.m_numConstants); }
- | '+' UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) UnaryPlusNode(GLOBAL_DATA, $2.m_node), $2.m_features, $2.m_numConstants); }
- | '-' UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(makeNegateNode(GLOBAL_DATA, $2.m_node), $2.m_features, $2.m_numConstants); }
- | '~' UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(makeBitwiseNotNode(GLOBAL_DATA, $2.m_node), $2.m_features, $2.m_numConstants); }
- | '!' UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) LogicalNotNode(GLOBAL_DATA, $2.m_node), $2.m_features, $2.m_numConstants); }
-
-UnaryExpr:
- PostfixExpr
- | UnaryExprCommon
-;
-
-UnaryExprNoBF:
- PostfixExprNoBF
- | UnaryExprCommon
-;
-
-MultiplicativeExpr:
- UnaryExpr
- | MultiplicativeExpr '*' UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(makeMultNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
- | MultiplicativeExpr '/' UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(makeDivNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
- | MultiplicativeExpr '%' UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) ModNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
-;
-
-MultiplicativeExprNoBF:
- UnaryExprNoBF
- | MultiplicativeExprNoBF '*' UnaryExpr
- { $$ = createNodeInfo<ExpressionNode*>(makeMultNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
- | MultiplicativeExprNoBF '/' UnaryExpr
- { $$ = createNodeInfo<ExpressionNode*>(makeDivNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
- | MultiplicativeExprNoBF '%' UnaryExpr
- { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) ModNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
-;
-
-AdditiveExpr:
- MultiplicativeExpr
- | AdditiveExpr '+' MultiplicativeExpr { $$ = createNodeInfo<ExpressionNode*>(makeAddNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
- | AdditiveExpr '-' MultiplicativeExpr { $$ = createNodeInfo<ExpressionNode*>(makeSubNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
-;
-
-AdditiveExprNoBF:
- MultiplicativeExprNoBF
- | AdditiveExprNoBF '+' MultiplicativeExpr
- { $$ = createNodeInfo<ExpressionNode*>(makeAddNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
- | AdditiveExprNoBF '-' MultiplicativeExpr
- { $$ = createNodeInfo<ExpressionNode*>(makeSubNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
-;
-
-ShiftExpr:
- AdditiveExpr
- | ShiftExpr LSHIFT AdditiveExpr { $$ = createNodeInfo<ExpressionNode*>(makeLeftShiftNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
- | ShiftExpr RSHIFT AdditiveExpr { $$ = createNodeInfo<ExpressionNode*>(makeRightShiftNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
- | ShiftExpr URSHIFT AdditiveExpr { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) UnsignedRightShiftNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
-;
-
-ShiftExprNoBF:
- AdditiveExprNoBF
- | ShiftExprNoBF LSHIFT AdditiveExpr { $$ = createNodeInfo<ExpressionNode*>(makeLeftShiftNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
- | ShiftExprNoBF RSHIFT AdditiveExpr { $$ = createNodeInfo<ExpressionNode*>(makeRightShiftNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
- | ShiftExprNoBF URSHIFT AdditiveExpr { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) UnsignedRightShiftNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
-;
-
-RelationalExpr:
- ShiftExpr
- | RelationalExpr '<' ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) LessNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
- | RelationalExpr '>' ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) GreaterNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
- | RelationalExpr LE ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) LessEqNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
- | RelationalExpr GE ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) GreaterEqNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
- | RelationalExpr INSTANCEOF ShiftExpr { InstanceOfNode* node = new (GLOBAL_DATA) InstanceOfNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature);
- setExceptionLocation(node, @1.first_column, @3.first_column, @3.last_column);
- $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
- | RelationalExpr INTOKEN ShiftExpr { InNode* node = new (GLOBAL_DATA) InNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature);
- setExceptionLocation(node, @1.first_column, @3.first_column, @3.last_column);
- $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
-;
-
-RelationalExprNoIn:
- ShiftExpr
- | RelationalExprNoIn '<' ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) LessNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
- | RelationalExprNoIn '>' ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) GreaterNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
- | RelationalExprNoIn LE ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) LessEqNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
- | RelationalExprNoIn GE ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) GreaterEqNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
- | RelationalExprNoIn INSTANCEOF ShiftExpr
- { InstanceOfNode* node = new (GLOBAL_DATA) InstanceOfNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature);
- setExceptionLocation(node, @1.first_column, @3.first_column, @3.last_column);
- $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
-;
-
-RelationalExprNoBF:
- ShiftExprNoBF
- | RelationalExprNoBF '<' ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) LessNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
- | RelationalExprNoBF '>' ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) GreaterNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
- | RelationalExprNoBF LE ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) LessEqNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
- | RelationalExprNoBF GE ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) GreaterEqNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
- | RelationalExprNoBF INSTANCEOF ShiftExpr
- { InstanceOfNode* node = new (GLOBAL_DATA) InstanceOfNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature);
- setExceptionLocation(node, @1.first_column, @3.first_column, @3.last_column);
- $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
- | RelationalExprNoBF INTOKEN ShiftExpr
- { InNode* node = new (GLOBAL_DATA) InNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature);
- setExceptionLocation(node, @1.first_column, @3.first_column, @3.last_column);
- $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
-;
-
-EqualityExpr:
- RelationalExpr
- | EqualityExpr EQEQ RelationalExpr { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) EqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
- | EqualityExpr NE RelationalExpr { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) NotEqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
- | EqualityExpr STREQ RelationalExpr { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) StrictEqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
- | EqualityExpr STRNEQ RelationalExpr { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) NotStrictEqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
-;
-
-EqualityExprNoIn:
- RelationalExprNoIn
- | EqualityExprNoIn EQEQ RelationalExprNoIn
- { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) EqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
- | EqualityExprNoIn NE RelationalExprNoIn
- { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) NotEqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
- | EqualityExprNoIn STREQ RelationalExprNoIn
- { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) StrictEqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
- | EqualityExprNoIn STRNEQ RelationalExprNoIn
- { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) NotStrictEqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
-;
-
-EqualityExprNoBF:
- RelationalExprNoBF
- | EqualityExprNoBF EQEQ RelationalExpr
- { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) EqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
- | EqualityExprNoBF NE RelationalExpr { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) NotEqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
- | EqualityExprNoBF STREQ RelationalExpr
- { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) StrictEqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
- | EqualityExprNoBF STRNEQ RelationalExpr
- { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) NotStrictEqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
-;
-
-BitwiseANDExpr:
- EqualityExpr
- | BitwiseANDExpr '&' EqualityExpr { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) BitAndNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
-;
-
-BitwiseANDExprNoIn:
- EqualityExprNoIn
- | BitwiseANDExprNoIn '&' EqualityExprNoIn
- { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) BitAndNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
-;
-
-BitwiseANDExprNoBF:
- EqualityExprNoBF
- | BitwiseANDExprNoBF '&' EqualityExpr { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) BitAndNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
-;
-
-BitwiseXORExpr:
- BitwiseANDExpr
- | BitwiseXORExpr '^' BitwiseANDExpr { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) BitXOrNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
-;
-
-BitwiseXORExprNoIn:
- BitwiseANDExprNoIn
- | BitwiseXORExprNoIn '^' BitwiseANDExprNoIn
- { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) BitXOrNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
-;
-
-BitwiseXORExprNoBF:
- BitwiseANDExprNoBF
- | BitwiseXORExprNoBF '^' BitwiseANDExpr
- { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) BitXOrNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
-;
-
-BitwiseORExpr:
- BitwiseXORExpr
- | BitwiseORExpr '|' BitwiseXORExpr { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) BitOrNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
-;
-
-BitwiseORExprNoIn:
- BitwiseXORExprNoIn
- | BitwiseORExprNoIn '|' BitwiseXORExprNoIn
- { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) BitOrNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
-;
-
-BitwiseORExprNoBF:
- BitwiseXORExprNoBF
- | BitwiseORExprNoBF '|' BitwiseXORExpr
- { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) BitOrNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
-;
-
-LogicalANDExpr:
- BitwiseORExpr
- | LogicalANDExpr AND BitwiseORExpr { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) LogicalOpNode(GLOBAL_DATA, $1.m_node, $3.m_node, OpLogicalAnd), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
-;
-
-LogicalANDExprNoIn:
- BitwiseORExprNoIn
- | LogicalANDExprNoIn AND BitwiseORExprNoIn
- { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) LogicalOpNode(GLOBAL_DATA, $1.m_node, $3.m_node, OpLogicalAnd), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
-;
-
-LogicalANDExprNoBF:
- BitwiseORExprNoBF
- | LogicalANDExprNoBF AND BitwiseORExpr
- { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) LogicalOpNode(GLOBAL_DATA, $1.m_node, $3.m_node, OpLogicalAnd), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
-;
-
-LogicalORExpr:
- LogicalANDExpr
- | LogicalORExpr OR LogicalANDExpr { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) LogicalOpNode(GLOBAL_DATA, $1.m_node, $3.m_node, OpLogicalOr), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
-;
-
-LogicalORExprNoIn:
- LogicalANDExprNoIn
- | LogicalORExprNoIn OR LogicalANDExprNoIn
- { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) LogicalOpNode(GLOBAL_DATA, $1.m_node, $3.m_node, OpLogicalOr), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
-;
-
-LogicalORExprNoBF:
- LogicalANDExprNoBF
- | LogicalORExprNoBF OR LogicalANDExpr { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) LogicalOpNode(GLOBAL_DATA, $1.m_node, $3.m_node, OpLogicalOr), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
-;
-
-ConditionalExpr:
- LogicalORExpr
- | LogicalORExpr '?' AssignmentExpr ':' AssignmentExpr
- { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) ConditionalNode(GLOBAL_DATA, $1.m_node, $3.m_node, $5.m_node), $1.m_features | $3.m_features | $5.m_features, $1.m_numConstants + $3.m_numConstants + $5.m_numConstants); }
-;
-
-ConditionalExprNoIn:
- LogicalORExprNoIn
- | LogicalORExprNoIn '?' AssignmentExprNoIn ':' AssignmentExprNoIn
- { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) ConditionalNode(GLOBAL_DATA, $1.m_node, $3.m_node, $5.m_node), $1.m_features | $3.m_features | $5.m_features, $1.m_numConstants + $3.m_numConstants + $5.m_numConstants); }
-;
-
-ConditionalExprNoBF:
- LogicalORExprNoBF
- | LogicalORExprNoBF '?' AssignmentExpr ':' AssignmentExpr
- { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) ConditionalNode(GLOBAL_DATA, $1.m_node, $3.m_node, $5.m_node), $1.m_features | $3.m_features | $5.m_features, $1.m_numConstants + $3.m_numConstants + $5.m_numConstants); }
-;
-
-AssignmentExpr:
- ConditionalExpr
- | LeftHandSideExpr AssignmentOperator AssignmentExpr
- { $$ = createNodeInfo<ExpressionNode*>(makeAssignNode(GLOBAL_DATA, $1.m_node, $2, $3.m_node, $1.m_features & AssignFeature, $3.m_features & AssignFeature,
- @1.first_column, @2.first_column + 1, @3.last_column), $1.m_features | $3.m_features | AssignFeature, $1.m_numConstants + $3.m_numConstants);
- }
-;
-
-AssignmentExprNoIn:
- ConditionalExprNoIn
- | LeftHandSideExpr AssignmentOperator AssignmentExprNoIn
- { $$ = createNodeInfo<ExpressionNode*>(makeAssignNode(GLOBAL_DATA, $1.m_node, $2, $3.m_node, $1.m_features & AssignFeature, $3.m_features & AssignFeature,
- @1.first_column, @2.first_column + 1, @3.last_column), $1.m_features | $3.m_features | AssignFeature, $1.m_numConstants + $3.m_numConstants);
- }
-;
-
-AssignmentExprNoBF:
- ConditionalExprNoBF
- | LeftHandSideExprNoBF AssignmentOperator AssignmentExpr
- { $$ = createNodeInfo<ExpressionNode*>(makeAssignNode(GLOBAL_DATA, $1.m_node, $2, $3.m_node, $1.m_features & AssignFeature, $3.m_features & AssignFeature,
- @1.first_column, @2.first_column + 1, @3.last_column), $1.m_features | $3.m_features | AssignFeature, $1.m_numConstants + $3.m_numConstants);
- }
-;
-
-AssignmentOperator:
- '=' { $$ = OpEqual; }
- | PLUSEQUAL { $$ = OpPlusEq; }
- | MINUSEQUAL { $$ = OpMinusEq; }
- | MULTEQUAL { $$ = OpMultEq; }
- | DIVEQUAL { $$ = OpDivEq; }
- | LSHIFTEQUAL { $$ = OpLShift; }
- | RSHIFTEQUAL { $$ = OpRShift; }
- | URSHIFTEQUAL { $$ = OpURShift; }
- | ANDEQUAL { $$ = OpAndEq; }
- | XOREQUAL { $$ = OpXOrEq; }
- | OREQUAL { $$ = OpOrEq; }
- | MODEQUAL { $$ = OpModEq; }
-;
-
-Expr:
- AssignmentExpr
- | Expr ',' AssignmentExpr { $$ = createNodeInfo<ExpressionNode*>(combineCommaNodes(GLOBAL_DATA, $1.m_node, $3.m_node), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
-;
-
-ExprNoIn:
- AssignmentExprNoIn
- | ExprNoIn ',' AssignmentExprNoIn { $$ = createNodeInfo<ExpressionNode*>(combineCommaNodes(GLOBAL_DATA, $1.m_node, $3.m_node), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
-;
-
-ExprNoBF:
- AssignmentExprNoBF
- | ExprNoBF ',' AssignmentExpr { $$ = createNodeInfo<ExpressionNode*>(combineCommaNodes(GLOBAL_DATA, $1.m_node, $3.m_node), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
-;
-
-Statement:
- Block
- | VariableStatement
- | ConstStatement
- | FunctionDeclaration
- | EmptyStatement
- | ExprStatement
- | IfStatement
- | IterationStatement
- | ContinueStatement
- | BreakStatement
- | ReturnStatement
- | WithStatement
- | SwitchStatement
- | LabelledStatement
- | ThrowStatement
- | TryStatement
- | DebuggerStatement
-;
-
-Block:
- OPENBRACE CLOSEBRACE { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) BlockNode(GLOBAL_DATA, 0), 0, 0, 0, 0);
- setStatementLocation($$.m_node, @1, @2); }
- | OPENBRACE SourceElements CLOSEBRACE { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) BlockNode(GLOBAL_DATA, $2.m_node), $2.m_varDeclarations, $2.m_funcDeclarations, $2.m_features, $2.m_numConstants);
- setStatementLocation($$.m_node, @1, @3); }
-;
-
-VariableStatement:
- VAR VariableDeclarationList ';' { $$ = createNodeDeclarationInfo<StatementNode*>(makeVarStatementNode(GLOBAL_DATA, $2.m_node), $2.m_varDeclarations, $2.m_funcDeclarations, $2.m_features, $2.m_numConstants);
- setStatementLocation($$.m_node, @1, @3); }
- | VAR VariableDeclarationList error { $$ = createNodeDeclarationInfo<StatementNode*>(makeVarStatementNode(GLOBAL_DATA, $2.m_node), $2.m_varDeclarations, $2.m_funcDeclarations, $2.m_features, $2.m_numConstants);
- setStatementLocation($$.m_node, @1, @2);
- AUTO_SEMICOLON; }
-;
-
-VariableDeclarationList:
- IDENT { $$.m_node = 0;
- $$.m_varDeclarations = new (GLOBAL_DATA) ParserArenaData<DeclarationStacks::VarStack>;
- appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, *$1, 0);
- $$.m_funcDeclarations = 0;
- $$.m_features = (*$1 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0;
- $$.m_numConstants = 0;
- }
- | IDENT Initializer { AssignResolveNode* node = new (GLOBAL_DATA) AssignResolveNode(GLOBAL_DATA, *$1, $2.m_node, $2.m_features & AssignFeature);
- setExceptionLocation(node, @1.first_column, @2.first_column + 1, @2.last_column);
- $$.m_node = node;
- $$.m_varDeclarations = new (GLOBAL_DATA) ParserArenaData<DeclarationStacks::VarStack>;
- appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, *$1, DeclarationStacks::HasInitializer);
- $$.m_funcDeclarations = 0;
- $$.m_features = ((*$1 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | $2.m_features;
- $$.m_numConstants = $2.m_numConstants;
- }
- | VariableDeclarationList ',' IDENT
- { $$.m_node = $1.m_node;
- $$.m_varDeclarations = $1.m_varDeclarations;
- appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, *$3, 0);
- $$.m_funcDeclarations = 0;
- $$.m_features = $1.m_features | ((*$3 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0);
- $$.m_numConstants = $1.m_numConstants;
- }
- | VariableDeclarationList ',' IDENT Initializer
- { AssignResolveNode* node = new (GLOBAL_DATA) AssignResolveNode(GLOBAL_DATA, *$3, $4.m_node, $4.m_features & AssignFeature);
- setExceptionLocation(node, @3.first_column, @4.first_column + 1, @4.last_column);
- $$.m_node = combineCommaNodes(GLOBAL_DATA, $1.m_node, node);
- $$.m_varDeclarations = $1.m_varDeclarations;
- appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, *$3, DeclarationStacks::HasInitializer);
- $$.m_funcDeclarations = 0;
- $$.m_features = $1.m_features | ((*$3 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | $4.m_features;
- $$.m_numConstants = $1.m_numConstants + $4.m_numConstants;
- }
-;
-
-VariableDeclarationListNoIn:
- IDENT { $$.m_node = 0;
- $$.m_varDeclarations = new (GLOBAL_DATA) ParserArenaData<DeclarationStacks::VarStack>;
- appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, *$1, 0);
- $$.m_funcDeclarations = 0;
- $$.m_features = (*$1 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0;
- $$.m_numConstants = 0;
- }
- | IDENT InitializerNoIn { AssignResolveNode* node = new (GLOBAL_DATA) AssignResolveNode(GLOBAL_DATA, *$1, $2.m_node, $2.m_features & AssignFeature);
- setExceptionLocation(node, @1.first_column, @2.first_column + 1, @2.last_column);
- $$.m_node = node;
- $$.m_varDeclarations = new (GLOBAL_DATA) ParserArenaData<DeclarationStacks::VarStack>;
- appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, *$1, DeclarationStacks::HasInitializer);
- $$.m_funcDeclarations = 0;
- $$.m_features = ((*$1 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | $2.m_features;
- $$.m_numConstants = $2.m_numConstants;
- }
- | VariableDeclarationListNoIn ',' IDENT
- { $$.m_node = $1.m_node;
- $$.m_varDeclarations = $1.m_varDeclarations;
- appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, *$3, 0);
- $$.m_funcDeclarations = 0;
- $$.m_features = $1.m_features | ((*$3 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0);
- $$.m_numConstants = $1.m_numConstants;
- }
- | VariableDeclarationListNoIn ',' IDENT InitializerNoIn
- { AssignResolveNode* node = new (GLOBAL_DATA) AssignResolveNode(GLOBAL_DATA, *$3, $4.m_node, $4.m_features & AssignFeature);
- setExceptionLocation(node, @3.first_column, @4.first_column + 1, @4.last_column);
- $$.m_node = combineCommaNodes(GLOBAL_DATA, $1.m_node, node);
- $$.m_varDeclarations = $1.m_varDeclarations;
- appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, *$3, DeclarationStacks::HasInitializer);
- $$.m_funcDeclarations = 0;
- $$.m_features = $1.m_features | ((*$3 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | $4.m_features;
- $$.m_numConstants = $1.m_numConstants + $4.m_numConstants;
- }
-;
-
-ConstStatement:
- CONSTTOKEN ConstDeclarationList ';' { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) ConstStatementNode(GLOBAL_DATA, $2.m_node.head), $2.m_varDeclarations, $2.m_funcDeclarations, $2.m_features, $2.m_numConstants);
- setStatementLocation($$.m_node, @1, @3); }
- | CONSTTOKEN ConstDeclarationList error
- { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) ConstStatementNode(GLOBAL_DATA, $2.m_node.head), $2.m_varDeclarations, $2.m_funcDeclarations, $2.m_features, $2.m_numConstants);
- setStatementLocation($$.m_node, @1, @2); AUTO_SEMICOLON; }
-;
-
-ConstDeclarationList:
- ConstDeclaration { $$.m_node.head = $1.m_node;
- $$.m_node.tail = $$.m_node.head;
- $$.m_varDeclarations = new (GLOBAL_DATA) ParserArenaData<DeclarationStacks::VarStack>;
- appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, $1.m_node);
- $$.m_funcDeclarations = 0;
- $$.m_features = $1.m_features;
- $$.m_numConstants = $1.m_numConstants;
- }
- | ConstDeclarationList ',' ConstDeclaration
- { $$.m_node.head = $1.m_node.head;
- $1.m_node.tail->m_next = $3.m_node;
- $$.m_node.tail = $3.m_node;
- $$.m_varDeclarations = $1.m_varDeclarations;
- appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, $3.m_node);
- $$.m_funcDeclarations = 0;
- $$.m_features = $1.m_features | $3.m_features;
- $$.m_numConstants = $1.m_numConstants + $3.m_numConstants; }
-;
-
-ConstDeclaration:
- IDENT { $$ = createNodeInfo<ConstDeclNode*>(new (GLOBAL_DATA) ConstDeclNode(GLOBAL_DATA, *$1, 0), (*$1 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0, 0); }
- | IDENT Initializer { $$ = createNodeInfo<ConstDeclNode*>(new (GLOBAL_DATA) ConstDeclNode(GLOBAL_DATA, *$1, $2.m_node), ((*$1 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | $2.m_features, $2.m_numConstants); }
-;
-
-Initializer:
- '=' AssignmentExpr { $$ = $2; }
-;
-
-InitializerNoIn:
- '=' AssignmentExprNoIn { $$ = $2; }
-;
-
-EmptyStatement:
- ';' { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) EmptyStatementNode(GLOBAL_DATA), 0, 0, 0, 0); }
-;
-
-ExprStatement:
- ExprNoBF ';' { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) ExprStatementNode(GLOBAL_DATA, $1.m_node), 0, 0, $1.m_features, $1.m_numConstants);
- setStatementLocation($$.m_node, @1, @2); }
- | ExprNoBF error { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) ExprStatementNode(GLOBAL_DATA, $1.m_node), 0, 0, $1.m_features, $1.m_numConstants);
- setStatementLocation($$.m_node, @1, @1); AUTO_SEMICOLON; }
-;
-
-IfStatement:
- IF '(' Expr ')' Statement %prec IF_WITHOUT_ELSE
- { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) IfNode(GLOBAL_DATA, $3.m_node, $5.m_node), $5.m_varDeclarations, $5.m_funcDeclarations, $3.m_features | $5.m_features, $3.m_numConstants + $5.m_numConstants);
- setStatementLocation($$.m_node, @1, @4); }
- | IF '(' Expr ')' Statement ELSE Statement
- { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) IfElseNode(GLOBAL_DATA, $3.m_node, $5.m_node, $7.m_node),
- mergeDeclarationLists($5.m_varDeclarations, $7.m_varDeclarations),
- mergeDeclarationLists($5.m_funcDeclarations, $7.m_funcDeclarations),
- $3.m_features | $5.m_features | $7.m_features,
- $3.m_numConstants + $5.m_numConstants + $7.m_numConstants);
- setStatementLocation($$.m_node, @1, @4); }
-;
-
-IterationStatement:
- DO Statement WHILE '(' Expr ')' ';' { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) DoWhileNode(GLOBAL_DATA, $2.m_node, $5.m_node), $2.m_varDeclarations, $2.m_funcDeclarations, $2.m_features | $5.m_features, $2.m_numConstants + $5.m_numConstants);
- setStatementLocation($$.m_node, @1, @3); }
- | DO Statement WHILE '(' Expr ')' error { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) DoWhileNode(GLOBAL_DATA, $2.m_node, $5.m_node), $2.m_varDeclarations, $2.m_funcDeclarations, $2.m_features | $5.m_features, $2.m_numConstants + $5.m_numConstants);
- setStatementLocation($$.m_node, @1, @3); } // Always performs automatic semicolon insertion.
- | WHILE '(' Expr ')' Statement { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) WhileNode(GLOBAL_DATA, $3.m_node, $5.m_node), $5.m_varDeclarations, $5.m_funcDeclarations, $3.m_features | $5.m_features, $3.m_numConstants + $5.m_numConstants);
- setStatementLocation($$.m_node, @1, @4); }
- | FOR '(' ExprNoInOpt ';' ExprOpt ';' ExprOpt ')' Statement
- { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) ForNode(GLOBAL_DATA, $3.m_node, $5.m_node, $7.m_node, $9.m_node, false), $9.m_varDeclarations, $9.m_funcDeclarations,
- $3.m_features | $5.m_features | $7.m_features | $9.m_features,
- $3.m_numConstants + $5.m_numConstants + $7.m_numConstants + $9.m_numConstants);
- setStatementLocation($$.m_node, @1, @8);
- }
- | FOR '(' VAR VariableDeclarationListNoIn ';' ExprOpt ';' ExprOpt ')' Statement
- { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) ForNode(GLOBAL_DATA, $4.m_node, $6.m_node, $8.m_node, $10.m_node, true),
- mergeDeclarationLists($4.m_varDeclarations, $10.m_varDeclarations),
- mergeDeclarationLists($4.m_funcDeclarations, $10.m_funcDeclarations),
- $4.m_features | $6.m_features | $8.m_features | $10.m_features,
- $4.m_numConstants + $6.m_numConstants + $8.m_numConstants + $10.m_numConstants);
- setStatementLocation($$.m_node, @1, @9); }
- | FOR '(' LeftHandSideExpr INTOKEN Expr ')' Statement
- {
- ForInNode* node = new (GLOBAL_DATA) ForInNode(GLOBAL_DATA, $3.m_node, $5.m_node, $7.m_node);
- setExceptionLocation(node, @3.first_column, @3.last_column, @5.last_column);
- $$ = createNodeDeclarationInfo<StatementNode*>(node, $7.m_varDeclarations, $7.m_funcDeclarations,
- $3.m_features | $5.m_features | $7.m_features,
- $3.m_numConstants + $5.m_numConstants + $7.m_numConstants);
- setStatementLocation($$.m_node, @1, @6);
- }
- | FOR '(' VAR IDENT INTOKEN Expr ')' Statement
- { ForInNode *forIn = new (GLOBAL_DATA) ForInNode(GLOBAL_DATA, *$4, 0, $6.m_node, $8.m_node, @5.first_column, @5.first_column - @4.first_column, @6.last_column - @5.first_column);
- setExceptionLocation(forIn, @4.first_column, @5.first_column + 1, @6.last_column);
- appendToVarDeclarationList(GLOBAL_DATA, $8.m_varDeclarations, *$4, DeclarationStacks::HasInitializer);
- $$ = createNodeDeclarationInfo<StatementNode*>(forIn, $8.m_varDeclarations, $8.m_funcDeclarations, ((*$4 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | $6.m_features | $8.m_features, $6.m_numConstants + $8.m_numConstants);
- setStatementLocation($$.m_node, @1, @7); }
- | FOR '(' VAR IDENT InitializerNoIn INTOKEN Expr ')' Statement
- { ForInNode *forIn = new (GLOBAL_DATA) ForInNode(GLOBAL_DATA, *$4, $5.m_node, $7.m_node, $9.m_node, @5.first_column, @5.first_column - @4.first_column, @5.last_column - @5.first_column);
- setExceptionLocation(forIn, @4.first_column, @6.first_column + 1, @7.last_column);
- appendToVarDeclarationList(GLOBAL_DATA, $9.m_varDeclarations, *$4, DeclarationStacks::HasInitializer);
- $$ = createNodeDeclarationInfo<StatementNode*>(forIn, $9.m_varDeclarations, $9.m_funcDeclarations,
- ((*$4 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | $5.m_features | $7.m_features | $9.m_features,
- $5.m_numConstants + $7.m_numConstants + $9.m_numConstants);
- setStatementLocation($$.m_node, @1, @8); }
-;
-
-ExprOpt:
- /* nothing */ { $$ = createNodeInfo<ExpressionNode*>(0, 0, 0); }
- | Expr
-;
-
-ExprNoInOpt:
- /* nothing */ { $$ = createNodeInfo<ExpressionNode*>(0, 0, 0); }
- | ExprNoIn
-;
-
-ContinueStatement:
- CONTINUE ';' { ContinueNode* node = new (GLOBAL_DATA) ContinueNode(GLOBAL_DATA);
- setExceptionLocation(node, @1.first_column, @1.last_column, @1.last_column);
- $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0, 0);
- setStatementLocation($$.m_node, @1, @2); }
- | CONTINUE error { ContinueNode* node = new (GLOBAL_DATA) ContinueNode(GLOBAL_DATA);
- setExceptionLocation(node, @1.first_column, @1.last_column, @1.last_column);
- $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0, 0);
- setStatementLocation($$.m_node, @1, @1); AUTO_SEMICOLON; }
- | CONTINUE IDENT ';' { ContinueNode* node = new (GLOBAL_DATA) ContinueNode(GLOBAL_DATA, *$2);
- setExceptionLocation(node, @1.first_column, @2.last_column, @2.last_column);
- $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0, 0);
- setStatementLocation($$.m_node, @1, @3); }
- | CONTINUE IDENT error { ContinueNode* node = new (GLOBAL_DATA) ContinueNode(GLOBAL_DATA, *$2);
- setExceptionLocation(node, @1.first_column, @2.last_column, @2.last_column);
- $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0, 0);
- setStatementLocation($$.m_node, @1, @2); AUTO_SEMICOLON; }
-;
-
-BreakStatement:
- BREAK ';' { BreakNode* node = new (GLOBAL_DATA) BreakNode(GLOBAL_DATA);
- setExceptionLocation(node, @1.first_column, @1.last_column, @1.last_column);
- $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0, 0); setStatementLocation($$.m_node, @1, @2); }
- | BREAK error { BreakNode* node = new (GLOBAL_DATA) BreakNode(GLOBAL_DATA);
- setExceptionLocation(node, @1.first_column, @1.last_column, @1.last_column);
- $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) BreakNode(GLOBAL_DATA), 0, 0, 0, 0); setStatementLocation($$.m_node, @1, @1); AUTO_SEMICOLON; }
- | BREAK IDENT ';' { BreakNode* node = new (GLOBAL_DATA) BreakNode(GLOBAL_DATA, *$2);
- setExceptionLocation(node, @1.first_column, @2.last_column, @2.last_column);
- $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0, 0); setStatementLocation($$.m_node, @1, @3); }
- | BREAK IDENT error { BreakNode* node = new (GLOBAL_DATA) BreakNode(GLOBAL_DATA, *$2);
- setExceptionLocation(node, @1.first_column, @2.last_column, @2.last_column);
- $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) BreakNode(GLOBAL_DATA, *$2), 0, 0, 0, 0); setStatementLocation($$.m_node, @1, @2); AUTO_SEMICOLON; }
-;
-
-ReturnStatement:
- RETURN ';' { ReturnNode* node = new (GLOBAL_DATA) ReturnNode(GLOBAL_DATA, 0);
- setExceptionLocation(node, @1.first_column, @1.last_column, @1.last_column);
- $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0, 0); setStatementLocation($$.m_node, @1, @2); }
- | RETURN error { ReturnNode* node = new (GLOBAL_DATA) ReturnNode(GLOBAL_DATA, 0);
- setExceptionLocation(node, @1.first_column, @1.last_column, @1.last_column);
- $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0, 0); setStatementLocation($$.m_node, @1, @1); AUTO_SEMICOLON; }
- | RETURN Expr ';' { ReturnNode* node = new (GLOBAL_DATA) ReturnNode(GLOBAL_DATA, $2.m_node);
- setExceptionLocation(node, @1.first_column, @2.last_column, @2.last_column);
- $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, $2.m_features, $2.m_numConstants); setStatementLocation($$.m_node, @1, @3); }
- | RETURN Expr error { ReturnNode* node = new (GLOBAL_DATA) ReturnNode(GLOBAL_DATA, $2.m_node);
- setExceptionLocation(node, @1.first_column, @2.last_column, @2.last_column);
- $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, $2.m_features, $2.m_numConstants); setStatementLocation($$.m_node, @1, @2); AUTO_SEMICOLON; }
-;
-
-WithStatement:
- WITH '(' Expr ')' Statement { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) WithNode(GLOBAL_DATA, $3.m_node, $5.m_node, @3.last_column, @3.last_column - @3.first_column),
- $5.m_varDeclarations, $5.m_funcDeclarations, $3.m_features | $5.m_features | WithFeature, $3.m_numConstants + $5.m_numConstants);
- setStatementLocation($$.m_node, @1, @4); }
-;
-
-SwitchStatement:
- SWITCH '(' Expr ')' CaseBlock { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) SwitchNode(GLOBAL_DATA, $3.m_node, $5.m_node), $5.m_varDeclarations, $5.m_funcDeclarations,
- $3.m_features | $5.m_features, $3.m_numConstants + $5.m_numConstants);
- setStatementLocation($$.m_node, @1, @4); }
-;
-
-CaseBlock:
- OPENBRACE CaseClausesOpt CLOSEBRACE { $$ = createNodeDeclarationInfo<CaseBlockNode*>(new (GLOBAL_DATA) CaseBlockNode(GLOBAL_DATA, $2.m_node.head, 0, 0), $2.m_varDeclarations, $2.m_funcDeclarations, $2.m_features, $2.m_numConstants); }
- | OPENBRACE CaseClausesOpt DefaultClause CaseClausesOpt CLOSEBRACE
- { $$ = createNodeDeclarationInfo<CaseBlockNode*>(new (GLOBAL_DATA) CaseBlockNode(GLOBAL_DATA, $2.m_node.head, $3.m_node, $4.m_node.head),
- mergeDeclarationLists(mergeDeclarationLists($2.m_varDeclarations, $3.m_varDeclarations), $4.m_varDeclarations),
- mergeDeclarationLists(mergeDeclarationLists($2.m_funcDeclarations, $3.m_funcDeclarations), $4.m_funcDeclarations),
- $2.m_features | $3.m_features | $4.m_features,
- $2.m_numConstants + $3.m_numConstants + $4.m_numConstants); }
-;
-
-CaseClausesOpt:
- /* nothing */ { $$.m_node.head = 0; $$.m_node.tail = 0; $$.m_varDeclarations = 0; $$.m_funcDeclarations = 0; $$.m_features = 0; $$.m_numConstants = 0; }
- | CaseClauses
-;
-
-CaseClauses:
- CaseClause { $$.m_node.head = new (GLOBAL_DATA) ClauseListNode(GLOBAL_DATA, $1.m_node);
- $$.m_node.tail = $$.m_node.head;
- $$.m_varDeclarations = $1.m_varDeclarations;
- $$.m_funcDeclarations = $1.m_funcDeclarations;
- $$.m_features = $1.m_features;
- $$.m_numConstants = $1.m_numConstants; }
- | CaseClauses CaseClause { $$.m_node.head = $1.m_node.head;
- $$.m_node.tail = new (GLOBAL_DATA) ClauseListNode(GLOBAL_DATA, $1.m_node.tail, $2.m_node);
- $$.m_varDeclarations = mergeDeclarationLists($1.m_varDeclarations, $2.m_varDeclarations);
- $$.m_funcDeclarations = mergeDeclarationLists($1.m_funcDeclarations, $2.m_funcDeclarations);
- $$.m_features = $1.m_features | $2.m_features;
- $$.m_numConstants = $1.m_numConstants + $2.m_numConstants;
- }
-;
-
-CaseClause:
- CASE Expr ':' { $$ = createNodeDeclarationInfo<CaseClauseNode*>(new (GLOBAL_DATA) CaseClauseNode(GLOBAL_DATA, $2.m_node), 0, 0, $2.m_features, $2.m_numConstants); }
- | CASE Expr ':' SourceElements { $$ = createNodeDeclarationInfo<CaseClauseNode*>(new (GLOBAL_DATA) CaseClauseNode(GLOBAL_DATA, $2.m_node, $4.m_node), $4.m_varDeclarations, $4.m_funcDeclarations, $2.m_features | $4.m_features, $2.m_numConstants + $4.m_numConstants); }
-;
-
-DefaultClause:
- DEFAULT ':' { $$ = createNodeDeclarationInfo<CaseClauseNode*>(new (GLOBAL_DATA) CaseClauseNode(GLOBAL_DATA, 0), 0, 0, 0, 0); }
- | DEFAULT ':' SourceElements { $$ = createNodeDeclarationInfo<CaseClauseNode*>(new (GLOBAL_DATA) CaseClauseNode(GLOBAL_DATA, 0, $3.m_node), $3.m_varDeclarations, $3.m_funcDeclarations, $3.m_features, $3.m_numConstants); }
-;
-
-LabelledStatement:
- IDENT ':' Statement { LabelNode* node = new (GLOBAL_DATA) LabelNode(GLOBAL_DATA, *$1, $3.m_node);
- setExceptionLocation(node, @1.first_column, @2.last_column, @2.last_column);
- $$ = createNodeDeclarationInfo<StatementNode*>(node, $3.m_varDeclarations, $3.m_funcDeclarations, $3.m_features, $3.m_numConstants); }
-;
-
-ThrowStatement:
- THROW Expr ';' { ThrowNode* node = new (GLOBAL_DATA) ThrowNode(GLOBAL_DATA, $2.m_node);
- setExceptionLocation(node, @1.first_column, @2.last_column, @2.last_column);
- $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, $2.m_features, $2.m_numConstants); setStatementLocation($$.m_node, @1, @2);
- }
- | THROW Expr error { ThrowNode* node = new (GLOBAL_DATA) ThrowNode(GLOBAL_DATA, $2.m_node);
- setExceptionLocation(node, @1.first_column, @2.last_column, @2.last_column);
- $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, $2.m_features, $2.m_numConstants); setStatementLocation($$.m_node, @1, @2); AUTO_SEMICOLON;
- }
-;
-
-TryStatement:
- TRY Block FINALLY Block { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) TryNode(GLOBAL_DATA, $2.m_node, GLOBAL_DATA->propertyNames->nullIdentifier, false, 0, $4.m_node),
- mergeDeclarationLists($2.m_varDeclarations, $4.m_varDeclarations),
- mergeDeclarationLists($2.m_funcDeclarations, $4.m_funcDeclarations),
- $2.m_features | $4.m_features,
- $2.m_numConstants + $4.m_numConstants);
- setStatementLocation($$.m_node, @1, @2); }
- | TRY Block CATCH '(' IDENT ')' Block { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) TryNode(GLOBAL_DATA, $2.m_node, *$5, ($7.m_features & EvalFeature) != 0, $7.m_node, 0),
- mergeDeclarationLists($2.m_varDeclarations, $7.m_varDeclarations),
- mergeDeclarationLists($2.m_funcDeclarations, $7.m_funcDeclarations),
- $2.m_features | $7.m_features | CatchFeature,
- $2.m_numConstants + $7.m_numConstants);
- setStatementLocation($$.m_node, @1, @2); }
- | TRY Block CATCH '(' IDENT ')' Block FINALLY Block
- { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) TryNode(GLOBAL_DATA, $2.m_node, *$5, ($7.m_features & EvalFeature) != 0, $7.m_node, $9.m_node),
- mergeDeclarationLists(mergeDeclarationLists($2.m_varDeclarations, $7.m_varDeclarations), $9.m_varDeclarations),
- mergeDeclarationLists(mergeDeclarationLists($2.m_funcDeclarations, $7.m_funcDeclarations), $9.m_funcDeclarations),
- $2.m_features | $7.m_features | $9.m_features | CatchFeature,
- $2.m_numConstants + $7.m_numConstants + $9.m_numConstants);
- setStatementLocation($$.m_node, @1, @2); }
-;
-
-DebuggerStatement:
- DEBUGGER ';' { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) DebuggerStatementNode(GLOBAL_DATA), 0, 0, 0, 0);
- setStatementLocation($$.m_node, @1, @2); }
- | DEBUGGER error { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) DebuggerStatementNode(GLOBAL_DATA), 0, 0, 0, 0);
- setStatementLocation($$.m_node, @1, @1); AUTO_SEMICOLON; }
-;
-
-FunctionDeclaration:
- FUNCTION IDENT '(' ')' OPENBRACE FunctionBody CLOSEBRACE { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) FuncDeclNode(GLOBAL_DATA, *$2, $6, GLOBAL_DATA->lexer->sourceCode($5, $7, @5.first_line)), 0, new (GLOBAL_DATA) ParserArenaData<DeclarationStacks::FunctionStack>, ((*$2 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | ClosureFeature, 0); setStatementLocation($6, @5, @7); $$.m_funcDeclarations->data.append(static_cast<FuncDeclNode*>($$.m_node)->body()); }
- | FUNCTION IDENT '(' FormalParameterList ')' OPENBRACE FunctionBody CLOSEBRACE
- {
- $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) FuncDeclNode(GLOBAL_DATA, *$2, $7, GLOBAL_DATA->lexer->sourceCode($6, $8, @6.first_line), $4.m_node.head), 0, new (GLOBAL_DATA) ParserArenaData<DeclarationStacks::FunctionStack>, ((*$2 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | $4.m_features | ClosureFeature, 0);
- if ($4.m_features & ArgumentsFeature)
- $7->setUsesArguments();
- setStatementLocation($7, @6, @8);
- $$.m_funcDeclarations->data.append(static_cast<FuncDeclNode*>($$.m_node)->body());
- }
-;
-
-FunctionExpr:
- FUNCTION '(' ')' OPENBRACE FunctionBody CLOSEBRACE { $$ = createNodeInfo(new (GLOBAL_DATA) FuncExprNode(GLOBAL_DATA, GLOBAL_DATA->propertyNames->nullIdentifier, $5, GLOBAL_DATA->lexer->sourceCode($4, $6, @4.first_line)), ClosureFeature, 0); setStatementLocation($5, @4, @6); }
- | FUNCTION '(' FormalParameterList ')' OPENBRACE FunctionBody CLOSEBRACE
- {
- $$ = createNodeInfo(new (GLOBAL_DATA) FuncExprNode(GLOBAL_DATA, GLOBAL_DATA->propertyNames->nullIdentifier, $6, GLOBAL_DATA->lexer->sourceCode($5, $7, @5.first_line), $3.m_node.head), $3.m_features | ClosureFeature, 0);
- if ($3.m_features & ArgumentsFeature)
- $6->setUsesArguments();
- setStatementLocation($6, @5, @7);
- }
- | FUNCTION IDENT '(' ')' OPENBRACE FunctionBody CLOSEBRACE { $$ = createNodeInfo(new (GLOBAL_DATA) FuncExprNode(GLOBAL_DATA, *$2, $6, GLOBAL_DATA->lexer->sourceCode($5, $7, @5.first_line)), ClosureFeature, 0); setStatementLocation($6, @5, @7); }
- | FUNCTION IDENT '(' FormalParameterList ')' OPENBRACE FunctionBody CLOSEBRACE
- {
- $$ = createNodeInfo(new (GLOBAL_DATA) FuncExprNode(GLOBAL_DATA, *$2, $7, GLOBAL_DATA->lexer->sourceCode($6, $8, @6.first_line), $4.m_node.head), $4.m_features | ClosureFeature, 0);
- if ($4.m_features & ArgumentsFeature)
- $7->setUsesArguments();
- setStatementLocation($7, @6, @8);
- }
-;
-
-FormalParameterList:
- IDENT { $$.m_node.head = new (GLOBAL_DATA) ParameterNode(GLOBAL_DATA, *$1);
- $$.m_features = (*$1 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0;
- $$.m_node.tail = $$.m_node.head; }
- | FormalParameterList ',' IDENT { $$.m_node.head = $1.m_node.head;
- $$.m_features = $1.m_features | ((*$3 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0);
- $$.m_node.tail = new (GLOBAL_DATA) ParameterNode(GLOBAL_DATA, $1.m_node.tail, *$3); }
-;
-
-FunctionBody:
- /* not in spec */ { $$ = FunctionBodyNode::create(GLOBAL_DATA); }
- | SourceElements_NoNode { $$ = FunctionBodyNode::create(GLOBAL_DATA); }
-;
-
-Program:
- /* not in spec */ { GLOBAL_DATA->parser->didFinishParsing(new (GLOBAL_DATA) SourceElements(GLOBAL_DATA), 0, 0, NoFeatures, @0.last_line, 0); }
- | SourceElements { GLOBAL_DATA->parser->didFinishParsing($1.m_node, $1.m_varDeclarations, $1.m_funcDeclarations, $1.m_features,
- @1.last_line, $1.m_numConstants); }
-;
-
-SourceElements:
- Statement { $$.m_node = new (GLOBAL_DATA) SourceElements(GLOBAL_DATA);
- $$.m_node->append($1.m_node);
- $$.m_varDeclarations = $1.m_varDeclarations;
- $$.m_funcDeclarations = $1.m_funcDeclarations;
- $$.m_features = $1.m_features;
- $$.m_numConstants = $1.m_numConstants;
- }
- | SourceElements Statement { $$.m_node->append($2.m_node);
- $$.m_varDeclarations = mergeDeclarationLists($1.m_varDeclarations, $2.m_varDeclarations);
- $$.m_funcDeclarations = mergeDeclarationLists($1.m_funcDeclarations, $2.m_funcDeclarations);
- $$.m_features = $1.m_features | $2.m_features;
- $$.m_numConstants = $1.m_numConstants + $2.m_numConstants;
- }
-;
-
-// Start NoNodes
-
-Literal_NoNode:
- NULLTOKEN
- | TRUETOKEN
- | FALSETOKEN
- | NUMBER { }
- | STRING { }
- | '/' /* regexp */ { if (!GLOBAL_DATA->lexer->skipRegExp()) YYABORT; }
- | DIVEQUAL /* regexp with /= */ { if (!GLOBAL_DATA->lexer->skipRegExp()) YYABORT; }
-;
-
-Property_NoNode:
- IDENT ':' AssignmentExpr_NoNode { }
- | STRING ':' AssignmentExpr_NoNode { }
- | NUMBER ':' AssignmentExpr_NoNode { }
- | IDENT IDENT '(' ')' OPENBRACE FunctionBody_NoNode CLOSEBRACE { if (*$1 != "get" && *$1 != "set") YYABORT; }
- | IDENT IDENT '(' FormalParameterList_NoNode ')' OPENBRACE FunctionBody_NoNode CLOSEBRACE { if (*$1 != "get" && *$1 != "set") YYABORT; }
-;
-
-PropertyList_NoNode:
- Property_NoNode
- | PropertyList_NoNode ',' Property_NoNode
-;
-
-PrimaryExpr_NoNode:
- PrimaryExprNoBrace_NoNode
- | OPENBRACE CLOSEBRACE { }
- | OPENBRACE PropertyList_NoNode CLOSEBRACE { }
- /* allow extra comma, see http://bugs.webkit.org/show_bug.cgi?id=5939 */
- | OPENBRACE PropertyList_NoNode ',' CLOSEBRACE { }
-;
-
-PrimaryExprNoBrace_NoNode:
- THISTOKEN
- | Literal_NoNode
- | ArrayLiteral_NoNode
- | IDENT { }
- | '(' Expr_NoNode ')'
-;
-
-ArrayLiteral_NoNode:
- '[' ElisionOpt_NoNode ']'
- | '[' ElementList_NoNode ']'
- | '[' ElementList_NoNode ',' ElisionOpt_NoNode ']'
-;
-
-ElementList_NoNode:
- ElisionOpt_NoNode AssignmentExpr_NoNode
- | ElementList_NoNode ',' ElisionOpt_NoNode AssignmentExpr_NoNode
-;
-
-ElisionOpt_NoNode:
- /* nothing */
- | Elision_NoNode
-;
-
-Elision_NoNode:
- ','
- | Elision_NoNode ','
-;
-
-MemberExpr_NoNode:
- PrimaryExpr_NoNode
- | FunctionExpr_NoNode
- | MemberExpr_NoNode '[' Expr_NoNode ']'
- | MemberExpr_NoNode '.' IDENT
- | NEW MemberExpr_NoNode Arguments_NoNode
-;
-
-MemberExprNoBF_NoNode:
- PrimaryExprNoBrace_NoNode
- | MemberExprNoBF_NoNode '[' Expr_NoNode ']'
- | MemberExprNoBF_NoNode '.' IDENT
- | NEW MemberExpr_NoNode Arguments_NoNode
-;
-
-NewExpr_NoNode:
- MemberExpr_NoNode
- | NEW NewExpr_NoNode
-;
-
-NewExprNoBF_NoNode:
- MemberExprNoBF_NoNode
- | NEW NewExpr_NoNode
-;
-
-CallExpr_NoNode:
- MemberExpr_NoNode Arguments_NoNode
- | CallExpr_NoNode Arguments_NoNode
- | CallExpr_NoNode '[' Expr_NoNode ']'
- | CallExpr_NoNode '.' IDENT
-;
-
-CallExprNoBF_NoNode:
- MemberExprNoBF_NoNode Arguments_NoNode
- | CallExprNoBF_NoNode Arguments_NoNode
- | CallExprNoBF_NoNode '[' Expr_NoNode ']'
- | CallExprNoBF_NoNode '.' IDENT
-;
-
-Arguments_NoNode:
- '(' ')'
- | '(' ArgumentList_NoNode ')'
-;
-
-ArgumentList_NoNode:
- AssignmentExpr_NoNode
- | ArgumentList_NoNode ',' AssignmentExpr_NoNode
-;
-
-LeftHandSideExpr_NoNode:
- NewExpr_NoNode
- | CallExpr_NoNode
-;
-
-LeftHandSideExprNoBF_NoNode:
- NewExprNoBF_NoNode
- | CallExprNoBF_NoNode
-;
-
-PostfixExpr_NoNode:
- LeftHandSideExpr_NoNode
- | LeftHandSideExpr_NoNode PLUSPLUS
- | LeftHandSideExpr_NoNode MINUSMINUS
-;
-
-PostfixExprNoBF_NoNode:
- LeftHandSideExprNoBF_NoNode
- | LeftHandSideExprNoBF_NoNode PLUSPLUS
- | LeftHandSideExprNoBF_NoNode MINUSMINUS
-;
-
-UnaryExprCommon_NoNode:
- DELETETOKEN UnaryExpr_NoNode
- | VOIDTOKEN UnaryExpr_NoNode
- | TYPEOF UnaryExpr_NoNode
- | PLUSPLUS UnaryExpr_NoNode
- | AUTOPLUSPLUS UnaryExpr_NoNode
- | MINUSMINUS UnaryExpr_NoNode
- | AUTOMINUSMINUS UnaryExpr_NoNode
- | '+' UnaryExpr_NoNode
- | '-' UnaryExpr_NoNode
- | '~' UnaryExpr_NoNode
- | '!' UnaryExpr_NoNode
-
-UnaryExpr_NoNode:
- PostfixExpr_NoNode
- | UnaryExprCommon_NoNode
-;
-
-UnaryExprNoBF_NoNode:
- PostfixExprNoBF_NoNode
- | UnaryExprCommon_NoNode
-;
-
-MultiplicativeExpr_NoNode:
- UnaryExpr_NoNode
- | MultiplicativeExpr_NoNode '*' UnaryExpr_NoNode
- | MultiplicativeExpr_NoNode '/' UnaryExpr_NoNode
- | MultiplicativeExpr_NoNode '%' UnaryExpr_NoNode
-;
-
-MultiplicativeExprNoBF_NoNode:
- UnaryExprNoBF_NoNode
- | MultiplicativeExprNoBF_NoNode '*' UnaryExpr_NoNode
- | MultiplicativeExprNoBF_NoNode '/' UnaryExpr_NoNode
- | MultiplicativeExprNoBF_NoNode '%' UnaryExpr_NoNode
-;
-
-AdditiveExpr_NoNode:
- MultiplicativeExpr_NoNode
- | AdditiveExpr_NoNode '+' MultiplicativeExpr_NoNode
- | AdditiveExpr_NoNode '-' MultiplicativeExpr_NoNode
-;
-
-AdditiveExprNoBF_NoNode:
- MultiplicativeExprNoBF_NoNode
- | AdditiveExprNoBF_NoNode '+' MultiplicativeExpr_NoNode
- | AdditiveExprNoBF_NoNode '-' MultiplicativeExpr_NoNode
-;
-
-ShiftExpr_NoNode:
- AdditiveExpr_NoNode
- | ShiftExpr_NoNode LSHIFT AdditiveExpr_NoNode
- | ShiftExpr_NoNode RSHIFT AdditiveExpr_NoNode
- | ShiftExpr_NoNode URSHIFT AdditiveExpr_NoNode
-;
-
-ShiftExprNoBF_NoNode:
- AdditiveExprNoBF_NoNode
- | ShiftExprNoBF_NoNode LSHIFT AdditiveExpr_NoNode
- | ShiftExprNoBF_NoNode RSHIFT AdditiveExpr_NoNode
- | ShiftExprNoBF_NoNode URSHIFT AdditiveExpr_NoNode
-;
-
-RelationalExpr_NoNode:
- ShiftExpr_NoNode
- | RelationalExpr_NoNode '<' ShiftExpr_NoNode
- | RelationalExpr_NoNode '>' ShiftExpr_NoNode
- | RelationalExpr_NoNode LE ShiftExpr_NoNode
- | RelationalExpr_NoNode GE ShiftExpr_NoNode
- | RelationalExpr_NoNode INSTANCEOF ShiftExpr_NoNode
- | RelationalExpr_NoNode INTOKEN ShiftExpr_NoNode
-;
-
-RelationalExprNoIn_NoNode:
- ShiftExpr_NoNode
- | RelationalExprNoIn_NoNode '<' ShiftExpr_NoNode
- | RelationalExprNoIn_NoNode '>' ShiftExpr_NoNode
- | RelationalExprNoIn_NoNode LE ShiftExpr_NoNode
- | RelationalExprNoIn_NoNode GE ShiftExpr_NoNode
- | RelationalExprNoIn_NoNode INSTANCEOF ShiftExpr_NoNode
-;
-
-RelationalExprNoBF_NoNode:
- ShiftExprNoBF_NoNode
- | RelationalExprNoBF_NoNode '<' ShiftExpr_NoNode
- | RelationalExprNoBF_NoNode '>' ShiftExpr_NoNode
- | RelationalExprNoBF_NoNode LE ShiftExpr_NoNode
- | RelationalExprNoBF_NoNode GE ShiftExpr_NoNode
- | RelationalExprNoBF_NoNode INSTANCEOF ShiftExpr_NoNode
- | RelationalExprNoBF_NoNode INTOKEN ShiftExpr_NoNode
-;
-
-EqualityExpr_NoNode:
- RelationalExpr_NoNode
- | EqualityExpr_NoNode EQEQ RelationalExpr_NoNode
- | EqualityExpr_NoNode NE RelationalExpr_NoNode
- | EqualityExpr_NoNode STREQ RelationalExpr_NoNode
- | EqualityExpr_NoNode STRNEQ RelationalExpr_NoNode
-;
-
-EqualityExprNoIn_NoNode:
- RelationalExprNoIn_NoNode
- | EqualityExprNoIn_NoNode EQEQ RelationalExprNoIn_NoNode
- | EqualityExprNoIn_NoNode NE RelationalExprNoIn_NoNode
- | EqualityExprNoIn_NoNode STREQ RelationalExprNoIn_NoNode
- | EqualityExprNoIn_NoNode STRNEQ RelationalExprNoIn_NoNode
-;
-
-EqualityExprNoBF_NoNode:
- RelationalExprNoBF_NoNode
- | EqualityExprNoBF_NoNode EQEQ RelationalExpr_NoNode
- | EqualityExprNoBF_NoNode NE RelationalExpr_NoNode
- | EqualityExprNoBF_NoNode STREQ RelationalExpr_NoNode
- | EqualityExprNoBF_NoNode STRNEQ RelationalExpr_NoNode
-;
-
-BitwiseANDExpr_NoNode:
- EqualityExpr_NoNode
- | BitwiseANDExpr_NoNode '&' EqualityExpr_NoNode
-;
-
-BitwiseANDExprNoIn_NoNode:
- EqualityExprNoIn_NoNode
- | BitwiseANDExprNoIn_NoNode '&' EqualityExprNoIn_NoNode
-;
-
-BitwiseANDExprNoBF_NoNode:
- EqualityExprNoBF_NoNode
- | BitwiseANDExprNoBF_NoNode '&' EqualityExpr_NoNode
-;
-
-BitwiseXORExpr_NoNode:
- BitwiseANDExpr_NoNode
- | BitwiseXORExpr_NoNode '^' BitwiseANDExpr_NoNode
-;
-
-BitwiseXORExprNoIn_NoNode:
- BitwiseANDExprNoIn_NoNode
- | BitwiseXORExprNoIn_NoNode '^' BitwiseANDExprNoIn_NoNode
-;
-
-BitwiseXORExprNoBF_NoNode:
- BitwiseANDExprNoBF_NoNode
- | BitwiseXORExprNoBF_NoNode '^' BitwiseANDExpr_NoNode
-;
-
-BitwiseORExpr_NoNode:
- BitwiseXORExpr_NoNode
- | BitwiseORExpr_NoNode '|' BitwiseXORExpr_NoNode
-;
-
-BitwiseORExprNoIn_NoNode:
- BitwiseXORExprNoIn_NoNode
- | BitwiseORExprNoIn_NoNode '|' BitwiseXORExprNoIn_NoNode
-;
-
-BitwiseORExprNoBF_NoNode:
- BitwiseXORExprNoBF_NoNode
- | BitwiseORExprNoBF_NoNode '|' BitwiseXORExpr_NoNode
-;
-
-LogicalANDExpr_NoNode:
- BitwiseORExpr_NoNode
- | LogicalANDExpr_NoNode AND BitwiseORExpr_NoNode
-;
-
-LogicalANDExprNoIn_NoNode:
- BitwiseORExprNoIn_NoNode
- | LogicalANDExprNoIn_NoNode AND BitwiseORExprNoIn_NoNode
-;
-
-LogicalANDExprNoBF_NoNode:
- BitwiseORExprNoBF_NoNode
- | LogicalANDExprNoBF_NoNode AND BitwiseORExpr_NoNode
-;
-
-LogicalORExpr_NoNode:
- LogicalANDExpr_NoNode
- | LogicalORExpr_NoNode OR LogicalANDExpr_NoNode
-;
-
-LogicalORExprNoIn_NoNode:
- LogicalANDExprNoIn_NoNode
- | LogicalORExprNoIn_NoNode OR LogicalANDExprNoIn_NoNode
-;
-
-LogicalORExprNoBF_NoNode:
- LogicalANDExprNoBF_NoNode
- | LogicalORExprNoBF_NoNode OR LogicalANDExpr_NoNode
-;
-
-ConditionalExpr_NoNode:
- LogicalORExpr_NoNode
- | LogicalORExpr_NoNode '?' AssignmentExpr_NoNode ':' AssignmentExpr_NoNode
-;
-
-ConditionalExprNoIn_NoNode:
- LogicalORExprNoIn_NoNode
- | LogicalORExprNoIn_NoNode '?' AssignmentExprNoIn_NoNode ':' AssignmentExprNoIn_NoNode
-;
-
-ConditionalExprNoBF_NoNode:
- LogicalORExprNoBF_NoNode
- | LogicalORExprNoBF_NoNode '?' AssignmentExpr_NoNode ':' AssignmentExpr_NoNode
-;
-
-AssignmentExpr_NoNode:
- ConditionalExpr_NoNode
- | LeftHandSideExpr_NoNode AssignmentOperator_NoNode AssignmentExpr_NoNode
-;
-
-AssignmentExprNoIn_NoNode:
- ConditionalExprNoIn_NoNode
- | LeftHandSideExpr_NoNode AssignmentOperator_NoNode AssignmentExprNoIn_NoNode
-;
-
-AssignmentExprNoBF_NoNode:
- ConditionalExprNoBF_NoNode
- | LeftHandSideExprNoBF_NoNode AssignmentOperator_NoNode AssignmentExpr_NoNode
-;
-
-AssignmentOperator_NoNode:
- '='
- | PLUSEQUAL
- | MINUSEQUAL
- | MULTEQUAL
- | DIVEQUAL
- | LSHIFTEQUAL
- | RSHIFTEQUAL
- | URSHIFTEQUAL
- | ANDEQUAL
- | XOREQUAL
- | OREQUAL
- | MODEQUAL
-;
-
-Expr_NoNode:
- AssignmentExpr_NoNode
- | Expr_NoNode ',' AssignmentExpr_NoNode
-;
-
-ExprNoIn_NoNode:
- AssignmentExprNoIn_NoNode
- | ExprNoIn_NoNode ',' AssignmentExprNoIn_NoNode
-;
-
-ExprNoBF_NoNode:
- AssignmentExprNoBF_NoNode
- | ExprNoBF_NoNode ',' AssignmentExpr_NoNode
-;
-
-Statement_NoNode:
- Block_NoNode
- | VariableStatement_NoNode
- | ConstStatement_NoNode
- | FunctionDeclaration_NoNode
- | EmptyStatement_NoNode
- | ExprStatement_NoNode
- | IfStatement_NoNode
- | IterationStatement_NoNode
- | ContinueStatement_NoNode
- | BreakStatement_NoNode
- | ReturnStatement_NoNode
- | WithStatement_NoNode
- | SwitchStatement_NoNode
- | LabelledStatement_NoNode
- | ThrowStatement_NoNode
- | TryStatement_NoNode
- | DebuggerStatement_NoNode
-;
-
-Block_NoNode:
- OPENBRACE CLOSEBRACE { }
- | OPENBRACE SourceElements_NoNode CLOSEBRACE { }
-;
-
-VariableStatement_NoNode:
- VAR VariableDeclarationList_NoNode ';'
- | VAR VariableDeclarationList_NoNode error { AUTO_SEMICOLON; }
-;
-
-VariableDeclarationList_NoNode:
- IDENT { }
- | IDENT Initializer_NoNode { }
- | VariableDeclarationList_NoNode ',' IDENT
- | VariableDeclarationList_NoNode ',' IDENT Initializer_NoNode
-;
-
-VariableDeclarationListNoIn_NoNode:
- IDENT { }
- | IDENT InitializerNoIn_NoNode { }
- | VariableDeclarationListNoIn_NoNode ',' IDENT
- | VariableDeclarationListNoIn_NoNode ',' IDENT InitializerNoIn_NoNode
-;
-
-ConstStatement_NoNode:
- CONSTTOKEN ConstDeclarationList_NoNode ';'
- | CONSTTOKEN ConstDeclarationList_NoNode error { AUTO_SEMICOLON; }
-;
-
-ConstDeclarationList_NoNode:
- ConstDeclaration_NoNode
- | ConstDeclarationList_NoNode ',' ConstDeclaration_NoNode
-;
-
-ConstDeclaration_NoNode:
- IDENT { }
- | IDENT Initializer_NoNode { }
-;
-
-Initializer_NoNode:
- '=' AssignmentExpr_NoNode
-;
-
-InitializerNoIn_NoNode:
- '=' AssignmentExprNoIn_NoNode
-;
-
-EmptyStatement_NoNode:
- ';'
-;
-
-ExprStatement_NoNode:
- ExprNoBF_NoNode ';'
- | ExprNoBF_NoNode error { AUTO_SEMICOLON; }
-;
-
-IfStatement_NoNode:
- IF '(' Expr_NoNode ')' Statement_NoNode %prec IF_WITHOUT_ELSE
- | IF '(' Expr_NoNode ')' Statement_NoNode ELSE Statement_NoNode
-;
-
-IterationStatement_NoNode:
- DO Statement_NoNode WHILE '(' Expr_NoNode ')' ';'
- | DO Statement_NoNode WHILE '(' Expr_NoNode ')' error // Always performs automatic semicolon insertion
- | WHILE '(' Expr_NoNode ')' Statement_NoNode
- | FOR '(' ExprNoInOpt_NoNode ';' ExprOpt_NoNode ';' ExprOpt_NoNode ')' Statement_NoNode
- | FOR '(' VAR VariableDeclarationListNoIn_NoNode ';' ExprOpt_NoNode ';' ExprOpt_NoNode ')' Statement_NoNode
- | FOR '(' LeftHandSideExpr_NoNode INTOKEN Expr_NoNode ')' Statement_NoNode
- | FOR '(' VAR IDENT INTOKEN Expr_NoNode ')' Statement_NoNode
- | FOR '(' VAR IDENT InitializerNoIn_NoNode INTOKEN Expr_NoNode ')' Statement_NoNode
-;
-
-ExprOpt_NoNode:
- /* nothing */
- | Expr_NoNode
-;
-
-ExprNoInOpt_NoNode:
- /* nothing */
- | ExprNoIn_NoNode
-;
-
-ContinueStatement_NoNode:
- CONTINUE ';'
- | CONTINUE error { AUTO_SEMICOLON; }
- | CONTINUE IDENT ';'
- | CONTINUE IDENT error { AUTO_SEMICOLON; }
-;
-
-BreakStatement_NoNode:
- BREAK ';'
- | BREAK error { AUTO_SEMICOLON; }
- | BREAK IDENT ';'
- | BREAK IDENT error { AUTO_SEMICOLON; }
-;
-
-ReturnStatement_NoNode:
- RETURN ';'
- | RETURN error { AUTO_SEMICOLON; }
- | RETURN Expr_NoNode ';'
- | RETURN Expr_NoNode error { AUTO_SEMICOLON; }
-;
-
-WithStatement_NoNode:
- WITH '(' Expr_NoNode ')' Statement_NoNode
-;
-
-SwitchStatement_NoNode:
- SWITCH '(' Expr_NoNode ')' CaseBlock_NoNode
-;
-
-CaseBlock_NoNode:
- OPENBRACE CaseClausesOpt_NoNode CLOSEBRACE { }
- | OPENBRACE CaseClausesOpt_NoNode DefaultClause_NoNode CaseClausesOpt_NoNode CLOSEBRACE { }
-;
-
-CaseClausesOpt_NoNode:
- /* nothing */
- | CaseClauses_NoNode
-;
-
-CaseClauses_NoNode:
- CaseClause_NoNode
- | CaseClauses_NoNode CaseClause_NoNode
-;
-
-CaseClause_NoNode:
- CASE Expr_NoNode ':'
- | CASE Expr_NoNode ':' SourceElements_NoNode
-;
-
-DefaultClause_NoNode:
- DEFAULT ':'
- | DEFAULT ':' SourceElements_NoNode
-;
-
-LabelledStatement_NoNode:
- IDENT ':' Statement_NoNode { }
-;
-
-ThrowStatement_NoNode:
- THROW Expr_NoNode ';'
- | THROW Expr_NoNode error { AUTO_SEMICOLON; }
-;
-
-TryStatement_NoNode:
- TRY Block_NoNode FINALLY Block_NoNode
- | TRY Block_NoNode CATCH '(' IDENT ')' Block_NoNode
- | TRY Block_NoNode CATCH '(' IDENT ')' Block_NoNode FINALLY Block_NoNode
-;
-
-DebuggerStatement_NoNode:
- DEBUGGER ';'
- | DEBUGGER error { AUTO_SEMICOLON; }
-;
-
-FunctionDeclaration_NoNode:
- FUNCTION IDENT '(' ')' OPENBRACE FunctionBody_NoNode CLOSEBRACE
- | FUNCTION IDENT '(' FormalParameterList_NoNode ')' OPENBRACE FunctionBody_NoNode CLOSEBRACE
-;
-
-FunctionExpr_NoNode:
- FUNCTION '(' ')' OPENBRACE FunctionBody_NoNode CLOSEBRACE
- | FUNCTION '(' FormalParameterList_NoNode ')' OPENBRACE FunctionBody_NoNode CLOSEBRACE
- | FUNCTION IDENT '(' ')' OPENBRACE FunctionBody_NoNode CLOSEBRACE
- | FUNCTION IDENT '(' FormalParameterList_NoNode ')' OPENBRACE FunctionBody_NoNode CLOSEBRACE
-;
-
-FormalParameterList_NoNode:
- IDENT { }
- | FormalParameterList_NoNode ',' IDENT
-;
-
-FunctionBody_NoNode:
- /* not in spec */
- | SourceElements_NoNode
-;
-
-SourceElements_NoNode:
- Statement_NoNode
- | SourceElements_NoNode Statement_NoNode
-;
-
-// End NoNodes
-
-%%
-
-#undef GLOBAL_DATA
-
-static ExpressionNode* makeAssignNode(JSGlobalData* globalData, ExpressionNode* loc, Operator op, ExpressionNode* expr, bool locHasAssignments, bool exprHasAssignments, int start, int divot, int end)
-{
- if (!loc->isLocation())
- return new (globalData) AssignErrorNode(globalData, loc, op, expr, divot, divot - start, end - divot);
-
- if (loc->isResolveNode()) {
- ResolveNode* resolve = static_cast<ResolveNode*>(loc);
- if (op == OpEqual) {
- AssignResolveNode* node = new (globalData) AssignResolveNode(globalData, resolve->identifier(), expr, exprHasAssignments);
- setExceptionLocation(node, start, divot, end);
- return node;
- } else
- return new (globalData) ReadModifyResolveNode(globalData, resolve->identifier(), op, expr, exprHasAssignments, divot, divot - start, end - divot);
- }
- if (loc->isBracketAccessorNode()) {
- BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(loc);
- if (op == OpEqual)
- return new (globalData) AssignBracketNode(globalData, bracket->base(), bracket->subscript(), expr, locHasAssignments, exprHasAssignments, bracket->divot(), bracket->divot() - start, end - bracket->divot());
- else {
- ReadModifyBracketNode* node = new (globalData) ReadModifyBracketNode(globalData, bracket->base(), bracket->subscript(), op, expr, locHasAssignments, exprHasAssignments, divot, divot - start, end - divot);
- node->setSubexpressionInfo(bracket->divot(), bracket->endOffset());
- return node;
- }
- }
- ASSERT(loc->isDotAccessorNode());
- DotAccessorNode* dot = static_cast<DotAccessorNode*>(loc);
- if (op == OpEqual)
- return new (globalData) AssignDotNode(globalData, dot->base(), dot->identifier(), expr, exprHasAssignments, dot->divot(), dot->divot() - start, end - dot->divot());
-
- ReadModifyDotNode* node = new (globalData) ReadModifyDotNode(globalData, dot->base(), dot->identifier(), op, expr, exprHasAssignments, divot, divot - start, end - divot);
- node->setSubexpressionInfo(dot->divot(), dot->endOffset());
- return node;
-}
-
-static ExpressionNode* makePrefixNode(JSGlobalData* globalData, ExpressionNode* expr, Operator op, int start, int divot, int end)
-{
- if (!expr->isLocation())
- return new (globalData) PrefixErrorNode(globalData, expr, op, divot, divot - start, end - divot);
-
- if (expr->isResolveNode()) {
- ResolveNode* resolve = static_cast<ResolveNode*>(expr);
- return new (globalData) PrefixResolveNode(globalData, resolve->identifier(), op, divot, divot - start, end - divot);
- }
- if (expr->isBracketAccessorNode()) {
- BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(expr);
- PrefixBracketNode* node = new (globalData) PrefixBracketNode(globalData, bracket->base(), bracket->subscript(), op, divot, divot - start, end - divot);
- node->setSubexpressionInfo(bracket->divot(), bracket->startOffset());
- return node;
- }
- ASSERT(expr->isDotAccessorNode());
- DotAccessorNode* dot = static_cast<DotAccessorNode*>(expr);
- PrefixDotNode* node = new (globalData) PrefixDotNode(globalData, dot->base(), dot->identifier(), op, divot, divot - start, end - divot);
- node->setSubexpressionInfo(dot->divot(), dot->startOffset());
- return node;
-}
-
-static ExpressionNode* makePostfixNode(JSGlobalData* globalData, ExpressionNode* expr, Operator op, int start, int divot, int end)
-{
- if (!expr->isLocation())
- return new (globalData) PostfixErrorNode(globalData, expr, op, divot, divot - start, end - divot);
-
- if (expr->isResolveNode()) {
- ResolveNode* resolve = static_cast<ResolveNode*>(expr);
- return new (globalData) PostfixResolveNode(globalData, resolve->identifier(), op, divot, divot - start, end - divot);
- }
- if (expr->isBracketAccessorNode()) {
- BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(expr);
- PostfixBracketNode* node = new (globalData) PostfixBracketNode(globalData, bracket->base(), bracket->subscript(), op, divot, divot - start, end - divot);
- node->setSubexpressionInfo(bracket->divot(), bracket->endOffset());
- return node;
-
- }
- ASSERT(expr->isDotAccessorNode());
- DotAccessorNode* dot = static_cast<DotAccessorNode*>(expr);
- PostfixDotNode* node = new (globalData) PostfixDotNode(globalData, dot->base(), dot->identifier(), op, divot, divot - start, end - divot);
- node->setSubexpressionInfo(dot->divot(), dot->endOffset());
- return node;
-}
-
-static ExpressionNodeInfo makeFunctionCallNode(JSGlobalData* globalData, ExpressionNodeInfo func, ArgumentsNodeInfo args, int start, int divot, int end)
-{
- CodeFeatures features = func.m_features | args.m_features;
- int numConstants = func.m_numConstants + args.m_numConstants;
- if (!func.m_node->isLocation())
- return createNodeInfo<ExpressionNode*>(new (globalData) FunctionCallValueNode(globalData, func.m_node, args.m_node, divot, divot - start, end - divot), features, numConstants);
- if (func.m_node->isResolveNode()) {
- ResolveNode* resolve = static_cast<ResolveNode*>(func.m_node);
- const Identifier& identifier = resolve->identifier();
- if (identifier == globalData->propertyNames->eval)
- return createNodeInfo<ExpressionNode*>(new (globalData) EvalFunctionCallNode(globalData, args.m_node, divot, divot - start, end - divot), EvalFeature | features, numConstants);
- return createNodeInfo<ExpressionNode*>(new (globalData) FunctionCallResolveNode(globalData, identifier, args.m_node, divot, divot - start, end - divot), features, numConstants);
- }
- if (func.m_node->isBracketAccessorNode()) {
- BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(func.m_node);
- FunctionCallBracketNode* node = new (globalData) FunctionCallBracketNode(globalData, bracket->base(), bracket->subscript(), args.m_node, divot, divot - start, end - divot);
- node->setSubexpressionInfo(bracket->divot(), bracket->endOffset());
- return createNodeInfo<ExpressionNode*>(node, features, numConstants);
- }
- ASSERT(func.m_node->isDotAccessorNode());
- DotAccessorNode* dot = static_cast<DotAccessorNode*>(func.m_node);
- FunctionCallDotNode* node;
- if (dot->identifier() == globalData->propertyNames->call)
- node = new (globalData) CallFunctionCallDotNode(globalData, dot->base(), dot->identifier(), args.m_node, divot, divot - start, end - divot);
- else if (dot->identifier() == globalData->propertyNames->apply)
- node = new (globalData) ApplyFunctionCallDotNode(globalData, dot->base(), dot->identifier(), args.m_node, divot, divot - start, end - divot);
- else
- node = new (globalData) FunctionCallDotNode(globalData, dot->base(), dot->identifier(), args.m_node, divot, divot - start, end - divot);
- node->setSubexpressionInfo(dot->divot(), dot->endOffset());
- return createNodeInfo<ExpressionNode*>(node, features, numConstants);
-}
-
-static ExpressionNode* makeTypeOfNode(JSGlobalData* globalData, ExpressionNode* expr)
-{
- if (expr->isResolveNode()) {
- ResolveNode* resolve = static_cast<ResolveNode*>(expr);
- return new (globalData) TypeOfResolveNode(globalData, resolve->identifier());
- }
- return new (globalData) TypeOfValueNode(globalData, expr);
-}
-
-static ExpressionNode* makeDeleteNode(JSGlobalData* globalData, ExpressionNode* expr, int start, int divot, int end)
-{
- if (!expr->isLocation())
- return new (globalData) DeleteValueNode(globalData, expr);
- if (expr->isResolveNode()) {
- ResolveNode* resolve = static_cast<ResolveNode*>(expr);
- return new (globalData) DeleteResolveNode(globalData, resolve->identifier(), divot, divot - start, end - divot);
- }
- if (expr->isBracketAccessorNode()) {
- BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(expr);
- return new (globalData) DeleteBracketNode(globalData, bracket->base(), bracket->subscript(), divot, divot - start, end - divot);
- }
- ASSERT(expr->isDotAccessorNode());
- DotAccessorNode* dot = static_cast<DotAccessorNode*>(expr);
- return new (globalData) DeleteDotNode(globalData, dot->base(), dot->identifier(), divot, divot - start, end - divot);
-}
-
-static PropertyNode* makeGetterOrSetterPropertyNode(JSGlobalData* globalData, const Identifier& getOrSet, const Identifier& name, ParameterNode* params, FunctionBodyNode* body, const SourceCode& source)
-{
- PropertyNode::Type type;
- if (getOrSet == "get")
- type = PropertyNode::Getter;
- else if (getOrSet == "set")
- type = PropertyNode::Setter;
- else
- return 0;
- return new (globalData) PropertyNode(globalData, name, new (globalData) FuncExprNode(globalData, globalData->propertyNames->nullIdentifier, body, source, params), type);
-}
-
-static ExpressionNode* makeNegateNode(JSGlobalData* globalData, ExpressionNode* n)
-{
- if (n->isNumber()) {
- NumberNode* numberNode = static_cast<NumberNode*>(n);
- numberNode->setValue(-numberNode->value());
- return numberNode;
- }
-
- return new (globalData) NegateNode(globalData, n);
-}
-
-static NumberNode* makeNumberNode(JSGlobalData* globalData, double d)
-{
- return new (globalData) NumberNode(globalData, d);
-}
-
-static ExpressionNode* makeBitwiseNotNode(JSGlobalData* globalData, ExpressionNode* expr)
-{
- if (expr->isNumber())
- return makeNumberNode(globalData, ~toInt32(static_cast<NumberNode*>(expr)->value()));
- return new (globalData) BitwiseNotNode(globalData, expr);
-}
-
-static ExpressionNode* makeMultNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
-{
- expr1 = expr1->stripUnaryPlus();
- expr2 = expr2->stripUnaryPlus();
-
- if (expr1->isNumber() && expr2->isNumber())
- return makeNumberNode(globalData, static_cast<NumberNode*>(expr1)->value() * static_cast<NumberNode*>(expr2)->value());
-
- if (expr1->isNumber() && static_cast<NumberNode*>(expr1)->value() == 1)
- return new (globalData) UnaryPlusNode(globalData, expr2);
-
- if (expr2->isNumber() && static_cast<NumberNode*>(expr2)->value() == 1)
- return new (globalData) UnaryPlusNode(globalData, expr1);
-
- return new (globalData) MultNode(globalData, expr1, expr2, rightHasAssignments);
-}
-
-static ExpressionNode* makeDivNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
-{
- expr1 = expr1->stripUnaryPlus();
- expr2 = expr2->stripUnaryPlus();
-
- if (expr1->isNumber() && expr2->isNumber())
- return makeNumberNode(globalData, static_cast<NumberNode*>(expr1)->value() / static_cast<NumberNode*>(expr2)->value());
- return new (globalData) DivNode(globalData, expr1, expr2, rightHasAssignments);
-}
-
-static ExpressionNode* makeAddNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
-{
- if (expr1->isNumber() && expr2->isNumber())
- return makeNumberNode(globalData, static_cast<NumberNode*>(expr1)->value() + static_cast<NumberNode*>(expr2)->value());
- return new (globalData) AddNode(globalData, expr1, expr2, rightHasAssignments);
-}
-
-static ExpressionNode* makeSubNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
-{
- expr1 = expr1->stripUnaryPlus();
- expr2 = expr2->stripUnaryPlus();
-
- if (expr1->isNumber() && expr2->isNumber())
- return makeNumberNode(globalData, static_cast<NumberNode*>(expr1)->value() - static_cast<NumberNode*>(expr2)->value());
- return new (globalData) SubNode(globalData, expr1, expr2, rightHasAssignments);
-}
-
-static ExpressionNode* makeLeftShiftNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
-{
- if (expr1->isNumber() && expr2->isNumber())
- return makeNumberNode(globalData, toInt32(static_cast<NumberNode*>(expr1)->value()) << (toUInt32(static_cast<NumberNode*>(expr2)->value()) & 0x1f));
- return new (globalData) LeftShiftNode(globalData, expr1, expr2, rightHasAssignments);
-}
-
-static ExpressionNode* makeRightShiftNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
-{
- if (expr1->isNumber() && expr2->isNumber())
- return makeNumberNode(globalData, toInt32(static_cast<NumberNode*>(expr1)->value()) >> (toUInt32(static_cast<NumberNode*>(expr2)->value()) & 0x1f));
- return new (globalData) RightShiftNode(globalData, expr1, expr2, rightHasAssignments);
-}
-
-// Called by yyparse on error.
-int yyerror(const char*)
-{
- return 1;
-}
-
-// May we automatically insert a semicolon?
-static bool allowAutomaticSemicolon(Lexer& lexer, int yychar)
-{
- return yychar == CLOSEBRACE || yychar == 0 || lexer.prevTerminator();
-}
-
-static ExpressionNode* combineCommaNodes(JSGlobalData* globalData, ExpressionNode* list, ExpressionNode* init)
-{
- if (!list)
- return init;
- if (list->isCommaNode()) {
- static_cast<CommaNode*>(list)->append(init);
- return list;
- }
- return new (globalData) CommaNode(globalData, list, init);
-}
-
-// We turn variable declarations into either assignments or empty
-// statements (which later get stripped out), because the actual
-// declaration work is hoisted up to the start of the function body
-static StatementNode* makeVarStatementNode(JSGlobalData* globalData, ExpressionNode* expr)
-{
- if (!expr)
- return new (globalData) EmptyStatementNode(globalData);
- return new (globalData) VarStatementNode(globalData, expr);
-}
--- /dev/null
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "JSParser.h"
+
+using namespace JSC;
+
+#include "CodeBlock.h"
+#include "JSGlobalData.h"
+#include "NodeInfo.h"
+#include "ASTBuilder.h"
+#include "SourceProvider.h"
+#include "SourceProviderCacheItem.h"
+#include <wtf/HashFunctions.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/WTFThreadData.h>
+#include <utility>
+
+using namespace std;
+
+namespace JSC {
+#define fail() do { m_error = true; return 0; } while (0)
+#define failIfFalse(cond) do { if (!(cond)) fail(); } while (0)
+#define failIfTrue(cond) do { if ((cond)) fail(); } while (0)
+#define failIfTrueIfStrict(cond) do { if ((cond) && strictMode()) fail(); } while (0)
+#define failIfFalseIfStrict(cond) do { if ((!(cond)) && strictMode()) fail(); } while (0)
+#define consumeOrFail(tokenType) do { if (!consume(tokenType)) fail(); } while (0)
+#define consumeOrFailWithFlags(tokenType, flags) do { if (!consume(tokenType, flags)) fail(); } while (0)
+#define matchOrFail(tokenType) do { if (!match(tokenType)) fail(); } while (0)
+#define failIfStackOverflow() do { failIfFalse(canRecurse()); } while (0)
+
+// Macros to make the more common TreeBuilder types a little less verbose
+#define TreeStatement typename TreeBuilder::Statement
+#define TreeExpression typename TreeBuilder::Expression
+#define TreeFormalParameterList typename TreeBuilder::FormalParameterList
+#define TreeSourceElements typename TreeBuilder::SourceElements
+#define TreeClause typename TreeBuilder::Clause
+#define TreeClauseList typename TreeBuilder::ClauseList
+#define TreeConstDeclList typename TreeBuilder::ConstDeclList
+#define TreeArguments typename TreeBuilder::Arguments
+#define TreeArgumentsList typename TreeBuilder::ArgumentsList
+#define TreeFunctionBody typename TreeBuilder::FunctionBody
+#define TreeProperty typename TreeBuilder::Property
+#define TreePropertyList typename TreeBuilder::PropertyList
+
+COMPILE_ASSERT(LastUntaggedToken < 64, LessThan64UntaggedTokens);
+
+class JSParser {
+public:
+ JSParser(Lexer*, JSGlobalData*, FunctionParameters*, bool isStrictContext, bool isFunction, SourceProvider*);
+ const char* parseProgram();
+private:
+ struct AllowInOverride {
+ AllowInOverride(JSParser* parser)
+ : m_parser(parser)
+ , m_oldAllowsIn(parser->m_allowsIn)
+ {
+ parser->m_allowsIn = true;
+ }
+ ~AllowInOverride()
+ {
+ m_parser->m_allowsIn = m_oldAllowsIn;
+ }
+ JSParser* m_parser;
+ bool m_oldAllowsIn;
+ };
+
+ struct ScopeLabelInfo {
+ ScopeLabelInfo(StringImpl* ident, bool isLoop)
+ : m_ident(ident)
+ , m_isLoop(isLoop)
+ {
+ }
+ StringImpl* m_ident;
+ bool m_isLoop;
+ };
+
+ ALWAYS_INLINE void next(unsigned lexType = 0)
+ {
+ m_lastLine = m_token.m_info.line;
+ m_lastTokenEnd = m_token.m_info.endOffset;
+ m_lexer->setLastLineNumber(m_lastLine);
+ m_token.m_type = m_lexer->lex(&m_token.m_data, &m_token.m_info, lexType, strictMode());
+ }
+
+ ALWAYS_INLINE void nextExpectIdentifier(unsigned lexType = 0)
+ {
+ m_lastLine = m_token.m_info.line;
+ m_lastTokenEnd = m_token.m_info.endOffset;
+ m_lexer->setLastLineNumber(m_lastLine);
+ m_token.m_type = m_lexer->lexExpectIdentifier(&m_token.m_data, &m_token.m_info, lexType, strictMode());
+ }
+
+ ALWAYS_INLINE bool nextTokenIsColon()
+ {
+ return m_lexer->nextTokenIsColon();
+ }
+
+ ALWAYS_INLINE bool consume(JSTokenType expected, unsigned flags = 0)
+ {
+ bool result = m_token.m_type == expected;
+ failIfFalse(result);
+ next(flags);
+ return result;
+ }
+
+ ALWAYS_INLINE bool match(JSTokenType expected)
+ {
+ return m_token.m_type == expected;
+ }
+
+ ALWAYS_INLINE int tokenStart()
+ {
+ return m_token.m_info.startOffset;
+ }
+
+ ALWAYS_INLINE int tokenLine()
+ {
+ return m_token.m_info.line;
+ }
+
+ ALWAYS_INLINE int tokenEnd()
+ {
+ return m_token.m_info.endOffset;
+ }
+
+ void startLoop() { currentScope()->startLoop(); }
+ void endLoop() { currentScope()->endLoop(); }
+ void startSwitch() { currentScope()->startSwitch(); }
+ void endSwitch() { currentScope()->endSwitch(); }
+ void setStrictMode() { currentScope()->setStrictMode(); }
+ bool strictMode() { return currentScope()->strictMode(); }
+ bool isValidStrictMode() { return currentScope()->isValidStrictMode(); }
+ bool declareParameter(const Identifier* ident) { return currentScope()->declareParameter(ident); }
+ bool breakIsValid()
+ {
+ ScopeRef current = currentScope();
+ while (!current->breakIsValid()) {
+ if (!current.hasContainingScope())
+ return false;
+ current = current.containingScope();
+ }
+ return true;
+ }
+ bool continueIsValid()
+ {
+ ScopeRef current = currentScope();
+ while (!current->continueIsValid()) {
+ if (!current.hasContainingScope())
+ return false;
+ current = current.containingScope();
+ }
+ return true;
+ }
+ void pushLabel(const Identifier* label, bool isLoop) { currentScope()->pushLabel(label, isLoop); }
+ void popLabel() { currentScope()->popLabel(); }
+ ScopeLabelInfo* getLabel(const Identifier* label)
+ {
+ ScopeRef current = currentScope();
+ ScopeLabelInfo* result = 0;
+ while (!(result = current->getLabel(label))) {
+ if (!current.hasContainingScope())
+ return 0;
+ current = current.containingScope();
+ }
+ return result;
+ }
+
+ enum SourceElementsMode { CheckForStrictMode, DontCheckForStrictMode };
+ template <SourceElementsMode mode, class TreeBuilder> TreeSourceElements parseSourceElements(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseStatement(TreeBuilder&, const Identifier*& directive);
+ template <class TreeBuilder> TreeStatement parseFunctionDeclaration(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseVarDeclaration(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseConstDeclaration(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseDoWhileStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseWhileStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseForStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseBreakStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseContinueStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseReturnStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseThrowStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseWithStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseSwitchStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeClauseList parseSwitchClauses(TreeBuilder&);
+ template <class TreeBuilder> TreeClause parseSwitchDefaultClause(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseTryStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseDebuggerStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseExpressionStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseExpressionOrLabelStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseIfStatement(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeStatement parseBlockStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeExpression parseExpression(TreeBuilder&);
+ template <class TreeBuilder> TreeExpression parseAssignmentExpression(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseConditionalExpression(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseBinaryExpression(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseUnaryExpression(TreeBuilder&);
+ template <class TreeBuilder> TreeExpression parseMemberExpression(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeExpression parsePrimaryExpression(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseArrayLiteral(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseObjectLiteral(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseStrictObjectLiteral(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeArguments parseArguments(TreeBuilder&);
+ template <bool strict, class TreeBuilder> ALWAYS_INLINE TreeProperty parseProperty(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeFunctionBody parseFunctionBody(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeFormalParameterList parseFormalParameters(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseVarDeclarationList(TreeBuilder&, int& declarations, const Identifier*& lastIdent, TreeExpression& lastInitializer, int& identStart, int& initStart, int& initEnd);
+ template <class TreeBuilder> ALWAYS_INLINE TreeConstDeclList parseConstDeclarationList(TreeBuilder& context);
+ enum FunctionRequirements { FunctionNoRequirements, FunctionNeedsName };
+ template <FunctionRequirements, bool nameIsInContainingScope, class TreeBuilder> bool parseFunctionInfo(TreeBuilder&, const Identifier*&, TreeFormalParameterList&, TreeFunctionBody&, int& openBrace, int& closeBrace, int& bodyStartLine);
+ ALWAYS_INLINE int isBinaryOperator(JSTokenType token);
+ bool allowAutomaticSemicolon();
+
+ bool autoSemiColon()
+ {
+ if (m_token.m_type == SEMICOLON) {
+ next();
+ return true;
+ }
+ return allowAutomaticSemicolon();
+ }
+
+ bool canRecurse()
+ {
+ return m_stack.recursionCheck();
+ }
+
+ int lastTokenEnd() const
+ {
+ return m_lastTokenEnd;
+ }
+
+ ParserArena m_arena;
+ Lexer* m_lexer;
+ StackBounds m_stack;
+ bool m_error;
+ const char* m_errorMessage;
+ JSGlobalData* m_globalData;
+ JSToken m_token;
+ bool m_allowsIn;
+ int m_lastLine;
+ int m_lastTokenEnd;
+ int m_assignmentCount;
+ int m_nonLHSCount;
+ bool m_syntaxAlreadyValidated;
+ int m_statementDepth;
+ int m_nonTrivialExpressionCount;
+ const Identifier* m_lastIdentifier;
+
+ struct DepthManager {
+ DepthManager(int* depth)
+ : m_originalDepth(*depth)
+ , m_depth(depth)
+ {
+ }
+
+ ~DepthManager()
+ {
+ *m_depth = m_originalDepth;
+ }
+
+ private:
+ int m_originalDepth;
+ int* m_depth;
+ };
+
+ struct Scope {
+ Scope(JSGlobalData* globalData, bool isFunction, bool strictMode)
+ : m_globalData(globalData)
+ , m_shadowsArguments(false)
+ , m_usesEval(false)
+ , m_needsFullActivation(false)
+ , m_allowsNewDecls(true)
+ , m_strictMode(strictMode)
+ , m_isFunction(isFunction)
+ , m_isFunctionBoundary(false)
+ , m_isValidStrictMode(true)
+ , m_loopDepth(0)
+ , m_switchDepth(0)
+ {
+ }
+
+ Scope(const Scope& rhs)
+ : m_globalData(rhs.m_globalData)
+ , m_shadowsArguments(rhs.m_shadowsArguments)
+ , m_usesEval(rhs.m_usesEval)
+ , m_needsFullActivation(rhs.m_needsFullActivation)
+ , m_allowsNewDecls(rhs.m_allowsNewDecls)
+ , m_strictMode(rhs.m_strictMode)
+ , m_isFunction(rhs.m_isFunction)
+ , m_isFunctionBoundary(rhs.m_isFunctionBoundary)
+ , m_isValidStrictMode(rhs.m_isValidStrictMode)
+ , m_loopDepth(rhs.m_loopDepth)
+ , m_switchDepth(rhs.m_switchDepth)
+ {
+ if (rhs.m_labels) {
+ m_labels = adoptPtr(new LabelStack);
+
+ typedef LabelStack::const_iterator iterator;
+ iterator end = rhs.m_labels->end();
+ for (iterator it = rhs.m_labels->begin(); it != end; ++it)
+ m_labels->append(ScopeLabelInfo(it->m_ident, it->m_isLoop));
+ }
+ }
+
+ void startSwitch() { m_switchDepth++; }
+ void endSwitch() { m_switchDepth--; }
+ void startLoop() { m_loopDepth++; }
+ void endLoop() { ASSERT(m_loopDepth); m_loopDepth--; }
+ bool inLoop() { return !!m_loopDepth; }
+ bool breakIsValid() { return m_loopDepth || m_switchDepth; }
+ bool continueIsValid() { return m_loopDepth; }
+
+ void pushLabel(const Identifier* label, bool isLoop)
+ {
+ if (!m_labels)
+ m_labels = adoptPtr(new LabelStack);
+ m_labels->append(ScopeLabelInfo(label->impl(), isLoop));
+ }
+
+ void popLabel()
+ {
+ ASSERT(m_labels);
+ ASSERT(m_labels->size());
+ m_labels->removeLast();
+ }
+
+ ScopeLabelInfo* getLabel(const Identifier* label)
+ {
+ if (!m_labels)
+ return 0;
+ for (int i = m_labels->size(); i > 0; i--) {
+ if (m_labels->at(i - 1).m_ident == label->impl())
+ return &m_labels->at(i - 1);
+ }
+ return 0;
+ }
+
+ void setIsFunction()
+ {
+ m_isFunction = true;
+ m_isFunctionBoundary = true;
+ }
+ bool isFunction() { return m_isFunction; }
+ bool isFunctionBoundary() { return m_isFunctionBoundary; }
+
+ bool declareVariable(const Identifier* ident)
+ {
+ bool isValidStrictMode = m_globalData->propertyNames->eval != *ident && m_globalData->propertyNames->arguments != *ident;
+ m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode;
+ m_declaredVariables.add(ident->ustring().impl());
+ return isValidStrictMode;
+ }
+
+ void declareWrite(const Identifier* ident)
+ {
+ ASSERT(m_strictMode);
+ m_writtenVariables.add(ident->impl());
+ }
+
+ void preventNewDecls() { m_allowsNewDecls = false; }
+ bool allowsNewDecls() const { return m_allowsNewDecls; }
+
+ bool declareParameter(const Identifier* ident)
+ {
+ bool isArguments = m_globalData->propertyNames->arguments == *ident;
+ bool isValidStrictMode = m_declaredVariables.add(ident->ustring().impl()).second && m_globalData->propertyNames->eval != *ident && !isArguments;
+ m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode;
+ if (isArguments)
+ m_shadowsArguments = true;
+ return isValidStrictMode;
+ }
+
+ void useVariable(const Identifier* ident, bool isEval)
+ {
+ m_usesEval |= isEval;
+ m_usedVariables.add(ident->ustring().impl());
+ }
+
+ void setNeedsFullActivation() { m_needsFullActivation = true; }
+
+ bool collectFreeVariables(Scope* nestedScope, bool shouldTrackClosedVariables)
+ {
+ if (nestedScope->m_usesEval)
+ m_usesEval = true;
+ IdentifierSet::iterator end = nestedScope->m_usedVariables.end();
+ for (IdentifierSet::iterator ptr = nestedScope->m_usedVariables.begin(); ptr != end; ++ptr) {
+ if (nestedScope->m_declaredVariables.contains(*ptr))
+ continue;
+ m_usedVariables.add(*ptr);
+ if (shouldTrackClosedVariables)
+ m_closedVariables.add(*ptr);
+ }
+ if (nestedScope->m_writtenVariables.size()) {
+ IdentifierSet::iterator end = nestedScope->m_writtenVariables.end();
+ for (IdentifierSet::iterator ptr = nestedScope->m_writtenVariables.begin(); ptr != end; ++ptr) {
+ if (nestedScope->m_declaredVariables.contains(*ptr))
+ continue;
+ m_writtenVariables.add(*ptr);
+ }
+ }
+
+ return true;
+ }
+
+ void getUncapturedWrittenVariables(IdentifierSet& writtenVariables)
+ {
+ IdentifierSet::iterator end = m_writtenVariables.end();
+ for (IdentifierSet::iterator ptr = m_writtenVariables.begin(); ptr != end; ++ptr) {
+ if (!m_declaredVariables.contains(*ptr))
+ writtenVariables.add(*ptr);
+ }
+ }
+
+ void getCapturedVariables(IdentifierSet& capturedVariables)
+ {
+ if (m_needsFullActivation || m_usesEval) {
+ capturedVariables.swap(m_declaredVariables);
+ return;
+ }
+ for (IdentifierSet::iterator ptr = m_closedVariables.begin(); ptr != m_closedVariables.end(); ++ptr) {
+ if (!m_declaredVariables.contains(*ptr))
+ continue;
+ capturedVariables.add(*ptr);
+ }
+ }
+ void setStrictMode() { m_strictMode = true; }
+ bool strictMode() const { return m_strictMode; }
+ bool isValidStrictMode() const { return m_isValidStrictMode; }
+ bool shadowsArguments() const { return m_shadowsArguments; }
+
+ void copyCapturedVariablesToVector(const IdentifierSet& capturedVariables, Vector<RefPtr<StringImpl> >& vector)
+ {
+ IdentifierSet::iterator end = capturedVariables.end();
+ for (IdentifierSet::iterator it = capturedVariables.begin(); it != end; ++it) {
+ if (m_declaredVariables.contains(*it))
+ continue;
+ vector.append(*it);
+ }
+ vector.shrinkToFit();
+ }
+
+ void saveFunctionInfo(SourceProviderCacheItem* info)
+ {
+ ASSERT(m_isFunction);
+ info->usesEval = m_usesEval;
+ copyCapturedVariablesToVector(m_writtenVariables, info->writtenVariables);
+ copyCapturedVariablesToVector(m_usedVariables, info->usedVariables);
+ }
+
+ void restoreFunctionInfo(const SourceProviderCacheItem* info)
+ {
+ ASSERT(m_isFunction);
+ m_usesEval = info->usesEval;
+ unsigned size = info->usedVariables.size();
+ for (unsigned i = 0; i < size; ++i)
+ m_usedVariables.add(info->usedVariables[i]);
+ size = info->writtenVariables.size();
+ for (unsigned i = 0; i < size; ++i)
+ m_writtenVariables.add(info->writtenVariables[i]);
+ }
+
+ private:
+ JSGlobalData* m_globalData;
+ bool m_shadowsArguments : 1;
+ bool m_usesEval : 1;
+ bool m_needsFullActivation : 1;
+ bool m_allowsNewDecls : 1;
+ bool m_strictMode : 1;
+ bool m_isFunction : 1;
+ bool m_isFunctionBoundary : 1;
+ bool m_isValidStrictMode : 1;
+ int m_loopDepth;
+ int m_switchDepth;
+
+ typedef Vector<ScopeLabelInfo, 2> LabelStack;
+ OwnPtr<LabelStack> m_labels;
+ IdentifierSet m_declaredVariables;
+ IdentifierSet m_usedVariables;
+ IdentifierSet m_closedVariables;
+ IdentifierSet m_writtenVariables;
+ };
+
+ typedef Vector<Scope, 10> ScopeStack;
+
+ struct ScopeRef {
+ ScopeRef(ScopeStack* scopeStack, unsigned index)
+ : m_scopeStack(scopeStack)
+ , m_index(index)
+ {
+ }
+ Scope* operator->() { return &m_scopeStack->at(m_index); }
+ unsigned index() const { return m_index; }
+
+ bool hasContainingScope()
+ {
+ return m_index && !m_scopeStack->at(m_index).isFunctionBoundary();
+ }
+
+ ScopeRef containingScope()
+ {
+ ASSERT(hasContainingScope());
+ return ScopeRef(m_scopeStack, m_index - 1);
+ }
+
+ private:
+ ScopeStack* m_scopeStack;
+ unsigned m_index;
+ };
+
+ struct AutoPopScopeRef : public ScopeRef {
+ AutoPopScopeRef(JSParser* parser, ScopeRef scope)
+ : ScopeRef(scope)
+ , m_parser(parser)
+ {
+ }
+
+ ~AutoPopScopeRef()
+ {
+ if (m_parser)
+ m_parser->popScope(*this, false);
+ }
+
+ void setPopped()
+ {
+ m_parser = 0;
+ }
+
+ private:
+ JSParser* m_parser;
+ };
+
+ ScopeRef currentScope()
+ {
+ return ScopeRef(&m_scopeStack, m_scopeStack.size() - 1);
+ }
+
+ ScopeRef pushScope()
+ {
+ bool isFunction = false;
+ bool isStrict = false;
+ if (!m_scopeStack.isEmpty()) {
+ isStrict = m_scopeStack.last().strictMode();
+ isFunction = m_scopeStack.last().isFunction();
+ }
+ m_scopeStack.append(Scope(m_globalData, isFunction, isStrict));
+ return currentScope();
+ }
+
+ bool popScopeInternal(ScopeRef& scope, bool shouldTrackClosedVariables)
+ {
+ ASSERT_UNUSED(scope, scope.index() == m_scopeStack.size() - 1);
+ ASSERT(m_scopeStack.size() > 1);
+ bool result = m_scopeStack[m_scopeStack.size() - 2].collectFreeVariables(&m_scopeStack.last(), shouldTrackClosedVariables);
+ m_scopeStack.removeLast();
+ return result;
+ }
+
+ bool popScope(ScopeRef& scope, bool shouldTrackClosedVariables)
+ {
+ return popScopeInternal(scope, shouldTrackClosedVariables);
+ }
+
+ bool popScope(AutoPopScopeRef& scope, bool shouldTrackClosedVariables)
+ {
+ scope.setPopped();
+ return popScopeInternal(scope, shouldTrackClosedVariables);
+ }
+
+ bool declareVariable(const Identifier* ident)
+ {
+ unsigned i = m_scopeStack.size() - 1;
+ ASSERT(i < m_scopeStack.size());
+ while (!m_scopeStack[i].allowsNewDecls()) {
+ i--;
+ ASSERT(i < m_scopeStack.size());
+ }
+ return m_scopeStack[i].declareVariable(ident);
+ }
+
+ void declareWrite(const Identifier* ident)
+ {
+ if (!m_syntaxAlreadyValidated)
+ m_scopeStack.last().declareWrite(ident);
+ }
+
+ ScopeStack m_scopeStack;
+
+ const SourceProviderCacheItem* findCachedFunctionInfo(int openBracePos)
+ {
+ return m_functionCache ? m_functionCache->get(openBracePos) : 0;
+ }
+
+ SourceProviderCache* m_functionCache;
+};
+
+const char* jsParse(JSGlobalData* globalData, FunctionParameters* parameters, JSParserStrictness strictness, JSParserMode parserMode, const SourceCode* source)
+{
+ JSParser parser(globalData->lexer, globalData, parameters, strictness == JSParseStrict, parserMode == JSParseFunctionCode, source->provider());
+ return parser.parseProgram();
+}
+
+JSParser::JSParser(Lexer* lexer, JSGlobalData* globalData, FunctionParameters* parameters, bool inStrictContext, bool isFunction, SourceProvider* provider)
+ : m_lexer(lexer)
+ , m_stack(globalData->stack())
+ , m_error(false)
+ , m_errorMessage("Parse error")
+ , m_globalData(globalData)
+ , m_allowsIn(true)
+ , m_lastLine(0)
+ , m_lastTokenEnd(0)
+ , m_assignmentCount(0)
+ , m_nonLHSCount(0)
+ , m_syntaxAlreadyValidated(provider->isValid())
+ , m_statementDepth(0)
+ , m_nonTrivialExpressionCount(0)
+ , m_lastIdentifier(0)
+ , m_functionCache(m_lexer->sourceProvider()->cache())
+{
+ ScopeRef scope = pushScope();
+ if (isFunction)
+ scope->setIsFunction();
+ if (inStrictContext)
+ scope->setStrictMode();
+ if (parameters) {
+ for (unsigned i = 0; i < parameters->size(); i++)
+ scope->declareParameter(¶meters->at(i));
+ }
+ next();
+ m_lexer->setLastLineNumber(tokenLine());
+}
+
+const char* JSParser::parseProgram()
+{
+ unsigned oldFunctionCacheSize = m_functionCache ? m_functionCache->byteSize() : 0;
+ ASTBuilder context(m_globalData, m_lexer);
+ if (m_lexer->isReparsing())
+ m_statementDepth--;
+ ScopeRef scope = currentScope();
+ SourceElements* sourceElements = parseSourceElements<CheckForStrictMode>(context);
+ if (!sourceElements || !consume(EOFTOK))
+ return m_errorMessage;
+ IdentifierSet capturedVariables;
+ scope->getCapturedVariables(capturedVariables);
+ CodeFeatures features = context.features();
+ if (scope->strictMode())
+ features |= StrictModeFeature;
+ if (scope->shadowsArguments())
+ features |= ShadowsArgumentsFeature;
+
+ unsigned functionCacheSize = m_functionCache ? m_functionCache->byteSize() : 0;
+ if (functionCacheSize != oldFunctionCacheSize)
+ m_lexer->sourceProvider()->notifyCacheSizeChanged(functionCacheSize - oldFunctionCacheSize);
+
+ m_globalData->parser->didFinishParsing(sourceElements, context.varDeclarations(), context.funcDeclarations(), features,
+ m_lastLine, context.numConstants(), capturedVariables);
+ return 0;
+}
+
+bool JSParser::allowAutomaticSemicolon()
+{
+ return match(CLOSEBRACE) || match(EOFTOK) || m_lexer->prevTerminator();
+}
+
+template <JSParser::SourceElementsMode mode, class TreeBuilder> TreeSourceElements JSParser::parseSourceElements(TreeBuilder& context)
+{
+ TreeSourceElements sourceElements = context.createSourceElements();
+ bool seenNonDirective = false;
+ const Identifier* directive = 0;
+ unsigned startOffset = m_token.m_info.startOffset;
+ unsigned oldLastLineNumber = m_lexer->lastLineNumber();
+ unsigned oldLineNumber = m_lexer->lineNumber();
+ bool hasSetStrict = false;
+ while (TreeStatement statement = parseStatement(context, directive)) {
+ if (mode == CheckForStrictMode && !seenNonDirective) {
+ if (directive) {
+ if (!hasSetStrict && m_globalData->propertyNames->useStrictIdentifier == *directive) {
+ setStrictMode();
+ hasSetStrict = true;
+ failIfFalse(isValidStrictMode());
+ m_lexer->setOffset(startOffset);
+ next();
+ m_lexer->setLastLineNumber(oldLastLineNumber);
+ m_lexer->setLineNumber(oldLineNumber);
+ failIfTrue(m_error);
+ continue;
+ }
+ } else
+ seenNonDirective = true;
+ }
+ context.appendStatement(sourceElements, statement);
+ }
+
+ if (m_error)
+ fail();
+ return sourceElements;
+}
+
+template <class TreeBuilder> TreeStatement JSParser::parseVarDeclaration(TreeBuilder& context)
+{
+ ASSERT(match(VAR));
+ int start = tokenLine();
+ int end = 0;
+ int scratch;
+ const Identifier* scratch1 = 0;
+ TreeExpression scratch2 = 0;
+ int scratch3 = 0;
+ TreeExpression varDecls = parseVarDeclarationList(context, scratch, scratch1, scratch2, scratch3, scratch3, scratch3);
+ failIfTrue(m_error);
+ failIfFalse(autoSemiColon());
+
+ return context.createVarStatement(varDecls, start, end);
+}
+
+template <class TreeBuilder> TreeStatement JSParser::parseConstDeclaration(TreeBuilder& context)
+{
+ ASSERT(match(CONSTTOKEN));
+ int start = tokenLine();
+ int end = 0;
+ TreeConstDeclList constDecls = parseConstDeclarationList(context);
+ failIfTrue(m_error);
+ failIfFalse(autoSemiColon());
+
+ return context.createConstStatement(constDecls, start, end);
+}
+
+template <class TreeBuilder> TreeStatement JSParser::parseDoWhileStatement(TreeBuilder& context)
+{
+ ASSERT(match(DO));
+ int startLine = tokenLine();
+ next();
+ const Identifier* unused = 0;
+ startLoop();
+ TreeStatement statement = parseStatement(context, unused);
+ endLoop();
+ failIfFalse(statement);
+ int endLine = tokenLine();
+ consumeOrFail(WHILE);
+ consumeOrFail(OPENPAREN);
+ TreeExpression expr = parseExpression(context);
+ failIfFalse(expr);
+ consumeOrFail(CLOSEPAREN);
+ if (match(SEMICOLON))
+ next(); // Always performs automatic semicolon insertion.
+ return context.createDoWhileStatement(statement, expr, startLine, endLine);
+}
+
+template <class TreeBuilder> TreeStatement JSParser::parseWhileStatement(TreeBuilder& context)
+{
+ ASSERT(match(WHILE));
+ int startLine = tokenLine();
+ next();
+ consumeOrFail(OPENPAREN);
+ TreeExpression expr = parseExpression(context);
+ failIfFalse(expr);
+ int endLine = tokenLine();
+ consumeOrFail(CLOSEPAREN);
+ const Identifier* unused = 0;
+ startLoop();
+ TreeStatement statement = parseStatement(context, unused);
+ endLoop();
+ failIfFalse(statement);
+ return context.createWhileStatement(expr, statement, startLine, endLine);
+}
+
+template <class TreeBuilder> TreeExpression JSParser::parseVarDeclarationList(TreeBuilder& context, int& declarations, const Identifier*& lastIdent, TreeExpression& lastInitializer, int& identStart, int& initStart, int& initEnd)
+{
+ TreeExpression varDecls = 0;
+ do {
+ declarations++;
+ next();
+ matchOrFail(IDENT);
+
+ int varStart = tokenStart();
+ identStart = varStart;
+ const Identifier* name = m_token.m_data.ident;
+ lastIdent = name;
+ next();
+ bool hasInitializer = match(EQUAL);
+ failIfFalseIfStrict(declareVariable(name));
+ context.addVar(name, (hasInitializer || (!m_allowsIn && match(INTOKEN))) ? DeclarationStacks::HasInitializer : 0);
+ if (hasInitializer) {
+ int varDivot = tokenStart() + 1;
+ initStart = tokenStart();
+ next(TreeBuilder::DontBuildStrings); // consume '='
+ int initialAssignments = m_assignmentCount;
+ TreeExpression initializer = parseAssignmentExpression(context);
+ initEnd = lastTokenEnd();
+ lastInitializer = initializer;
+ failIfFalse(initializer);
+
+ TreeExpression node = context.createAssignResolve(*name, initializer, initialAssignments != m_assignmentCount, varStart, varDivot, lastTokenEnd());
+ if (!varDecls)
+ varDecls = node;
+ else
+ varDecls = context.combineCommaNodes(varDecls, node);
+ }
+ } while (match(COMMA));
+ return varDecls;
+}
+
+template <class TreeBuilder> TreeConstDeclList JSParser::parseConstDeclarationList(TreeBuilder& context)
+{
+ failIfTrue(strictMode());
+ TreeConstDeclList constDecls = 0;
+ TreeConstDeclList tail = 0;
+ do {
+ next();
+ matchOrFail(IDENT);
+ const Identifier* name = m_token.m_data.ident;
+ next();
+ bool hasInitializer = match(EQUAL);
+ declareVariable(name);
+ context.addVar(name, DeclarationStacks::IsConstant | (hasInitializer ? DeclarationStacks::HasInitializer : 0));
+ TreeExpression initializer = 0;
+ if (hasInitializer) {
+ next(TreeBuilder::DontBuildStrings); // consume '='
+ initializer = parseAssignmentExpression(context);
+ }
+ tail = context.appendConstDecl(tail, name, initializer);
+ if (!constDecls)
+ constDecls = tail;
+ } while (match(COMMA));
+ return constDecls;
+}
+
+template <class TreeBuilder> TreeStatement JSParser::parseForStatement(TreeBuilder& context)
+{
+ ASSERT(match(FOR));
+ int startLine = tokenLine();
+ next();
+ consumeOrFail(OPENPAREN);
+ int nonLHSCount = m_nonLHSCount;
+ int declarations = 0;
+ int declsStart = 0;
+ int declsEnd = 0;
+ TreeExpression decls = 0;
+ bool hasDeclaration = false;
+ if (match(VAR)) {
+ /*
+ for (var IDENT in expression) statement
+ for (var IDENT = expression in expression) statement
+ for (var varDeclarationList; expressionOpt; expressionOpt)
+ */
+ hasDeclaration = true;
+ const Identifier* forInTarget = 0;
+ TreeExpression forInInitializer = 0;
+ m_allowsIn = false;
+ int initStart = 0;
+ int initEnd = 0;
+ decls = parseVarDeclarationList(context, declarations, forInTarget, forInInitializer, declsStart, initStart, initEnd);
+ m_allowsIn = true;
+ if (m_error)
+ fail();
+
+ // Remainder of a standard for loop is handled identically
+ if (match(SEMICOLON))
+ goto standardForLoop;
+
+ failIfFalse(declarations == 1);
+
+ // Handle for-in with var declaration
+ int inLocation = tokenStart();
+ if (!consume(INTOKEN))
+ fail();
+
+ TreeExpression expr = parseExpression(context);
+ failIfFalse(expr);
+ int exprEnd = lastTokenEnd();
+
+ int endLine = tokenLine();
+ consumeOrFail(CLOSEPAREN);
+
+ const Identifier* unused = 0;
+ startLoop();
+ TreeStatement statement = parseStatement(context, unused);
+ endLoop();
+ failIfFalse(statement);
+
+ return context.createForInLoop(forInTarget, forInInitializer, expr, statement, declsStart, inLocation, exprEnd, initStart, initEnd, startLine, endLine);
+ }
+
+ if (!match(SEMICOLON)) {
+ m_allowsIn = false;
+ declsStart = tokenStart();
+ decls = parseExpression(context);
+ declsEnd = lastTokenEnd();
+ m_allowsIn = true;
+ failIfFalse(decls);
+ }
+
+ if (match(SEMICOLON)) {
+ standardForLoop:
+ // Standard for loop
+ next();
+ TreeExpression condition = 0;
+
+ if (!match(SEMICOLON)) {
+ condition = parseExpression(context);
+ failIfFalse(condition);
+ }
+ consumeOrFail(SEMICOLON);
+
+ TreeExpression increment = 0;
+ if (!match(CLOSEPAREN)) {
+ increment = parseExpression(context);
+ failIfFalse(increment);
+ }
+ int endLine = tokenLine();
+ consumeOrFail(CLOSEPAREN);
+ const Identifier* unused = 0;
+ startLoop();
+ TreeStatement statement = parseStatement(context, unused);
+ endLoop();
+ failIfFalse(statement);
+ return context.createForLoop(decls, condition, increment, statement, hasDeclaration, startLine, endLine);
+ }
+
+ // For-in loop
+ failIfFalse(nonLHSCount == m_nonLHSCount);
+ consumeOrFail(INTOKEN);
+ TreeExpression expr = parseExpression(context);
+ failIfFalse(expr);
+ int exprEnd = lastTokenEnd();
+ int endLine = tokenLine();
+ consumeOrFail(CLOSEPAREN);
+ const Identifier* unused = 0;
+ startLoop();
+ TreeStatement statement = parseStatement(context, unused);
+ endLoop();
+ failIfFalse(statement);
+
+ return context.createForInLoop(decls, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine);
+}
+
+template <class TreeBuilder> TreeStatement JSParser::parseBreakStatement(TreeBuilder& context)
+{
+ ASSERT(match(BREAK));
+ int startCol = tokenStart();
+ int endCol = tokenEnd();
+ int startLine = tokenLine();
+ int endLine = tokenLine();
+ next();
+
+ if (autoSemiColon()) {
+ failIfFalse(breakIsValid());
+ return context.createBreakStatement(startCol, endCol, startLine, endLine);
+ }
+ matchOrFail(IDENT);
+ const Identifier* ident = m_token.m_data.ident;
+ failIfFalse(getLabel(ident));
+ endCol = tokenEnd();
+ endLine = tokenLine();
+ next();
+ failIfFalse(autoSemiColon());
+ return context.createBreakStatement(ident, startCol, endCol, startLine, endLine);
+}
+
+template <class TreeBuilder> TreeStatement JSParser::parseContinueStatement(TreeBuilder& context)
+{
+ ASSERT(match(CONTINUE));
+ int startCol = tokenStart();
+ int endCol = tokenEnd();
+ int startLine = tokenLine();
+ int endLine = tokenLine();
+ next();
+
+ if (autoSemiColon()) {
+ failIfFalse(continueIsValid());
+ return context.createContinueStatement(startCol, endCol, startLine, endLine);
+ }
+ matchOrFail(IDENT);
+ const Identifier* ident = m_token.m_data.ident;
+ ScopeLabelInfo* label = getLabel(ident);
+ failIfFalse(label);
+ failIfFalse(label->m_isLoop);
+ endCol = tokenEnd();
+ endLine = tokenLine();
+ next();
+ failIfFalse(autoSemiColon());
+ return context.createContinueStatement(ident, startCol, endCol, startLine, endLine);
+}
+
+template <class TreeBuilder> TreeStatement JSParser::parseReturnStatement(TreeBuilder& context)
+{
+ ASSERT(match(RETURN));
+ failIfFalse(currentScope()->isFunction());
+ int startLine = tokenLine();
+ int endLine = startLine;
+ int start = tokenStart();
+ int end = tokenEnd();
+ next();
+ // We do the auto semicolon check before attempting to parse an expression
+ // as we need to ensure the a line break after the return correctly terminates
+ // the statement
+ if (match(SEMICOLON))
+ endLine = tokenLine();
+ if (autoSemiColon())
+ return context.createReturnStatement(0, start, end, startLine, endLine);
+ TreeExpression expr = parseExpression(context);
+ failIfFalse(expr);
+ end = lastTokenEnd();
+ if (match(SEMICOLON))
+ endLine = tokenLine();
+ failIfFalse(autoSemiColon());
+ return context.createReturnStatement(expr, start, end, startLine, endLine);
+}
+
+template <class TreeBuilder> TreeStatement JSParser::parseThrowStatement(TreeBuilder& context)
+{
+ ASSERT(match(THROW));
+ int eStart = tokenStart();
+ int startLine = tokenLine();
+ next();
+
+ failIfTrue(autoSemiColon());
+
+ TreeExpression expr = parseExpression(context);
+ failIfFalse(expr);
+ int eEnd = lastTokenEnd();
+ int endLine = tokenLine();
+ failIfFalse(autoSemiColon());
+
+ return context.createThrowStatement(expr, eStart, eEnd, startLine, endLine);
+}
+
+template <class TreeBuilder> TreeStatement JSParser::parseWithStatement(TreeBuilder& context)
+{
+ ASSERT(match(WITH));
+ failIfTrue(strictMode());
+ currentScope()->setNeedsFullActivation();
+ int startLine = tokenLine();
+ next();
+ consumeOrFail(OPENPAREN);
+ int start = tokenStart();
+ TreeExpression expr = parseExpression(context);
+ failIfFalse(expr);
+ int end = lastTokenEnd();
+
+ int endLine = tokenLine();
+ consumeOrFail(CLOSEPAREN);
+ const Identifier* unused = 0;
+ TreeStatement statement = parseStatement(context, unused);
+ failIfFalse(statement);
+
+ return context.createWithStatement(expr, statement, start, end, startLine, endLine);
+}
+
+template <class TreeBuilder> TreeStatement JSParser::parseSwitchStatement(TreeBuilder& context)
+{
+ ASSERT(match(SWITCH));
+ int startLine = tokenLine();
+ next();
+ consumeOrFail(OPENPAREN);
+ TreeExpression expr = parseExpression(context);
+ failIfFalse(expr);
+ int endLine = tokenLine();
+ consumeOrFail(CLOSEPAREN);
+ consumeOrFail(OPENBRACE);
+ startSwitch();
+ TreeClauseList firstClauses = parseSwitchClauses(context);
+ failIfTrue(m_error);
+
+ TreeClause defaultClause = parseSwitchDefaultClause(context);
+ failIfTrue(m_error);
+
+ TreeClauseList secondClauses = parseSwitchClauses(context);
+ failIfTrue(m_error);
+ endSwitch();
+ consumeOrFail(CLOSEBRACE);
+
+ return context.createSwitchStatement(expr, firstClauses, defaultClause, secondClauses, startLine, endLine);
+
+}
+
+template <class TreeBuilder> TreeClauseList JSParser::parseSwitchClauses(TreeBuilder& context)
+{
+ if (!match(CASE))
+ return 0;
+ next();
+ TreeExpression condition = parseExpression(context);
+ failIfFalse(condition);
+ consumeOrFail(COLON);
+ TreeSourceElements statements = parseSourceElements<DontCheckForStrictMode>(context);
+ failIfFalse(statements);
+ TreeClause clause = context.createClause(condition, statements);
+ TreeClauseList clauseList = context.createClauseList(clause);
+ TreeClauseList tail = clauseList;
+
+ while (match(CASE)) {
+ next();
+ TreeExpression condition = parseExpression(context);
+ failIfFalse(condition);
+ consumeOrFail(COLON);
+ TreeSourceElements statements = parseSourceElements<DontCheckForStrictMode>(context);
+ failIfFalse(statements);
+ clause = context.createClause(condition, statements);
+ tail = context.createClauseList(tail, clause);
+ }
+ return clauseList;
+}
+
+template <class TreeBuilder> TreeClause JSParser::parseSwitchDefaultClause(TreeBuilder& context)
+{
+ if (!match(DEFAULT))
+ return 0;
+ next();
+ consumeOrFail(COLON);
+ TreeSourceElements statements = parseSourceElements<DontCheckForStrictMode>(context);
+ failIfFalse(statements);
+ return context.createClause(0, statements);
+}
+
+template <class TreeBuilder> TreeStatement JSParser::parseTryStatement(TreeBuilder& context)
+{
+ ASSERT(match(TRY));
+ TreeStatement tryBlock = 0;
+ const Identifier* ident = &m_globalData->propertyNames->nullIdentifier;
+ bool catchHasEval = false;
+ TreeStatement catchBlock = 0;
+ TreeStatement finallyBlock = 0;
+ int firstLine = tokenLine();
+ next();
+ matchOrFail(OPENBRACE);
+
+ tryBlock = parseBlockStatement(context);
+ failIfFalse(tryBlock);
+ int lastLine = m_lastLine;
+
+ if (match(CATCH)) {
+ currentScope()->setNeedsFullActivation();
+ next();
+ consumeOrFail(OPENPAREN);
+ matchOrFail(IDENT);
+ ident = m_token.m_data.ident;
+ next();
+ AutoPopScopeRef catchScope(this, pushScope());
+ failIfFalseIfStrict(catchScope->declareVariable(ident));
+ catchScope->preventNewDecls();
+ consumeOrFail(CLOSEPAREN);
+ matchOrFail(OPENBRACE);
+ int initialEvalCount = context.evalCount();
+ catchBlock = parseBlockStatement(context);
+ failIfFalse(catchBlock);
+ catchHasEval = initialEvalCount != context.evalCount();
+ failIfFalse(popScope(catchScope, TreeBuilder::NeedsFreeVariableInfo));
+ }
+
+ if (match(FINALLY)) {
+ next();
+ matchOrFail(OPENBRACE);
+ finallyBlock = parseBlockStatement(context);
+ failIfFalse(finallyBlock);
+ }
+ failIfFalse(catchBlock || finallyBlock);
+ return context.createTryStatement(tryBlock, ident, catchHasEval, catchBlock, finallyBlock, firstLine, lastLine);
+}
+
+template <class TreeBuilder> TreeStatement JSParser::parseDebuggerStatement(TreeBuilder& context)
+{
+ ASSERT(match(DEBUGGER));
+ int startLine = tokenLine();
+ int endLine = startLine;
+ next();
+ if (match(SEMICOLON))
+ startLine = tokenLine();
+ failIfFalse(autoSemiColon());
+ return context.createDebugger(startLine, endLine);
+}
+
+template <class TreeBuilder> TreeStatement JSParser::parseBlockStatement(TreeBuilder& context)
+{
+ ASSERT(match(OPENBRACE));
+ int start = tokenLine();
+ next();
+ if (match(CLOSEBRACE)) {
+ next();
+ return context.createBlockStatement(0, start, m_lastLine);
+ }
+ TreeSourceElements subtree = parseSourceElements<DontCheckForStrictMode>(context);
+ failIfFalse(subtree);
+ matchOrFail(CLOSEBRACE);
+ next();
+ return context.createBlockStatement(subtree, start, m_lastLine);
+}
+
+template <class TreeBuilder> TreeStatement JSParser::parseStatement(TreeBuilder& context, const Identifier*& directive)
+{
+ DepthManager statementDepth(&m_statementDepth);
+ m_statementDepth++;
+ directive = 0;
+ int nonTrivialExpressionCount = 0;
+ failIfStackOverflow();
+ switch (m_token.m_type) {
+ case OPENBRACE:
+ return parseBlockStatement(context);
+ case VAR:
+ return parseVarDeclaration(context);
+ case CONSTTOKEN:
+ return parseConstDeclaration(context);
+ case FUNCTION:
+ failIfFalseIfStrict(m_statementDepth == 1);
+ return parseFunctionDeclaration(context);
+ case SEMICOLON:
+ next();
+ return context.createEmptyStatement();
+ case IF:
+ return parseIfStatement(context);
+ case DO:
+ return parseDoWhileStatement(context);
+ case WHILE:
+ return parseWhileStatement(context);
+ case FOR:
+ return parseForStatement(context);
+ case CONTINUE:
+ return parseContinueStatement(context);
+ case BREAK:
+ return parseBreakStatement(context);
+ case RETURN:
+ return parseReturnStatement(context);
+ case WITH:
+ return parseWithStatement(context);
+ case SWITCH:
+ return parseSwitchStatement(context);
+ case THROW:
+ return parseThrowStatement(context);
+ case TRY:
+ return parseTryStatement(context);
+ case DEBUGGER:
+ return parseDebuggerStatement(context);
+ case EOFTOK:
+ case CASE:
+ case CLOSEBRACE:
+ case DEFAULT:
+ // These tokens imply the end of a set of source elements
+ return 0;
+ case IDENT:
+ return parseExpressionOrLabelStatement(context);
+ case STRING:
+ directive = m_token.m_data.ident;
+ nonTrivialExpressionCount = m_nonTrivialExpressionCount;
+ default:
+ TreeStatement exprStatement = parseExpressionStatement(context);
+ if (directive && nonTrivialExpressionCount != m_nonTrivialExpressionCount)
+ directive = 0;
+ return exprStatement;
+ }
+}
+
+template <class TreeBuilder> TreeFormalParameterList JSParser::parseFormalParameters(TreeBuilder& context)
+{
+ matchOrFail(IDENT);
+ failIfFalseIfStrict(declareParameter(m_token.m_data.ident));
+ TreeFormalParameterList list = context.createFormalParameterList(*m_token.m_data.ident);
+ TreeFormalParameterList tail = list;
+ next();
+ while (match(COMMA)) {
+ next();
+ matchOrFail(IDENT);
+ const Identifier* ident = m_token.m_data.ident;
+ failIfFalseIfStrict(declareParameter(ident));
+ next();
+ tail = context.createFormalParameterList(tail, *ident);
+ }
+ return list;
+}
+
+template <class TreeBuilder> TreeFunctionBody JSParser::parseFunctionBody(TreeBuilder& context)
+{
+ if (match(CLOSEBRACE))
+ return context.createFunctionBody(strictMode());
+ DepthManager statementDepth(&m_statementDepth);
+ m_statementDepth = 0;
+ typename TreeBuilder::FunctionBodyBuilder bodyBuilder(m_globalData, m_lexer);
+ failIfFalse(parseSourceElements<CheckForStrictMode>(bodyBuilder));
+ return context.createFunctionBody(strictMode());
+}
+
+template <JSParser::FunctionRequirements requirements, bool nameIsInContainingScope, class TreeBuilder> bool JSParser::parseFunctionInfo(TreeBuilder& context, const Identifier*& name, TreeFormalParameterList& parameters, TreeFunctionBody& body, int& openBracePos, int& closeBracePos, int& bodyStartLine)
+{
+ AutoPopScopeRef functionScope(this, pushScope());
+ functionScope->setIsFunction();
+ if (match(IDENT)) {
+ name = m_token.m_data.ident;
+ failIfTrue(*name == m_globalData->propertyNames->underscoreProto);
+ next();
+ if (!nameIsInContainingScope)
+ failIfFalseIfStrict(functionScope->declareVariable(name));
+ } else if (requirements == FunctionNeedsName)
+ return false;
+ consumeOrFail(OPENPAREN);
+ if (!match(CLOSEPAREN)) {
+ parameters = parseFormalParameters(context);
+ failIfFalse(parameters);
+ }
+ consumeOrFail(CLOSEPAREN);
+ matchOrFail(OPENBRACE);
+
+ openBracePos = m_token.m_data.intValue;
+ bodyStartLine = tokenLine();
+
+ if (const SourceProviderCacheItem* cachedInfo = TreeBuilder::CanUseFunctionCache ? findCachedFunctionInfo(openBracePos) : 0) {
+ // If we know about this function already, we can use the cached info and skip the parser to the end of the function.
+ body = context.createFunctionBody(strictMode());
+
+ functionScope->restoreFunctionInfo(cachedInfo);
+ failIfFalse(popScope(functionScope, TreeBuilder::NeedsFreeVariableInfo));
+
+ closeBracePos = cachedInfo->closeBracePos;
+ m_token = cachedInfo->closeBraceToken();
+ m_lexer->setOffset(m_token.m_info.endOffset);
+ m_lexer->setLineNumber(m_token.m_info.line);
+
+ next();
+ return true;
+ }
+
+ next();
+
+ body = parseFunctionBody(context);
+ failIfFalse(body);
+ if (functionScope->strictMode() && name) {
+ failIfTrue(m_globalData->propertyNames->arguments == *name);
+ failIfTrue(m_globalData->propertyNames->eval == *name);
+ }
+ closeBracePos = m_token.m_data.intValue;
+
+ // Cache the tokenizer state and the function scope the first time the function is parsed.
+ // Any future reparsing can then skip the function.
+ static const int minimumFunctionLengthToCache = 64;
+ OwnPtr<SourceProviderCacheItem> newInfo;
+ int functionLength = closeBracePos - openBracePos;
+ if (TreeBuilder::CanUseFunctionCache && m_functionCache && functionLength > minimumFunctionLengthToCache) {
+ newInfo = adoptPtr(new SourceProviderCacheItem(m_token.m_info.line, closeBracePos));
+ functionScope->saveFunctionInfo(newInfo.get());
+ }
+
+ failIfFalse(popScope(functionScope, TreeBuilder::NeedsFreeVariableInfo));
+ matchOrFail(CLOSEBRACE);
+
+ if (newInfo) {
+ unsigned approximateByteSize = newInfo->approximateByteSize();
+ m_functionCache->add(openBracePos, newInfo.release(), approximateByteSize);
+ }
+
+ next();
+ return true;
+}
+
+template <class TreeBuilder> TreeStatement JSParser::parseFunctionDeclaration(TreeBuilder& context)
+{
+ ASSERT(match(FUNCTION));
+ next();
+ const Identifier* name = 0;
+ TreeFormalParameterList parameters = 0;
+ TreeFunctionBody body = 0;
+ int openBracePos = 0;
+ int closeBracePos = 0;
+ int bodyStartLine = 0;
+ failIfFalse((parseFunctionInfo<FunctionNeedsName, true>(context, name, parameters, body, openBracePos, closeBracePos, bodyStartLine)));
+ failIfFalse(name);
+ failIfFalseIfStrict(declareVariable(name));
+ return context.createFuncDeclStatement(name, body, parameters, openBracePos, closeBracePos, bodyStartLine, m_lastLine);
+}
+
+struct LabelInfo {
+ LabelInfo(const Identifier* ident, int start, int end)
+ : m_ident(ident)
+ , m_start(start)
+ , m_end(end)
+ {
+ }
+
+ const Identifier* m_ident;
+ int m_start;
+ int m_end;
+};
+
+template <class TreeBuilder> TreeStatement JSParser::parseExpressionOrLabelStatement(TreeBuilder& context)
+{
+
+ /* Expression and Label statements are ambiguous at LL(1), so we have a
+ * special case that looks for a colon as the next character in the input.
+ */
+ Vector<LabelInfo> labels;
+
+ do {
+ int start = tokenStart();
+ int startLine = tokenLine();
+ if (!nextTokenIsColon()) {
+ // If we hit this path we're making a expression statement, which
+ // by definition can't make use of continue/break so we can just
+ // ignore any labels we might have accumulated.
+ TreeExpression expression = parseExpression(context);
+ failIfFalse(expression);
+ failIfFalse(autoSemiColon());
+ return context.createExprStatement(expression, startLine, m_lastLine);
+ }
+ const Identifier* ident = m_token.m_data.ident;
+ int end = tokenEnd();
+ next();
+ consumeOrFail(COLON);
+ if (!m_syntaxAlreadyValidated) {
+ // This is O(N^2) over the current list of consecutive labels, but I
+ // have never seen more than one label in a row in the real world.
+ for (size_t i = 0; i < labels.size(); i++)
+ failIfTrue(ident->impl() == labels[i].m_ident->impl());
+ failIfTrue(getLabel(ident));
+ labels.append(LabelInfo(ident, start, end));
+ }
+ } while (match(IDENT));
+ bool isLoop = false;
+ switch (m_token.m_type) {
+ case FOR:
+ case WHILE:
+ case DO:
+ isLoop = true;
+ break;
+
+ default:
+ break;
+ }
+ const Identifier* unused = 0;
+ if (!m_syntaxAlreadyValidated) {
+ for (size_t i = 0; i < labels.size(); i++)
+ pushLabel(labels[i].m_ident, isLoop);
+ }
+ TreeStatement statement = parseStatement(context, unused);
+ if (!m_syntaxAlreadyValidated) {
+ for (size_t i = 0; i < labels.size(); i++)
+ popLabel();
+ }
+ failIfFalse(statement);
+ for (size_t i = 0; i < labels.size(); i++) {
+ const LabelInfo& info = labels[labels.size() - i - 1];
+ statement = context.createLabelStatement(info.m_ident, statement, info.m_start, info.m_end);
+ }
+ return statement;
+}
+
+template <class TreeBuilder> TreeStatement JSParser::parseExpressionStatement(TreeBuilder& context)
+{
+ int startLine = tokenLine();
+ TreeExpression expression = parseExpression(context);
+ failIfFalse(expression);
+ failIfFalse(autoSemiColon());
+ return context.createExprStatement(expression, startLine, m_lastLine);
+}
+
+template <class TreeBuilder> TreeStatement JSParser::parseIfStatement(TreeBuilder& context)
+{
+ ASSERT(match(IF));
+
+ int start = tokenLine();
+ next();
+
+ consumeOrFail(OPENPAREN);
+
+ TreeExpression condition = parseExpression(context);
+ failIfFalse(condition);
+ int end = tokenLine();
+ consumeOrFail(CLOSEPAREN);
+
+ const Identifier* unused = 0;
+ TreeStatement trueBlock = parseStatement(context, unused);
+ failIfFalse(trueBlock);
+
+ if (!match(ELSE))
+ return context.createIfStatement(condition, trueBlock, start, end);
+
+ Vector<TreeExpression> exprStack;
+ Vector<pair<int, int> > posStack;
+ Vector<TreeStatement> statementStack;
+ bool trailingElse = false;
+ do {
+ next();
+ if (!match(IF)) {
+ const Identifier* unused = 0;
+ TreeStatement block = parseStatement(context, unused);
+ failIfFalse(block);
+ statementStack.append(block);
+ trailingElse = true;
+ break;
+ }
+ int innerStart = tokenLine();
+ next();
+
+ consumeOrFail(OPENPAREN);
+
+ TreeExpression innerCondition = parseExpression(context);
+ failIfFalse(innerCondition);
+ int innerEnd = tokenLine();
+ consumeOrFail(CLOSEPAREN);
+ const Identifier* unused = 0;
+ TreeStatement innerTrueBlock = parseStatement(context, unused);
+ failIfFalse(innerTrueBlock);
+ exprStack.append(innerCondition);
+ posStack.append(make_pair(innerStart, innerEnd));
+ statementStack.append(innerTrueBlock);
+ } while (match(ELSE));
+
+ if (!trailingElse) {
+ TreeExpression condition = exprStack.last();
+ exprStack.removeLast();
+ TreeStatement trueBlock = statementStack.last();
+ statementStack.removeLast();
+ pair<int, int> pos = posStack.last();
+ posStack.removeLast();
+ statementStack.append(context.createIfStatement(condition, trueBlock, pos.first, pos.second));
+ }
+
+ while (!exprStack.isEmpty()) {
+ TreeExpression condition = exprStack.last();
+ exprStack.removeLast();
+ TreeStatement falseBlock = statementStack.last();
+ statementStack.removeLast();
+ TreeStatement trueBlock = statementStack.last();
+ statementStack.removeLast();
+ pair<int, int> pos = posStack.last();
+ posStack.removeLast();
+ statementStack.append(context.createIfStatement(condition, trueBlock, falseBlock, pos.first, pos.second));
+ }
+
+ return context.createIfStatement(condition, trueBlock, statementStack.last(), start, end);
+}
+
+template <class TreeBuilder> TreeExpression JSParser::parseExpression(TreeBuilder& context)
+{
+ failIfStackOverflow();
+ TreeExpression node = parseAssignmentExpression(context);
+ failIfFalse(node);
+ if (!match(COMMA))
+ return node;
+ next();
+ m_nonTrivialExpressionCount++;
+ m_nonLHSCount++;
+ TreeExpression right = parseAssignmentExpression(context);
+ failIfFalse(right);
+ typename TreeBuilder::Comma commaNode = context.createCommaExpr(node, right);
+ while (match(COMMA)) {
+ next(TreeBuilder::DontBuildStrings);
+ right = parseAssignmentExpression(context);
+ failIfFalse(right);
+ context.appendToComma(commaNode, right);
+ }
+ return commaNode;
+}
+
+
+template <typename TreeBuilder> TreeExpression JSParser::parseAssignmentExpression(TreeBuilder& context)
+{
+ failIfStackOverflow();
+ int start = tokenStart();
+ int initialAssignmentCount = m_assignmentCount;
+ int initialNonLHSCount = m_nonLHSCount;
+ TreeExpression lhs = parseConditionalExpression(context);
+ failIfFalse(lhs);
+ if (initialNonLHSCount != m_nonLHSCount)
+ return lhs;
+
+ int assignmentStack = 0;
+ Operator op;
+ bool hadAssignment = false;
+ while (true) {
+ switch (m_token.m_type) {
+ case EQUAL: op = OpEqual; break;
+ case PLUSEQUAL: op = OpPlusEq; break;
+ case MINUSEQUAL: op = OpMinusEq; break;
+ case MULTEQUAL: op = OpMultEq; break;
+ case DIVEQUAL: op = OpDivEq; break;
+ case LSHIFTEQUAL: op = OpLShift; break;
+ case RSHIFTEQUAL: op = OpRShift; break;
+ case URSHIFTEQUAL: op = OpURShift; break;
+ case ANDEQUAL: op = OpAndEq; break;
+ case XOREQUAL: op = OpXOrEq; break;
+ case OREQUAL: op = OpOrEq; break;
+ case MODEQUAL: op = OpModEq; break;
+ default:
+ goto end;
+ }
+ m_nonTrivialExpressionCount++;
+ hadAssignment = true;
+ context.assignmentStackAppend(assignmentStack, lhs, start, tokenStart(), m_assignmentCount, op);
+ start = tokenStart();
+ m_assignmentCount++;
+ next(TreeBuilder::DontBuildStrings);
+ if (strictMode() && m_lastIdentifier && context.isResolve(lhs)) {
+ failIfTrueIfStrict(m_globalData->propertyNames->eval == *m_lastIdentifier);
+ failIfTrueIfStrict(m_globalData->propertyNames->arguments == *m_lastIdentifier);
+ declareWrite(m_lastIdentifier);
+ m_lastIdentifier = 0;
+ }
+ lhs = parseConditionalExpression(context);
+ failIfFalse(lhs);
+ if (initialNonLHSCount != m_nonLHSCount)
+ break;
+ }
+end:
+ if (hadAssignment)
+ m_nonLHSCount++;
+
+ if (!TreeBuilder::CreatesAST)
+ return lhs;
+
+ while (assignmentStack)
+ lhs = context.createAssignment(assignmentStack, lhs, initialAssignmentCount, m_assignmentCount, lastTokenEnd());
+
+ return lhs;
+}
+
+template <class TreeBuilder> TreeExpression JSParser::parseConditionalExpression(TreeBuilder& context)
+{
+ TreeExpression cond = parseBinaryExpression(context);
+ failIfFalse(cond);
+ if (!match(QUESTION))
+ return cond;
+ m_nonTrivialExpressionCount++;
+ m_nonLHSCount++;
+ next(TreeBuilder::DontBuildStrings);
+ TreeExpression lhs = parseAssignmentExpression(context);
+ consumeOrFailWithFlags(COLON, TreeBuilder::DontBuildStrings);
+
+ TreeExpression rhs = parseAssignmentExpression(context);
+ failIfFalse(rhs);
+ return context.createConditionalExpr(cond, lhs, rhs);
+}
+
+ALWAYS_INLINE static bool isUnaryOp(JSTokenType token)
+{
+ return token & UnaryOpTokenFlag;
+}
+
+int JSParser::isBinaryOperator(JSTokenType token)
+{
+ if (m_allowsIn)
+ return token & (BinaryOpTokenPrecedenceMask << BinaryOpTokenAllowsInPrecedenceAdditionalShift);
+ return token & BinaryOpTokenPrecedenceMask;
+}
+
+template <class TreeBuilder> TreeExpression JSParser::parseBinaryExpression(TreeBuilder& context)
+{
+
+ int operandStackDepth = 0;
+ int operatorStackDepth = 0;
+ typename TreeBuilder::BinaryExprContext binaryExprContext(context);
+ while (true) {
+ int exprStart = tokenStart();
+ int initialAssignments = m_assignmentCount;
+ TreeExpression current = parseUnaryExpression(context);
+ failIfFalse(current);
+
+ context.appendBinaryExpressionInfo(operandStackDepth, current, exprStart, lastTokenEnd(), lastTokenEnd(), initialAssignments != m_assignmentCount);
+ int precedence = isBinaryOperator(m_token.m_type);
+ if (!precedence)
+ break;
+ m_nonTrivialExpressionCount++;
+ m_nonLHSCount++;
+ int operatorToken = m_token.m_type;
+ next(TreeBuilder::DontBuildStrings);
+
+ while (operatorStackDepth && context.operatorStackHasHigherPrecedence(operatorStackDepth, precedence)) {
+ ASSERT(operandStackDepth > 1);
+
+ typename TreeBuilder::BinaryOperand rhs = context.getFromOperandStack(-1);
+ typename TreeBuilder::BinaryOperand lhs = context.getFromOperandStack(-2);
+ context.shrinkOperandStackBy(operandStackDepth, 2);
+ context.appendBinaryOperation(operandStackDepth, operatorStackDepth, lhs, rhs);
+ context.operatorStackPop(operatorStackDepth);
+ }
+ context.operatorStackAppend(operatorStackDepth, operatorToken, precedence);
+ }
+ while (operatorStackDepth) {
+ ASSERT(operandStackDepth > 1);
+
+ typename TreeBuilder::BinaryOperand rhs = context.getFromOperandStack(-1);
+ typename TreeBuilder::BinaryOperand lhs = context.getFromOperandStack(-2);
+ context.shrinkOperandStackBy(operandStackDepth, 2);
+ context.appendBinaryOperation(operandStackDepth, operatorStackDepth, lhs, rhs);
+ context.operatorStackPop(operatorStackDepth);
+ }
+ return context.popOperandStack(operandStackDepth);
+}
+
+
+template <bool complete, class TreeBuilder> TreeProperty JSParser::parseProperty(TreeBuilder& context)
+{
+ bool wasIdent = false;
+ switch (m_token.m_type) {
+ namedProperty:
+ case IDENT:
+ wasIdent = true;
+ case STRING: {
+ const Identifier* ident = m_token.m_data.ident;
+ if (complete || (wasIdent && (*ident == m_globalData->propertyNames->get || *ident == m_globalData->propertyNames->set)))
+ nextExpectIdentifier(Lexer::IgnoreReservedWords);
+ else
+ nextExpectIdentifier(Lexer::IgnoreReservedWords | TreeBuilder::DontBuildKeywords);
+
+ if (match(COLON)) {
+ next();
+ TreeExpression node = parseAssignmentExpression(context);
+ failIfFalse(node);
+ return context.template createProperty<complete>(ident, node, PropertyNode::Constant);
+ }
+ failIfFalse(wasIdent);
+ matchOrFail(IDENT);
+ const Identifier* accessorName = 0;
+ TreeFormalParameterList parameters = 0;
+ TreeFunctionBody body = 0;
+ int openBracePos = 0;
+ int closeBracePos = 0;
+ int bodyStartLine = 0;
+ PropertyNode::Type type;
+ if (*ident == m_globalData->propertyNames->get)
+ type = PropertyNode::Getter;
+ else if (*ident == m_globalData->propertyNames->set)
+ type = PropertyNode::Setter;
+ else
+ fail();
+ failIfFalse((parseFunctionInfo<FunctionNeedsName, false>(context, accessorName, parameters, body, openBracePos, closeBracePos, bodyStartLine)));
+ return context.template createGetterOrSetterProperty<complete>(type, accessorName, parameters, body, openBracePos, closeBracePos, bodyStartLine, m_lastLine);
+ }
+ case NUMBER: {
+ double propertyName = m_token.m_data.doubleValue;
+ next();
+ consumeOrFail(COLON);
+ TreeExpression node = parseAssignmentExpression(context);
+ failIfFalse(node);
+ return context.template createProperty<complete>(m_globalData, propertyName, node, PropertyNode::Constant);
+ }
+ default:
+ failIfFalse(m_token.m_type & KeywordTokenFlag);
+ goto namedProperty;
+ }
+}
+
+template <class TreeBuilder> TreeExpression JSParser::parseObjectLiteral(TreeBuilder& context)
+{
+ int startOffset = m_token.m_data.intValue;
+ consumeOrFailWithFlags(OPENBRACE, TreeBuilder::DontBuildStrings);
+
+ if (match(CLOSEBRACE)) {
+ next();
+ return context.createObjectLiteral();
+ }
+
+ TreeProperty property = parseProperty<false>(context);
+ failIfFalse(property);
+ if (!m_syntaxAlreadyValidated && context.getType(property) != PropertyNode::Constant) {
+ m_lexer->setOffset(startOffset);
+ next();
+ return parseStrictObjectLiteral(context);
+ }
+ TreePropertyList propertyList = context.createPropertyList(property);
+ TreePropertyList tail = propertyList;
+ while (match(COMMA)) {
+ next(TreeBuilder::DontBuildStrings);
+ // allow extra comma, see http://bugs.webkit.org/show_bug.cgi?id=5939
+ if (match(CLOSEBRACE))
+ break;
+ property = parseProperty<false>(context);
+ failIfFalse(property);
+ if (!m_syntaxAlreadyValidated && context.getType(property) != PropertyNode::Constant) {
+ m_lexer->setOffset(startOffset);
+ next();
+ return parseStrictObjectLiteral(context);
+ }
+ tail = context.createPropertyList(property, tail);
+ }
+
+ consumeOrFail(CLOSEBRACE);
+
+ return context.createObjectLiteral(propertyList);
+}
+
+template <class TreeBuilder> TreeExpression JSParser::parseStrictObjectLiteral(TreeBuilder& context)
+{
+ consumeOrFail(OPENBRACE);
+
+ if (match(CLOSEBRACE)) {
+ next();
+ return context.createObjectLiteral();
+ }
+
+ TreeProperty property = parseProperty<true>(context);
+ failIfFalse(property);
+
+ typedef HashMap<RefPtr<StringImpl>, unsigned, IdentifierRepHash> ObjectValidationMap;
+ ObjectValidationMap objectValidator;
+ // Add the first property
+ if (!m_syntaxAlreadyValidated)
+ objectValidator.add(context.getName(property).impl(), context.getType(property));
+
+ TreePropertyList propertyList = context.createPropertyList(property);
+ TreePropertyList tail = propertyList;
+ while (match(COMMA)) {
+ next();
+ // allow extra comma, see http://bugs.webkit.org/show_bug.cgi?id=5939
+ if (match(CLOSEBRACE))
+ break;
+ property = parseProperty<true>(context);
+ failIfFalse(property);
+ if (!m_syntaxAlreadyValidated) {
+ std::pair<ObjectValidationMap::iterator, bool> propertyEntryIter = objectValidator.add(context.getName(property).impl(), context.getType(property));
+ if (!propertyEntryIter.second) {
+ failIfTrue(propertyEntryIter.first->second == PropertyNode::Constant);
+ failIfTrue(context.getType(property) == PropertyNode::Constant);
+ failIfTrue(context.getType(property) & propertyEntryIter.first->second);
+ propertyEntryIter.first->second |= context.getType(property);
+ }
+ }
+ tail = context.createPropertyList(property, tail);
+ }
+
+ consumeOrFail(CLOSEBRACE);
+
+ return context.createObjectLiteral(propertyList);
+}
+
+template <class TreeBuilder> TreeExpression JSParser::parseArrayLiteral(TreeBuilder& context)
+{
+ consumeOrFailWithFlags(OPENBRACKET, TreeBuilder::DontBuildStrings);
+
+ int elisions = 0;
+ while (match(COMMA)) {
+ next(TreeBuilder::DontBuildStrings);
+ elisions++;
+ }
+ if (match(CLOSEBRACKET)) {
+ next(TreeBuilder::DontBuildStrings);
+ return context.createArray(elisions);
+ }
+
+ TreeExpression elem = parseAssignmentExpression(context);
+ failIfFalse(elem);
+ typename TreeBuilder::ElementList elementList = context.createElementList(elisions, elem);
+ typename TreeBuilder::ElementList tail = elementList;
+ elisions = 0;
+ while (match(COMMA)) {
+ next(TreeBuilder::DontBuildStrings);
+ elisions = 0;
+
+ while (match(COMMA)) {
+ next();
+ elisions++;
+ }
+
+ if (match(CLOSEBRACKET)) {
+ next(TreeBuilder::DontBuildStrings);
+ return context.createArray(elisions, elementList);
+ }
+ TreeExpression elem = parseAssignmentExpression(context);
+ failIfFalse(elem);
+ tail = context.createElementList(tail, elisions, elem);
+ }
+
+ consumeOrFail(CLOSEBRACKET);
+
+ return context.createArray(elementList);
+}
+
+template <class TreeBuilder> TreeExpression JSParser::parsePrimaryExpression(TreeBuilder& context)
+{
+ switch (m_token.m_type) {
+ case OPENBRACE:
+ if (strictMode())
+ return parseStrictObjectLiteral(context);
+ return parseObjectLiteral(context);
+ case OPENBRACKET:
+ return parseArrayLiteral(context);
+ case OPENPAREN: {
+ next();
+ int oldNonLHSCount = m_nonLHSCount;
+ TreeExpression result = parseExpression(context);
+ m_nonLHSCount = oldNonLHSCount;
+ consumeOrFail(CLOSEPAREN);
+
+ return result;
+ }
+ case THISTOKEN: {
+ next();
+ return context.thisExpr();
+ }
+ case IDENT: {
+ int start = tokenStart();
+ const Identifier* ident = m_token.m_data.ident;
+ next();
+ currentScope()->useVariable(ident, m_globalData->propertyNames->eval == *ident);
+ m_lastIdentifier = ident;
+ return context.createResolve(ident, start);
+ }
+ case STRING: {
+ const Identifier* ident = m_token.m_data.ident;
+ next();
+ return context.createString(ident);
+ }
+ case NUMBER: {
+ double d = m_token.m_data.doubleValue;
+ next();
+ return context.createNumberExpr(d);
+ }
+ case NULLTOKEN: {
+ next();
+ return context.createNull();
+ }
+ case TRUETOKEN: {
+ next();
+ return context.createBoolean(true);
+ }
+ case FALSETOKEN: {
+ next();
+ return context.createBoolean(false);
+ }
+ case DIVEQUAL:
+ case DIVIDE: {
+ /* regexp */
+ const Identifier* pattern;
+ const Identifier* flags;
+ if (match(DIVEQUAL))
+ failIfFalse(m_lexer->scanRegExp(pattern, flags, '='));
+ else
+ failIfFalse(m_lexer->scanRegExp(pattern, flags));
+
+ int start = tokenStart();
+ next();
+ TreeExpression re = context.createRegExp(*pattern, *flags, start);
+ if (!re) {
+ m_errorMessage = Yarr::checkSyntax(pattern->ustring());
+ ASSERT(m_errorMessage);
+ fail();
+ }
+ return re;
+ }
+ default:
+ fail();
+ }
+}
+
+template <class TreeBuilder> TreeArguments JSParser::parseArguments(TreeBuilder& context)
+{
+ consumeOrFailWithFlags(OPENPAREN, TreeBuilder::DontBuildStrings);
+ if (match(CLOSEPAREN)) {
+ next(TreeBuilder::DontBuildStrings);
+ return context.createArguments();
+ }
+ TreeExpression firstArg = parseAssignmentExpression(context);
+ failIfFalse(firstArg);
+
+ TreeArgumentsList argList = context.createArgumentsList(firstArg);
+ TreeArgumentsList tail = argList;
+ while (match(COMMA)) {
+ next(TreeBuilder::DontBuildStrings);
+ TreeExpression arg = parseAssignmentExpression(context);
+ failIfFalse(arg);
+ tail = context.createArgumentsList(tail, arg);
+ }
+ consumeOrFail(CLOSEPAREN);
+ return context.createArguments(argList);
+}
+
+template <class TreeBuilder> TreeExpression JSParser::parseMemberExpression(TreeBuilder& context)
+{
+ TreeExpression base = 0;
+ int start = tokenStart();
+ int expressionStart = start;
+ int newCount = 0;
+ while (match(NEW)) {
+ next();
+ newCount++;
+ }
+
+ if (match(FUNCTION)) {
+ const Identifier* name = &m_globalData->propertyNames->nullIdentifier;
+ TreeFormalParameterList parameters = 0;
+ TreeFunctionBody body = 0;
+ int openBracePos = 0;
+ int closeBracePos = 0;
+ int bodyStartLine = 0;
+ next();
+ failIfFalse((parseFunctionInfo<FunctionNoRequirements, false>(context, name, parameters, body, openBracePos, closeBracePos, bodyStartLine)));
+ base = context.createFunctionExpr(name, body, parameters, openBracePos, closeBracePos, bodyStartLine, m_lastLine);
+ } else
+ base = parsePrimaryExpression(context);
+
+ failIfFalse(base);
+ while (true) {
+ switch (m_token.m_type) {
+ case OPENBRACKET: {
+ m_nonTrivialExpressionCount++;
+ int expressionEnd = lastTokenEnd();
+ next();
+ int nonLHSCount = m_nonLHSCount;
+ int initialAssignments = m_assignmentCount;
+ TreeExpression property = parseExpression(context);
+ failIfFalse(property);
+ base = context.createBracketAccess(base, property, initialAssignments != m_assignmentCount, expressionStart, expressionEnd, tokenEnd());
+ if (!consume(CLOSEBRACKET))
+ fail();
+ m_nonLHSCount = nonLHSCount;
+ break;
+ }
+ case OPENPAREN: {
+ m_nonTrivialExpressionCount++;
+ if (newCount) {
+ newCount--;
+ if (match(OPENPAREN)) {
+ int exprEnd = lastTokenEnd();
+ TreeArguments arguments = parseArguments(context);
+ failIfFalse(arguments);
+ base = context.createNewExpr(base, arguments, start, exprEnd, lastTokenEnd());
+ } else
+ base = context.createNewExpr(base, start, lastTokenEnd());
+ } else {
+ int nonLHSCount = m_nonLHSCount;
+ int expressionEnd = lastTokenEnd();
+ TreeArguments arguments = parseArguments(context);
+ failIfFalse(arguments);
+ base = context.makeFunctionCallNode(base, arguments, expressionStart, expressionEnd, lastTokenEnd());
+ m_nonLHSCount = nonLHSCount;
+ }
+ break;
+ }
+ case DOT: {
+ m_nonTrivialExpressionCount++;
+ int expressionEnd = lastTokenEnd();
+ nextExpectIdentifier(Lexer::IgnoreReservedWords | TreeBuilder::DontBuildKeywords);
+ matchOrFail(IDENT);
+ base = context.createDotAccess(base, m_token.m_data.ident, expressionStart, expressionEnd, tokenEnd());
+ next();
+ break;
+ }
+ default:
+ goto endMemberExpression;
+ }
+ }
+endMemberExpression:
+ while (newCount--)
+ base = context.createNewExpr(base, start, lastTokenEnd());
+ return base;
+}
+
+template <class TreeBuilder> TreeExpression JSParser::parseUnaryExpression(TreeBuilder& context)
+{
+ typename TreeBuilder::UnaryExprContext unaryExprContext(context);
+ AllowInOverride allowInOverride(this);
+ int tokenStackDepth = 0;
+ bool modifiesExpr = false;
+ bool requiresLExpr = false;
+ while (isUnaryOp(m_token.m_type)) {
+ if (strictMode()) {
+ switch (m_token.m_type) {
+ case PLUSPLUS:
+ case MINUSMINUS:
+ case AUTOPLUSPLUS:
+ case AUTOMINUSMINUS:
+ failIfTrue(requiresLExpr);
+ modifiesExpr = true;
+ requiresLExpr = true;
+ break;
+ case DELETETOKEN:
+ failIfTrue(requiresLExpr);
+ requiresLExpr = true;
+ break;
+ default:
+ failIfTrue(requiresLExpr);
+ break;
+ }
+ }
+ m_nonLHSCount++;
+ context.appendUnaryToken(tokenStackDepth, m_token.m_type, tokenStart());
+ next();
+ m_nonTrivialExpressionCount++;
+ }
+ int subExprStart = tokenStart();
+ TreeExpression expr = parseMemberExpression(context);
+ failIfFalse(expr);
+ bool isEvalOrArguments = false;
+ if (strictMode() && !m_syntaxAlreadyValidated) {
+ if (context.isResolve(expr)) {
+ isEvalOrArguments = *m_lastIdentifier == m_globalData->propertyNames->eval || *m_lastIdentifier == m_globalData->propertyNames->arguments;
+ }
+ }
+ failIfTrueIfStrict(isEvalOrArguments && modifiesExpr);
+ switch (m_token.m_type) {
+ case PLUSPLUS:
+ m_nonTrivialExpressionCount++;
+ m_nonLHSCount++;
+ expr = context.makePostfixNode(expr, OpPlusPlus, subExprStart, lastTokenEnd(), tokenEnd());
+ m_assignmentCount++;
+ failIfTrueIfStrict(isEvalOrArguments);
+ failIfTrueIfStrict(requiresLExpr);
+ next();
+ break;
+ case MINUSMINUS:
+ m_nonTrivialExpressionCount++;
+ m_nonLHSCount++;
+ expr = context.makePostfixNode(expr, OpMinusMinus, subExprStart, lastTokenEnd(), tokenEnd());
+ m_assignmentCount++;
+ failIfTrueIfStrict(isEvalOrArguments);
+ failIfTrueIfStrict(requiresLExpr);
+ next();
+ break;
+ default:
+ break;
+ }
+
+ int end = lastTokenEnd();
+
+ if (!TreeBuilder::CreatesAST && (m_syntaxAlreadyValidated || !strictMode()))
+ return expr;
+
+ while (tokenStackDepth) {
+ switch (context.unaryTokenStackLastType(tokenStackDepth)) {
+ case EXCLAMATION:
+ expr = context.createLogicalNot(expr);
+ break;
+ case TILDE:
+ expr = context.makeBitwiseNotNode(expr);
+ break;
+ case MINUS:
+ expr = context.makeNegateNode(expr);
+ break;
+ case PLUS:
+ expr = context.createUnaryPlus(expr);
+ break;
+ case PLUSPLUS:
+ case AUTOPLUSPLUS:
+ expr = context.makePrefixNode(expr, OpPlusPlus, context.unaryTokenStackLastStart(tokenStackDepth), subExprStart + 1, end);
+ m_assignmentCount++;
+ break;
+ case MINUSMINUS:
+ case AUTOMINUSMINUS:
+ expr = context.makePrefixNode(expr, OpMinusMinus, context.unaryTokenStackLastStart(tokenStackDepth), subExprStart + 1, end);
+ m_assignmentCount++;
+ break;
+ case TYPEOF:
+ expr = context.makeTypeOfNode(expr);
+ break;
+ case VOIDTOKEN:
+ expr = context.createVoid(expr);
+ break;
+ case DELETETOKEN:
+ failIfTrueIfStrict(context.isResolve(expr));
+ expr = context.makeDeleteNode(expr, context.unaryTokenStackLastStart(tokenStackDepth), end, end);
+ break;
+ default:
+ // If we get here something has gone horribly horribly wrong
+ CRASH();
+ }
+ subExprStart = context.unaryTokenStackLastStart(tokenStackDepth);
+ context.unaryTokenStackRemoveLast(tokenStackDepth);
+ }
+ return expr;
+}
+
+}
+
+namespace WTF
+{
+ template <> struct VectorTraits<JSC::JSParser::Scope> : SimpleClassVectorTraits {
+ static const bool canInitializeWithMemset = false; // Not all Scope data members initialize to 0.
+ };
+}
--- /dev/null
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef JSParser_h
+#define JSParser_h
+
+namespace JSC {
+
+class ExecState;
+class FunctionParameters;
+class Identifier;
+class JSGlobalData;
+class SourceCode;
+
+enum {
+ UnaryOpTokenFlag = 64,
+ KeywordTokenFlag = 128,
+ BinaryOpTokenPrecedenceShift = 8,
+ BinaryOpTokenAllowsInPrecedenceAdditionalShift = 4,
+ BinaryOpTokenPrecedenceMask = 15 << BinaryOpTokenPrecedenceShift,
+};
+
+#define BINARY_OP_PRECEDENCE(prec) (((prec) << BinaryOpTokenPrecedenceShift) | ((prec) << (BinaryOpTokenPrecedenceShift + BinaryOpTokenAllowsInPrecedenceAdditionalShift)))
+#define IN_OP_PRECEDENCE(prec) ((prec) << (BinaryOpTokenPrecedenceShift + BinaryOpTokenAllowsInPrecedenceAdditionalShift))
+
+enum JSTokenType {
+ NULLTOKEN = KeywordTokenFlag,
+ TRUETOKEN,
+ FALSETOKEN,
+ BREAK,
+ CASE,
+ DEFAULT,
+ FOR,
+ NEW,
+ VAR,
+ CONSTTOKEN,
+ CONTINUE,
+ FUNCTION,
+ RETURN,
+ IF,
+ THISTOKEN,
+ DO,
+ WHILE,
+ SWITCH,
+ WITH,
+ RESERVED,
+ THROW,
+ TRY,
+ CATCH,
+ FINALLY,
+ DEBUGGER,
+ ELSE,
+ OPENBRACE = 0,
+ CLOSEBRACE,
+ OPENPAREN,
+ CLOSEPAREN,
+ OPENBRACKET,
+ CLOSEBRACKET,
+ COMMA,
+ QUESTION,
+ NUMBER,
+ IDENT,
+ STRING,
+ SEMICOLON,
+ COLON,
+ DOT,
+ ERRORTOK,
+ EOFTOK,
+ EQUAL,
+ PLUSEQUAL,
+ MINUSEQUAL,
+ MULTEQUAL,
+ DIVEQUAL,
+ LSHIFTEQUAL,
+ RSHIFTEQUAL,
+ URSHIFTEQUAL,
+ ANDEQUAL,
+ MODEQUAL,
+ XOREQUAL,
+ OREQUAL,
+ LastUntaggedToken,
+
+ // Begin tagged tokens
+ PLUSPLUS = 0 | UnaryOpTokenFlag,
+ MINUSMINUS = 1 | UnaryOpTokenFlag,
+ EXCLAMATION = 2 | UnaryOpTokenFlag,
+ TILDE = 3 | UnaryOpTokenFlag,
+ AUTOPLUSPLUS = 4 | UnaryOpTokenFlag,
+ AUTOMINUSMINUS = 5 | UnaryOpTokenFlag,
+ TYPEOF = 6 | UnaryOpTokenFlag | KeywordTokenFlag,
+ VOIDTOKEN = 7 | UnaryOpTokenFlag | KeywordTokenFlag,
+ DELETETOKEN = 8 | UnaryOpTokenFlag | KeywordTokenFlag,
+ OR = 0 | BINARY_OP_PRECEDENCE(1),
+ AND = 1 | BINARY_OP_PRECEDENCE(2),
+ BITOR = 2 | BINARY_OP_PRECEDENCE(3),
+ BITXOR = 3 | BINARY_OP_PRECEDENCE(4),
+ BITAND = 4 | BINARY_OP_PRECEDENCE(5),
+ EQEQ = 5 | BINARY_OP_PRECEDENCE(6),
+ NE = 6 | BINARY_OP_PRECEDENCE(6),
+ STREQ = 7 | BINARY_OP_PRECEDENCE(6),
+ STRNEQ = 8 | BINARY_OP_PRECEDENCE(6),
+ LT = 9 | BINARY_OP_PRECEDENCE(7),
+ GT = 10 | BINARY_OP_PRECEDENCE(7),
+ LE = 11 | BINARY_OP_PRECEDENCE(7),
+ GE = 12 | BINARY_OP_PRECEDENCE(7),
+ INSTANCEOF = 13 | BINARY_OP_PRECEDENCE(7) | KeywordTokenFlag,
+ INTOKEN = 14 | IN_OP_PRECEDENCE(7) | KeywordTokenFlag,
+ LSHIFT = 15 | BINARY_OP_PRECEDENCE(8),
+ RSHIFT = 16 | BINARY_OP_PRECEDENCE(8),
+ URSHIFT = 17 | BINARY_OP_PRECEDENCE(8),
+ PLUS = 18 | BINARY_OP_PRECEDENCE(9) | UnaryOpTokenFlag,
+ MINUS = 19 | BINARY_OP_PRECEDENCE(9) | UnaryOpTokenFlag,
+ TIMES = 20 | BINARY_OP_PRECEDENCE(10),
+ DIVIDE = 21 | BINARY_OP_PRECEDENCE(10),
+ MOD = 22 | BINARY_OP_PRECEDENCE(10)
+};
+
+union JSTokenData {
+ int intValue;
+ double doubleValue;
+ const Identifier* ident;
+};
+
+struct JSTokenInfo {
+ JSTokenInfo() : line(0) {}
+ int line;
+ int startOffset;
+ int endOffset;
+};
+
+struct JSToken {
+ JSTokenType m_type;
+ JSTokenData m_data;
+ JSTokenInfo m_info;
+};
+
+enum JSParserStrictness { JSParseNormal, JSParseStrict };
+enum JSParserMode { JSParseProgramCode, JSParseFunctionCode };
+
+const char* jsParse(JSGlobalData*, FunctionParameters*, JSParserStrictness, JSParserMode, const SourceCode*);
+}
+#endif // JSParser_h
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
* Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All Rights Reserved.
* Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
+ * Copyright (C) 2010 Zoltan Herczeg (zherczeg@inf.u-szeged.hu)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
#include "Lexer.h"
#include "JSFunction.h"
+
#include "JSGlobalObjectFunctions.h"
+#include "Identifier.h"
#include "NodeInfo.h"
#include "Nodes.h"
#include "dtoa.h"
using namespace WTF;
using namespace Unicode;
-// We can't specify the namespace in yacc's C output, so do it here instead.
-using namespace JSC;
-
-#include "Grammar.h"
+#include "JSParser.h"
+#include "KeywordLookup.h"
#include "Lookup.h"
#include "Lexer.lut.h"
namespace JSC {
-static const UChar byteOrderMark = 0xFEFF;
+
+enum CharacterType {
+ // Types for the main switch
+
+ // The first three types are fixed, and also used for identifying
+ // ASCII alpha and alphanumeric characters (see isIdentStart and isIdentPart).
+ CharacterIdentifierStart,
+ CharacterZero,
+ CharacterNumber,
+
+ CharacterInvalid,
+ CharacterLineTerminator,
+ CharacterExclamationMark,
+ CharacterOpenParen,
+ CharacterCloseParen,
+ CharacterOpenBracket,
+ CharacterCloseBracket,
+ CharacterComma,
+ CharacterColon,
+ CharacterQuestion,
+ CharacterTilde,
+ CharacterQuote,
+ CharacterDot,
+ CharacterSlash,
+ CharacterBackSlash,
+ CharacterSemicolon,
+ CharacterOpenBrace,
+ CharacterCloseBrace,
+
+ CharacterAdd,
+ CharacterSub,
+ CharacterMultiply,
+ CharacterModulo,
+ CharacterAnd,
+ CharacterXor,
+ CharacterOr,
+ CharacterLess,
+ CharacterGreater,
+ CharacterEqual,
+
+ // Other types (only one so far)
+ CharacterWhiteSpace,
+};
+
+// 128 ASCII codes
+static const unsigned short typesOfASCIICharacters[128] = {
+/* 0 - Null */ CharacterInvalid,
+/* 1 - Start of Heading */ CharacterInvalid,
+/* 2 - Start of Text */ CharacterInvalid,
+/* 3 - End of Text */ CharacterInvalid,
+/* 4 - End of Transm. */ CharacterInvalid,
+/* 5 - Enquiry */ CharacterInvalid,
+/* 6 - Acknowledgment */ CharacterInvalid,
+/* 7 - Bell */ CharacterInvalid,
+/* 8 - Back Space */ CharacterInvalid,
+/* 9 - Horizontal Tab */ CharacterWhiteSpace,
+/* 10 - Line Feed */ CharacterLineTerminator,
+/* 11 - Vertical Tab */ CharacterWhiteSpace,
+/* 12 - Form Feed */ CharacterWhiteSpace,
+/* 13 - Carriage Return */ CharacterLineTerminator,
+/* 14 - Shift Out */ CharacterInvalid,
+/* 15 - Shift In */ CharacterInvalid,
+/* 16 - Data Line Escape */ CharacterInvalid,
+/* 17 - Device Control 1 */ CharacterInvalid,
+/* 18 - Device Control 2 */ CharacterInvalid,
+/* 19 - Device Control 3 */ CharacterInvalid,
+/* 20 - Device Control 4 */ CharacterInvalid,
+/* 21 - Negative Ack. */ CharacterInvalid,
+/* 22 - Synchronous Idle */ CharacterInvalid,
+/* 23 - End of Transmit */ CharacterInvalid,
+/* 24 - Cancel */ CharacterInvalid,
+/* 25 - End of Medium */ CharacterInvalid,
+/* 26 - Substitute */ CharacterInvalid,
+/* 27 - Escape */ CharacterInvalid,
+/* 28 - File Separator */ CharacterInvalid,
+/* 29 - Group Separator */ CharacterInvalid,
+/* 30 - Record Separator */ CharacterInvalid,
+/* 31 - Unit Separator */ CharacterInvalid,
+/* 32 - Space */ CharacterWhiteSpace,
+/* 33 - ! */ CharacterExclamationMark,
+/* 34 - " */ CharacterQuote,
+/* 35 - # */ CharacterInvalid,
+/* 36 - $ */ CharacterIdentifierStart,
+/* 37 - % */ CharacterModulo,
+/* 38 - & */ CharacterAnd,
+/* 39 - ' */ CharacterQuote,
+/* 40 - ( */ CharacterOpenParen,
+/* 41 - ) */ CharacterCloseParen,
+/* 42 - * */ CharacterMultiply,
+/* 43 - + */ CharacterAdd,
+/* 44 - , */ CharacterComma,
+/* 45 - - */ CharacterSub,
+/* 46 - . */ CharacterDot,
+/* 47 - / */ CharacterSlash,
+/* 48 - 0 */ CharacterZero,
+/* 49 - 1 */ CharacterNumber,
+/* 50 - 2 */ CharacterNumber,
+/* 51 - 3 */ CharacterNumber,
+/* 52 - 4 */ CharacterNumber,
+/* 53 - 5 */ CharacterNumber,
+/* 54 - 6 */ CharacterNumber,
+/* 55 - 7 */ CharacterNumber,
+/* 56 - 8 */ CharacterNumber,
+/* 57 - 9 */ CharacterNumber,
+/* 58 - : */ CharacterColon,
+/* 59 - ; */ CharacterSemicolon,
+/* 60 - < */ CharacterLess,
+/* 61 - = */ CharacterEqual,
+/* 62 - > */ CharacterGreater,
+/* 63 - ? */ CharacterQuestion,
+/* 64 - @ */ CharacterInvalid,
+/* 65 - A */ CharacterIdentifierStart,
+/* 66 - B */ CharacterIdentifierStart,
+/* 67 - C */ CharacterIdentifierStart,
+/* 68 - D */ CharacterIdentifierStart,
+/* 69 - E */ CharacterIdentifierStart,
+/* 70 - F */ CharacterIdentifierStart,
+/* 71 - G */ CharacterIdentifierStart,
+/* 72 - H */ CharacterIdentifierStart,
+/* 73 - I */ CharacterIdentifierStart,
+/* 74 - J */ CharacterIdentifierStart,
+/* 75 - K */ CharacterIdentifierStart,
+/* 76 - L */ CharacterIdentifierStart,
+/* 77 - M */ CharacterIdentifierStart,
+/* 78 - N */ CharacterIdentifierStart,
+/* 79 - O */ CharacterIdentifierStart,
+/* 80 - P */ CharacterIdentifierStart,
+/* 81 - Q */ CharacterIdentifierStart,
+/* 82 - R */ CharacterIdentifierStart,
+/* 83 - S */ CharacterIdentifierStart,
+/* 84 - T */ CharacterIdentifierStart,
+/* 85 - U */ CharacterIdentifierStart,
+/* 86 - V */ CharacterIdentifierStart,
+/* 87 - W */ CharacterIdentifierStart,
+/* 88 - X */ CharacterIdentifierStart,
+/* 89 - Y */ CharacterIdentifierStart,
+/* 90 - Z */ CharacterIdentifierStart,
+/* 91 - [ */ CharacterOpenBracket,
+/* 92 - \ */ CharacterBackSlash,
+/* 93 - ] */ CharacterCloseBracket,
+/* 94 - ^ */ CharacterXor,
+/* 95 - _ */ CharacterIdentifierStart,
+/* 96 - ` */ CharacterInvalid,
+/* 97 - a */ CharacterIdentifierStart,
+/* 98 - b */ CharacterIdentifierStart,
+/* 99 - c */ CharacterIdentifierStart,
+/* 100 - d */ CharacterIdentifierStart,
+/* 101 - e */ CharacterIdentifierStart,
+/* 102 - f */ CharacterIdentifierStart,
+/* 103 - g */ CharacterIdentifierStart,
+/* 104 - h */ CharacterIdentifierStart,
+/* 105 - i */ CharacterIdentifierStart,
+/* 106 - j */ CharacterIdentifierStart,
+/* 107 - k */ CharacterIdentifierStart,
+/* 108 - l */ CharacterIdentifierStart,
+/* 109 - m */ CharacterIdentifierStart,
+/* 110 - n */ CharacterIdentifierStart,
+/* 111 - o */ CharacterIdentifierStart,
+/* 112 - p */ CharacterIdentifierStart,
+/* 113 - q */ CharacterIdentifierStart,
+/* 114 - r */ CharacterIdentifierStart,
+/* 115 - s */ CharacterIdentifierStart,
+/* 116 - t */ CharacterIdentifierStart,
+/* 117 - u */ CharacterIdentifierStart,
+/* 118 - v */ CharacterIdentifierStart,
+/* 119 - w */ CharacterIdentifierStart,
+/* 120 - x */ CharacterIdentifierStart,
+/* 121 - y */ CharacterIdentifierStart,
+/* 122 - z */ CharacterIdentifierStart,
+/* 123 - { */ CharacterOpenBrace,
+/* 124 - | */ CharacterOr,
+/* 125 - } */ CharacterCloseBrace,
+/* 126 - ~ */ CharacterTilde,
+/* 127 - Delete */ CharacterInvalid,
+};
Lexer::Lexer(JSGlobalData* globalData)
: m_isReparsing(false)
m_keywordTable.deleteTable();
}
-inline const UChar* Lexer::currentCharacter() const
+ALWAYS_INLINE const UChar* Lexer::currentCharacter() const
{
- return m_code - 4;
+ ASSERT(m_code <= m_codeEnd);
+ return m_code;
}
-inline int Lexer::currentOffset() const
+ALWAYS_INLINE int Lexer::currentOffset() const
{
return currentCharacter() - m_codeStart;
}
-ALWAYS_INLINE void Lexer::shift1()
-{
- m_current = m_next1;
- m_next1 = m_next2;
- m_next2 = m_next3;
- if (LIKELY(m_code < m_codeEnd))
- m_next3 = m_code[0];
- else
- m_next3 = -1;
-
- ++m_code;
-}
-
-ALWAYS_INLINE void Lexer::shift2()
-{
- m_current = m_next2;
- m_next1 = m_next3;
- if (LIKELY(m_code + 1 < m_codeEnd)) {
- m_next2 = m_code[0];
- m_next3 = m_code[1];
- } else {
- m_next2 = m_code < m_codeEnd ? m_code[0] : -1;
- m_next3 = -1;
- }
-
- m_code += 2;
-}
-
-ALWAYS_INLINE void Lexer::shift3()
-{
- m_current = m_next3;
- if (LIKELY(m_code + 2 < m_codeEnd)) {
- m_next1 = m_code[0];
- m_next2 = m_code[1];
- m_next3 = m_code[2];
- } else {
- m_next1 = m_code < m_codeEnd ? m_code[0] : -1;
- m_next2 = m_code + 1 < m_codeEnd ? m_code[1] : -1;
- m_next3 = -1;
- }
-
- m_code += 3;
-}
-
-ALWAYS_INLINE void Lexer::shift4()
-{
- if (LIKELY(m_code + 3 < m_codeEnd)) {
- m_current = m_code[0];
- m_next1 = m_code[1];
- m_next2 = m_code[2];
- m_next3 = m_code[3];
- } else {
- m_current = m_code < m_codeEnd ? m_code[0] : -1;
- m_next1 = m_code + 1 < m_codeEnd ? m_code[1] : -1;
- m_next2 = m_code + 2 < m_codeEnd ? m_code[2] : -1;
- m_next3 = -1;
- }
-
- m_code += 4;
-}
-
void Lexer::setCode(const SourceCode& source, ParserArena& arena)
{
m_arena = &arena.identifierArena();
m_buffer8.reserveInitialCapacity(initialReadBufferCapacity);
m_buffer16.reserveInitialCapacity((m_codeEnd - m_code) / 2);
- // ECMA-262 calls for stripping all Cf characters, but we only strip BOM characters.
- // See <https://bugs.webkit.org/show_bug.cgi?id=4931> for details.
- if (source.provider()->hasBOMs()) {
- for (const UChar* p = m_codeStart; p < m_codeEnd; ++p) {
- if (UNLIKELY(*p == byteOrderMark)) {
- copyCodeWithoutBOMs();
- break;
- }
- }
- }
-
- // Read the first characters into the 4-character buffer.
- shift4();
+ if (LIKELY(m_code < m_codeEnd))
+ m_current = *m_code;
+ else
+ m_current = -1;
ASSERT(currentOffset() == source.startOffset());
}
-void Lexer::copyCodeWithoutBOMs()
+template <int shiftAmount, Lexer::ShiftType shouldBoundsCheck> ALWAYS_INLINE void Lexer::internalShift()
{
- // Note: In this case, the character offset data for debugging will be incorrect.
- // If it's important to correctly debug code with extraneous BOMs, then the caller
- // should strip the BOMs when creating the SourceProvider object and do its own
- // mapping of offsets within the stripped text to original text offset.
-
- m_codeWithoutBOMs.reserveCapacity(m_codeEnd - m_code);
- for (const UChar* p = m_code; p < m_codeEnd; ++p) {
- UChar c = *p;
- if (c != byteOrderMark)
- m_codeWithoutBOMs.append(c);
+ if (shouldBoundsCheck == DoBoundsCheck) {
+ // Faster than an if-else sequence
+ ASSERT(m_current != -1);
+ m_current = -1;
+ m_code += shiftAmount;
+ if (LIKELY(m_code < m_codeEnd))
+ m_current = *m_code;
+ } else {
+ m_code += shiftAmount;
+ m_current = *m_code;
}
- ptrdiff_t startDelta = m_codeStart - m_code;
- m_code = m_codeWithoutBOMs.data();
- m_codeStart = m_code + startDelta;
- m_codeEnd = m_codeWithoutBOMs.data() + m_codeWithoutBOMs.size();
+}
+
+ALWAYS_INLINE void Lexer::shift()
+{
+ internalShift<1, DoBoundsCheck>();
+}
+
+ALWAYS_INLINE int Lexer::peek(int offset)
+{
+ // Only use if necessary
+ ASSERT(offset > 0 && offset < 5);
+ const UChar* code = m_code + offset;
+ return (code < m_codeEnd) ? *code : -1;
+}
+
+int Lexer::getUnicodeCharacter()
+{
+ int char1 = peek(1);
+ int char2 = peek(2);
+ int char3 = peek(3);
+
+ if (UNLIKELY(!isASCIIHexDigit(m_current) || !isASCIIHexDigit(char1) || !isASCIIHexDigit(char2) || !isASCIIHexDigit(char3)))
+ return -1;
+
+ int result = convertUnicode(m_current, char1, char2, char3);
+ shift();
+ shift();
+ shift();
+ shift();
+ return result;
}
void Lexer::shiftLineTerminator()
{
ASSERT(isLineTerminator(m_current));
+ int m_prev = m_current;
+ shift();
+
// Allow both CRLF and LFCR.
- if (m_current + m_next1 == '\n' + '\r')
- shift2();
- else
- shift1();
+ if (m_prev + m_current == '\n' + '\r')
+ shift();
++m_lineNumber;
}
-ALWAYS_INLINE const Identifier* Lexer::makeIdentifier(const UChar* characters, size_t length)
-{
- return &m_arena->makeIdentifier(m_globalData, characters, length);
-}
-
-inline bool Lexer::lastTokenWasRestrKeyword() const
+ALWAYS_INLINE bool Lexer::lastTokenWasRestrKeyword() const
{
return m_lastToken == CONTINUE || m_lastToken == BREAK || m_lastToken == RETURN || m_lastToken == THROW;
}
static inline bool isIdentStart(int c)
{
- return isASCII(c) ? isASCIIAlpha(c) || c == '$' || c == '_' : isNonASCIIIdentStart(c);
+ return isASCII(c) ? typesOfASCIICharacters[c] == CharacterIdentifierStart : isNonASCIIIdentStart(c);
}
static NEVER_INLINE bool isNonASCIIIdentPart(int c)
| Mark_NonSpacing | Mark_SpacingCombining | Number_DecimalDigit | Punctuation_Connector);
}
-static inline bool isIdentPart(int c)
+static ALWAYS_INLINE bool isIdentPart(int c)
{
- return isASCII(c) ? isASCIIAlphanumeric(c) || c == '$' || c == '_' : isNonASCIIIdentPart(c);
+ // Character types are divided into two groups depending on whether they can be part of an
+ // identifier or not. Those whose type value is less or equal than CharacterNumber can be
+ // part of an identifier. (See the CharacterType definition for more details.)
+ return isASCII(c) ? typesOfASCIICharacters[c] <= CharacterNumber : isNonASCIIIdentPart(c);
}
static inline int singleEscape(int c)
{
switch (c) {
- case 'b':
- return 0x08;
- case 't':
- return 0x09;
- case 'n':
- return 0x0A;
- case 'v':
- return 0x0B;
- case 'f':
- return 0x0C;
- case 'r':
- return 0x0D;
- default:
- return c;
+ case 'b':
+ return 0x08;
+ case 't':
+ return 0x09;
+ case 'n':
+ return 0x0A;
+ case 'v':
+ return 0x0B;
+ case 'f':
+ return 0x0C;
+ case 'r':
+ return 0x0D;
+ case '\\':
+ return '\\';
+ case '\'':
+ return '\'';
+ case '"':
+ return '"';
+ default:
+ return 0;
}
}
record16(UChar(static_cast<unsigned short>(c)));
}
-int Lexer::lex(void* p1, void* p2)
+template <bool shouldCreateIdentifier> ALWAYS_INLINE JSTokenType Lexer::parseIdentifier(JSTokenData* tokenData, unsigned lexType)
+{
+ const ptrdiff_t remaining = m_codeEnd - m_code;
+ if ((remaining >= maxTokenLength) && !(lexType & IgnoreReservedWords)) {
+ JSTokenType keyword = parseKeyword<shouldCreateIdentifier>(tokenData);
+ if (keyword != IDENT) {
+ ASSERT((!shouldCreateIdentifier) || tokenData->ident);
+ return keyword;
+ }
+ }
+ const UChar* identifierStart = currentCharacter();
+ bool bufferRequired = false;
+
+ while (true) {
+ if (LIKELY(isIdentPart(m_current))) {
+ shift();
+ continue;
+ }
+ if (LIKELY(m_current != '\\'))
+ break;
+
+ // \uXXXX unicode characters.
+ bufferRequired = true;
+ if (identifierStart != currentCharacter())
+ m_buffer16.append(identifierStart, currentCharacter() - identifierStart);
+ shift();
+ if (UNLIKELY(m_current != 'u'))
+ return ERRORTOK;
+ shift();
+ int character = getUnicodeCharacter();
+ if (UNLIKELY(character == -1))
+ return ERRORTOK;
+ if (UNLIKELY(m_buffer16.size() ? !isIdentPart(character) : !isIdentStart(character)))
+ return ERRORTOK;
+ if (shouldCreateIdentifier)
+ record16(character);
+ identifierStart = currentCharacter();
+ }
+
+ int identifierLength;
+ const Identifier* ident = 0;
+ if (shouldCreateIdentifier) {
+ if (!bufferRequired)
+ identifierLength = currentCharacter() - identifierStart;
+ else {
+ if (identifierStart != currentCharacter())
+ m_buffer16.append(identifierStart, currentCharacter() - identifierStart);
+ identifierStart = m_buffer16.data();
+ identifierLength = m_buffer16.size();
+ }
+
+ ident = makeIdentifier(identifierStart, identifierLength);
+ tokenData->ident = ident;
+ } else
+ tokenData->ident = 0;
+
+ m_delimited = false;
+
+ if (LIKELY(!bufferRequired && !(lexType & IgnoreReservedWords))) {
+ ASSERT(shouldCreateIdentifier);
+ // Keywords must not be recognized if there was an \uXXXX in the identifier.
+ if (remaining < maxTokenLength) {
+ const HashEntry* entry = m_keywordTable.entry(m_globalData, *ident);
+ ASSERT((remaining < maxTokenLength) || !entry);
+ return entry ? static_cast<JSTokenType>(entry->lexerValue()) : IDENT;
+ }
+ return IDENT;
+ }
+
+ m_buffer16.resize(0);
+ return IDENT;
+}
+
+bool Lexer::isKeyword(const Identifier& ident)
+{
+ return m_keywordTable.entry(m_globalData, ident);
+}
+
+template <bool shouldBuildStrings> ALWAYS_INLINE bool Lexer::parseString(JSTokenData* tokenData, bool strictMode)
+{
+ int stringQuoteCharacter = m_current;
+ shift();
+
+ const UChar* stringStart = currentCharacter();
+
+ while (m_current != stringQuoteCharacter) {
+ if (UNLIKELY(m_current == '\\')) {
+ if (stringStart != currentCharacter() && shouldBuildStrings)
+ m_buffer16.append(stringStart, currentCharacter() - stringStart);
+ shift();
+
+ int escape = singleEscape(m_current);
+
+ // Most common escape sequences first
+ if (escape) {
+ if (shouldBuildStrings)
+ record16(escape);
+ shift();
+ } else if (UNLIKELY(isLineTerminator(m_current)))
+ shiftLineTerminator();
+ else if (m_current == 'x') {
+ shift();
+ if (isASCIIHexDigit(m_current) && isASCIIHexDigit(peek(1))) {
+ int prev = m_current;
+ shift();
+ if (shouldBuildStrings)
+ record16(convertHex(prev, m_current));
+ shift();
+ } else if (shouldBuildStrings)
+ record16('x');
+ } else if (m_current == 'u') {
+ shift();
+ int character = getUnicodeCharacter();
+ if (character != -1) {
+ if (shouldBuildStrings)
+ record16(character);
+ } else if (m_current == stringQuoteCharacter) {
+ if (shouldBuildStrings)
+ record16('u');
+ } else // Only stringQuoteCharacter allowed after \u
+ return false;
+ } else if (strictMode && isASCIIDigit(m_current)) {
+ // The only valid numeric escape in strict mode is '\0', and this must not be followed by a decimal digit.
+ int character1 = m_current;
+ shift();
+ if (character1 != '0' || isASCIIDigit(m_current))
+ return false;
+ if (shouldBuildStrings)
+ record16(0);
+ } else if (!strictMode && isASCIIOctalDigit(m_current)) {
+ // Octal character sequences
+ int character1 = m_current;
+ shift();
+ if (isASCIIOctalDigit(m_current)) {
+ // Two octal characters
+ int character2 = m_current;
+ shift();
+ if (character1 >= '0' && character1 <= '3' && isASCIIOctalDigit(m_current)) {
+ if (shouldBuildStrings)
+ record16((character1 - '0') * 64 + (character2 - '0') * 8 + m_current - '0');
+ shift();
+ } else {
+ if (shouldBuildStrings)
+ record16((character1 - '0') * 8 + character2 - '0');
+ }
+ } else {
+ if (shouldBuildStrings)
+ record16(character1 - '0');
+ }
+ } else if (m_current != -1) {
+ if (shouldBuildStrings)
+ record16(m_current);
+ shift();
+ } else
+ return false;
+
+ stringStart = currentCharacter();
+ continue;
+ }
+ // Fast check for characters that require special handling.
+ // Catches -1, \n, \r, 0x2028, and 0x2029 as efficiently
+ // as possible, and lets through all common ASCII characters.
+ if (UNLIKELY(((static_cast<unsigned>(m_current) - 0xE) & 0x2000))) {
+ // New-line or end of input is not allowed
+ if (UNLIKELY(isLineTerminator(m_current)) || UNLIKELY(m_current == -1))
+ return false;
+ // Anything else is just a normal character
+ }
+ shift();
+ }
+
+ if (currentCharacter() != stringStart && shouldBuildStrings)
+ m_buffer16.append(stringStart, currentCharacter() - stringStart);
+ if (shouldBuildStrings)
+ tokenData->ident = makeIdentifier(m_buffer16.data(), m_buffer16.size());
+ else
+ tokenData->ident = 0;
+
+ m_buffer16.resize(0);
+ return true;
+}
+
+ALWAYS_INLINE void Lexer::parseHex(double& returnValue)
+{
+ // Optimization: most hexadecimal values fit into 4 bytes.
+ uint32_t hexValue = 0;
+ int maximumDigits = 7;
+
+ // Shift out the 'x' prefix.
+ shift();
+
+ do {
+ hexValue = (hexValue << 4) + toASCIIHexValue(m_current);
+ shift();
+ --maximumDigits;
+ } while (isASCIIHexDigit(m_current) && maximumDigits >= 0);
+
+ if (maximumDigits >= 0) {
+ returnValue = hexValue;
+ return;
+ }
+
+ // No more place in the hexValue buffer.
+ // The values are shifted out and placed into the m_buffer8 vector.
+ for (int i = 0; i < 8; ++i) {
+ int digit = hexValue >> 28;
+ if (digit < 10)
+ record8(digit + '0');
+ else
+ record8(digit - 10 + 'a');
+ hexValue <<= 4;
+ }
+
+ while (isASCIIHexDigit(m_current)) {
+ record8(m_current);
+ shift();
+ }
+
+ returnValue = parseIntOverflow(m_buffer8.data(), m_buffer8.size(), 16);
+}
+
+ALWAYS_INLINE bool Lexer::parseOctal(double& returnValue)
+{
+ // Optimization: most octal values fit into 4 bytes.
+ uint32_t octalValue = 0;
+ int maximumDigits = 9;
+ // Temporary buffer for the digits. Makes easier
+ // to reconstruct the input characters when needed.
+ char digits[10];
+
+ do {
+ octalValue = octalValue * 8 + (m_current - '0');
+ digits[maximumDigits] = m_current;
+ shift();
+ --maximumDigits;
+ } while (isASCIIOctalDigit(m_current) && maximumDigits >= 0);
+
+ if (!isASCIIDigit(m_current) && maximumDigits >= 0) {
+ returnValue = octalValue;
+ return true;
+ }
+
+ for (int i = 9; i > maximumDigits; --i)
+ record8(digits[i]);
+
+ while (isASCIIOctalDigit(m_current)) {
+ record8(m_current);
+ shift();
+ }
+
+ if (isASCIIDigit(m_current))
+ return false;
+
+ returnValue = parseIntOverflow(m_buffer8.data(), m_buffer8.size(), 8);
+ return true;
+}
+
+ALWAYS_INLINE bool Lexer::parseDecimal(double& returnValue)
+{
+ // Optimization: most decimal values fit into 4 bytes.
+ uint32_t decimalValue = 0;
+
+ // Since parseOctal may be executed before parseDecimal,
+ // the m_buffer8 may hold ascii digits.
+ if (!m_buffer8.size()) {
+ int maximumDigits = 9;
+ // Temporary buffer for the digits. Makes easier
+ // to reconstruct the input characters when needed.
+ char digits[10];
+
+ do {
+ decimalValue = decimalValue * 10 + (m_current - '0');
+ digits[maximumDigits] = m_current;
+ shift();
+ --maximumDigits;
+ } while (isASCIIDigit(m_current) && maximumDigits >= 0);
+
+ if (maximumDigits >= 0 && m_current != '.' && (m_current | 0x20) != 'e') {
+ returnValue = decimalValue;
+ return true;
+ }
+
+ for (int i = 9; i > maximumDigits; --i)
+ record8(digits[i]);
+ }
+
+ while (isASCIIDigit(m_current)) {
+ record8(m_current);
+ shift();
+ }
+
+ return false;
+}
+
+ALWAYS_INLINE void Lexer::parseNumberAfterDecimalPoint()
+{
+ record8('.');
+ while (isASCIIDigit(m_current)) {
+ record8(m_current);
+ shift();
+ }
+}
+
+ALWAYS_INLINE bool Lexer::parseNumberAfterExponentIndicator()
+{
+ record8('e');
+ shift();
+ if (m_current == '+' || m_current == '-') {
+ record8(m_current);
+ shift();
+ }
+
+ if (!isASCIIDigit(m_current))
+ return false;
+
+ do {
+ record8(m_current);
+ shift();
+ } while (isASCIIDigit(m_current));
+ return true;
+}
+
+ALWAYS_INLINE bool Lexer::parseMultilineComment()
+{
+ while (true) {
+ while (UNLIKELY(m_current == '*')) {
+ shift();
+ if (m_current == '/') {
+ shift();
+ return true;
+ }
+ }
+
+ if (UNLIKELY(m_current == -1))
+ return false;
+
+ if (isLineTerminator(m_current))
+ shiftLineTerminator();
+ else
+ shift();
+ }
+}
+
+bool Lexer::nextTokenIsColon()
+{
+ const UChar* code = m_code;
+ while (code < m_codeEnd && (isWhiteSpace(*code) || isLineTerminator(*code)))
+ code++;
+
+ return code < m_codeEnd && *code == ':';
+}
+
+JSTokenType Lexer::lex(JSTokenData* tokenData, JSTokenInfo* tokenInfo, unsigned lexType, bool strictMode)
{
ASSERT(!m_error);
ASSERT(m_buffer8.isEmpty());
ASSERT(m_buffer16.isEmpty());
- YYSTYPE* lvalp = static_cast<YYSTYPE*>(p1);
- YYLTYPE* llocp = static_cast<YYLTYPE*>(p2);
- int token = 0;
+ JSTokenType token = ERRORTOK;
m_terminator = false;
start:
while (isWhiteSpace(m_current))
- shift1();
+ shift();
int startOffset = currentOffset();
- if (m_current == -1) {
- if (!m_terminator && !m_delimited && !m_isReparsing) {
- // automatic semicolon insertion if program incomplete
- token = ';';
- goto doneSemicolon;
- }
- return 0;
- }
+ if (UNLIKELY(m_current == -1))
+ return EOFTOK;
m_delimited = false;
- switch (m_current) {
- case '>':
- if (m_next1 == '>' && m_next2 == '>') {
- if (m_next3 == '=') {
- shift4();
+
+ CharacterType type;
+ if (LIKELY(isASCII(m_current)))
+ type = static_cast<CharacterType>(typesOfASCIICharacters[m_current]);
+ else if (isNonASCIIIdentStart(m_current))
+ type = CharacterIdentifierStart;
+ else if (isLineTerminator(m_current))
+ type = CharacterLineTerminator;
+ else
+ type = CharacterInvalid;
+
+ switch (type) {
+ case CharacterGreater:
+ shift();
+ if (m_current == '>') {
+ shift();
+ if (m_current == '>') {
+ shift();
+ if (m_current == '=') {
+ shift();
token = URSHIFTEQUAL;
break;
}
- shift3();
token = URSHIFT;
break;
}
- if (m_next1 == '>') {
- if (m_next2 == '=') {
- shift3();
- token = RSHIFTEQUAL;
- break;
- }
- shift2();
- token = RSHIFT;
- break;
- }
- if (m_next1 == '=') {
- shift2();
- token = GE;
+ if (m_current == '=') {
+ shift();
+ token = RSHIFTEQUAL;
break;
}
- shift1();
- token = '>';
+ token = RSHIFT;
break;
- case '=':
- if (m_next1 == '=') {
- if (m_next2 == '=') {
- shift3();
- token = STREQ;
- break;
- }
- shift2();
- token = EQEQ;
- break;
- }
- shift1();
- token = '=';
+ }
+ if (m_current == '=') {
+ shift();
+ token = GE;
break;
- case '!':
- if (m_next1 == '=') {
- if (m_next2 == '=') {
- shift3();
- token = STRNEQ;
- break;
- }
- shift2();
- token = NE;
+ }
+ token = GT;
+ break;
+ case CharacterEqual:
+ shift();
+ if (m_current == '=') {
+ shift();
+ if (m_current == '=') {
+ shift();
+ token = STREQ;
break;
}
- shift1();
- token = '!';
+ token = EQEQ;
break;
- case '<':
- if (m_next1 == '!' && m_next2 == '-' && m_next3 == '-') {
- // <!-- marks the beginning of a line comment (for www usage)
- shift4();
- goto inSingleLineComment;
- }
- if (m_next1 == '<') {
- if (m_next2 == '=') {
- shift3();
- token = LSHIFTEQUAL;
- break;
- }
- shift2();
- token = LSHIFT;
- break;
- }
- if (m_next1 == '=') {
- shift2();
- token = LE;
+ }
+ token = EQUAL;
+ break;
+ case CharacterLess:
+ shift();
+ if (m_current == '!' && peek(1) == '-' && peek(2) == '-') {
+ // <!-- marks the beginning of a line comment (for www usage)
+ goto inSingleLineComment;
+ }
+ if (m_current == '<') {
+ shift();
+ if (m_current == '=') {
+ shift();
+ token = LSHIFTEQUAL;
break;
}
- shift1();
- token = '<';
+ token = LSHIFT;
break;
- case '+':
- if (m_next1 == '+') {
- shift2();
- if (m_terminator) {
- token = AUTOPLUSPLUS;
- break;
- }
- token = PLUSPLUS;
- break;
- }
- if (m_next1 == '=') {
- shift2();
- token = PLUSEQUAL;
- break;
- }
- shift1();
- token = '+';
+ }
+ if (m_current == '=') {
+ shift();
+ token = LE;
break;
- case '-':
- if (m_next1 == '-') {
- if (m_atLineStart && m_next2 == '>') {
- shift3();
- goto inSingleLineComment;
- }
- shift2();
- if (m_terminator) {
- token = AUTOMINUSMINUS;
- break;
- }
- token = MINUSMINUS;
- break;
- }
- if (m_next1 == '=') {
- shift2();
- token = MINUSEQUAL;
+ }
+ token = LT;
+ break;
+ case CharacterExclamationMark:
+ shift();
+ if (m_current == '=') {
+ shift();
+ if (m_current == '=') {
+ shift();
+ token = STRNEQ;
break;
}
- shift1();
- token = '-';
+ token = NE;
break;
- case '*':
- if (m_next1 == '=') {
- shift2();
- token = MULTEQUAL;
- break;
- }
- shift1();
- token = '*';
+ }
+ token = EXCLAMATION;
+ break;
+ case CharacterAdd:
+ shift();
+ if (m_current == '+') {
+ shift();
+ token = (!m_terminator) ? PLUSPLUS : AUTOPLUSPLUS;
+ break;
+ }
+ if (m_current == '=') {
+ shift();
+ token = PLUSEQUAL;
break;
- case '/':
- if (m_next1 == '/') {
- shift2();
+ }
+ token = PLUS;
+ break;
+ case CharacterSub:
+ shift();
+ if (m_current == '-') {
+ shift();
+ if (m_atLineStart && m_current == '>') {
+ shift();
goto inSingleLineComment;
}
- if (m_next1 == '*')
- goto inMultiLineComment;
- if (m_next1 == '=') {
- shift2();
- token = DIVEQUAL;
- break;
- }
- shift1();
- token = '/';
+ token = (!m_terminator) ? MINUSMINUS : AUTOMINUSMINUS;
break;
- case '&':
- if (m_next1 == '&') {
- shift2();
- token = AND;
- break;
- }
- if (m_next1 == '=') {
- shift2();
- token = ANDEQUAL;
- break;
- }
- shift1();
- token = '&';
+ }
+ if (m_current == '=') {
+ shift();
+ token = MINUSEQUAL;
break;
- case '^':
- if (m_next1 == '=') {
- shift2();
- token = XOREQUAL;
- break;
- }
- shift1();
- token = '^';
+ }
+ token = MINUS;
+ break;
+ case CharacterMultiply:
+ shift();
+ if (m_current == '=') {
+ shift();
+ token = MULTEQUAL;
break;
- case '%':
- if (m_next1 == '=') {
- shift2();
- token = MODEQUAL;
- break;
- }
- shift1();
- token = '%';
+ }
+ token = TIMES;
+ break;
+ case CharacterSlash:
+ shift();
+ if (m_current == '/') {
+ shift();
+ goto inSingleLineComment;
+ }
+ if (m_current == '*') {
+ shift();
+ if (parseMultilineComment())
+ goto start;
+ goto returnError;
+ }
+ if (m_current == '=') {
+ shift();
+ token = DIVEQUAL;
break;
- case '|':
- if (m_next1 == '=') {
- shift2();
- token = OREQUAL;
- break;
- }
- if (m_next1 == '|') {
- shift2();
- token = OR;
- break;
- }
- shift1();
- token = '|';
+ }
+ token = DIVIDE;
+ break;
+ case CharacterAnd:
+ shift();
+ if (m_current == '&') {
+ shift();
+ token = AND;
break;
- case '.':
- if (isASCIIDigit(m_next1)) {
- record8('.');
- shift1();
- goto inNumberAfterDecimalPoint;
- }
- token = '.';
- shift1();
+ }
+ if (m_current == '=') {
+ shift();
+ token = ANDEQUAL;
break;
- case ',':
- case '~':
- case '?':
- case ':':
- case '(':
- case ')':
- case '[':
- case ']':
- token = m_current;
- shift1();
+ }
+ token = BITAND;
+ break;
+ case CharacterXor:
+ shift();
+ if (m_current == '=') {
+ shift();
+ token = XOREQUAL;
break;
- case ';':
- shift1();
- m_delimited = true;
- token = ';';
+ }
+ token = BITXOR;
+ break;
+ case CharacterModulo:
+ shift();
+ if (m_current == '=') {
+ shift();
+ token = MODEQUAL;
break;
- case '{':
- lvalp->intValue = currentOffset();
- shift1();
- token = OPENBRACE;
+ }
+ token = MOD;
+ break;
+ case CharacterOr:
+ shift();
+ if (m_current == '=') {
+ shift();
+ token = OREQUAL;
break;
- case '}':
- lvalp->intValue = currentOffset();
- shift1();
- m_delimited = true;
- token = CLOSEBRACE;
+ }
+ if (m_current == '|') {
+ shift();
+ token = OR;
break;
- case '\\':
- goto startIdentifierWithBackslash;
- case '0':
- goto startNumberWithZeroDigit;
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- goto startNumber;
- case '"':
- case '\'':
- goto startString;
- default:
- if (isIdentStart(m_current))
- goto startIdentifierOrKeyword;
- if (isLineTerminator(m_current)) {
- shiftLineTerminator();
- m_atLineStart = true;
- m_terminator = true;
- if (lastTokenWasRestrKeyword()) {
- token = ';';
- goto doneSemicolon;
+ }
+ token = BITOR;
+ break;
+ case CharacterOpenParen:
+ token = OPENPAREN;
+ shift();
+ break;
+ case CharacterCloseParen:
+ token = CLOSEPAREN;
+ shift();
+ break;
+ case CharacterOpenBracket:
+ token = OPENBRACKET;
+ shift();
+ break;
+ case CharacterCloseBracket:
+ token = CLOSEBRACKET;
+ shift();
+ break;
+ case CharacterComma:
+ token = COMMA;
+ shift();
+ break;
+ case CharacterColon:
+ token = COLON;
+ shift();
+ break;
+ case CharacterQuestion:
+ token = QUESTION;
+ shift();
+ break;
+ case CharacterTilde:
+ token = TILDE;
+ shift();
+ break;
+ case CharacterSemicolon:
+ m_delimited = true;
+ shift();
+ token = SEMICOLON;
+ break;
+ case CharacterOpenBrace:
+ tokenData->intValue = currentOffset();
+ shift();
+ token = OPENBRACE;
+ break;
+ case CharacterCloseBrace:
+ tokenData->intValue = currentOffset();
+ m_delimited = true;
+ shift();
+ token = CLOSEBRACE;
+ break;
+ case CharacterDot:
+ shift();
+ if (!isASCIIDigit(m_current)) {
+ token = DOT;
+ break;
+ }
+ goto inNumberAfterDecimalPoint;
+ case CharacterZero:
+ shift();
+ if ((m_current | 0x20) == 'x' && isASCIIHexDigit(peek(1))) {
+ parseHex(tokenData->doubleValue);
+ token = NUMBER;
+ } else {
+ record8('0');
+ if (isASCIIOctalDigit(m_current)) {
+ if (parseOctal(tokenData->doubleValue)) {
+ if (strictMode)
+ goto returnError;
+ token = NUMBER;
}
- goto start;
}
- goto returnError;
- }
-
- m_atLineStart = false;
- goto returnToken;
-
-startString: {
- int stringQuoteCharacter = m_current;
- shift1();
-
- const UChar* stringStart = currentCharacter();
- while (m_current != stringQuoteCharacter) {
- // Fast check for characters that require special handling.
- // Catches -1, \n, \r, \, 0x2028, and 0x2029 as efficiently
- // as possible, and lets through all common ASCII characters.
- if (UNLIKELY(m_current == '\\') || UNLIKELY(((static_cast<unsigned>(m_current) - 0xE) & 0x2000))) {
- m_buffer16.append(stringStart, currentCharacter() - stringStart);
- goto inString;
}
- shift1();
- }
- lvalp->ident = makeIdentifier(stringStart, currentCharacter() - stringStart);
- shift1();
- m_atLineStart = false;
- m_delimited = false;
- token = STRING;
- goto returnToken;
+ // Fall through into CharacterNumber
+ case CharacterNumber:
+ if (LIKELY(token != NUMBER)) {
+ if (!parseDecimal(tokenData->doubleValue)) {
+ if (m_current == '.') {
+ shift();
+inNumberAfterDecimalPoint:
+ parseNumberAfterDecimalPoint();
+ }
+ if ((m_current | 0x20) == 'e')
+ if (!parseNumberAfterExponentIndicator())
+ goto returnError;
+ // Null-terminate string for strtod.
+ m_buffer8.append('\0');
+ tokenData->doubleValue = WTF::strtod(m_buffer8.data(), 0);
+ }
+ token = NUMBER;
+ }
-inString:
- while (m_current != stringQuoteCharacter) {
- if (m_current == '\\')
- goto inStringEscapeSequence;
- if (UNLIKELY(isLineTerminator(m_current)))
- goto returnError;
- if (UNLIKELY(m_current == -1))
+ // No identifiers allowed directly after numeric literal, e.g. "3in" is bad.
+ if (UNLIKELY(isIdentStart(m_current)))
goto returnError;
- record16(m_current);
- shift1();
- }
- goto doneString;
-
-inStringEscapeSequence:
- shift1();
- if (m_current == 'x') {
- shift1();
- if (isASCIIHexDigit(m_current) && isASCIIHexDigit(m_next1)) {
- record16(convertHex(m_current, m_next1));
- shift2();
- goto inString;
- }
- record16('x');
- if (m_current == stringQuoteCharacter)
- goto doneString;
- goto inString;
- }
- if (m_current == 'u') {
- shift1();
- if (isASCIIHexDigit(m_current) && isASCIIHexDigit(m_next1) && isASCIIHexDigit(m_next2) && isASCIIHexDigit(m_next3)) {
- record16(convertUnicode(m_current, m_next1, m_next2, m_next3));
- shift4();
- goto inString;
- }
- if (m_current == stringQuoteCharacter) {
- record16('u');
- goto doneString;
- }
- goto returnError;
- }
- if (isASCIIOctalDigit(m_current)) {
- if (m_current >= '0' && m_current <= '3' && isASCIIOctalDigit(m_next1) && isASCIIOctalDigit(m_next2)) {
- record16((m_current - '0') * 64 + (m_next1 - '0') * 8 + m_next2 - '0');
- shift3();
- goto inString;
- }
- if (isASCIIOctalDigit(m_next1)) {
- record16((m_current - '0') * 8 + m_next1 - '0');
- shift2();
- goto inString;
+ m_buffer8.resize(0);
+ m_delimited = false;
+ break;
+ case CharacterQuote:
+ if (lexType & DontBuildStrings) {
+ if (UNLIKELY(!parseString<false>(tokenData, strictMode)))
+ goto returnError;
+ } else {
+ if (UNLIKELY(!parseString<true>(tokenData, strictMode)))
+ goto returnError;
}
- record16(m_current - '0');
- shift1();
- goto inString;
- }
- if (isLineTerminator(m_current)) {
+ shift();
+ m_delimited = false;
+ token = STRING;
+ break;
+ case CharacterIdentifierStart:
+ ASSERT(isIdentStart(m_current));
+ // Fall through into CharacterBackSlash.
+ case CharacterBackSlash:
+ if (lexType & DontBuildKeywords)
+ token = parseIdentifier<false>(tokenData, lexType);
+ else
+ token = parseIdentifier<true>(tokenData, lexType);
+ break;
+ case CharacterLineTerminator:
+ ASSERT(isLineTerminator(m_current));
shiftLineTerminator();
- goto inString;
- }
- if (m_current == -1)
- goto returnError;
- record16(singleEscape(m_current));
- shift1();
- goto inString;
-}
-
-startIdentifierWithBackslash:
- shift1();
- if (UNLIKELY(m_current != 'u'))
- goto returnError;
- shift1();
- if (UNLIKELY(!isASCIIHexDigit(m_current) || !isASCIIHexDigit(m_next1) || !isASCIIHexDigit(m_next2) || !isASCIIHexDigit(m_next3)))
+ m_atLineStart = true;
+ m_terminator = true;
+ goto start;
+ case CharacterInvalid:
goto returnError;
- token = convertUnicode(m_current, m_next1, m_next2, m_next3);
- if (UNLIKELY(!isIdentStart(token)))
+ default:
+ ASSERT_NOT_REACHED();
goto returnError;
- goto inIdentifierAfterCharacterCheck;
-
-startIdentifierOrKeyword: {
- const UChar* identifierStart = currentCharacter();
- shift1();
- while (isIdentPart(m_current))
- shift1();
- if (LIKELY(m_current != '\\')) {
- lvalp->ident = makeIdentifier(identifierStart, currentCharacter() - identifierStart);
- goto doneIdentifierOrKeyword;
}
- m_buffer16.append(identifierStart, currentCharacter() - identifierStart);
-}
- do {
- shift1();
- if (UNLIKELY(m_current != 'u'))
- goto returnError;
- shift1();
- if (UNLIKELY(!isASCIIHexDigit(m_current) || !isASCIIHexDigit(m_next1) || !isASCIIHexDigit(m_next2) || !isASCIIHexDigit(m_next3)))
- goto returnError;
- token = convertUnicode(m_current, m_next1, m_next2, m_next3);
- if (UNLIKELY(!isIdentPart(token)))
- goto returnError;
-inIdentifierAfterCharacterCheck:
- record16(token);
- shift4();
-
- while (isIdentPart(m_current)) {
- record16(m_current);
- shift1();
- }
- } while (UNLIKELY(m_current == '\\'));
- goto doneIdentifier;
+ m_atLineStart = false;
+ goto returnToken;
inSingleLineComment:
while (!isLineTerminator(m_current)) {
if (UNLIKELY(m_current == -1))
- return 0;
- shift1();
+ return EOFTOK;
+ shift();
}
shiftLineTerminator();
m_atLineStart = true;
m_terminator = true;
- if (lastTokenWasRestrKeyword())
- goto doneSemicolon;
- goto start;
-
-inMultiLineComment:
- shift2();
- while (m_current != '*' || m_next1 != '/') {
- if (isLineTerminator(m_current))
- shiftLineTerminator();
- else {
- shift1();
- if (UNLIKELY(m_current == -1))
- goto returnError;
- }
- }
- shift2();
- m_atLineStart = false;
- goto start;
-
-startNumberWithZeroDigit:
- shift1();
- if ((m_current | 0x20) == 'x' && isASCIIHexDigit(m_next1)) {
- shift1();
- goto inHex;
- }
- if (m_current == '.') {
- record8('0');
- record8('.');
- shift1();
- goto inNumberAfterDecimalPoint;
- }
- if ((m_current | 0x20) == 'e') {
- record8('0');
- record8('e');
- shift1();
- goto inExponentIndicator;
- }
- if (isASCIIOctalDigit(m_current))
- goto inOctal;
- if (isASCIIDigit(m_current))
- goto startNumber;
- lvalp->doubleValue = 0;
- goto doneNumeric;
-
-inNumberAfterDecimalPoint:
- while (isASCIIDigit(m_current)) {
- record8(m_current);
- shift1();
- }
- if ((m_current | 0x20) == 'e') {
- record8('e');
- shift1();
- goto inExponentIndicator;
- }
- goto doneNumber;
-
-inExponentIndicator:
- if (m_current == '+' || m_current == '-') {
- record8(m_current);
- shift1();
- }
- if (!isASCIIDigit(m_current))
- goto returnError;
- do {
- record8(m_current);
- shift1();
- } while (isASCIIDigit(m_current));
- goto doneNumber;
+ if (!lastTokenWasRestrKeyword())
+ goto start;
-inOctal: {
- do {
- record8(m_current);
- shift1();
- } while (isASCIIOctalDigit(m_current));
- if (isASCIIDigit(m_current))
- goto startNumber;
-
- double dval = 0;
-
- const char* end = m_buffer8.end();
- for (const char* p = m_buffer8.data(); p < end; ++p) {
- dval *= 8;
- dval += *p - '0';
- }
- if (dval >= mantissaOverflowLowerBound)
- dval = parseIntOverflow(m_buffer8.data(), end - m_buffer8.data(), 8);
-
- m_buffer8.resize(0);
-
- lvalp->doubleValue = dval;
- goto doneNumeric;
-}
-
-inHex: {
- do {
- record8(m_current);
- shift1();
- } while (isASCIIHexDigit(m_current));
-
- double dval = 0;
-
- const char* end = m_buffer8.end();
- for (const char* p = m_buffer8.data(); p < end; ++p) {
- dval *= 16;
- dval += toASCIIHexValue(*p);
- }
- if (dval >= mantissaOverflowLowerBound)
- dval = parseIntOverflow(m_buffer8.data(), end - m_buffer8.data(), 16);
-
- m_buffer8.resize(0);
-
- lvalp->doubleValue = dval;
- goto doneNumeric;
-}
-
-startNumber:
- record8(m_current);
- shift1();
- while (isASCIIDigit(m_current)) {
- record8(m_current);
- shift1();
- }
- if (m_current == '.') {
- record8('.');
- shift1();
- goto inNumberAfterDecimalPoint;
- }
- if ((m_current | 0x20) == 'e') {
- record8('e');
- shift1();
- goto inExponentIndicator;
- }
-
- // Fall through into doneNumber.
-
-doneNumber:
- // Null-terminate string for strtod.
- m_buffer8.append('\0');
- lvalp->doubleValue = WTF::strtod(m_buffer8.data(), 0);
- m_buffer8.resize(0);
-
- // Fall through into doneNumeric.
-
-doneNumeric:
- // No identifiers allowed directly after numeric literal, e.g. "3in" is bad.
- if (UNLIKELY(isIdentStart(m_current)))
- goto returnError;
-
- m_atLineStart = false;
- m_delimited = false;
- token = NUMBER;
- goto returnToken;
-
-doneSemicolon:
- token = ';';
+ token = SEMICOLON;
m_delimited = true;
- goto returnToken;
-
-doneIdentifier:
- m_atLineStart = false;
- m_delimited = false;
- lvalp->ident = makeIdentifier(m_buffer16.data(), m_buffer16.size());
- m_buffer16.resize(0);
- token = IDENT;
- goto returnToken;
-
-doneIdentifierOrKeyword: {
- m_atLineStart = false;
- m_delimited = false;
- m_buffer16.resize(0);
- const HashEntry* entry = m_keywordTable.entry(m_globalData, *lvalp->ident);
- token = entry ? entry->lexerValue() : IDENT;
- goto returnToken;
-}
-
-doneString:
- // Atomize constant strings in case they're later used in property lookup.
- shift1();
- m_atLineStart = false;
- m_delimited = false;
- lvalp->ident = makeIdentifier(m_buffer16.data(), m_buffer16.size());
- m_buffer16.resize(0);
- token = STRING;
-
// Fall through into returnToken.
-returnToken: {
- int lineNumber = m_lineNumber;
- llocp->first_line = lineNumber;
- llocp->last_line = lineNumber;
- llocp->first_column = startOffset;
- llocp->last_column = currentOffset();
-
+returnToken:
+ tokenInfo->line = m_lineNumber;
+ tokenInfo->startOffset = startOffset;
+ tokenInfo->endOffset = currentOffset();
m_lastToken = token;
return token;
-}
returnError:
m_error = true;
- return -1;
+ return ERRORTOK;
}
bool Lexer::scanRegExp(const Identifier*& pattern, const Identifier*& flags, UChar patternPrefix)
return false;
}
- shift1();
+ shift();
if (current == '/' && !lastWasEscape && !inBrackets)
break;
while (isIdentPart(m_current)) {
record16(m_current);
- shift1();
+ shift();
}
flags = makeIdentifier(m_buffer16.data(), m_buffer16.size());
if (isLineTerminator(current) || current == -1)
return false;
- shift1();
+ shift();
if (current == '/' && !lastWasEscape && !inBrackets)
break;
}
while (isIdentPart(m_current))
- shift1();
+ shift();
return true;
}
void Lexer::clear()
{
m_arena = 0;
- m_codeWithoutBOMs.clear();
Vector<char> newBuffer8;
m_buffer8.swap(newBuffer8);
SourceCode Lexer::sourceCode(int openBrace, int closeBrace, int firstLine)
{
- if (m_codeWithoutBOMs.isEmpty())
- return SourceCode(m_source->provider(), openBrace, closeBrace + 1, firstLine);
-
- const UChar* data = m_source->provider()->data();
-
- ASSERT(openBrace < closeBrace);
- int i;
- for (i = m_source->startOffset(); i < openBrace; ++i) {
- if (data[i] == byteOrderMark) {
- openBrace++;
- closeBrace++;
- }
- }
- for (; i < closeBrace; ++i) {
- if (data[i] == byteOrderMark)
- closeBrace++;
- }
-
- ASSERT(openBrace < closeBrace);
-
+ ASSERT(m_source->provider()->data()[openBrace] == '{');
+ ASSERT(m_source->provider()->data()[closeBrace] == '}');
return SourceCode(m_source->provider(), openBrace, closeBrace + 1, firstLine);
}
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Zoltan Herczeg (zherczeg@inf.u-szeged.hu)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
#ifndef Lexer_h
#define Lexer_h
+#include "JSParser.h"
#include "Lookup.h"
#include "ParserArena.h"
#include "SourceCode.h"
#include <wtf/ASCIICType.h>
+#include <wtf/AlwaysInline.h>
#include <wtf/SegmentedVector.h>
#include <wtf/Vector.h>
#include <wtf/unicode/Unicode.h>
class RegExp;
- class Lexer : public Noncopyable {
+ class Lexer {
+ WTF_MAKE_NONCOPYABLE(Lexer); WTF_MAKE_FAST_ALLOCATED;
public:
// Character manipulation functions.
static bool isWhiteSpace(int character);
// Functions to set up parsing.
void setCode(const SourceCode&, ParserArena&);
void setIsReparsing() { m_isReparsing = true; }
+ bool isReparsing() const { return m_isReparsing; }
// Functions for the parser itself.
- int lex(void* lvalp, void* llocp);
+ enum LexType {
+ IgnoreReservedWords = 1,
+ DontBuildStrings = 2,
+ DontBuildKeywords = 4
+ };
+ JSTokenType lex(JSTokenData*, JSTokenInfo*, unsigned, bool strictMode);
+ bool nextTokenIsColon();
int lineNumber() const { return m_lineNumber; }
+ void setLastLineNumber(int lastLineNumber) { m_lastLineNumber = lastLineNumber; }
+ int lastLineNumber() const { return m_lastLineNumber; }
bool prevTerminator() const { return m_terminator; }
SourceCode sourceCode(int openBrace, int closeBrace, int firstLine);
bool scanRegExp(const Identifier*& pattern, const Identifier*& flags, UChar patternPrefix = 0);
// Functions for use after parsing.
bool sawError() const { return m_error; }
void clear();
+ int currentOffset() { return m_code - m_codeStart; }
+ void setOffset(int offset)
+ {
+ m_error = 0;
+ m_code = m_codeStart + offset;
+ m_buffer8.resize(0);
+ m_buffer16.resize(0);
+ // Faster than an if-else sequence
+ m_current = -1;
+ if (LIKELY(m_code < m_codeEnd))
+ m_current = *m_code;
+ }
+ void setLineNumber(int line)
+ {
+ m_lineNumber = line;
+ }
+
+ SourceProvider* sourceProvider() const { return m_source->provider(); }
+
+ JSTokenType lexExpectIdentifier(JSTokenData*, JSTokenInfo*, unsigned, bool strictMode);
+
+ bool isKeyword(const Identifier&);
private:
friend class JSGlobalData;
Lexer(JSGlobalData*);
~Lexer();
- void shift1();
- void shift2();
- void shift3();
- void shift4();
- void shiftLineTerminator();
-
void record8(int);
void record16(int);
void record16(UChar);
void copyCodeWithoutBOMs();
- int currentOffset() const;
- const UChar* currentCharacter() const;
+ ALWAYS_INLINE void shift();
+ ALWAYS_INLINE int peek(int offset);
+ int getUnicodeCharacter();
+ void shiftLineTerminator();
+
+ ALWAYS_INLINE const UChar* currentCharacter() const;
+ ALWAYS_INLINE int currentOffset() const;
+
+ ALWAYS_INLINE const Identifier* makeIdentifier(const UChar* characters, size_t length);
- const Identifier* makeIdentifier(const UChar* characters, size_t length);
+ ALWAYS_INLINE bool lastTokenWasRestrKeyword() const;
- bool lastTokenWasRestrKeyword() const;
+ enum ShiftType { DoBoundsCheck, DoNotBoundsCheck };
+ template <int shiftAmount, ShiftType shouldBoundsCheck> void internalShift();
+ template <bool shouldCreateIdentifier> ALWAYS_INLINE JSTokenType parseKeyword(JSTokenData*);
+ template <bool shouldBuildIdentifiers> ALWAYS_INLINE JSTokenType parseIdentifier(JSTokenData*, unsigned);
+ template <bool shouldBuildStrings> ALWAYS_INLINE bool parseString(JSTokenData*, bool strictMode);
+ ALWAYS_INLINE void parseHex(double& returnValue);
+ ALWAYS_INLINE bool parseOctal(double& returnValue);
+ ALWAYS_INLINE bool parseDecimal(double& returnValue);
+ ALWAYS_INLINE void parseNumberAfterDecimalPoint();
+ ALWAYS_INLINE bool parseNumberAfterExponentIndicator();
+ ALWAYS_INLINE bool parseMultilineComment();
static const size_t initialReadBufferCapacity = 32;
int m_lineNumber;
+ int m_lastLineNumber;
Vector<char> m_buffer8;
Vector<UChar> m_buffer16;
// current and following unicode characters (int to allow for -1 for end-of-file marker)
int m_current;
- int m_next1;
- int m_next2;
- int m_next3;
-
+
IdentifierArena* m_arena;
JSGlobalData* m_globalData;
const HashTable m_keywordTable;
-
- Vector<UChar> m_codeWithoutBOMs;
};
- inline bool Lexer::isWhiteSpace(int ch)
+ ALWAYS_INLINE bool Lexer::isWhiteSpace(int ch)
{
- return isASCII(ch) ? (ch == ' ' || ch == '\t' || ch == 0xB || ch == 0xC) : WTF::Unicode::isSeparatorSpace(ch);
+ return isASCII(ch) ? (ch == ' ' || ch == '\t' || ch == 0xB || ch == 0xC) : (WTF::Unicode::isSeparatorSpace(ch) || ch == 0xFEFF);
}
- inline bool Lexer::isLineTerminator(int ch)
+ ALWAYS_INLINE bool Lexer::isLineTerminator(int ch)
{
return ch == '\r' || ch == '\n' || (ch & ~1) == 0x2028;
}
{
return (convertHex(c1, c2) << 8) | convertHex(c3, c4);
}
+
+ ALWAYS_INLINE const Identifier* Lexer::makeIdentifier(const UChar* characters, size_t length)
+ {
+ return &m_arena->makeIdentifier(m_globalData, characters, length);
+ }
- // A bridge for yacc from the C world to the C++ world.
- inline int jscyylex(void* lvalp, void* llocp, void* globalData)
+ ALWAYS_INLINE JSTokenType Lexer::lexExpectIdentifier(JSTokenData* tokenData, JSTokenInfo* tokenInfo, unsigned lexType, bool strictMode)
{
- return static_cast<JSGlobalData*>(globalData)->lexer->lex(lvalp, llocp);
+ ASSERT((lexType & IgnoreReservedWords));
+ const UChar* start = m_code;
+ const UChar* ptr = start;
+ const UChar* end = m_codeEnd;
+ if (ptr >= end) {
+ ASSERT(ptr == end);
+ goto slowCase;
+ }
+ if (!WTF::isASCIIAlpha(*ptr))
+ goto slowCase;
+ ++ptr;
+ while (ptr < end) {
+ if (!WTF::isASCIIAlphanumeric(*ptr))
+ break;
+ ++ptr;
+ }
+
+ // Here's the shift
+ if (ptr < end) {
+ if ((!WTF::isASCII(*ptr)) || (*ptr == '\\') || (*ptr == '_') || (*ptr == '$'))
+ goto slowCase;
+ m_current = *ptr;
+ } else
+ m_current = -1;
+
+ m_code = ptr;
+
+ // Create the identifier if needed
+ if (lexType & DontBuildKeywords)
+ tokenData->ident = 0;
+ else
+ tokenData->ident = makeIdentifier(start, ptr - start);
+ tokenInfo->line = m_lineNumber;
+ tokenInfo->startOffset = start - m_codeStart;
+ tokenInfo->endOffset = currentOffset();
+ m_lastToken = IDENT;
+ return IDENT;
+
+ slowCase:
+ return lex(tokenData, tokenInfo, lexType, strictMode);
}
} // namespace JSC
}
inline Node::Node(JSGlobalData* globalData)
- : m_line(globalData->lexer->lineNumber())
+ : m_line(globalData->lexer->lastLineNumber())
{
}
m_statements.append(statement);
}
-inline StatementNode* SourceElements::singleStatement() const
+StatementNode* SourceElements::singleStatement() const
{
size_t size = m_statements.size();
return size == 1 ? m_statements[0] : 0;
// -----------------------------ScopeNodeData ---------------------------
-ScopeNodeData::ScopeNodeData(ParserArena& arena, SourceElements* statements, VarStack* varStack, FunctionStack* funcStack, int numConstants)
+ScopeNodeData::ScopeNodeData(ParserArena& arena, SourceElements* statements, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, int numConstants)
: m_numConstants(numConstants)
, m_statements(statements)
{
m_varStack.swap(*varStack);
if (funcStack)
m_functionStack.swap(*funcStack);
+ m_capturedVariables.swap(capturedVariables);
}
// ------------------------------ ScopeNode -----------------------------
-ScopeNode::ScopeNode(JSGlobalData* globalData)
+ScopeNode::ScopeNode(JSGlobalData* globalData, bool inStrictContext)
: StatementNode(globalData)
, ParserArenaRefCounted(globalData)
- , m_features(NoFeatures)
+ , m_features(inStrictContext ? StrictModeFeature : NoFeatures)
{
}
-ScopeNode::ScopeNode(JSGlobalData* globalData, const SourceCode& source, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, CodeFeatures features, int numConstants)
+ScopeNode::ScopeNode(JSGlobalData* globalData, const SourceCode& source, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, CodeFeatures features, int numConstants)
: StatementNode(globalData)
, ParserArenaRefCounted(globalData)
- , m_data(new ScopeNodeData(globalData->parser->arena(), children, varStack, funcStack, numConstants))
+ , m_data(adoptPtr(new ScopeNodeData(globalData->parser->arena(), children, varStack, funcStack, capturedVariables, numConstants)))
, m_features(features)
, m_source(source)
{
// ------------------------------ ProgramNode -----------------------------
-inline ProgramNode::ProgramNode(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& source, CodeFeatures features, int numConstants)
- : ScopeNode(globalData, source, children, varStack, funcStack, features, numConstants)
+inline ProgramNode::ProgramNode(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, const SourceCode& source, CodeFeatures features, int numConstants)
+ : ScopeNode(globalData, source, children, varStack, funcStack, capturedVariables, features, numConstants)
{
}
-PassRefPtr<ProgramNode> ProgramNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& source, CodeFeatures features, int numConstants)
+PassRefPtr<ProgramNode> ProgramNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, const SourceCode& source, CodeFeatures features, int numConstants)
{
- RefPtr<ProgramNode> node = new ProgramNode(globalData, children, varStack, funcStack, source, features, numConstants);
+ RefPtr<ProgramNode> node = new ProgramNode(globalData, children, varStack, funcStack, capturedVariables, source, features, numConstants);
ASSERT(node->data()->m_arena.last() == node);
node->data()->m_arena.removeLast();
// ------------------------------ EvalNode -----------------------------
-inline EvalNode::EvalNode(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& source, CodeFeatures features, int numConstants)
- : ScopeNode(globalData, source, children, varStack, funcStack, features, numConstants)
+inline EvalNode::EvalNode(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, const SourceCode& source, CodeFeatures features, int numConstants)
+ : ScopeNode(globalData, source, children, varStack, funcStack, capturedVariables, features, numConstants)
{
}
-PassRefPtr<EvalNode> EvalNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& source, CodeFeatures features, int numConstants)
+PassRefPtr<EvalNode> EvalNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, const SourceCode& source, CodeFeatures features, int numConstants)
{
- RefPtr<EvalNode> node = new EvalNode(globalData, children, varStack, funcStack, source, features, numConstants);
+ RefPtr<EvalNode> node = new EvalNode(globalData, children, varStack, funcStack, capturedVariables, source, features, numConstants);
ASSERT(node->data()->m_arena.last() == node);
node->data()->m_arena.removeLast();
append(parameter->ident());
}
-inline FunctionBodyNode::FunctionBodyNode(JSGlobalData* globalData)
- : ScopeNode(globalData)
+inline FunctionBodyNode::FunctionBodyNode(JSGlobalData* globalData, bool inStrictContext)
+ : ScopeNode(globalData, inStrictContext)
{
}
-inline FunctionBodyNode::FunctionBodyNode(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& sourceCode, CodeFeatures features, int numConstants)
- : ScopeNode(globalData, sourceCode, children, varStack, funcStack, features, numConstants)
+inline FunctionBodyNode::FunctionBodyNode(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, const SourceCode& sourceCode, CodeFeatures features, int numConstants)
+ : ScopeNode(globalData, sourceCode, children, varStack, funcStack, capturedVariables, features, numConstants)
{
}
m_ident = ident;
}
-FunctionBodyNode* FunctionBodyNode::create(JSGlobalData* globalData)
+FunctionBodyNode* FunctionBodyNode::create(JSGlobalData* globalData, bool inStrictContext)
{
- return new FunctionBodyNode(globalData);
+ return new FunctionBodyNode(globalData, inStrictContext);
}
-PassRefPtr<FunctionBodyNode> FunctionBodyNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& sourceCode, CodeFeatures features, int numConstants)
+PassRefPtr<FunctionBodyNode> FunctionBodyNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, const SourceCode& sourceCode, CodeFeatures features, int numConstants)
{
- RefPtr<FunctionBodyNode> node = new FunctionBodyNode(globalData, children, varStack, funcStack, sourceCode, features, numConstants);
+ RefPtr<FunctionBodyNode> node = new FunctionBodyNode(globalData, children, varStack, funcStack, capturedVariables, sourceCode, features, numConstants);
ASSERT(node->data()->m_arena.last() == node);
node->data()->m_arena.removeLast();
const CodeFeatures WithFeature = 1 << 4;
const CodeFeatures CatchFeature = 1 << 5;
const CodeFeatures ThisFeature = 1 << 6;
- const CodeFeatures AllFeatures = EvalFeature | ClosureFeature | AssignFeature | ArgumentsFeature | WithFeature | CatchFeature | ThisFeature;
+ const CodeFeatures StrictModeFeature = 1 << 7;
+ const CodeFeatures ShadowsArgumentsFeature = 1 << 8;
+
+
+ const CodeFeatures AllFeatures = EvalFeature | ClosureFeature | AssignFeature | ArgumentsFeature | WithFeature | CatchFeature | ThisFeature | StrictModeFeature | ShadowsArgumentsFeature;
enum Operator {
OpEqual,
OpLogicalOr
};
+ typedef HashSet<RefPtr<StringImpl>, IdentifierRepHash> IdentifierSet;
+
namespace DeclarationStacks {
enum VarAttrs { IsConstant = 1, HasInitializer = 2 };
typedef Vector<std::pair<const Identifier*, unsigned> > VarStack;
virtual bool isCommaNode() const { return false; }
virtual bool isSimpleArray() const { return false; }
virtual bool isAdd() const { return false; }
+ virtual bool isSubtract() const { return false; }
virtual bool hasConditionContextCodegen() const { return false; }
virtual void emitBytecodeInConditionContext(BytecodeGenerator&, Label*, Label*, bool) { ASSERT_NOT_REACHED(); }
uint16_t endOffset() const { return m_endOffset; }
protected:
- RegisterID* emitThrowError(BytecodeGenerator&, ErrorType, const char* message);
- RegisterID* emitThrowError(BytecodeGenerator&, ErrorType, const char* message, const UString&);
- RegisterID* emitThrowError(BytecodeGenerator&, ErrorType, const char* message, const Identifier&);
+ RegisterID* emitThrowReferenceError(BytecodeGenerator&, const UString& message);
private:
uint32_t m_divot;
class PropertyNode : public ParserArenaFreeable {
public:
- enum Type { Constant, Getter, Setter };
+ enum Type { Constant = 1, Getter = 2, Setter = 4 };
PropertyNode(JSGlobalData*, const Identifier& name, ExpressionNode* value, Type);
PropertyNode(JSGlobalData*, double name, ExpressionNode* value, Type);
const Identifier& name() const { return m_name; }
+ Type type() const { return m_type; }
private:
friend class PropertyListNode;
RegisterID* emitStrcat(BytecodeGenerator& generator, RegisterID* destination, RegisterID* lhs = 0, ReadModifyResolveNode* emitExpressionInfoForMe = 0);
+ ExpressionNode* lhs() { return m_expr1; };
+ ExpressionNode* rhs() { return m_expr2; };
+
private:
virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
class SubNode : public BinaryOpNode {
public:
SubNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+
+ virtual bool isSubtract() const { return true; }
};
class LeftShiftNode : public BinaryOpNode {
public:
BlockNode(JSGlobalData*, SourceElements* = 0);
+ StatementNode* singleStatement() const;
StatementNode* lastStatement() const;
private:
public:
ReturnNode(JSGlobalData*, ExpressionNode* value);
+ ExpressionNode* value() { return m_value; }
+
private:
virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
ParameterNode* m_next;
};
- struct ScopeNodeData : FastAllocBase {
+ struct ScopeNodeData {
+ WTF_MAKE_FAST_ALLOCATED;
+ public:
typedef DeclarationStacks::VarStack VarStack;
typedef DeclarationStacks::FunctionStack FunctionStack;
- ScopeNodeData(ParserArena&, SourceElements*, VarStack*, FunctionStack*, int numConstants);
+ ScopeNodeData(ParserArena&, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, int numConstants);
ParserArena m_arena;
VarStack m_varStack;
FunctionStack m_functionStack;
int m_numConstants;
SourceElements* m_statements;
+ IdentifierSet m_capturedVariables;
};
class ScopeNode : public StatementNode, public ParserArenaRefCounted {
typedef DeclarationStacks::VarStack VarStack;
typedef DeclarationStacks::FunctionStack FunctionStack;
- ScopeNode(JSGlobalData*);
- ScopeNode(JSGlobalData*, const SourceCode&, SourceElements*, VarStack*, FunctionStack*, CodeFeatures, int numConstants);
+ ScopeNode(JSGlobalData*, bool inStrictContext);
+ ScopeNode(JSGlobalData*, const SourceCode&, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, CodeFeatures, int numConstants);
using ParserArenaRefCounted::operator new;
CodeFeatures features() { return m_features; }
bool usesEval() const { return m_features & EvalFeature; }
- bool usesArguments() const { return m_features & ArgumentsFeature; }
+ bool usesArguments() const { return (m_features & ArgumentsFeature) && !(m_features & ShadowsArgumentsFeature); }
+ bool isStrictMode() const { return m_features & StrictModeFeature; }
void setUsesArguments() { m_features |= ArgumentsFeature; }
bool usesThis() const { return m_features & ThisFeature; }
- bool needsActivation() const { return m_features & (EvalFeature | ClosureFeature | WithFeature | CatchFeature); }
+ bool needsActivationForMoreThanVariables() const { ASSERT(m_data); return m_features & (EvalFeature | WithFeature | CatchFeature); }
+ bool needsActivation() const { ASSERT(m_data); return (hasCapturedVariables()) || (m_features & (EvalFeature | WithFeature | CatchFeature)); }
+ bool hasCapturedVariables() const { return !!m_data->m_capturedVariables.size(); }
+ size_t capturedVariableCount() const { return m_data->m_capturedVariables.size(); }
+ bool captures(const Identifier& ident) { return m_data->m_capturedVariables.contains(ident.impl()); }
VarStack& varStack() { ASSERT(m_data); return m_data->m_varStack; }
FunctionStack& functionStack() { ASSERT(m_data); return m_data->m_functionStack; }
class ProgramNode : public ScopeNode {
public:
- static PassRefPtr<ProgramNode> create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants);
+ static const bool isFunctionNode = false;
+ static PassRefPtr<ProgramNode> create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, const SourceCode&, CodeFeatures, int numConstants);
static const bool scopeIsFunction = false;
private:
- ProgramNode(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants);
+ ProgramNode(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, const SourceCode&, CodeFeatures, int numConstants);
virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
};
class EvalNode : public ScopeNode {
public:
- static PassRefPtr<EvalNode> create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants);
+ static const bool isFunctionNode = false;
+ static PassRefPtr<EvalNode> create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, const SourceCode&, CodeFeatures, int numConstants);
static const bool scopeIsFunction = false;
private:
- EvalNode(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants);
+ EvalNode(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, const SourceCode&, CodeFeatures, int numConstants);
virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
};
class FunctionParameters : public Vector<Identifier>, public RefCounted<FunctionParameters> {
+ WTF_MAKE_FAST_ALLOCATED;
public:
static PassRefPtr<FunctionParameters> create(ParameterNode* firstParameter) { return adoptRef(new FunctionParameters(firstParameter)); }
class FunctionBodyNode : public ScopeNode {
public:
- static FunctionBodyNode* create(JSGlobalData*);
- static PassRefPtr<FunctionBodyNode> create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants);
+ static const bool isFunctionNode = true;
+ static FunctionBodyNode* create(JSGlobalData*, bool isStrictMode);
+ static PassRefPtr<FunctionBodyNode> create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, const SourceCode&, CodeFeatures, int numConstants);
FunctionParameters* parameters() const { return m_parameters.get(); }
size_t parameterCount() const { return m_parameters->size(); }
static const bool scopeIsFunction = true;
private:
- FunctionBodyNode(JSGlobalData*);
- FunctionBodyNode(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants);
+ FunctionBodyNode(JSGlobalData*, bool inStrictContext);
+ FunctionBodyNode(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, const SourceCode&, CodeFeatures, int numConstants);
Identifier m_ident;
RefPtr<FunctionParameters> m_parameters;
#include "Parser.h"
#include "Debugger.h"
+#include "JSParser.h"
#include "Lexer.h"
-#include <wtf/HashSet.h>
-#include <wtf/Vector.h>
-
-#ifndef yyparse
-extern int jscyyparse(void*);
-#endif
namespace JSC {
-void Parser::parse(JSGlobalData* globalData, int* errLine, UString* errMsg)
+void Parser::parse(JSGlobalData* globalData, FunctionParameters* parameters, JSParserStrictness strictness, JSParserMode mode, int* errLine, UString* errMsg)
{
+ ASSERT(globalData);
m_sourceElements = 0;
int defaultErrLine;
Lexer& lexer = *globalData->lexer;
lexer.setCode(*m_source, m_arena);
- int parseError = jscyyparse(globalData);
- bool lexError = lexer.sawError();
+ const char* parseError = jsParse(globalData, parameters, strictness, mode, m_source);
int lineNumber = lexer.lineNumber();
+ bool lexError = lexer.sawError();
lexer.clear();
if (parseError || lexError) {
*errLine = lineNumber;
- *errMsg = "Parse error";
+ *errMsg = parseError ? parseError : "Parse error";
m_sourceElements = 0;
}
}
void Parser::didFinishParsing(SourceElements* sourceElements, ParserArenaData<DeclarationStacks::VarStack>* varStack,
- ParserArenaData<DeclarationStacks::FunctionStack>* funcStack, CodeFeatures features, int lastLine, int numConstants)
+ ParserArenaData<DeclarationStacks::FunctionStack>* funcStack, CodeFeatures features, int lastLine, int numConstants, IdentifierSet& capturedVars)
{
m_sourceElements = sourceElements;
m_varDeclarations = varStack;
m_funcDeclarations = funcStack;
+ m_capturedVariables.swap(capturedVars);
m_features = features;
m_lastLine = lastLine;
m_numConstants = numConstants;
#define Parser_h
#include "Debugger.h"
+#include "ExceptionHelpers.h"
#include "Executable.h"
#include "JSGlobalObject.h"
#include "Lexer.h"
namespace JSC {
class FunctionBodyNode;
+
class ProgramNode;
class UString;
template <typename T> struct ParserArenaData : ParserArenaDeletable { T data; };
- class Parser : public Noncopyable {
+ class Parser {
+ WTF_MAKE_NONCOPYABLE(Parser); WTF_MAKE_FAST_ALLOCATED;
public:
+ Parser() { }
template <class ParsedNode>
- PassRefPtr<ParsedNode> parse(JSGlobalData* globalData, Debugger*, ExecState*, const SourceCode& source, int* errLine = 0, UString* errMsg = 0);
+ PassRefPtr<ParsedNode> parse(JSGlobalObject* lexicalGlobalObject, Debugger*, ExecState*, const SourceCode& source, FunctionParameters*, JSParserStrictness strictness, JSObject** exception);
void didFinishParsing(SourceElements*, ParserArenaData<DeclarationStacks::VarStack>*,
- ParserArenaData<DeclarationStacks::FunctionStack>*, CodeFeatures features, int lastLine, int numConstants);
+ ParserArenaData<DeclarationStacks::FunctionStack>*, CodeFeatures features,
+ int lastLine, int numConstants, IdentifierSet&);
ParserArena& arena() { return m_arena; }
private:
- void parse(JSGlobalData*, int* errLine, UString* errMsg);
+ void parse(JSGlobalData*, FunctionParameters*, JSParserStrictness strictness, JSParserMode mode, int* errLine, UString* errMsg);
+
+ // Used to determine type of error to report.
+ bool isFunctionBodyNode(ScopeNode*) { return false; }
+ bool isFunctionBodyNode(FunctionBodyNode*) { return true; }
ParserArena m_arena;
const SourceCode* m_source;
SourceElements* m_sourceElements;
ParserArenaData<DeclarationStacks::VarStack>* m_varDeclarations;
ParserArenaData<DeclarationStacks::FunctionStack>* m_funcDeclarations;
+ IdentifierSet m_capturedVariables;
CodeFeatures m_features;
int m_lastLine;
int m_numConstants;
};
template <class ParsedNode>
- PassRefPtr<ParsedNode> Parser::parse(JSGlobalData* globalData, Debugger* debugger, ExecState* debuggerExecState, const SourceCode& source, int* errLine, UString* errMsg)
+ PassRefPtr<ParsedNode> Parser::parse(JSGlobalObject* lexicalGlobalObject, Debugger* debugger, ExecState* debuggerExecState, const SourceCode& source, FunctionParameters* parameters, JSParserStrictness strictness, JSObject** exception)
{
+ ASSERT(lexicalGlobalObject);
+ ASSERT(exception && !*exception);
+ int errLine;
+ UString errMsg;
+
m_source = &source;
if (ParsedNode::scopeIsFunction)
- globalData->lexer->setIsReparsing();
- parse(globalData, errLine, errMsg);
+ lexicalGlobalObject->globalData().lexer->setIsReparsing();
+ parse(&lexicalGlobalObject->globalData(), parameters, strictness, ParsedNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, &errLine, &errMsg);
RefPtr<ParsedNode> result;
if (m_sourceElements) {
- result = ParsedNode::create(globalData,
- m_sourceElements,
- m_varDeclarations ? &m_varDeclarations->data : 0,
- m_funcDeclarations ? &m_funcDeclarations->data : 0,
- source,
- m_features,
- m_numConstants);
+ result = ParsedNode::create(&lexicalGlobalObject->globalData(),
+ m_sourceElements,
+ m_varDeclarations ? &m_varDeclarations->data : 0,
+ m_funcDeclarations ? &m_funcDeclarations->data : 0,
+ m_capturedVariables,
+ source,
+ m_features,
+ m_numConstants);
result->setLoc(m_source->firstLine(), m_lastLine);
+ } else if (lexicalGlobalObject) {
+ // We can never see a syntax error when reparsing a function, since we should have
+ // reported the error when parsing the containing program or eval code. So if we're
+ // parsing a function body node, we assume that what actually happened here is that
+ // we ran out of stack while parsing. If we see an error while parsing eval or program
+ // code we assume that it was a syntax error since running out of stack is much less
+ // likely, and we are currently unable to distinguish between the two cases.
+ if (isFunctionBodyNode(static_cast<ParsedNode*>(0)))
+ *exception = createStackOverflowError(lexicalGlobalObject);
+ else
+ *exception = addErrorInfo(&lexicalGlobalObject->globalData(), createSyntaxError(lexicalGlobalObject, errMsg), errLine, source);
}
m_arena.reset();
m_funcDeclarations = 0;
if (debugger && !ParsedNode::scopeIsFunction)
- debugger->sourceParsed(debuggerExecState, source, *errLine, *errMsg);
+ debugger->sourceParsed(debuggerExecState, source.provider(), errLine, errMsg);
return result.release();
}
/*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2009, 2010 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
#include "ParserArena.h"
#include "Nodes.h"
+#include <wtf/PassOwnPtr.h>
namespace JSC {
ParserArena::ParserArena()
: m_freeableMemory(0)
, m_freeablePoolEnd(0)
- , m_identifierArena(new IdentifierArena)
+ , m_identifierArena(adoptPtr(new IdentifierArena))
{
}
class ParserArenaDeletable;
class ParserArenaRefCounted;
- class IdentifierArena : public FastAllocBase {
+ class IdentifierArena {
+ WTF_MAKE_FAST_ALLOCATED;
public:
+ IdentifierArena()
+ {
+ clear();
+ }
+
ALWAYS_INLINE const Identifier& makeIdentifier(JSGlobalData*, const UChar* characters, size_t length);
const Identifier& makeNumericIdentifier(JSGlobalData*, double number);
- void clear() { m_identifiers.clear(); }
+ void clear()
+ {
+ m_identifiers.clear();
+ for (unsigned i = 0; i < 128; i++)
+ m_shortIdentifiers[i] = 0;
+ }
bool isEmpty() const { return m_identifiers.isEmpty(); }
private:
+ static const int MaximumCachableCharacter = 128;
typedef SegmentedVector<Identifier, 64> IdentifierVector;
IdentifierVector m_identifiers;
+ FixedArray<Identifier*, MaximumCachableCharacter> m_shortIdentifiers;
};
ALWAYS_INLINE const Identifier& IdentifierArena::makeIdentifier(JSGlobalData* globalData, const UChar* characters, size_t length)
{
+ if (length == 1 && characters[0] < MaximumCachableCharacter) {
+ if (Identifier* ident = m_shortIdentifiers[characters[0]])
+ return *ident;
+ m_identifiers.append(Identifier(globalData, characters, length));
+ m_shortIdentifiers[characters[0]] = &m_identifiers.last();
+ return m_identifiers.last();
+ }
m_identifiers.append(Identifier(globalData, characters, length));
return m_identifiers.last();
}
inline const Identifier& IdentifierArena::makeNumericIdentifier(JSGlobalData* globalData, double number)
{
- m_identifiers.append(Identifier(globalData, UString::from(number)));
+ m_identifiers.append(Identifier(globalData, UString::number(number)));
return m_identifiers.last();
}
- class ParserArena : Noncopyable {
+ class ParserArena {
+ WTF_MAKE_NONCOPYABLE(ParserArena);
public:
ParserArena();
~ParserArena();
#ifndef SourceProvider_h
#define SourceProvider_h
+#include "SourceProviderCache.h"
#include "UString.h"
+#include <wtf/PassOwnPtr.h>
#include <wtf/RefCounted.h>
+#include <wtf/UnusedParam.h>
+#include <wtf/text/TextPosition.h>
namespace JSC {
- enum SourceBOMPresence { SourceHasNoBOMs, SourceCouldHaveBOMs };
-
class SourceProvider : public RefCounted<SourceProvider> {
public:
- SourceProvider(const UString& url, SourceBOMPresence hasBOMs = SourceCouldHaveBOMs)
+ SourceProvider(const UString& url, SourceProviderCache* cache = 0)
: m_url(url)
- , m_hasBOMs(hasBOMs)
+ , m_validated(false)
+ , m_cache(cache ? cache : new SourceProviderCache)
+ , m_cacheOwned(!cache)
+ {
+ }
+ virtual ~SourceProvider()
{
+ if (m_cacheOwned)
+ delete m_cache;
}
- virtual ~SourceProvider() { }
virtual UString getRange(int start, int end) const = 0;
virtual const UChar* data() const = 0;
virtual int length() const = 0;
const UString& url() { return m_url; }
+ virtual TextPosition1 startPosition() const { return TextPosition1::minimumPosition(); }
intptr_t asID() { return reinterpret_cast<intptr_t>(this); }
- SourceBOMPresence hasBOMs() const { return m_hasBOMs; }
+ bool isValid() const { return m_validated; }
+ void setValid() { m_validated = true; }
+ SourceProviderCache* cache() const { return m_cache; }
+ void notifyCacheSizeChanged(int delta) { if (!m_cacheOwned) cacheSizeChanged(delta); }
+
private:
+ virtual void cacheSizeChanged(int delta) { UNUSED_PARAM(delta); }
+
UString m_url;
- SourceBOMPresence m_hasBOMs;
+ bool m_validated;
+ SourceProviderCache* m_cache;
+ bool m_cacheOwned;
};
class UStringSourceProvider : public SourceProvider {
return adoptRef(new UStringSourceProvider(source, url));
}
- UString getRange(int start, int end) const { return m_source.substr(start, end - start); }
- const UChar* data() const { return m_source.data(); }
- int length() const { return m_source.size(); }
+ UString getRange(int start, int end) const
+ {
+ return m_source.substringSharingImpl(start, end - start);
+ }
+ const UChar* data() const { return m_source.characters(); }
+ int length() const { return m_source.length(); }
private:
UStringSourceProvider(const UString& source, const UString& url)
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "SourceProviderCache.h"
+
+#include "SourceProviderCacheItem.h"
+
+namespace JSC {
+
+SourceProviderCache::~SourceProviderCache()
+{
+ clear();
+}
+
+void SourceProviderCache::clear()
+{
+ deleteAllValues(m_map);
+ m_map.clear();
+ m_contentByteSize = 0;
+}
+
+unsigned SourceProviderCache::byteSize() const
+{
+ return m_contentByteSize + sizeof(*this) + m_map.capacity() * sizeof(SourceProviderCacheItem*);
+}
+
+void SourceProviderCache::add(int sourcePosition, PassOwnPtr<SourceProviderCacheItem> item, unsigned size)
+{
+ m_map.add(sourcePosition, item.leakPtr());
+ m_contentByteSize += size;
+}
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <wtf/HashMap.h>
+#include <wtf/PassOwnPtr.h>
+
+namespace JSC {
+
+class SourceProviderCacheItem;
+
+class SourceProviderCache {
+public:
+ SourceProviderCache() : m_contentByteSize(0) {}
+ ~SourceProviderCache();
+
+ void clear();
+ unsigned byteSize() const;
+ void add(int sourcePosition, PassOwnPtr<SourceProviderCacheItem>, unsigned size);
+ const SourceProviderCacheItem* get(int sourcePosition) const { return m_map.get(sourcePosition); }
+
+private:
+ HashMap<int, SourceProviderCacheItem*> m_map;
+ unsigned m_contentByteSize;
+};
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "JSParser.h"
+#include <wtf/Vector.h>
+#include <wtf/text/WTFString.h>
+
+namespace JSC {
+
+class SourceProviderCacheItem {
+public:
+ SourceProviderCacheItem(int closeBraceLine, int closeBracePos)
+ : closeBraceLine(closeBraceLine)
+ , closeBracePos(closeBracePos)
+ {
+ }
+ unsigned approximateByteSize() const
+ {
+ // The identifiers are uniqued strings so most likely there are few names that actually use any additional memory.
+ static const unsigned assummedAverageIdentifierSize = sizeof(RefPtr<StringImpl>) + 2;
+ unsigned size = sizeof(*this);
+ size += usedVariables.size() * assummedAverageIdentifierSize;
+ size += writtenVariables.size() * assummedAverageIdentifierSize;
+ return size;
+ }
+ JSToken closeBraceToken() const
+ {
+ JSToken token;
+ token.m_type = CLOSEBRACE;
+ token.m_data.intValue = closeBracePos;
+ token.m_info.startOffset = closeBracePos;
+ token.m_info.endOffset = closeBracePos + 1;
+ token.m_info.line = closeBraceLine;
+ return token;
+ }
+
+ int closeBraceLine;
+ int closeBracePos;
+ bool usesEval;
+ Vector<RefPtr<StringImpl> > usedVariables;
+ Vector<RefPtr<StringImpl> > writtenVariables;
+};
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SyntaxChecker_h
+#define SyntaxChecker_h
+
+#include "Lexer.h"
+#include <yarr/YarrSyntaxChecker.h>
+
+namespace JSC {
+class SyntaxChecker {
+public:
+ struct BinaryExprContext {
+ BinaryExprContext(SyntaxChecker& context)
+ : m_context(&context)
+ {
+ m_context->m_topBinaryExprs.append(m_context->m_topBinaryExpr);
+ m_context->m_topBinaryExpr = 0;
+ }
+ ~BinaryExprContext()
+ {
+ m_context->m_topBinaryExpr = m_context->m_topBinaryExprs.last();
+ m_context->m_topBinaryExprs.removeLast();
+ }
+ private:
+ SyntaxChecker* m_context;
+ };
+ struct UnaryExprContext {
+ UnaryExprContext(SyntaxChecker& context)
+ : m_context(&context)
+ {
+ m_context->m_topUnaryTokens.append(m_context->m_topUnaryToken);
+ m_context->m_topUnaryToken = 0;
+ }
+ ~UnaryExprContext()
+ {
+ m_context->m_topUnaryToken = m_context->m_topUnaryTokens.last();
+ m_context->m_topUnaryTokens.removeLast();
+ }
+ private:
+ SyntaxChecker* m_context;
+ };
+
+ SyntaxChecker(JSGlobalData* , Lexer*)
+ {
+ }
+
+ typedef SyntaxChecker FunctionBodyBuilder;
+ enum { NoneExpr = 0,
+ ResolveEvalExpr, ResolveExpr, NumberExpr, StringExpr,
+ ThisExpr, NullExpr, BoolExpr, RegExpExpr, ObjectLiteralExpr,
+ FunctionExpr, BracketExpr, DotExpr, CallExpr,
+ NewExpr, PreExpr, PostExpr, UnaryExpr, BinaryExpr,
+ ConditionalExpr, AssignmentExpr, TypeofExpr,
+ DeleteExpr, ArrayLiteralExpr };
+ typedef int ExpressionType;
+
+ typedef ExpressionType Expression;
+ typedef int SourceElements;
+ typedef int Arguments;
+ typedef ExpressionType Comma;
+ struct Property {
+ ALWAYS_INLINE Property(void* = 0)
+ : type((PropertyNode::Type)0)
+ {
+ }
+ ALWAYS_INLINE Property(const Identifier* ident, PropertyNode::Type ty)
+ : name(ident)
+ , type(ty)
+ {
+ }
+ ALWAYS_INLINE Property(PropertyNode::Type ty)
+ : name(0)
+ , type(ty)
+ {
+ }
+ ALWAYS_INLINE bool operator!() { return !type; }
+ const Identifier* name;
+ PropertyNode::Type type;
+ };
+ typedef int PropertyList;
+ typedef int ElementList;
+ typedef int ArgumentsList;
+ typedef int FormalParameterList;
+ typedef int FunctionBody;
+ typedef int Statement;
+ typedef int ClauseList;
+ typedef int Clause;
+ typedef int ConstDeclList;
+ typedef int BinaryOperand;
+
+ static const bool CreatesAST = false;
+ static const bool NeedsFreeVariableInfo = false;
+ static const bool CanUseFunctionCache = true;
+ static const unsigned DontBuildKeywords = Lexer::DontBuildKeywords;
+ static const unsigned DontBuildStrings = Lexer::DontBuildStrings;
+
+ int createSourceElements() { return 1; }
+ ExpressionType makeFunctionCallNode(int, int, int, int, int) { return CallExpr; }
+ void appendToComma(ExpressionType& base, ExpressionType right) { base = right; }
+ ExpressionType createCommaExpr(ExpressionType, ExpressionType right) { return right; }
+ ExpressionType makeAssignNode(ExpressionType, Operator, ExpressionType, bool, bool, int, int, int) { return AssignmentExpr; }
+ ExpressionType makePrefixNode(ExpressionType, Operator, int, int, int) { return PreExpr; }
+ ExpressionType makePostfixNode(ExpressionType, Operator, int, int, int) { return PostExpr; }
+ ExpressionType makeTypeOfNode(ExpressionType) { return TypeofExpr; }
+ ExpressionType makeDeleteNode(ExpressionType, int, int, int) { return DeleteExpr; }
+ ExpressionType makeNegateNode(ExpressionType) { return UnaryExpr; }
+ ExpressionType makeBitwiseNotNode(ExpressionType) { return UnaryExpr; }
+ ExpressionType createLogicalNot(ExpressionType) { return UnaryExpr; }
+ ExpressionType createUnaryPlus(ExpressionType) { return UnaryExpr; }
+ ExpressionType createVoid(ExpressionType) { return UnaryExpr; }
+ ExpressionType thisExpr() { return ThisExpr; }
+ ExpressionType createResolve(const Identifier*, int) { return ResolveExpr; }
+ ExpressionType createObjectLiteral() { return ObjectLiteralExpr; }
+ ExpressionType createObjectLiteral(int) { return ObjectLiteralExpr; }
+ ExpressionType createArray(int) { return ArrayLiteralExpr; }
+ ExpressionType createArray(int, int) { return ArrayLiteralExpr; }
+ ExpressionType createNumberExpr(double) { return NumberExpr; }
+ ExpressionType createString(const Identifier*) { return StringExpr; }
+ ExpressionType createBoolean(bool) { return BoolExpr; }
+ ExpressionType createNull() { return NullExpr; }
+ ExpressionType createBracketAccess(ExpressionType, ExpressionType, bool, int, int, int) { return BracketExpr; }
+ ExpressionType createDotAccess(ExpressionType, const Identifier*, int, int, int) { return DotExpr; }
+ ExpressionType createRegExp(const Identifier& pattern, const Identifier&, int) { return Yarr::checkSyntax(pattern.ustring()) ? 0 : RegExpExpr; }
+ ExpressionType createNewExpr(ExpressionType, int, int, int, int) { return NewExpr; }
+ ExpressionType createNewExpr(ExpressionType, int, int) { return NewExpr; }
+ ExpressionType createConditionalExpr(ExpressionType, ExpressionType, ExpressionType) { return ConditionalExpr; }
+ ExpressionType createAssignResolve(const Identifier&, ExpressionType, bool, int, int, int) { return AssignmentExpr; }
+ ExpressionType createFunctionExpr(const Identifier*, int, int, int, int, int, int) { return FunctionExpr; }
+ int createFunctionBody(bool) { return 1; }
+ int createArguments() { return 1; }
+ int createArguments(int) { return 1; }
+ int createArgumentsList(int) { return 1; }
+ int createArgumentsList(int, int) { return 1; }
+ template <bool complete> Property createProperty(const Identifier* name, int, PropertyNode::Type type)
+ {
+ if (!complete)
+ return Property(type);
+ ASSERT(name);
+ return Property(name, type);
+ }
+ template <bool complete> Property createProperty(JSGlobalData* globalData, double name, int, PropertyNode::Type type)
+ {
+ if (!complete)
+ return Property(type);
+ return Property(&globalData->parser->arena().identifierArena().makeNumericIdentifier(globalData, name), type);
+ }
+ int createPropertyList(Property) { return 1; }
+ int createPropertyList(Property, int) { return 1; }
+ int createElementList(int, int) { return 1; }
+ int createElementList(int, int, int) { return 1; }
+ int createFormalParameterList(const Identifier&) { return 1; }
+ int createFormalParameterList(int, const Identifier&) { return 1; }
+ int createClause(int, int) { return 1; }
+ int createClauseList(int) { return 1; }
+ int createClauseList(int, int) { return 1; }
+ void setUsesArguments(int) { }
+ int createFuncDeclStatement(const Identifier*, int, int, int, int, int, int) { return 1; }
+ int createBlockStatement(int, int, int) { return 1; }
+ int createExprStatement(int, int, int) { return 1; }
+ int createIfStatement(int, int, int, int) { return 1; }
+ int createIfStatement(int, int, int, int, int) { return 1; }
+ int createForLoop(int, int, int, int, bool, int, int) { return 1; }
+ int createForInLoop(const Identifier*, int, int, int, int, int, int, int, int, int, int) { return 1; }
+ int createForInLoop(int, int, int, int, int, int, int, int) { return 1; }
+ int createEmptyStatement() { return 1; }
+ int createVarStatement(int, int, int) { return 1; }
+ int createReturnStatement(int, int, int, int, int) { return 1; }
+ int createBreakStatement(int, int, int, int) { return 1; }
+ int createBreakStatement(const Identifier*, int, int, int, int) { return 1; }
+ int createContinueStatement(int, int, int, int) { return 1; }
+ int createContinueStatement(const Identifier*, int, int, int, int) { return 1; }
+ int createTryStatement(int, const Identifier*, bool, int, int, int, int) { return 1; }
+ int createSwitchStatement(int, int, int, int, int, int) { return 1; }
+ int createWhileStatement(int, int, int, int) { return 1; }
+ int createWithStatement(int, int, int, int, int, int) { return 1; }
+ int createDoWhileStatement(int, int, int, int) { return 1; }
+ int createLabelStatement(const Identifier*, int, int, int) { return 1; }
+ int createThrowStatement(int, int, int, int, int) { return 1; }
+ int createDebugger(int, int) { return 1; }
+ int createConstStatement(int, int, int) { return 1; }
+ int appendConstDecl(int, const Identifier*, int) { return 1; }
+ template <bool strict> Property createGetterOrSetterProperty(PropertyNode::Type type, const Identifier* name, int, int, int, int, int, int)
+ {
+ ASSERT(name);
+ if (!strict)
+ return Property(type);
+ return Property(name, type);
+ }
+
+ void appendStatement(int, int) { }
+ void addVar(const Identifier*, bool) { }
+ int combineCommaNodes(int, int) { return 1; }
+ int evalCount() const { return 0; }
+ void appendBinaryExpressionInfo(int& operandStackDepth, int expr, int, int, int, bool)
+ {
+ if (!m_topBinaryExpr)
+ m_topBinaryExpr = expr;
+ else
+ m_topBinaryExpr = BinaryExpr;
+ operandStackDepth++;
+ }
+
+ // Logic to handle datastructures used during parsing of binary expressions
+ void operatorStackPop(int& operatorStackDepth) { operatorStackDepth--; }
+ bool operatorStackHasHigherPrecedence(int&, int) { return true; }
+ BinaryOperand getFromOperandStack(int) { return m_topBinaryExpr; }
+ void shrinkOperandStackBy(int& operandStackDepth, int amount) { operandStackDepth -= amount; }
+ void appendBinaryOperation(int& operandStackDepth, int&, BinaryOperand, BinaryOperand) { operandStackDepth++; }
+ void operatorStackAppend(int& operatorStackDepth, int, int) { operatorStackDepth++; }
+ int popOperandStack(int&) { int res = m_topBinaryExpr; m_topBinaryExpr = 0; return res; }
+
+ void appendUnaryToken(int& stackDepth, int tok, int) { stackDepth = 1; m_topUnaryToken = tok; }
+ int unaryTokenStackLastType(int&) { return m_topUnaryToken; }
+ int unaryTokenStackLastStart(int&) { return 0; }
+ void unaryTokenStackRemoveLast(int& stackDepth) { stackDepth = 0; }
+
+ void assignmentStackAppend(int, int, int, int, int, Operator) { }
+ int createAssignment(int, int, int, int, int) { ASSERT_NOT_REACHED(); return 1; }
+ const Identifier& getName(const Property& property) const { ASSERT(property.name); return *property.name; }
+ PropertyNode::Type getType(const Property& property) const { return property.type; }
+ bool isResolve(ExpressionType expr) const { return expr == ResolveExpr || expr == ResolveEvalExpr; }
+
+private:
+ int m_topBinaryExpr;
+ int m_topUnaryToken;
+ Vector<int, 8> m_topBinaryExprs;
+ Vector<int, 8> m_topUnaryTokens;
+};
+
+}
+
+#endif
+++ /dev/null
-Originally written by: Philip Hazel
-Email local part: ph10
-Email domain: cam.ac.uk
-
-University of Cambridge Computing Service,
-Cambridge, England. Phone: +44 1223 334714.
-
-Copyright (c) 1997-2005 University of Cambridge. All rights reserved.
-
-Adapted for JavaScriptCore and WebKit by Apple Inc.
-
-Copyright (c) 2005, 2006, 2007 Apple Inc. All rights reserved.
+++ /dev/null
-PCRE is a library of functions to support regular expressions whose syntax
-and semantics are as close as possible to those of the Perl 5 language.
-
-This is JavaScriptCore's variant of the PCRE library. While this library
-started out as a copy of PCRE, many of the features of PCRE have been
-removed.
-
-Copyright (c) 1997-2005 University of Cambridge. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the name of Apple
- Inc. nor the names of their contributors may be used to endorse or
- promote products derived from this software without specific prior
- written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
+++ /dev/null
-#!/usr/bin/perl -w
-#
-# This is JavaScriptCore's variant of the PCRE library. While this library
-# started out as a copy of PCRE, many of the features of PCRE have been
-# removed. This library now supports only the regular expression features
-# required by the JavaScript language specification, and has only the functions
-# needed by JavaScriptCore and the rest of WebKit.
-#
-# Originally written by Philip Hazel
-# Copyright (c) 1997-2006 University of Cambridge
-# Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
-#
-# -----------------------------------------------------------------------------
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# * Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-#
-# * Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution.
-#
-# * Neither the name of the University of Cambridge nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-# -----------------------------------------------------------------------------
-
-# This is a freestanding support program to generate a file containing
-# character tables. The tables are built according to the default C
-# locale.
-
-use strict;
-
-use File::Basename;
-use File::Spec;
-use File::Temp qw(tempfile);
-use Getopt::Long;
-
-sub readHeaderValues();
-
-my %pcre_internal;
-
-if (scalar(@ARGV) < 1) {
- print STDERR "Usage: ", basename($0), " [--preprocessor=program] output-file\n";
- exit 1;
-}
-
-my $outputFile;
-my $preprocessor;
-GetOptions('preprocessor=s' => \$preprocessor);
-if (not $preprocessor) {
- $preprocessor = "cpp";
-}
-
-$outputFile = $ARGV[0];
-die('Must specify output file.') unless defined($outputFile);
-
-readHeaderValues();
-
-open(OUT, ">", $outputFile) or die "$!";
-binmode(OUT);
-
-printf(OUT
- "/*************************************************\n" .
- "* Perl-Compatible Regular Expressions *\n" .
- "*************************************************/\n\n" .
- "/* This file is automatically written by the dftables auxiliary \n" .
- "program. If you edit it by hand, you might like to edit the Makefile to \n" .
- "prevent its ever being regenerated.\n\n");
-printf(OUT
- "This file contains the default tables for characters with codes less than\n" .
- "128 (ASCII characters). These tables are used when no external tables are\n" .
- "passed to PCRE. */\n\n" .
- "const unsigned char jsc_pcre_default_tables[%d] = {\n\n" .
- "/* This table is a lower casing table. */\n\n", $pcre_internal{tables_length});
-
-if ($pcre_internal{lcc_offset} != 0) {
- die "lcc_offset != 0";
-}
-
-printf(OUT " ");
-for (my $i = 0; $i < 128; $i++) {
- if (($i & 7) == 0 && $i != 0) {
- printf(OUT "\n ");
- }
- printf(OUT "0x%02X", ord(lc(chr($i))));
- if ($i != 127) {
- printf(OUT ", ");
- }
-}
-printf(OUT ",\n\n");
-
-printf(OUT "/* This table is a case flipping table. */\n\n");
-
-if ($pcre_internal{fcc_offset} != 128) {
- die "fcc_offset != 128";
-}
-
-printf(OUT " ");
-for (my $i = 0; $i < 128; $i++) {
- if (($i & 7) == 0 && $i != 0) {
- printf(OUT "\n ");
- }
- my $c = chr($i);
- printf(OUT "0x%02X", $c =~ /[[:lower:]]/ ? ord(uc($c)) : ord(lc($c)));
- if ($i != 127) {
- printf(OUT ", ");
- }
-}
-printf(OUT ",\n\n");
-
-printf(OUT
- "/* This table contains bit maps for various character classes.\n" .
- "Each map is 32 bytes long and the bits run from the least\n" .
- "significant end of each byte. The classes are: space, digit, word. */\n\n");
-
-if ($pcre_internal{cbits_offset} != $pcre_internal{fcc_offset} + 128) {
- die "cbits_offset != fcc_offset + 128";
-}
-
-my @cbit_table = (0) x $pcre_internal{cbit_length};
-for (my $i = ord('0'); $i <= ord('9'); $i++) {
- $cbit_table[$pcre_internal{cbit_digit} + $i / 8] |= 1 << ($i & 7);
-}
-$cbit_table[$pcre_internal{cbit_word} + ord('_') / 8] |= 1 << (ord('_') & 7);
-for (my $i = 0; $i < 128; $i++) {
- my $c = chr($i);
- if ($c =~ /[[:alnum:]]/) {
- $cbit_table[$pcre_internal{cbit_word} + $i / 8] |= 1 << ($i & 7);
- }
- if ($c =~ /[[:space:]]/) {
- $cbit_table[$pcre_internal{cbit_space} + $i / 8] |= 1 << ($i & 7);
- }
-}
-
-printf(OUT " ");
-for (my $i = 0; $i < $pcre_internal{cbit_length}; $i++) {
- if (($i & 7) == 0 && $i != 0) {
- if (($i & 31) == 0) {
- printf(OUT "\n");
- }
- printf(OUT "\n ");
- }
- printf(OUT "0x%02X", $cbit_table[$i]);
- if ($i != $pcre_internal{cbit_length} - 1) {
- printf(OUT ", ");
- }
-}
-printf(OUT ",\n\n");
-
-printf(OUT
- "/* This table identifies various classes of character by individual bits:\n" .
- " 0x%02x white space character\n" .
- " 0x%02x hexadecimal digit\n" .
- " 0x%02x alphanumeric or '_'\n*/\n\n",
- $pcre_internal{ctype_space}, $pcre_internal{ctype_xdigit}, $pcre_internal{ctype_word});
-
-if ($pcre_internal{ctypes_offset} != $pcre_internal{cbits_offset} + $pcre_internal{cbit_length}) {
- die "ctypes_offset != cbits_offset + cbit_length";
-}
-
-printf(OUT " ");
-for (my $i = 0; $i < 128; $i++) {
- my $x = 0;
- my $c = chr($i);
- if ($c =~ /[[:space:]]/) {
- $x += $pcre_internal{ctype_space};
- }
- if ($c =~ /[[:xdigit:]]/) {
- $x += $pcre_internal{ctype_xdigit};
- }
- if ($c =~ /[[:alnum:]_]/) {
- $x += $pcre_internal{ctype_word};
- }
- printf(OUT "0x%02X", $x);
- if ($i != 127) {
- printf(OUT ", ");
- } else {
- printf(OUT "};");
- }
- if (($i & 7) == 7) {
- printf(OUT " /* ");
- my $d = chr($i - 7);
- if ($d =~ /[[:print:]]/) {
- printf(OUT " %c -", $i - 7);
- } else {
- printf(OUT "%3d-", $i - 7);
- }
- if ($c =~ m/[[:print:]]/) {
- printf(OUT " %c ", $i);
- } else {
- printf(OUT "%3d", $i);
- }
- printf(OUT " */\n");
- if ($i != 127) {
- printf(OUT " ");
- }
- }
-}
-
-if ($pcre_internal{tables_length} != $pcre_internal{ctypes_offset} + 128) {
- die "tables_length != ctypes_offset + 128";
-}
-
-printf(OUT "\n\n/* End of chartables.c */\n");
-
-close(OUT);
-
-exit 0;
-
-sub readHeaderValues()
-{
- my @variables = qw(
- cbit_digit
- cbit_length
- cbit_space
- cbit_word
- cbits_offset
- ctype_space
- ctype_word
- ctype_xdigit
- ctypes_offset
- fcc_offset
- lcc_offset
- tables_length
- );
-
- local $/ = undef;
-
- my $headerPath = File::Spec->catfile(dirname($0), "pcre_internal.h");
-
- my ($fh, $tempFile) = tempfile(
- basename($0) . "-XXXXXXXX",
- DIR => File::Spec->tmpdir(),
- SUFFIX => ".in",
- UNLINK => 0,
- );
-
- print $fh "#define DFTABLES\n\n";
-
- open(HEADER, "<", $headerPath) or die "$!";
- print $fh <HEADER>;
- close(HEADER);
-
- print $fh "\n\n";
-
- for my $v (@variables) {
- print $fh "\$pcre_internal{\"$v\"} = $v;\n";
- }
-
- close($fh);
-
- open(CPP, "$preprocessor \"$tempFile\" |") or die "$!";
- my $content = <CPP>;
- close(CPP);
-
- eval $content;
- die "$@" if $@;
- unlink $tempFile;
-}
+++ /dev/null
-/* This is the public header file for JavaScriptCore's variant of the PCRE
-library. While this library started out as a copy of PCRE, many of the
-features of PCRE have been removed. This library now supports only the
-regular expression features required by the JavaScript language
-specification, and has only the functions needed by JavaScriptCore and the
-rest of WebKit.
-
- Copyright (c) 1997-2005 University of Cambridge
- Copyright (C) 2002, 2004, 2006, 2007 Apple Inc. All rights reserved.
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-// FIXME: This file needs to be renamed to JSRegExp.h; it's no longer PCRE.
-
-#ifndef JSRegExp_h
-#define JSRegExp_h
-
-#include <wtf/unicode/Unicode.h>
-
-struct JSRegExp;
-
-enum JSRegExpIgnoreCaseOption { JSRegExpDoNotIgnoreCase, JSRegExpIgnoreCase };
-enum JSRegExpMultilineOption { JSRegExpSingleLine, JSRegExpMultiline };
-
-/* jsRegExpExecute error codes */
-const int JSRegExpErrorNoMatch = -1;
-const int JSRegExpErrorHitLimit = -2;
-const int JSRegExpErrorNoMemory = -3;
-const int JSRegExpErrorInternal = -4;
-
-JSRegExp* jsRegExpCompile(const UChar* pattern, int patternLength,
- JSRegExpIgnoreCaseOption, JSRegExpMultilineOption,
- unsigned* numSubpatterns, const char** errorMessage);
-
-int jsRegExpExecute(const JSRegExp*,
- const UChar* subject, int subjectLength, int startOffset,
- int* offsetsVector, int offsetsVectorLength);
-
-void jsRegExpFree(JSRegExp*);
-
-#endif
+++ /dev/null
-# Perl Compatible Regular Expressions - Qt4 build info
-VPATH += $$PWD
-INCLUDEPATH += $$PWD $$OUTPUT_DIR/JavaScriptCore/tmp
-DEPENDPATH += $$PWD
-
-SOURCES += \
- pcre_compile.cpp \
- pcre_exec.cpp \
- pcre_tables.cpp \
- pcre_ucp_searchfuncs.cpp \
- pcre_xclass.cpp
-
+++ /dev/null
-/* This is JavaScriptCore's variant of the PCRE library. While this library
-started out as a copy of PCRE, many of the features of PCRE have been
-removed. This library now supports only the regular expression features
-required by the JavaScript language specification, and has only the functions
-needed by JavaScriptCore and the rest of WebKit.
-
- Originally written by Philip Hazel
- Copyright (c) 1997-2006 University of Cambridge
- Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
- Copyright (C) 2007 Eric Seidel <eric@webkit.org>
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-/* This module contains the external function jsRegExpExecute(), along with
-supporting internal functions that are not used by other modules. */
-
-#include "config.h"
-
-#include "pcre_internal.h"
-
-#include <string.h>
-#include <wtf/ASCIICType.h>
-#include <wtf/FastMalloc.h>
-
-using namespace WTF;
-
-/* Negative values for the firstchar and reqchar variables */
-
-#define REQ_UNSET (-2)
-#define REQ_NONE (-1)
-
-/*************************************************
-* Code parameters and static tables *
-*************************************************/
-
-/* Maximum number of items on the nested bracket stacks at compile time. This
-applies to the nesting of all kinds of parentheses. It does not limit
-un-nested, non-capturing parentheses. This number can be made bigger if
-necessary - it is used to dimension one int and one unsigned char vector at
-compile time. */
-
-#define BRASTACK_SIZE 200
-
-/* Table for handling escaped characters in the range '0'-'z'. Positive returns
-are simple data values; negative values are for special things like \d and so
-on. Zero means further processing is needed (for things like \x), or the escape
-is invalid. */
-
-static const short escapes[] = {
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0 - 7 */
- 0, 0, ':', ';', '<', '=', '>', '?', /* 8 - ? */
- '@', 0, -ESC_B, 0, -ESC_D, 0, 0, 0, /* @ - G */
- 0, 0, 0, 0, 0, 0, 0, 0, /* H - O */
- 0, 0, 0, -ESC_S, 0, 0, 0, -ESC_W, /* P - W */
- 0, 0, 0, '[', '\\', ']', '^', '_', /* X - _ */
- '`', 7, -ESC_b, 0, -ESC_d, 0, '\f', 0, /* ` - g */
- 0, 0, 0, 0, 0, 0, '\n', 0, /* h - o */
- 0, 0, '\r', -ESC_s, '\t', 0, '\v', -ESC_w, /* p - w */
- 0, 0, 0 /* x - z */
-};
-
-/* Error code numbers. They are given names so that they can more easily be
-tracked. */
-
-enum ErrorCode {
- ERR0, ERR1, ERR2, ERR3, ERR4, ERR5, ERR6, ERR7, ERR8, ERR9,
- ERR10, ERR11, ERR12, ERR13, ERR14, ERR15, ERR16, ERR17
-};
-
-/* The texts of compile-time error messages. These are "char *" because they
-are passed to the outside world. */
-
-static const char* errorText(ErrorCode code)
-{
- static const char errorTexts[] =
- /* 1 */
- "\\ at end of pattern\0"
- "\\c at end of pattern\0"
- "character value in \\x{...} sequence is too large\0"
- "numbers out of order in {} quantifier\0"
- /* 5 */
- "number too big in {} quantifier\0"
- "missing terminating ] for character class\0"
- "internal error: code overflow\0"
- "range out of order in character class\0"
- "nothing to repeat\0"
- /* 10 */
- "unmatched parentheses\0"
- "internal error: unexpected repeat\0"
- "unrecognized character after (?\0"
- "failed to get memory\0"
- "missing )\0"
- /* 15 */
- "reference to non-existent subpattern\0"
- "regular expression too large\0"
- "parentheses nested too deeply"
- ;
-
- int i = code;
- const char* text = errorTexts;
- while (i > 1)
- i -= !*text++;
- return text;
-}
-
-/* Structure for passing "static" information around between the functions
-doing the compiling. */
-
-struct CompileData {
- CompileData() {
- topBackref = 0;
- backrefMap = 0;
- reqVaryOpt = 0;
- needOuterBracket = false;
- numCapturingBrackets = 0;
- }
- int topBackref; /* Maximum back reference */
- unsigned backrefMap; /* Bitmap of low back refs */
- int reqVaryOpt; /* "After variable item" flag for reqByte */
- bool needOuterBracket;
- int numCapturingBrackets;
-};
-
-/* Definitions to allow mutual recursion */
-
-static bool compileBracket(int, int*, unsigned char**, const UChar**, const UChar*, ErrorCode*, int, int*, int*, CompileData&);
-static bool bracketIsAnchored(const unsigned char* code);
-static bool bracketNeedsLineStart(const unsigned char* code, unsigned captureMap, unsigned backrefMap);
-static int bracketFindFirstAssertedCharacter(const unsigned char* code, bool inassert);
-
-/*************************************************
-* Handle escapes *
-*************************************************/
-
-/* This function is called when a \ has been encountered. It either returns a
-positive value for a simple escape such as \n, or a negative value which
-encodes one of the more complicated things such as \d. When UTF-8 is enabled,
-a positive value greater than 255 may be returned. On entry, ptr is pointing at
-the \. On exit, it is on the final character of the escape sequence.
-
-Arguments:
- ptrPtr points to the pattern position pointer
- errorCodePtr points to the errorcode variable
- bracount number of previous extracting brackets
- options the options bits
- isClass true if inside a character class
-
-Returns: zero or positive => a data character
- negative => a special escape sequence
- on error, errorPtr is set
-*/
-
-static int checkEscape(const UChar** ptrPtr, const UChar* patternEnd, ErrorCode* errorCodePtr, int bracount, bool isClass)
-{
- const UChar* ptr = *ptrPtr + 1;
-
- /* If backslash is at the end of the pattern, it's an error. */
- if (ptr == patternEnd) {
- *errorCodePtr = ERR1;
- *ptrPtr = ptr;
- return 0;
- }
-
- int c = *ptr;
-
- /* Non-alphamerics are literals. For digits or letters, do an initial lookup in
- a table. A non-zero result is something that can be returned immediately.
- Otherwise further processing may be required. */
-
- if (c < '0' || c > 'z') { /* Not alphameric */
- } else if (int escapeValue = escapes[c - '0']) {
- c = escapeValue;
- if (isClass) {
- if (-c == ESC_b)
- c = '\b'; /* \b is backslash in a class */
- else if (-c == ESC_B)
- c = 'B'; /* and \B is a capital B in a class (in browsers event though ECMAScript 15.10.2.19 says it raises an error) */
- }
- /* Escapes that need further processing, or are illegal. */
-
- } else {
- switch (c) {
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- /* Escape sequences starting with a non-zero digit are backreferences,
- unless there are insufficient brackets, in which case they are octal
- escape sequences. Those sequences end on the first non-octal character
- or when we overflow 0-255, whichever comes first. */
-
- if (!isClass) {
- const UChar* oldptr = ptr;
- c -= '0';
- while ((ptr + 1 < patternEnd) && isASCIIDigit(ptr[1]) && c <= bracount)
- c = c * 10 + *(++ptr) - '0';
- if (c <= bracount) {
- c = -(ESC_REF + c);
- break;
- }
- ptr = oldptr; /* Put the pointer back and fall through */
- }
-
- /* Handle an octal number following \. If the first digit is 8 or 9,
- this is not octal. */
-
- if ((c = *ptr) >= '8') {
- c = '\\';
- ptr -= 1;
- break;
- }
-
- /* \0 always starts an octal number, but we may drop through to here with a
- larger first octal digit. */
-
- case '0': {
- c -= '0';
- int i;
- for (i = 1; i <= 2; ++i) {
- if (ptr + i >= patternEnd || ptr[i] < '0' || ptr[i] > '7')
- break;
- int cc = c * 8 + ptr[i] - '0';
- if (cc > 255)
- break;
- c = cc;
- }
- ptr += i - 1;
- break;
- }
-
- case 'x': {
- c = 0;
- int i;
- for (i = 1; i <= 2; ++i) {
- if (ptr + i >= patternEnd || !isASCIIHexDigit(ptr[i])) {
- c = 'x';
- i = 1;
- break;
- }
- int cc = ptr[i];
- if (cc >= 'a')
- cc -= 32; /* Convert to upper case */
- c = c * 16 + cc - ((cc < 'A') ? '0' : ('A' - 10));
- }
- ptr += i - 1;
- break;
- }
-
- case 'u': {
- c = 0;
- int i;
- for (i = 1; i <= 4; ++i) {
- if (ptr + i >= patternEnd || !isASCIIHexDigit(ptr[i])) {
- c = 'u';
- i = 1;
- break;
- }
- int cc = ptr[i];
- if (cc >= 'a')
- cc -= 32; /* Convert to upper case */
- c = c * 16 + cc - ((cc < 'A') ? '0' : ('A' - 10));
- }
- ptr += i - 1;
- break;
- }
-
- case 'c':
- if (++ptr == patternEnd) {
- *errorCodePtr = ERR2;
- return 0;
- }
-
- c = *ptr;
-
- /* To match Firefox, inside a character class, we also accept
- numbers and '_' as control characters */
- if ((!isClass && !isASCIIAlpha(c)) || (!isASCIIAlphanumeric(c) && c != '_')) {
- c = '\\';
- ptr -= 2;
- break;
- }
-
- /* A letter is upper-cased; then the 0x40 bit is flipped. This coding
- is ASCII-specific, but then the whole concept of \cx is ASCII-specific. */
- c = toASCIIUpper(c) ^ 0x40;
- break;
- }
- }
-
- *ptrPtr = ptr;
- return c;
-}
-
-/*************************************************
-* Check for counted repeat *
-*************************************************/
-
-/* This function is called when a '{' is encountered in a place where it might
-start a quantifier. It looks ahead to see if it really is a quantifier or not.
-It is only a quantifier if it is one of the forms {ddd} {ddd,} or {ddd,ddd}
-where the ddds are digits.
-
-Arguments:
- p pointer to the first char after '{'
-
-Returns: true or false
-*/
-
-static bool isCountedRepeat(const UChar* p, const UChar* patternEnd)
-{
- if (p >= patternEnd || !isASCIIDigit(*p))
- return false;
- p++;
- while (p < patternEnd && isASCIIDigit(*p))
- p++;
- if (p < patternEnd && *p == '}')
- return true;
-
- if (p >= patternEnd || *p++ != ',')
- return false;
- if (p < patternEnd && *p == '}')
- return true;
-
- if (p >= patternEnd || !isASCIIDigit(*p))
- return false;
- p++;
- while (p < patternEnd && isASCIIDigit(*p))
- p++;
-
- return (p < patternEnd && *p == '}');
-}
-
-/*************************************************
-* Read repeat counts *
-*************************************************/
-
-/* Read an item of the form {n,m} and return the values. This is called only
-after isCountedRepeat() has confirmed that a repeat-count quantifier exists,
-so the syntax is guaranteed to be correct, but we need to check the values.
-
-Arguments:
- p pointer to first char after '{'
- minp pointer to int for min
- maxp pointer to int for max
- returned as -1 if no max
- errorCodePtr points to error code variable
-
-Returns: pointer to '}' on success;
- current ptr on error, with errorCodePtr set non-zero
-*/
-
-static const UChar* readRepeatCounts(const UChar* p, int* minp, int* maxp, ErrorCode* errorCodePtr)
-{
- int min = 0;
- int max = -1;
-
- /* Read the minimum value and do a paranoid check: a negative value indicates
- an integer overflow. */
-
- while (isASCIIDigit(*p))
- min = min * 10 + *p++ - '0';
- if (min < 0 || min > 65535) {
- *errorCodePtr = ERR5;
- return p;
- }
-
- /* Read the maximum value if there is one, and again do a paranoid on its size.
- Also, max must not be less than min. */
-
- if (*p == '}')
- max = min;
- else {
- if (*(++p) != '}') {
- max = 0;
- while (isASCIIDigit(*p))
- max = max * 10 + *p++ - '0';
- if (max < 0 || max > 65535) {
- *errorCodePtr = ERR5;
- return p;
- }
- if (max < min) {
- *errorCodePtr = ERR4;
- return p;
- }
- }
- }
-
- /* Fill in the required variables, and pass back the pointer to the terminating
- '}'. */
-
- *minp = min;
- *maxp = max;
- return p;
-}
-
-/*************************************************
-* Find first significant op code *
-*************************************************/
-
-/* This is called by several functions that scan a compiled expression looking
-for a fixed first character, or an anchoring op code etc. It skips over things
-that do not influence this.
-
-Arguments:
- code pointer to the start of the group
-Returns: pointer to the first significant opcode
-*/
-
-static const unsigned char* firstSignificantOpcode(const unsigned char* code)
-{
- while (*code == OP_BRANUMBER)
- code += 3;
- return code;
-}
-
-static const unsigned char* firstSignificantOpcodeSkippingAssertions(const unsigned char* code)
-{
- while (true) {
- switch (*code) {
- case OP_ASSERT_NOT:
- advanceToEndOfBracket(code);
- code += 1 + LINK_SIZE;
- break;
- case OP_WORD_BOUNDARY:
- case OP_NOT_WORD_BOUNDARY:
- ++code;
- break;
- case OP_BRANUMBER:
- code += 3;
- break;
- default:
- return code;
- }
- }
-}
-
-/*************************************************
-* Get othercase range *
-*************************************************/
-
-/* This function is passed the start and end of a class range, in UTF-8 mode
-with UCP support. It searches up the characters, looking for internal ranges of
-characters in the "other" case. Each call returns the next one, updating the
-start address.
-
-Arguments:
- cptr points to starting character value; updated
- d end value
- ocptr where to put start of othercase range
- odptr where to put end of othercase range
-
-Yield: true when range returned; false when no more
-*/
-
-static bool getOthercaseRange(int* cptr, int d, int* ocptr, int* odptr)
-{
- int c, othercase = 0;
-
- for (c = *cptr; c <= d; c++) {
- if ((othercase = jsc_pcre_ucp_othercase(c)) >= 0)
- break;
- }
-
- if (c > d)
- return false;
-
- *ocptr = othercase;
- int next = othercase + 1;
-
- for (++c; c <= d; c++) {
- if (jsc_pcre_ucp_othercase(c) != next)
- break;
- next++;
- }
-
- *odptr = next - 1;
- *cptr = c;
-
- return true;
-}
-
-/*************************************************
- * Convert character value to UTF-8 *
- *************************************************/
-
-/* This function takes an integer value in the range 0 - 0x7fffffff
- and encodes it as a UTF-8 character in 0 to 6 bytes.
-
- Arguments:
- cvalue the character value
- buffer pointer to buffer for result - at least 6 bytes long
-
- Returns: number of characters placed in the buffer
- */
-
-static int encodeUTF8(int cvalue, unsigned char *buffer)
-{
- int i;
- for (i = 0; i < jsc_pcre_utf8_table1_size; i++)
- if (cvalue <= jsc_pcre_utf8_table1[i])
- break;
- buffer += i;
- for (int j = i; j > 0; j--) {
- *buffer-- = 0x80 | (cvalue & 0x3f);
- cvalue >>= 6;
- }
- *buffer = jsc_pcre_utf8_table2[i] | cvalue;
- return i + 1;
-}
-
-/*************************************************
-* Compile one branch *
-*************************************************/
-
-/* Scan the pattern, compiling it into the code vector.
-
-Arguments:
- options the option bits
- brackets points to number of extracting brackets used
- codePtr points to the pointer to the current code point
- ptrPtr points to the current pattern pointer
- errorCodePtr points to error code variable
- firstbyteptr set to initial literal character, or < 0 (REQ_UNSET, REQ_NONE)
- reqbyteptr set to the last literal character required, else < 0
- cd contains pointers to tables etc.
-
-Returns: true on success
- false, with *errorCodePtr set non-zero on error
-*/
-
-static inline bool safelyCheckNextChar(const UChar* ptr, const UChar* patternEnd, UChar expected)
-{
- return ((ptr + 1 < patternEnd) && ptr[1] == expected);
-}
-
-static bool
-compileBranch(int options, int* brackets, unsigned char** codePtr,
- const UChar** ptrPtr, const UChar* patternEnd, ErrorCode* errorCodePtr, int *firstbyteptr,
- int* reqbyteptr, CompileData& cd)
-{
- int repeatType, opType;
- int repeatMin = 0, repeat_max = 0; /* To please picky compilers */
- int bravalue = 0;
- int reqvary, tempreqvary;
- int c;
- unsigned char* code = *codePtr;
- unsigned char* tempcode;
- bool didGroupSetFirstByte = false;
- const UChar* ptr = *ptrPtr;
- const UChar* tempptr;
- unsigned char* previous = NULL;
- unsigned char classbits[32];
-
- bool class_utf8;
- unsigned char* class_utf8data;
- unsigned char utf8_char[6];
-
- /* Initialize no first byte, no required byte. REQ_UNSET means "no char
- matching encountered yet". It gets changed to REQ_NONE if we hit something that
- matches a non-fixed char first char; reqByte just remains unset if we never
- find one.
-
- When we hit a repeat whose minimum is zero, we may have to adjust these values
- to take the zero repeat into account. This is implemented by setting them to
- zeroFirstByte and zeroReqByte when such a repeat is encountered. The individual
- item types that can be repeated set these backoff variables appropriately. */
-
- int firstByte = REQ_UNSET;
- int reqByte = REQ_UNSET;
- int zeroReqByte = REQ_UNSET;
- int zeroFirstByte = REQ_UNSET;
-
- /* The variable reqCaseOpt contains either the REQ_IGNORE_CASE value or zero,
- according to the current setting of the ignores-case flag. REQ_IGNORE_CASE is a bit
- value > 255. It is added into the firstByte or reqByte variables to record the
- case status of the value. This is used only for ASCII characters. */
-
- int reqCaseOpt = (options & IgnoreCaseOption) ? REQ_IGNORE_CASE : 0;
-
- /* Switch on next character until the end of the branch */
-
- for (;; ptr++) {
- bool negateClass;
- bool shouldFlipNegation; /* If a negative special such as \S is used, we should negate the whole class to properly support Unicode. */
- int classCharCount;
- int classLastChar;
- int skipBytes;
- int subReqByte;
- int subFirstByte;
- int mcLength;
- unsigned char mcbuffer[8];
-
- /* Next byte in the pattern */
-
- c = ptr < patternEnd ? *ptr : 0;
-
- /* Fill in length of a previous callout, except when the next thing is
- a quantifier. */
-
- bool isQuantifier = c == '*' || c == '+' || c == '?' || (c == '{' && isCountedRepeat(ptr + 1, patternEnd));
-
- switch (c) {
- /* The branch terminates at end of string, |, or ). */
-
- case 0:
- if (ptr < patternEnd)
- goto NORMAL_CHAR;
- // End of string; fall through
- case '|':
- case ')':
- *firstbyteptr = firstByte;
- *reqbyteptr = reqByte;
- *codePtr = code;
- *ptrPtr = ptr;
- return true;
-
- /* Handle single-character metacharacters. In multiline mode, ^ disables
- the setting of any following char as a first character. */
-
- case '^':
- if (options & MatchAcrossMultipleLinesOption) {
- if (firstByte == REQ_UNSET)
- firstByte = REQ_NONE;
- *code++ = OP_BOL;
- } else
- *code++ = OP_CIRC;
- previous = NULL;
- break;
-
- case '$':
- previous = NULL;
- if (options & MatchAcrossMultipleLinesOption)
- *code++ = OP_EOL;
- else
- *code++ = OP_DOLL;
- break;
-
- /* There can never be a first char if '.' is first, whatever happens about
- repeats. The value of reqByte doesn't change either. */
-
- case '.':
- if (firstByte == REQ_UNSET)
- firstByte = REQ_NONE;
- zeroFirstByte = firstByte;
- zeroReqByte = reqByte;
- previous = code;
- *code++ = OP_NOT_NEWLINE;
- break;
-
- /* Character classes. If the included characters are all < 256, we build a
- 32-byte bitmap of the permitted characters, except in the special case
- where there is only one such character. For negated classes, we build the
- map as usual, then invert it at the end. However, we use a different opcode
- so that data characters > 255 can be handled correctly.
-
- If the class contains characters outside the 0-255 range, a different
- opcode is compiled. It may optionally have a bit map for characters < 256,
- but those above are are explicitly listed afterwards. A flag byte tells
- whether the bitmap is present, and whether this is a negated class or not.
- */
-
- case '[': {
- previous = code;
- shouldFlipNegation = false;
-
- /* PCRE supports POSIX class stuff inside a class. Perl gives an error if
- they are encountered at the top level, so we'll do that too. */
-
- /* If the first character is '^', set the negation flag and skip it. */
-
- if (ptr + 1 >= patternEnd) {
- *errorCodePtr = ERR6;
- return false;
- }
-
- if (ptr[1] == '^') {
- negateClass = true;
- ++ptr;
- } else
- negateClass = false;
-
- /* Keep a count of chars with values < 256 so that we can optimize the case
- of just a single character (as long as it's < 256). For higher valued UTF-8
- characters, we don't yet do any optimization. */
-
- classCharCount = 0;
- classLastChar = -1;
-
- class_utf8 = false; /* No chars >= 256 */
- class_utf8data = code + LINK_SIZE + 34; /* For UTF-8 items */
-
- /* Initialize the 32-char bit map to all zeros. We have to build the
- map in a temporary bit of store, in case the class contains only 1
- character (< 256), because in that case the compiled code doesn't use the
- bit map. */
-
- memset(classbits, 0, 32 * sizeof(unsigned char));
-
- /* Process characters until ] is reached. The first pass
- through the regex checked the overall syntax, so we don't need to be very
- strict here. At the start of the loop, c contains the first byte of the
- character. */
-
- while ((++ptr < patternEnd) && (c = *ptr) != ']') {
- /* Backslash may introduce a single character, or it may introduce one
- of the specials, which just set a flag. Escaped items are checked for
- validity in the pre-compiling pass. The sequence \b is a special case.
- Inside a class (and only there) it is treated as backspace. Elsewhere
- it marks a word boundary. Other escapes have preset maps ready to
- or into the one we are building. We assume they have more than one
- character in them, so set classCharCount bigger than one. */
-
- if (c == '\\') {
- c = checkEscape(&ptr, patternEnd, errorCodePtr, cd.numCapturingBrackets, true);
- if (c < 0) {
- classCharCount += 2; /* Greater than 1 is what matters */
- switch (-c) {
- case ESC_d:
- for (c = 0; c < 32; c++)
- classbits[c] |= classBitmapForChar(c + cbit_digit);
- continue;
-
- case ESC_D:
- shouldFlipNegation = true;
- for (c = 0; c < 32; c++)
- classbits[c] |= ~classBitmapForChar(c + cbit_digit);
- continue;
-
- case ESC_w:
- for (c = 0; c < 32; c++)
- classbits[c] |= classBitmapForChar(c + cbit_word);
- continue;
-
- case ESC_W:
- shouldFlipNegation = true;
- for (c = 0; c < 32; c++)
- classbits[c] |= ~classBitmapForChar(c + cbit_word);
- continue;
-
- case ESC_s:
- for (c = 0; c < 32; c++)
- classbits[c] |= classBitmapForChar(c + cbit_space);
- continue;
-
- case ESC_S:
- shouldFlipNegation = true;
- for (c = 0; c < 32; c++)
- classbits[c] |= ~classBitmapForChar(c + cbit_space);
- continue;
-
- /* Unrecognized escapes are faulted if PCRE is running in its
- strict mode. By default, for compatibility with Perl, they are
- treated as literals. */
-
- default:
- c = *ptr; /* The final character */
- classCharCount -= 2; /* Undo the default count from above */
- }
- }
-
- /* Fall through if we have a single character (c >= 0). This may be
- > 256 in UTF-8 mode. */
-
- } /* End of backslash handling */
-
- /* A single character may be followed by '-' to form a range. However,
- Perl does not permit ']' to be the end of the range. A '-' character
- here is treated as a literal. */
-
- if ((ptr + 2 < patternEnd) && ptr[1] == '-' && ptr[2] != ']') {
- ptr += 2;
-
- int d = *ptr;
-
- /* The second part of a range can be a single-character escape, but
- not any of the other escapes. Perl 5.6 treats a hyphen as a literal
- in such circumstances. */
-
- if (d == '\\') {
- const UChar* oldptr = ptr;
- d = checkEscape(&ptr, patternEnd, errorCodePtr, cd.numCapturingBrackets, true);
-
- /* \X is literal X; any other special means the '-' was literal */
- if (d < 0) {
- ptr = oldptr - 2;
- goto LONE_SINGLE_CHARACTER; /* A few lines below */
- }
- }
-
- /* The check that the two values are in the correct order happens in
- the pre-pass. Optimize one-character ranges */
-
- if (d == c)
- goto LONE_SINGLE_CHARACTER; /* A few lines below */
-
- /* In UTF-8 mode, if the upper limit is > 255, or > 127 for caseless
- matching, we have to use an XCLASS with extra data items. Caseless
- matching for characters > 127 is available only if UCP support is
- available. */
-
- if ((d > 255 || ((options & IgnoreCaseOption) && d > 127))) {
- class_utf8 = true;
-
- /* With UCP support, we can find the other case equivalents of
- the relevant characters. There may be several ranges. Optimize how
- they fit with the basic range. */
-
- if (options & IgnoreCaseOption) {
- int occ, ocd;
- int cc = c;
- int origd = d;
- while (getOthercaseRange(&cc, origd, &occ, &ocd)) {
- if (occ >= c && ocd <= d)
- continue; /* Skip embedded ranges */
-
- if (occ < c && ocd >= c - 1) /* Extend the basic range */
- { /* if there is overlap, */
- c = occ; /* noting that if occ < c */
- continue; /* we can't have ocd > d */
- } /* because a subrange is */
- if (ocd > d && occ <= d + 1) /* always shorter than */
- { /* the basic range. */
- d = ocd;
- continue;
- }
-
- if (occ == ocd)
- *class_utf8data++ = XCL_SINGLE;
- else {
- *class_utf8data++ = XCL_RANGE;
- class_utf8data += encodeUTF8(occ, class_utf8data);
- }
- class_utf8data += encodeUTF8(ocd, class_utf8data);
- }
- }
-
- /* Now record the original range, possibly modified for UCP caseless
- overlapping ranges. */
-
- *class_utf8data++ = XCL_RANGE;
- class_utf8data += encodeUTF8(c, class_utf8data);
- class_utf8data += encodeUTF8(d, class_utf8data);
-
- /* With UCP support, we are done. Without UCP support, there is no
- caseless matching for UTF-8 characters > 127; we can use the bit map
- for the smaller ones. */
-
- continue; /* With next character in the class */
- }
-
- /* We use the bit map for all cases when not in UTF-8 mode; else
- ranges that lie entirely within 0-127 when there is UCP support; else
- for partial ranges without UCP support. */
-
- for (; c <= d; c++) {
- classbits[c/8] |= (1 << (c&7));
- if (options & IgnoreCaseOption) {
- int uc = flipCase(c);
- classbits[uc/8] |= (1 << (uc&7));
- }
- classCharCount++; /* in case a one-char range */
- classLastChar = c;
- }
-
- continue; /* Go get the next char in the class */
- }
-
- /* Handle a lone single character - we can get here for a normal
- non-escape char, or after \ that introduces a single character or for an
- apparent range that isn't. */
-
- LONE_SINGLE_CHARACTER:
-
- /* Handle a character that cannot go in the bit map */
-
- if ((c > 255 || ((options & IgnoreCaseOption) && c > 127))) {
- class_utf8 = true;
- *class_utf8data++ = XCL_SINGLE;
- class_utf8data += encodeUTF8(c, class_utf8data);
-
- if (options & IgnoreCaseOption) {
- int othercase;
- if ((othercase = jsc_pcre_ucp_othercase(c)) >= 0) {
- *class_utf8data++ = XCL_SINGLE;
- class_utf8data += encodeUTF8(othercase, class_utf8data);
- }
- }
- } else {
- /* Handle a single-byte character */
- classbits[c/8] |= (1 << (c&7));
- if (options & IgnoreCaseOption) {
- c = flipCase(c);
- classbits[c/8] |= (1 << (c&7));
- }
- classCharCount++;
- classLastChar = c;
- }
- }
-
- /* If classCharCount is 1, we saw precisely one character whose value is
- less than 256. In non-UTF-8 mode we can always optimize. In UTF-8 mode, we
- can optimize the negative case only if there were no characters >= 128
- because OP_NOT and the related opcodes like OP_NOTSTAR operate on
- single-bytes only. This is an historical hangover. Maybe one day we can
- tidy these opcodes to handle multi-byte characters.
-
- The optimization throws away the bit map. We turn the item into a
- 1-character OP_CHAR[NC] if it's positive, or OP_NOT if it's negative. Note
- that OP_NOT does not support multibyte characters. In the positive case, it
- can cause firstByte to be set. Otherwise, there can be no first char if
- this item is first, whatever repeat count may follow. In the case of
- reqByte, save the previous value for reinstating. */
-
- if (classCharCount == 1 && (!class_utf8 && (!negateClass || classLastChar < 128))) {
- zeroReqByte = reqByte;
-
- /* The OP_NOT opcode works on one-byte characters only. */
-
- if (negateClass) {
- if (firstByte == REQ_UNSET)
- firstByte = REQ_NONE;
- zeroFirstByte = firstByte;
- *code++ = OP_NOT;
- *code++ = classLastChar;
- break;
- }
-
- /* For a single, positive character, get the value into c, and
- then we can handle this with the normal one-character code. */
-
- c = classLastChar;
- goto NORMAL_CHAR;
- } /* End of 1-char optimization */
-
- /* The general case - not the one-char optimization. If this is the first
- thing in the branch, there can be no first char setting, whatever the
- repeat count. Any reqByte setting must remain unchanged after any kind of
- repeat. */
-
- if (firstByte == REQ_UNSET) firstByte = REQ_NONE;
- zeroFirstByte = firstByte;
- zeroReqByte = reqByte;
-
- /* If there are characters with values > 255, we have to compile an
- extended class, with its own opcode. If there are no characters < 256,
- we can omit the bitmap. */
-
- if (class_utf8 && !shouldFlipNegation) {
- *class_utf8data++ = XCL_END; /* Marks the end of extra data */
- *code++ = OP_XCLASS;
- code += LINK_SIZE;
- *code = negateClass? XCL_NOT : 0;
-
- /* If the map is required, install it, and move on to the end of
- the extra data */
-
- if (classCharCount > 0) {
- *code++ |= XCL_MAP;
- memcpy(code, classbits, 32);
- code = class_utf8data;
- }
-
- /* If the map is not required, slide down the extra data. */
-
- else {
- int len = class_utf8data - (code + 33);
- memmove(code + 1, code + 33, len);
- code += len + 1;
- }
-
- /* Now fill in the complete length of the item */
-
- putLinkValue(previous + 1, code - previous);
- break; /* End of class handling */
- }
-
- /* If there are no characters > 255, negate the 32-byte map if necessary,
- and copy it into the code vector. If this is the first thing in the branch,
- there can be no first char setting, whatever the repeat count. Any reqByte
- setting must remain unchanged after any kind of repeat. */
-
- *code++ = (negateClass == shouldFlipNegation) ? OP_CLASS : OP_NCLASS;
- if (negateClass)
- for (c = 0; c < 32; c++)
- code[c] = ~classbits[c];
- else
- memcpy(code, classbits, 32);
- code += 32;
- break;
- }
-
- /* Various kinds of repeat; '{' is not necessarily a quantifier, but this
- has been tested above. */
-
- case '{':
- if (!isQuantifier)
- goto NORMAL_CHAR;
- ptr = readRepeatCounts(ptr + 1, &repeatMin, &repeat_max, errorCodePtr);
- if (*errorCodePtr)
- goto FAILED;
- goto REPEAT;
-
- case '*':
- repeatMin = 0;
- repeat_max = -1;
- goto REPEAT;
-
- case '+':
- repeatMin = 1;
- repeat_max = -1;
- goto REPEAT;
-
- case '?':
- repeatMin = 0;
- repeat_max = 1;
-
- REPEAT:
- if (!previous) {
- *errorCodePtr = ERR9;
- goto FAILED;
- }
-
- if (repeatMin == 0) {
- firstByte = zeroFirstByte; /* Adjust for zero repeat */
- reqByte = zeroReqByte; /* Ditto */
- }
-
- /* Remember whether this is a variable length repeat */
-
- reqvary = (repeatMin == repeat_max) ? 0 : REQ_VARY;
-
- opType = 0; /* Default single-char op codes */
-
- /* Save start of previous item, in case we have to move it up to make space
- for an inserted OP_ONCE for the additional '+' extension. */
- /* FIXME: Probably don't need this because we don't use OP_ONCE. */
-
- tempcode = previous;
-
- /* If the next character is '+', we have a possessive quantifier. This
- implies greediness, whatever the setting of the PCRE_UNGREEDY option.
- If the next character is '?' this is a minimizing repeat, by default,
- but if PCRE_UNGREEDY is set, it works the other way round. We change the
- repeat type to the non-default. */
-
- if (safelyCheckNextChar(ptr, patternEnd, '?')) {
- repeatType = 1;
- ptr++;
- } else
- repeatType = 0;
-
- /* If previous was a character match, abolish the item and generate a
- repeat item instead. If a char item has a minumum of more than one, ensure
- that it is set in reqByte - it might not be if a sequence such as x{3} is
- the first thing in a branch because the x will have gone into firstByte
- instead. */
-
- if (*previous == OP_CHAR || *previous == OP_CHAR_IGNORING_CASE) {
- /* Deal with UTF-8 characters that take up more than one byte. It's
- easier to write this out separately than try to macrify it. Use c to
- hold the length of the character in bytes, plus 0x80 to flag that it's a
- length rather than a small character. */
-
- if (code[-1] & 0x80) {
- unsigned char *lastchar = code - 1;
- while((*lastchar & 0xc0) == 0x80)
- lastchar--;
- c = code - lastchar; /* Length of UTF-8 character */
- memcpy(utf8_char, lastchar, c); /* Save the char */
- c |= 0x80; /* Flag c as a length */
- }
- else {
- c = code[-1];
- if (repeatMin > 1)
- reqByte = c | reqCaseOpt | cd.reqVaryOpt;
- }
-
- goto OUTPUT_SINGLE_REPEAT; /* Code shared with single character types */
- }
-
- else if (*previous == OP_ASCII_CHAR || *previous == OP_ASCII_LETTER_IGNORING_CASE) {
- c = previous[1];
- if (repeatMin > 1)
- reqByte = c | reqCaseOpt | cd.reqVaryOpt;
- goto OUTPUT_SINGLE_REPEAT;
- }
-
- /* If previous was a single negated character ([^a] or similar), we use
- one of the special opcodes, replacing it. The code is shared with single-
- character repeats by setting opt_type to add a suitable offset into
- repeatType. OP_NOT is currently used only for single-byte chars. */
-
- else if (*previous == OP_NOT) {
- opType = OP_NOTSTAR - OP_STAR; /* Use "not" opcodes */
- c = previous[1];
- goto OUTPUT_SINGLE_REPEAT;
- }
-
- /* If previous was a character type match (\d or similar), abolish it and
- create a suitable repeat item. The code is shared with single-character
- repeats by setting opType to add a suitable offset into repeatType. */
-
- else if (*previous <= OP_NOT_NEWLINE) {
- opType = OP_TYPESTAR - OP_STAR; /* Use type opcodes */
- c = *previous;
-
- OUTPUT_SINGLE_REPEAT:
- int prop_type = -1;
- int prop_value = -1;
-
- unsigned char* oldcode = code;
- code = previous; /* Usually overwrite previous item */
-
- /* If the maximum is zero then the minimum must also be zero; Perl allows
- this case, so we do too - by simply omitting the item altogether. */
-
- if (repeat_max == 0)
- goto END_REPEAT;
-
- /* Combine the opType with the repeatType */
-
- repeatType += opType;
-
- /* A minimum of zero is handled either as the special case * or ?, or as
- an UPTO, with the maximum given. */
-
- if (repeatMin == 0) {
- if (repeat_max == -1)
- *code++ = OP_STAR + repeatType;
- else if (repeat_max == 1)
- *code++ = OP_QUERY + repeatType;
- else {
- *code++ = OP_UPTO + repeatType;
- put2ByteValueAndAdvance(code, repeat_max);
- }
- }
-
- /* A repeat minimum of 1 is optimized into some special cases. If the
- maximum is unlimited, we use OP_PLUS. Otherwise, the original item it
- left in place and, if the maximum is greater than 1, we use OP_UPTO with
- one less than the maximum. */
-
- else if (repeatMin == 1) {
- if (repeat_max == -1)
- *code++ = OP_PLUS + repeatType;
- else {
- code = oldcode; /* leave previous item in place */
- if (repeat_max == 1)
- goto END_REPEAT;
- *code++ = OP_UPTO + repeatType;
- put2ByteValueAndAdvance(code, repeat_max - 1);
- }
- }
-
- /* The case {n,n} is just an EXACT, while the general case {n,m} is
- handled as an EXACT followed by an UPTO. */
-
- else {
- *code++ = OP_EXACT + opType; /* NB EXACT doesn't have repeatType */
- put2ByteValueAndAdvance(code, repeatMin);
-
- /* If the maximum is unlimited, insert an OP_STAR. Before doing so,
- we have to insert the character for the previous code. For a repeated
- Unicode property match, there are two extra bytes that define the
- required property. In UTF-8 mode, long characters have their length in
- c, with the 0x80 bit as a flag. */
-
- if (repeat_max < 0) {
- if (c >= 128) {
- memcpy(code, utf8_char, c & 7);
- code += c & 7;
- } else {
- *code++ = c;
- if (prop_type >= 0) {
- *code++ = prop_type;
- *code++ = prop_value;
- }
- }
- *code++ = OP_STAR + repeatType;
- }
-
- /* Else insert an UPTO if the max is greater than the min, again
- preceded by the character, for the previously inserted code. */
-
- else if (repeat_max != repeatMin) {
- if (c >= 128) {
- memcpy(code, utf8_char, c & 7);
- code += c & 7;
- } else
- *code++ = c;
- if (prop_type >= 0) {
- *code++ = prop_type;
- *code++ = prop_value;
- }
- repeat_max -= repeatMin;
- *code++ = OP_UPTO + repeatType;
- put2ByteValueAndAdvance(code, repeat_max);
- }
- }
-
- /* The character or character type itself comes last in all cases. */
-
- if (c >= 128) {
- memcpy(code, utf8_char, c & 7);
- code += c & 7;
- } else
- *code++ = c;
-
- /* For a repeated Unicode property match, there are two extra bytes that
- define the required property. */
-
- if (prop_type >= 0) {
- *code++ = prop_type;
- *code++ = prop_value;
- }
- }
-
- /* If previous was a character class or a back reference, we put the repeat
- stuff after it, but just skip the item if the repeat was {0,0}. */
-
- else if (*previous == OP_CLASS ||
- *previous == OP_NCLASS ||
- *previous == OP_XCLASS ||
- *previous == OP_REF)
- {
- if (repeat_max == 0) {
- code = previous;
- goto END_REPEAT;
- }
-
- if (repeatMin == 0 && repeat_max == -1)
- *code++ = OP_CRSTAR + repeatType;
- else if (repeatMin == 1 && repeat_max == -1)
- *code++ = OP_CRPLUS + repeatType;
- else if (repeatMin == 0 && repeat_max == 1)
- *code++ = OP_CRQUERY + repeatType;
- else {
- *code++ = OP_CRRANGE + repeatType;
- put2ByteValueAndAdvance(code, repeatMin);
- if (repeat_max == -1)
- repeat_max = 0; /* 2-byte encoding for max */
- put2ByteValueAndAdvance(code, repeat_max);
- }
- }
-
- /* If previous was a bracket group, we may have to replicate it in certain
- cases. */
-
- else if (*previous >= OP_BRA) {
- int ketoffset = 0;
- int len = code - previous;
- unsigned char* bralink = NULL;
-
- /* If the maximum repeat count is unlimited, find the end of the bracket
- by scanning through from the start, and compute the offset back to it
- from the current code pointer. There may be an OP_OPT setting following
- the final KET, so we can't find the end just by going back from the code
- pointer. */
-
- if (repeat_max == -1) {
- const unsigned char* ket = previous;
- advanceToEndOfBracket(ket);
- ketoffset = code - ket;
- }
-
- /* The case of a zero minimum is special because of the need to stick
- OP_BRAZERO in front of it, and because the group appears once in the
- data, whereas in other cases it appears the minimum number of times. For
- this reason, it is simplest to treat this case separately, as otherwise
- the code gets far too messy. There are several special subcases when the
- minimum is zero. */
-
- if (repeatMin == 0) {
- /* If the maximum is also zero, we just omit the group from the output
- altogether. */
-
- if (repeat_max == 0) {
- code = previous;
- goto END_REPEAT;
- }
-
- /* If the maximum is 1 or unlimited, we just have to stick in the
- BRAZERO and do no more at this point. However, we do need to adjust
- any OP_RECURSE calls inside the group that refer to the group itself or
- any internal group, because the offset is from the start of the whole
- regex. Temporarily terminate the pattern while doing this. */
-
- if (repeat_max <= 1) {
- *code = OP_END;
- memmove(previous+1, previous, len);
- code++;
- *previous++ = OP_BRAZERO + repeatType;
- }
-
- /* If the maximum is greater than 1 and limited, we have to replicate
- in a nested fashion, sticking OP_BRAZERO before each set of brackets.
- The first one has to be handled carefully because it's the original
- copy, which has to be moved up. The remainder can be handled by code
- that is common with the non-zero minimum case below. We have to
- adjust the value of repeat_max, since one less copy is required. */
-
- else {
- *code = OP_END;
- memmove(previous + 2 + LINK_SIZE, previous, len);
- code += 2 + LINK_SIZE;
- *previous++ = OP_BRAZERO + repeatType;
- *previous++ = OP_BRA;
-
- /* We chain together the bracket offset fields that have to be
- filled in later when the ends of the brackets are reached. */
-
- int offset = (!bralink) ? 0 : previous - bralink;
- bralink = previous;
- putLinkValueAllowZeroAndAdvance(previous, offset);
- }
-
- repeat_max--;
- }
-
- /* If the minimum is greater than zero, replicate the group as many
- times as necessary, and adjust the maximum to the number of subsequent
- copies that we need. If we set a first char from the group, and didn't
- set a required char, copy the latter from the former. */
-
- else {
- if (repeatMin > 1) {
- if (didGroupSetFirstByte && reqByte < 0)
- reqByte = firstByte;
- for (int i = 1; i < repeatMin; i++) {
- memcpy(code, previous, len);
- code += len;
- }
- }
- if (repeat_max > 0)
- repeat_max -= repeatMin;
- }
-
- /* This code is common to both the zero and non-zero minimum cases. If
- the maximum is limited, it replicates the group in a nested fashion,
- remembering the bracket starts on a stack. In the case of a zero minimum,
- the first one was set up above. In all cases the repeat_max now specifies
- the number of additional copies needed. */
-
- if (repeat_max >= 0) {
- for (int i = repeat_max - 1; i >= 0; i--) {
- *code++ = OP_BRAZERO + repeatType;
-
- /* All but the final copy start a new nesting, maintaining the
- chain of brackets outstanding. */
-
- if (i != 0) {
- *code++ = OP_BRA;
- int offset = (!bralink) ? 0 : code - bralink;
- bralink = code;
- putLinkValueAllowZeroAndAdvance(code, offset);
- }
-
- memcpy(code, previous, len);
- code += len;
- }
-
- /* Now chain through the pending brackets, and fill in their length
- fields (which are holding the chain links pro tem). */
-
- while (bralink) {
- int offset = code - bralink + 1;
- unsigned char* bra = code - offset;
- int oldlinkoffset = getLinkValueAllowZero(bra + 1);
- bralink = (!oldlinkoffset) ? 0 : bralink - oldlinkoffset;
- *code++ = OP_KET;
- putLinkValueAndAdvance(code, offset);
- putLinkValue(bra + 1, offset);
- }
- }
-
- /* If the maximum is unlimited, set a repeater in the final copy. We
- can't just offset backwards from the current code point, because we
- don't know if there's been an options resetting after the ket. The
- correct offset was computed above. */
-
- else
- code[-ketoffset] = OP_KETRMAX + repeatType;
- }
-
- // A quantifier after an assertion is mostly meaningless, but it
- // can nullify the assertion if it has a 0 minimum.
- else if (*previous == OP_ASSERT || *previous == OP_ASSERT_NOT) {
- if (repeatMin == 0) {
- code = previous;
- goto END_REPEAT;
- }
- }
-
- /* Else there's some kind of shambles */
-
- else {
- *errorCodePtr = ERR11;
- goto FAILED;
- }
-
- /* In all case we no longer have a previous item. We also set the
- "follows varying string" flag for subsequently encountered reqbytes if
- it isn't already set and we have just passed a varying length item. */
-
- END_REPEAT:
- previous = NULL;
- cd.reqVaryOpt |= reqvary;
- break;
-
- /* Start of nested bracket sub-expression, or comment or lookahead or
- lookbehind or option setting or condition. First deal with special things
- that can come after a bracket; all are introduced by ?, and the appearance
- of any of them means that this is not a referencing group. They were
- checked for validity in the first pass over the string, so we don't have to
- check for syntax errors here. */
-
- case '(':
- skipBytes = 0;
-
- if (*(++ptr) == '?') {
- switch (*(++ptr)) {
- case ':': /* Non-extracting bracket */
- bravalue = OP_BRA;
- ptr++;
- break;
-
- case '=': /* Positive lookahead */
- bravalue = OP_ASSERT;
- ptr++;
- break;
-
- case '!': /* Negative lookahead */
- bravalue = OP_ASSERT_NOT;
- ptr++;
- break;
-
- /* Character after (? not specially recognized */
-
- default:
- *errorCodePtr = ERR12;
- goto FAILED;
- }
- }
-
- /* Else we have a referencing group; adjust the opcode. If the bracket
- number is greater than EXTRACT_BASIC_MAX, we set the opcode one higher, and
- arrange for the true number to follow later, in an OP_BRANUMBER item. */
-
- else {
- if (++(*brackets) > EXTRACT_BASIC_MAX) {
- bravalue = OP_BRA + EXTRACT_BASIC_MAX + 1;
- code[1 + LINK_SIZE] = OP_BRANUMBER;
- put2ByteValue(code + 2 + LINK_SIZE, *brackets);
- skipBytes = 3;
- }
- else
- bravalue = OP_BRA + *brackets;
- }
-
- /* Process nested bracketed re. We copy code into a non-variable
- in order to be able to pass its address because some compilers
- complain otherwise. Pass in a new setting for the ims options
- if they have changed. */
-
- previous = code;
- *code = bravalue;
- tempcode = code;
- tempreqvary = cd.reqVaryOpt; /* Save value before bracket */
-
- if (!compileBracket(
- options,
- brackets, /* Extracting bracket count */
- &tempcode, /* Where to put code (updated) */
- &ptr, /* Input pointer (updated) */
- patternEnd,
- errorCodePtr, /* Where to put an error message */
- skipBytes, /* Skip over OP_BRANUMBER */
- &subFirstByte, /* For possible first char */
- &subReqByte, /* For possible last char */
- cd)) /* Tables block */
- goto FAILED;
-
- /* At the end of compiling, code is still pointing to the start of the
- group, while tempcode has been updated to point past the end of the group
- and any option resetting that may follow it. The pattern pointer (ptr)
- is on the bracket. */
-
- /* Handle updating of the required and first characters. Update for normal
- brackets of all kinds, and conditions with two branches (see code above).
- If the bracket is followed by a quantifier with zero repeat, we have to
- back off. Hence the definition of zeroReqByte and zeroFirstByte outside the
- main loop so that they can be accessed for the back off. */
-
- zeroReqByte = reqByte;
- zeroFirstByte = firstByte;
- didGroupSetFirstByte = false;
-
- if (bravalue >= OP_BRA) {
- /* If we have not yet set a firstByte in this branch, take it from the
- subpattern, remembering that it was set here so that a repeat of more
- than one can replicate it as reqByte if necessary. If the subpattern has
- no firstByte, set "none" for the whole branch. In both cases, a zero
- repeat forces firstByte to "none". */
-
- if (firstByte == REQ_UNSET) {
- if (subFirstByte >= 0) {
- firstByte = subFirstByte;
- didGroupSetFirstByte = true;
- }
- else
- firstByte = REQ_NONE;
- zeroFirstByte = REQ_NONE;
- }
-
- /* If firstByte was previously set, convert the subpattern's firstByte
- into reqByte if there wasn't one, using the vary flag that was in
- existence beforehand. */
-
- else if (subFirstByte >= 0 && subReqByte < 0)
- subReqByte = subFirstByte | tempreqvary;
-
- /* If the subpattern set a required byte (or set a first byte that isn't
- really the first byte - see above), set it. */
-
- if (subReqByte >= 0)
- reqByte = subReqByte;
- }
-
- /* For a forward assertion, we take the reqByte, if set. This can be
- helpful if the pattern that follows the assertion doesn't set a different
- char. For example, it's useful for /(?=abcde).+/. We can't set firstByte
- for an assertion, however because it leads to incorrect effect for patterns
- such as /(?=a)a.+/ when the "real" "a" would then become a reqByte instead
- of a firstByte. This is overcome by a scan at the end if there's no
- firstByte, looking for an asserted first char. */
-
- else if (bravalue == OP_ASSERT && subReqByte >= 0)
- reqByte = subReqByte;
-
- /* Now update the main code pointer to the end of the group. */
-
- code = tempcode;
-
- /* Error if hit end of pattern */
-
- if (ptr >= patternEnd || *ptr != ')') {
- *errorCodePtr = ERR14;
- goto FAILED;
- }
- break;
-
- /* Check \ for being a real metacharacter; if not, fall through and handle
- it as a data character at the start of a string. Escape items are checked
- for validity in the pre-compiling pass. */
-
- case '\\':
- tempptr = ptr;
- c = checkEscape(&ptr, patternEnd, errorCodePtr, cd.numCapturingBrackets, false);
-
- /* Handle metacharacters introduced by \. For ones like \d, the ESC_ values
- are arranged to be the negation of the corresponding OP_values. For the
- back references, the values are ESC_REF plus the reference number. Only
- back references and those types that consume a character may be repeated.
- We can test for values between ESC_b and ESC_w for the latter; this may
- have to change if any new ones are ever created. */
-
- if (c < 0) {
- /* For metasequences that actually match a character, we disable the
- setting of a first character if it hasn't already been set. */
-
- if (firstByte == REQ_UNSET && -c > ESC_b && -c <= ESC_w)
- firstByte = REQ_NONE;
-
- /* Set values to reset to if this is followed by a zero repeat. */
-
- zeroFirstByte = firstByte;
- zeroReqByte = reqByte;
-
- /* Back references are handled specially */
-
- if (-c >= ESC_REF) {
- int number = -c - ESC_REF;
- previous = code;
- *code++ = OP_REF;
- put2ByteValueAndAdvance(code, number);
- }
-
- /* For the rest, we can obtain the OP value by negating the escape
- value */
-
- else {
- previous = (-c > ESC_b && -c <= ESC_w) ? code : NULL;
- *code++ = -c;
- }
- continue;
- }
-
- /* Fall through. */
-
- /* Handle a literal character. It is guaranteed not to be whitespace or #
- when the extended flag is set. If we are in UTF-8 mode, it may be a
- multi-byte literal character. */
-
- default:
- NORMAL_CHAR:
-
- previous = code;
-
- if (c < 128) {
- mcLength = 1;
- mcbuffer[0] = c;
-
- if ((options & IgnoreCaseOption) && (c | 0x20) >= 'a' && (c | 0x20) <= 'z') {
- *code++ = OP_ASCII_LETTER_IGNORING_CASE;
- *code++ = c | 0x20;
- } else {
- *code++ = OP_ASCII_CHAR;
- *code++ = c;
- }
- } else {
- mcLength = encodeUTF8(c, mcbuffer);
-
- *code++ = (options & IgnoreCaseOption) ? OP_CHAR_IGNORING_CASE : OP_CHAR;
- for (c = 0; c < mcLength; c++)
- *code++ = mcbuffer[c];
- }
-
- /* Set the first and required bytes appropriately. If no previous first
- byte, set it from this character, but revert to none on a zero repeat.
- Otherwise, leave the firstByte value alone, and don't change it on a zero
- repeat. */
-
- if (firstByte == REQ_UNSET) {
- zeroFirstByte = REQ_NONE;
- zeroReqByte = reqByte;
-
- /* If the character is more than one byte long, we can set firstByte
- only if it is not to be matched caselessly. */
-
- if (mcLength == 1 || reqCaseOpt == 0) {
- firstByte = mcbuffer[0] | reqCaseOpt;
- if (mcLength != 1)
- reqByte = code[-1] | cd.reqVaryOpt;
- }
- else
- firstByte = reqByte = REQ_NONE;
- }
-
- /* firstByte was previously set; we can set reqByte only the length is
- 1 or the matching is caseful. */
-
- else {
- zeroFirstByte = firstByte;
- zeroReqByte = reqByte;
- if (mcLength == 1 || reqCaseOpt == 0)
- reqByte = code[-1] | reqCaseOpt | cd.reqVaryOpt;
- }
-
- break; /* End of literal character handling */
- }
- } /* end of big loop */
-
- /* Control never reaches here by falling through, only by a goto for all the
- error states. Pass back the position in the pattern so that it can be displayed
- to the user for diagnosing the error. */
-
-FAILED:
- *ptrPtr = ptr;
- return false;
-}
-
-/*************************************************
-* Compile sequence of alternatives *
-*************************************************/
-
-/* On entry, ptr is pointing past the bracket character, but on return
-it points to the closing bracket, or vertical bar, or end of string.
-The code variable is pointing at the byte into which the BRA operator has been
-stored. If the ims options are changed at the start (for a (?ims: group) or
-during any branch, we need to insert an OP_OPT item at the start of every
-following branch to ensure they get set correctly at run time, and also pass
-the new options into every subsequent branch compile.
-
-Argument:
- options option bits, including any changes for this subpattern
- brackets -> int containing the number of extracting brackets used
- codePtr -> the address of the current code pointer
- ptrPtr -> the address of the current pattern pointer
- errorCodePtr -> pointer to error code variable
- skipBytes skip this many bytes at start (for OP_BRANUMBER)
- firstbyteptr place to put the first required character, or a negative number
- reqbyteptr place to put the last required character, or a negative number
- cd points to the data block with tables pointers etc.
-
-Returns: true on success
-*/
-
-static bool
-compileBracket(int options, int* brackets, unsigned char** codePtr,
- const UChar** ptrPtr, const UChar* patternEnd, ErrorCode* errorCodePtr, int skipBytes,
- int* firstbyteptr, int* reqbyteptr, CompileData& cd)
-{
- const UChar* ptr = *ptrPtr;
- unsigned char* code = *codePtr;
- unsigned char* lastBranch = code;
- unsigned char* start_bracket = code;
- int firstByte = REQ_UNSET;
- int reqByte = REQ_UNSET;
-
- /* Offset is set zero to mark that this bracket is still open */
-
- putLinkValueAllowZero(code + 1, 0);
- code += 1 + LINK_SIZE + skipBytes;
-
- /* Loop for each alternative branch */
-
- while (true) {
- /* Now compile the branch */
-
- int branchFirstByte;
- int branchReqByte;
- if (!compileBranch(options, brackets, &code, &ptr, patternEnd, errorCodePtr,
- &branchFirstByte, &branchReqByte, cd)) {
- *ptrPtr = ptr;
- return false;
- }
-
- /* If this is the first branch, the firstByte and reqByte values for the
- branch become the values for the regex. */
-
- if (*lastBranch != OP_ALT) {
- firstByte = branchFirstByte;
- reqByte = branchReqByte;
- }
-
- /* If this is not the first branch, the first char and reqByte have to
- match the values from all the previous branches, except that if the previous
- value for reqByte didn't have REQ_VARY set, it can still match, and we set
- REQ_VARY for the regex. */
-
- else {
- /* If we previously had a firstByte, but it doesn't match the new branch,
- we have to abandon the firstByte for the regex, but if there was previously
- no reqByte, it takes on the value of the old firstByte. */
-
- if (firstByte >= 0 && firstByte != branchFirstByte) {
- if (reqByte < 0)
- reqByte = firstByte;
- firstByte = REQ_NONE;
- }
-
- /* If we (now or from before) have no firstByte, a firstByte from the
- branch becomes a reqByte if there isn't a branch reqByte. */
-
- if (firstByte < 0 && branchFirstByte >= 0 && branchReqByte < 0)
- branchReqByte = branchFirstByte;
-
- /* Now ensure that the reqbytes match */
-
- if ((reqByte & ~REQ_VARY) != (branchReqByte & ~REQ_VARY))
- reqByte = REQ_NONE;
- else
- reqByte |= branchReqByte; /* To "or" REQ_VARY */
- }
-
- /* Reached end of expression, either ')' or end of pattern. Go back through
- the alternative branches and reverse the chain of offsets, with the field in
- the BRA item now becoming an offset to the first alternative. If there are
- no alternatives, it points to the end of the group. The length in the
- terminating ket is always the length of the whole bracketed item. If any of
- the ims options were changed inside the group, compile a resetting op-code
- following, except at the very end of the pattern. Return leaving the pointer
- at the terminating char. */
-
- if (ptr >= patternEnd || *ptr != '|') {
- int length = code - lastBranch;
- do {
- int prevLength = getLinkValueAllowZero(lastBranch + 1);
- putLinkValue(lastBranch + 1, length);
- length = prevLength;
- lastBranch -= length;
- } while (length > 0);
-
- /* Fill in the ket */
-
- *code = OP_KET;
- putLinkValue(code + 1, code - start_bracket);
- code += 1 + LINK_SIZE;
-
- /* Set values to pass back */
-
- *codePtr = code;
- *ptrPtr = ptr;
- *firstbyteptr = firstByte;
- *reqbyteptr = reqByte;
- return true;
- }
-
- /* Another branch follows; insert an "or" node. Its length field points back
- to the previous branch while the bracket remains open. At the end the chain
- is reversed. It's done like this so that the start of the bracket has a
- zero offset until it is closed, making it possible to detect recursion. */
-
- *code = OP_ALT;
- putLinkValue(code + 1, code - lastBranch);
- lastBranch = code;
- code += 1 + LINK_SIZE;
- ptr++;
- }
- ASSERT_NOT_REACHED();
-}
-
-/*************************************************
-* Check for anchored expression *
-*************************************************/
-
-/* Try to find out if this is an anchored regular expression. Consider each
-alternative branch. If they all start OP_CIRC, or with a bracket
-all of whose alternatives start OP_CIRC (recurse ad lib), then
-it's anchored.
-
-Arguments:
- code points to start of expression (the bracket)
- captureMap a bitmap of which brackets we are inside while testing; this
- handles up to substring 31; all brackets after that share
- the zero bit
- backrefMap the back reference bitmap
-*/
-
-static bool branchIsAnchored(const unsigned char* code)
-{
- const unsigned char* scode = firstSignificantOpcode(code);
- int op = *scode;
-
- /* Brackets */
- if (op >= OP_BRA || op == OP_ASSERT)
- return bracketIsAnchored(scode);
-
- /* Check for explicit anchoring */
- return op == OP_CIRC;
-}
-
-static bool bracketIsAnchored(const unsigned char* code)
-{
- do {
- if (!branchIsAnchored(code + 1 + LINK_SIZE))
- return false;
- code += getLinkValue(code + 1);
- } while (*code == OP_ALT); /* Loop for each alternative */
- return true;
-}
-
-/*************************************************
-* Check for starting with ^ or .* *
-*************************************************/
-
-/* This is called to find out if every branch starts with ^ or .* so that
-"first char" processing can be done to speed things up in multiline
-matching and for non-DOTALL patterns that start with .* (which must start at
-the beginning or after \n)
-
-Except when the .* appears inside capturing parentheses, and there is a
-subsequent back reference to those parentheses. By keeping a bitmap of the
-first 31 back references, we can catch some of the more common cases more
-precisely; all the greater back references share a single bit.
-
-Arguments:
- code points to start of expression (the bracket)
- captureMap a bitmap of which brackets we are inside while testing; this
- handles up to substring 31; all brackets after that share
- the zero bit
- backrefMap the back reference bitmap
-*/
-
-static bool branchNeedsLineStart(const unsigned char* code, unsigned captureMap, unsigned backrefMap)
-{
- const unsigned char* scode = firstSignificantOpcode(code);
- int op = *scode;
-
- /* Capturing brackets */
- if (op > OP_BRA) {
- int captureNum = op - OP_BRA;
- if (captureNum > EXTRACT_BASIC_MAX)
- captureNum = get2ByteValue(scode + 2 + LINK_SIZE);
- int bracketMask = (captureNum < 32) ? (1 << captureNum) : 1;
- return bracketNeedsLineStart(scode, captureMap | bracketMask, backrefMap);
- }
-
- /* Other brackets */
- if (op == OP_BRA || op == OP_ASSERT)
- return bracketNeedsLineStart(scode, captureMap, backrefMap);
-
- /* .* means "start at start or after \n" if it isn't in brackets that
- may be referenced. */
-
- if (op == OP_TYPESTAR || op == OP_TYPEMINSTAR)
- return scode[1] == OP_NOT_NEWLINE && !(captureMap & backrefMap);
-
- /* Explicit ^ */
- return op == OP_CIRC || op == OP_BOL;
-}
-
-static bool bracketNeedsLineStart(const unsigned char* code, unsigned captureMap, unsigned backrefMap)
-{
- do {
- if (!branchNeedsLineStart(code + 1 + LINK_SIZE, captureMap, backrefMap))
- return false;
- code += getLinkValue(code + 1);
- } while (*code == OP_ALT); /* Loop for each alternative */
- return true;
-}
-
-/*************************************************
-* Check for asserted fixed first char *
-*************************************************/
-
-/* During compilation, the "first char" settings from forward assertions are
-discarded, because they can cause conflicts with actual literals that follow.
-However, if we end up without a first char setting for an unanchored pattern,
-it is worth scanning the regex to see if there is an initial asserted first
-char. If all branches start with the same asserted char, or with a bracket all
-of whose alternatives start with the same asserted char (recurse ad lib), then
-we return that char, otherwise -1.
-
-Arguments:
- code points to start of expression (the bracket)
- options pointer to the options (used to check casing changes)
- inassert true if in an assertion
-
-Returns: -1 or the fixed first char
-*/
-
-static int branchFindFirstAssertedCharacter(const unsigned char* code, bool inassert)
-{
- const unsigned char* scode = firstSignificantOpcodeSkippingAssertions(code);
- int op = *scode;
-
- if (op >= OP_BRA)
- op = OP_BRA;
-
- switch (op) {
- default:
- return -1;
-
- case OP_BRA:
- case OP_ASSERT:
- return bracketFindFirstAssertedCharacter(scode, op == OP_ASSERT);
-
- case OP_EXACT:
- scode += 2;
- /* Fall through */
-
- case OP_CHAR:
- case OP_CHAR_IGNORING_CASE:
- case OP_ASCII_CHAR:
- case OP_ASCII_LETTER_IGNORING_CASE:
- case OP_PLUS:
- case OP_MINPLUS:
- if (!inassert)
- return -1;
- return scode[1];
- }
-}
-
-static int bracketFindFirstAssertedCharacter(const unsigned char* code, bool inassert)
-{
- int c = -1;
- do {
- int d = branchFindFirstAssertedCharacter(code + 1 + LINK_SIZE, inassert);
- if (d < 0)
- return -1;
- if (c < 0)
- c = d;
- else if (c != d)
- return -1;
- code += getLinkValue(code + 1);
- } while (*code == OP_ALT);
- return c;
-}
-
-static inline int multiplyWithOverflowCheck(int a, int b)
-{
- if (!a || !b)
- return 0;
- if (a > MAX_PATTERN_SIZE / b)
- return -1;
- return a * b;
-}
-
-static int calculateCompiledPatternLength(const UChar* pattern, int patternLength, JSRegExpIgnoreCaseOption ignoreCase,
- CompileData& cd, ErrorCode& errorcode)
-{
- /* Make a pass over the pattern to compute the
- amount of store required to hold the compiled code. This does not have to be
- perfect as long as errors are overestimates. */
-
- if (patternLength > MAX_PATTERN_SIZE) {
- errorcode = ERR16;
- return -1;
- }
-
- int length = 1 + LINK_SIZE; /* For initial BRA plus length */
- int branch_extra = 0;
- int lastitemlength = 0;
- unsigned brastackptr = 0;
- int brastack[BRASTACK_SIZE];
- unsigned char bralenstack[BRASTACK_SIZE];
- int bracount = 0;
-
- const UChar* ptr = (const UChar*)(pattern - 1);
- const UChar* patternEnd = (const UChar*)(pattern + patternLength);
-
- while (++ptr < patternEnd) {
- int minRepeats = 0, maxRepeats = 0;
- int c = *ptr;
-
- switch (c) {
- /* A backslashed item may be an escaped data character or it may be a
- character type. */
-
- case '\\':
- c = checkEscape(&ptr, patternEnd, &errorcode, cd.numCapturingBrackets, false);
- if (errorcode != 0)
- return -1;
-
- lastitemlength = 1; /* Default length of last item for repeats */
-
- if (c >= 0) { /* Data character */
- length += 2; /* For a one-byte character */
-
- if (c > 127) {
- int i;
- for (i = 0; i < jsc_pcre_utf8_table1_size; i++)
- if (c <= jsc_pcre_utf8_table1[i]) break;
- length += i;
- lastitemlength += i;
- }
-
- continue;
- }
-
- /* Other escapes need one byte */
-
- length++;
-
- /* A back reference needs an additional 2 bytes, plus either one or 5
- bytes for a repeat. We also need to keep the value of the highest
- back reference. */
-
- if (c <= -ESC_REF) {
- int refnum = -c - ESC_REF;
- cd.backrefMap |= (refnum < 32) ? (1 << refnum) : 1;
- if (refnum > cd.topBackref)
- cd.topBackref = refnum;
- length += 2; /* For single back reference */
- if (safelyCheckNextChar(ptr, patternEnd, '{') && isCountedRepeat(ptr + 2, patternEnd)) {
- ptr = readRepeatCounts(ptr + 2, &minRepeats, &maxRepeats, &errorcode);
- if (errorcode)
- return -1;
- if ((minRepeats == 0 && (maxRepeats == 1 || maxRepeats == -1)) ||
- (minRepeats == 1 && maxRepeats == -1))
- length++;
- else
- length += 5;
- if (safelyCheckNextChar(ptr, patternEnd, '?'))
- ptr++;
- }
- }
- continue;
-
- case '^': /* Single-byte metacharacters */
- case '.':
- case '$':
- length++;
- lastitemlength = 1;
- continue;
-
- case '*': /* These repeats won't be after brackets; */
- case '+': /* those are handled separately */
- case '?':
- length++;
- goto POSSESSIVE;
-
- /* This covers the cases of braced repeats after a single char, metachar,
- class, or back reference. */
-
- case '{':
- if (!isCountedRepeat(ptr + 1, patternEnd))
- goto NORMAL_CHAR;
- ptr = readRepeatCounts(ptr + 1, &minRepeats, &maxRepeats, &errorcode);
- if (errorcode != 0)
- return -1;
-
- /* These special cases just insert one extra opcode */
-
- if ((minRepeats == 0 && (maxRepeats == 1 || maxRepeats == -1)) ||
- (minRepeats == 1 && maxRepeats == -1))
- length++;
-
- /* These cases might insert additional copies of a preceding character. */
-
- else {
- if (minRepeats != 1) {
- length -= lastitemlength; /* Uncount the original char or metachar */
- if (minRepeats > 0)
- length += 3 + lastitemlength;
- }
- length += lastitemlength + ((maxRepeats > 0) ? 3 : 1);
- }
-
- if (safelyCheckNextChar(ptr, patternEnd, '?'))
- ptr++; /* Needs no extra length */
-
- POSSESSIVE: /* Test for possessive quantifier */
- if (safelyCheckNextChar(ptr, patternEnd, '+')) {
- ptr++;
- length += 2 + 2 * LINK_SIZE; /* Allow for atomic brackets */
- }
- continue;
-
- /* An alternation contains an offset to the next branch or ket. If any ims
- options changed in the previous branch(es), and/or if we are in a
- lookbehind assertion, extra space will be needed at the start of the
- branch. This is handled by branch_extra. */
-
- case '|':
- if (brastackptr == 0)
- cd.needOuterBracket = true;
- length += 1 + LINK_SIZE + branch_extra;
- continue;
-
- /* A character class uses 33 characters provided that all the character
- values are less than 256. Otherwise, it uses a bit map for low valued
- characters, and individual items for others. Don't worry about character
- types that aren't allowed in classes - they'll get picked up during the
- compile. A character class that contains only one single-byte character
- uses 2 or 3 bytes, depending on whether it is negated or not. Notice this
- where we can. (In UTF-8 mode we can do this only for chars < 128.) */
-
- case '[': {
- int class_optcount;
- if (*(++ptr) == '^') {
- class_optcount = 10; /* Greater than one */
- ptr++;
- }
- else
- class_optcount = 0;
-
- bool class_utf8 = false;
-
- for (; ptr < patternEnd && *ptr != ']'; ++ptr) {
- /* Check for escapes */
-
- if (*ptr == '\\') {
- c = checkEscape(&ptr, patternEnd, &errorcode, cd.numCapturingBrackets, true);
- if (errorcode != 0)
- return -1;
-
- /* Handle escapes that turn into characters */
-
- if (c >= 0)
- goto NON_SPECIAL_CHARACTER;
-
- /* Escapes that are meta-things. The normal ones just affect the
- bit map, but Unicode properties require an XCLASS extended item. */
-
- else
- class_optcount = 10; /* \d, \s etc; make sure > 1 */
- }
-
- /* Anything else increments the possible optimization count. We have to
- detect ranges here so that we can compute the number of extra ranges for
- caseless wide characters when UCP support is available. If there are wide
- characters, we are going to have to use an XCLASS, even for single
- characters. */
-
- else {
- c = *ptr;
-
- /* Come here from handling \ above when it escapes to a char value */
-
- NON_SPECIAL_CHARACTER:
- class_optcount++;
-
- int d = -1;
- if (safelyCheckNextChar(ptr, patternEnd, '-')) {
- const UChar* hyptr = ptr++;
- if (safelyCheckNextChar(ptr, patternEnd, '\\')) {
- ptr++;
- d = checkEscape(&ptr, patternEnd, &errorcode, cd.numCapturingBrackets, true);
- if (errorcode != 0)
- return -1;
- }
- else if ((ptr + 1 < patternEnd) && ptr[1] != ']')
- d = *++ptr;
- if (d < 0)
- ptr = hyptr; /* go back to hyphen as data */
- }
-
- /* If d >= 0 we have a range. In UTF-8 mode, if the end is > 255, or >
- 127 for caseless matching, we will need to use an XCLASS. */
-
- if (d >= 0) {
- class_optcount = 10; /* Ensure > 1 */
- if (d < c) {
- errorcode = ERR8;
- return -1;
- }
-
- if ((d > 255 || (ignoreCase && d > 127))) {
- unsigned char buffer[6];
- if (!class_utf8) /* Allow for XCLASS overhead */
- {
- class_utf8 = true;
- length += LINK_SIZE + 2;
- }
-
- /* If we have UCP support, find out how many extra ranges are
- needed to map the other case of characters within this range. We
- have to mimic the range optimization here, because extending the
- range upwards might push d over a boundary that makes it use
- another byte in the UTF-8 representation. */
-
- if (ignoreCase) {
- int occ, ocd;
- int cc = c;
- int origd = d;
- while (getOthercaseRange(&cc, origd, &occ, &ocd)) {
- if (occ >= c && ocd <= d)
- continue; /* Skip embedded */
-
- if (occ < c && ocd >= c - 1) /* Extend the basic range */
- { /* if there is overlap, */
- c = occ; /* noting that if occ < c */
- continue; /* we can't have ocd > d */
- } /* because a subrange is */
- if (ocd > d && occ <= d + 1) /* always shorter than */
- { /* the basic range. */
- d = ocd;
- continue;
- }
-
- /* An extra item is needed */
-
- length += 1 + encodeUTF8(occ, buffer) +
- ((occ == ocd) ? 0 : encodeUTF8(ocd, buffer));
- }
- }
-
- /* The length of the (possibly extended) range */
-
- length += 1 + encodeUTF8(c, buffer) + encodeUTF8(d, buffer);
- }
-
- }
-
- /* We have a single character. There is nothing to be done unless we
- are in UTF-8 mode. If the char is > 255, or 127 when caseless, we must
- allow for an XCL_SINGLE item, doubled for caselessness if there is UCP
- support. */
-
- else {
- if ((c > 255 || (ignoreCase && c > 127))) {
- unsigned char buffer[6];
- class_optcount = 10; /* Ensure > 1 */
- if (!class_utf8) /* Allow for XCLASS overhead */
- {
- class_utf8 = true;
- length += LINK_SIZE + 2;
- }
- length += (ignoreCase ? 2 : 1) * (1 + encodeUTF8(c, buffer));
- }
- }
- }
- }
-
- if (ptr >= patternEnd) { /* Missing terminating ']' */
- errorcode = ERR6;
- return -1;
- }
-
- /* We can optimize when there was only one optimizable character.
- Note that this does not detect the case of a negated single character.
- In that case we do an incorrect length computation, but it's not a serious
- problem because the computed length is too large rather than too small. */
-
- if (class_optcount == 1)
- goto NORMAL_CHAR;
-
- /* Here, we handle repeats for the class opcodes. */
- {
- length += 33;
-
- /* A repeat needs either 1 or 5 bytes. If it is a possessive quantifier,
- we also need extra for wrapping the whole thing in a sub-pattern. */
-
- if (safelyCheckNextChar(ptr, patternEnd, '{') && isCountedRepeat(ptr + 2, patternEnd)) {
- ptr = readRepeatCounts(ptr + 2, &minRepeats, &maxRepeats, &errorcode);
- if (errorcode != 0)
- return -1;
- if ((minRepeats == 0 && (maxRepeats == 1 || maxRepeats == -1)) ||
- (minRepeats == 1 && maxRepeats == -1))
- length++;
- else
- length += 5;
- if (safelyCheckNextChar(ptr, patternEnd, '+')) {
- ptr++;
- length += 2 + 2 * LINK_SIZE;
- } else if (safelyCheckNextChar(ptr, patternEnd, '?'))
- ptr++;
- }
- }
- continue;
- }
-
- /* Brackets may be genuine groups or special things */
-
- case '(': {
- int branch_newextra = 0;
- int bracket_length = 1 + LINK_SIZE;
- bool capturing = false;
-
- /* Handle special forms of bracket, which all start (? */
-
- if (safelyCheckNextChar(ptr, patternEnd, '?')) {
- switch (c = (ptr + 2 < patternEnd ? ptr[2] : 0)) {
- /* Non-referencing groups and lookaheads just move the pointer on, and
- then behave like a non-special bracket, except that they don't increment
- the count of extracting brackets. Ditto for the "once only" bracket,
- which is in Perl from version 5.005. */
-
- case ':':
- case '=':
- case '!':
- ptr += 2;
- break;
-
- /* Else loop checking valid options until ) is met. Anything else is an
- error. If we are without any brackets, i.e. at top level, the settings
- act as if specified in the options, so massage the options immediately.
- This is for backward compatibility with Perl 5.004. */
-
- default:
- errorcode = ERR12;
- return -1;
- }
- } else
- capturing = 1;
-
- /* Capturing brackets must be counted so we can process escapes in a
- Perlish way. If the number exceeds EXTRACT_BASIC_MAX we are going to need
- an additional 3 bytes of memory per capturing bracket. */
-
- if (capturing) {
- bracount++;
- if (bracount > EXTRACT_BASIC_MAX)
- bracket_length += 3;
- }
-
- /* Save length for computing whole length at end if there's a repeat that
- requires duplication of the group. Also save the current value of
- branch_extra, and start the new group with the new value. If non-zero, this
- will either be 2 for a (?imsx: group, or 3 for a lookbehind assertion. */
-
- if (brastackptr >= sizeof(brastack)/sizeof(int)) {
- errorcode = ERR17;
- return -1;
- }
-
- bralenstack[brastackptr] = branch_extra;
- branch_extra = branch_newextra;
-
- brastack[brastackptr++] = length;
- length += bracket_length;
- continue;
- }
-
- /* Handle ket. Look for subsequent maxRepeats/minRepeats; for certain sets of values we
- have to replicate this bracket up to that many times. If brastackptr is
- 0 this is an unmatched bracket which will generate an error, but take care
- not to try to access brastack[-1] when computing the length and restoring
- the branch_extra value. */
-
- case ')': {
- int duplength;
- length += 1 + LINK_SIZE;
- if (brastackptr > 0) {
- duplength = length - brastack[--brastackptr];
- branch_extra = bralenstack[brastackptr];
- }
- else
- duplength = 0;
-
- /* Leave ptr at the final char; for readRepeatCounts this happens
- automatically; for the others we need an increment. */
-
- if ((ptr + 1 < patternEnd) && (c = ptr[1]) == '{' && isCountedRepeat(ptr + 2, patternEnd)) {
- ptr = readRepeatCounts(ptr + 2, &minRepeats, &maxRepeats, &errorcode);
- if (errorcode)
- return -1;
- } else if (c == '*') {
- minRepeats = 0;
- maxRepeats = -1;
- ptr++;
- } else if (c == '+') {
- minRepeats = 1;
- maxRepeats = -1;
- ptr++;
- } else if (c == '?') {
- minRepeats = 0;
- maxRepeats = 1;
- ptr++;
- } else {
- minRepeats = 1;
- maxRepeats = 1;
- }
-
- /* If the minimum is zero, we have to allow for an OP_BRAZERO before the
- group, and if the maximum is greater than zero, we have to replicate
- maxval-1 times; each replication acquires an OP_BRAZERO plus a nesting
- bracket set. */
-
- int repeatsLength;
- if (minRepeats == 0) {
- length++;
- if (maxRepeats > 0) {
- repeatsLength = multiplyWithOverflowCheck(maxRepeats - 1, duplength + 3 + 2 * LINK_SIZE);
- if (repeatsLength < 0) {
- errorcode = ERR16;
- return -1;
- }
- length += repeatsLength;
- if (length > MAX_PATTERN_SIZE) {
- errorcode = ERR16;
- return -1;
- }
- }
- }
-
- /* When the minimum is greater than zero, we have to replicate up to
- minval-1 times, with no additions required in the copies. Then, if there
- is a limited maximum we have to replicate up to maxval-1 times allowing
- for a BRAZERO item before each optional copy and nesting brackets for all
- but one of the optional copies. */
-
- else {
- repeatsLength = multiplyWithOverflowCheck(minRepeats - 1, duplength);
- if (repeatsLength < 0) {
- errorcode = ERR16;
- return -1;
- }
- length += repeatsLength;
- if (maxRepeats > minRepeats) { /* Need this test as maxRepeats=-1 means no limit */
- repeatsLength = multiplyWithOverflowCheck(maxRepeats - minRepeats, duplength + 3 + 2 * LINK_SIZE);
- if (repeatsLength < 0) {
- errorcode = ERR16;
- return -1;
- }
- length += repeatsLength - (2 + 2 * LINK_SIZE);
- }
- if (length > MAX_PATTERN_SIZE) {
- errorcode = ERR16;
- return -1;
- }
- }
-
- /* Allow space for once brackets for "possessive quantifier" */
-
- if (safelyCheckNextChar(ptr, patternEnd, '+')) {
- ptr++;
- length += 2 + 2 * LINK_SIZE;
- }
- continue;
- }
-
- /* Non-special character. It won't be space or # in extended mode, so it is
- always a genuine character. If we are in a \Q...\E sequence, check for the
- end; if not, we have a literal. */
-
- default:
- NORMAL_CHAR:
- length += 2; /* For a one-byte character */
- lastitemlength = 1; /* Default length of last item for repeats */
-
- if (c > 127) {
- int i;
- for (i = 0; i < jsc_pcre_utf8_table1_size; i++)
- if (c <= jsc_pcre_utf8_table1[i])
- break;
- length += i;
- lastitemlength += i;
- }
-
- continue;
- }
- }
-
- length += 2 + LINK_SIZE; /* For final KET and END */
-
- cd.numCapturingBrackets = bracount;
- return length;
-}
-
-/*************************************************
-* Compile a Regular Expression *
-*************************************************/
-
-/* This function takes a string and returns a pointer to a block of store
-holding a compiled version of the expression. The original API for this
-function had no error code return variable; it is retained for backwards
-compatibility. The new function is given a new name.
-
-Arguments:
- pattern the regular expression
- options various option bits
- errorCodePtr pointer to error code variable (pcre_compile2() only)
- can be NULL if you don't want a code value
- errorPtr pointer to pointer to error text
- erroroffset ptr offset in pattern where error was detected
- tables pointer to character tables or NULL
-
-Returns: pointer to compiled data block, or NULL on error,
- with errorPtr and erroroffset set
-*/
-
-static inline JSRegExp* returnError(ErrorCode errorcode, const char** errorPtr)
-{
- *errorPtr = errorText(errorcode);
- return 0;
-}
-
-JSRegExp* jsRegExpCompile(const UChar* pattern, int patternLength,
- JSRegExpIgnoreCaseOption ignoreCase, JSRegExpMultilineOption multiline,
- unsigned* numSubpatterns, const char** errorPtr)
-{
- /* We can't pass back an error message if errorPtr is NULL; I guess the best we
- can do is just return NULL, but we can set a code value if there is a code pointer. */
- if (!errorPtr)
- return 0;
- *errorPtr = NULL;
-
- CompileData cd;
-
- ErrorCode errorcode = ERR0;
- /* Call this once just to count the brackets. */
- calculateCompiledPatternLength(pattern, patternLength, ignoreCase, cd, errorcode);
- /* Call it again to compute the length. */
- int length = calculateCompiledPatternLength(pattern, patternLength, ignoreCase, cd, errorcode);
- if (errorcode)
- return returnError(errorcode, errorPtr);
-
- if (length > MAX_PATTERN_SIZE)
- return returnError(ERR16, errorPtr);
-
- size_t size = length + sizeof(JSRegExp);
-#if REGEXP_HISTOGRAM
- size_t stringOffset = (size + sizeof(UChar) - 1) / sizeof(UChar) * sizeof(UChar);
- size = stringOffset + patternLength * sizeof(UChar);
-#endif
- JSRegExp* re = reinterpret_cast<JSRegExp*>(new char[size]);
-
- if (!re)
- return returnError(ERR13, errorPtr);
-
- re->options = (ignoreCase ? IgnoreCaseOption : 0) | (multiline ? MatchAcrossMultipleLinesOption : 0);
-
- /* The starting points of the name/number translation table and of the code are
- passed around in the compile data block. */
-
- const unsigned char* codeStart = (const unsigned char*)(re + 1);
-
- /* Set up a starting, non-extracting bracket, then compile the expression. On
- error, errorcode will be set non-zero, so we don't need to look at the result
- of the function here. */
-
- const UChar* ptr = (const UChar*)pattern;
- const UChar* patternEnd = pattern + patternLength;
- unsigned char* code = const_cast<unsigned char*>(codeStart);
- int firstByte, reqByte;
- int bracketCount = 0;
- if (!cd.needOuterBracket)
- compileBranch(re->options, &bracketCount, &code, &ptr, patternEnd, &errorcode, &firstByte, &reqByte, cd);
- else {
- *code = OP_BRA;
- compileBracket(re->options, &bracketCount, &code, &ptr, patternEnd, &errorcode, 0, &firstByte, &reqByte, cd);
- }
- re->topBracket = bracketCount;
- re->topBackref = cd.topBackref;
-
- /* If not reached end of pattern on success, there's an excess bracket. */
-
- if (errorcode == 0 && ptr < patternEnd)
- errorcode = ERR10;
-
- /* Fill in the terminating state and check for disastrous overflow, but
- if debugging, leave the test till after things are printed out. */
-
- *code++ = OP_END;
-
- ASSERT(code - codeStart <= length);
- if (code - codeStart > length)
- errorcode = ERR7;
-
- /* Give an error if there's back reference to a non-existent capturing
- subpattern. */
-
- if (re->topBackref > re->topBracket)
- errorcode = ERR15;
-
- /* Failed to compile, or error while post-processing */
-
- if (errorcode != ERR0) {
- delete [] reinterpret_cast<char*>(re);
- return returnError(errorcode, errorPtr);
- }
-
- /* If the anchored option was not passed, set the flag if we can determine that
- the pattern is anchored by virtue of ^ characters or \A or anything else (such
- as starting with .* when DOTALL is set).
-
- Otherwise, if we know what the first character has to be, save it, because that
- speeds up unanchored matches no end. If not, see if we can set the
- UseMultiLineFirstByteOptimizationOption flag. This is helpful for multiline matches when all branches
- start with ^. and also when all branches start with .* for non-DOTALL matches.
- */
-
- if (cd.needOuterBracket ? bracketIsAnchored(codeStart) : branchIsAnchored(codeStart))
- re->options |= IsAnchoredOption;
- else {
- if (firstByte < 0) {
- firstByte = (cd.needOuterBracket
- ? bracketFindFirstAssertedCharacter(codeStart, false)
- : branchFindFirstAssertedCharacter(codeStart, false))
- | ((re->options & IgnoreCaseOption) ? REQ_IGNORE_CASE : 0);
- }
- if (firstByte >= 0) {
- int ch = firstByte & 255;
- if (ch < 127) {
- re->firstByte = ((firstByte & REQ_IGNORE_CASE) && flipCase(ch) == ch) ? ch : firstByte;
- re->options |= UseFirstByteOptimizationOption;
- }
- } else {
- if (cd.needOuterBracket ? bracketNeedsLineStart(codeStart, 0, cd.backrefMap) : branchNeedsLineStart(codeStart, 0, cd.backrefMap))
- re->options |= UseMultiLineFirstByteOptimizationOption;
- }
- }
-
- /* For an anchored pattern, we use the "required byte" only if it follows a
- variable length item in the regex. Remove the caseless flag for non-caseable
- bytes. */
-
- if (reqByte >= 0 && (!(re->options & IsAnchoredOption) || (reqByte & REQ_VARY))) {
- int ch = reqByte & 255;
- if (ch < 127) {
- re->reqByte = ((reqByte & REQ_IGNORE_CASE) && flipCase(ch) == ch) ? (reqByte & ~REQ_IGNORE_CASE) : reqByte;
- re->options |= UseRequiredByteOptimizationOption;
- }
- }
-
-#if REGEXP_HISTOGRAM
- re->stringOffset = stringOffset;
- re->stringLength = patternLength;
- memcpy(reinterpret_cast<char*>(re) + stringOffset, pattern, patternLength * 2);
-#endif
-
- if (numSubpatterns)
- *numSubpatterns = re->topBracket;
- return re;
-}
-
-void jsRegExpFree(JSRegExp* re)
-{
- delete [] reinterpret_cast<char*>(re);
-}
+++ /dev/null
-/* This is JavaScriptCore's variant of the PCRE library. While this library
-started out as a copy of PCRE, many of the features of PCRE have been
-removed. This library now supports only the regular expression features
-required by the JavaScript language specification, and has only the functions
-needed by JavaScriptCore and the rest of WebKit.
-
- Originally written by Philip Hazel
- Copyright (c) 1997-2006 University of Cambridge
- Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
- Copyright (C) 2007 Eric Seidel <eric@webkit.org>
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-/* This module contains jsRegExpExecute(), the externally visible function
-that does pattern matching using an NFA algorithm, following the rules from
-the JavaScript specification. There are also some supporting functions. */
-
-#include "config.h"
-#include "pcre_internal.h"
-
-#include <limits.h>
-#include <wtf/ASCIICType.h>
-#include <wtf/Vector.h>
-
-#if REGEXP_HISTOGRAM
-#include <wtf/DateMath.h>
-#include <runtime/UString.h>
-#endif
-
-using namespace WTF;
-
-#if COMPILER(GCC)
-#define USE_COMPUTED_GOTO_FOR_MATCH_RECURSION
-//#define USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP
-#endif
-
-/* Avoid warnings on Windows. */
-#undef min
-#undef max
-
-#ifndef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION
-typedef int ReturnLocation;
-#else
-typedef void* ReturnLocation;
-#endif
-
-#if !REGEXP_HISTOGRAM
-
-class HistogramTimeLogger {
-public:
- HistogramTimeLogger(const JSRegExp*) { }
-};
-
-#else
-
-using namespace JSC;
-
-class Histogram {
-public:
- ~Histogram();
- void add(const JSRegExp*, double);
-
-private:
- typedef HashMap<RefPtr<UString::Rep>, double> Map;
- Map times;
-};
-
-class HistogramTimeLogger {
-public:
- HistogramTimeLogger(const JSRegExp*);
- ~HistogramTimeLogger();
-
-private:
- const JSRegExp* m_re;
- double m_startTime;
-};
-
-#endif
-
-/* Structure for building a chain of data for holding the values of
-the subject pointer at the start of each bracket, used to detect when
-an empty string has been matched by a bracket to break infinite loops. */
-struct BracketChainNode {
- BracketChainNode* previousBracket;
- const UChar* bracketStart;
-};
-
-struct MatchFrame : FastAllocBase {
- ReturnLocation returnLocation;
- struct MatchFrame* previousFrame;
-
- /* Function arguments that may change */
- struct {
- const UChar* subjectPtr;
- const unsigned char* instructionPtr;
- int offsetTop;
- BracketChainNode* bracketChain;
- } args;
-
-
- /* PCRE uses "fake" recursion built off of gotos, thus
- stack-based local variables are not safe to use. Instead we have to
- store local variables on the current MatchFrame. */
- struct {
- const unsigned char* data;
- const unsigned char* startOfRepeatingBracket;
- const UChar* subjectPtrAtStartOfInstruction; // Several instrutions stash away a subjectPtr here for later compare
- const unsigned char* instructionPtrAtStartOfOnce;
-
- int repeatOthercase;
-
- int ctype;
- int fc;
- int fi;
- int length;
- int max;
- int number;
- int offset;
- int saveOffset1;
- int saveOffset2;
- int saveOffset3;
-
- BracketChainNode bracketChainNode;
- } locals;
-};
-
-/* Structure for passing "static" information around between the functions
-doing traditional NFA matching, so that they are thread-safe. */
-
-struct MatchData {
- int* offsetVector; /* Offset vector */
- int offsetEnd; /* One past the end */
- int offsetMax; /* The maximum usable for return data */
- bool offsetOverflow; /* Set if too many extractions */
- const UChar* startSubject; /* Start of the subject string */
- const UChar* endSubject; /* End of the subject string */
- const UChar* endMatchPtr; /* Subject position at end match */
- int endOffsetTop; /* Highwater mark at end of match */
- bool multiline;
- bool ignoreCase;
-};
-
-/* The maximum remaining length of subject we are prepared to search for a
-reqByte match. */
-
-#define REQ_BYTE_MAX 1000
-
-/* The below limit restricts the number of "recursive" match calls in order to
-avoid spending exponential time on complex regular expressions. */
-
-static const unsigned matchLimit = 1000000;
-
-#ifdef DEBUG
-/*************************************************
-* Debugging function to print chars *
-*************************************************/
-
-/* Print a sequence of chars in printable format, stopping at the end of the
-subject if the requested.
-
-Arguments:
- p points to characters
- length number to print
- isSubject true if printing from within md.startSubject
- md pointer to matching data block, if isSubject is true
-*/
-
-static void pchars(const UChar* p, int length, bool isSubject, const MatchData& md)
-{
- if (isSubject && length > md.endSubject - p)
- length = md.endSubject - p;
- while (length-- > 0) {
- int c;
- if (isASCIIPrintable(c = *(p++)))
- printf("%c", c);
- else if (c < 256)
- printf("\\x%02x", c);
- else
- printf("\\x{%x}", c);
- }
-}
-#endif
-
-/*************************************************
-* Match a back-reference *
-*************************************************/
-
-/* If a back reference hasn't been set, the length that is passed is greater
-than the number of characters left in the string, so the match fails.
-
-Arguments:
- offset index into the offset vector
- subjectPtr points into the subject
- length length to be matched
- md points to match data block
-
-Returns: true if matched
-*/
-
-static bool matchRef(int offset, const UChar* subjectPtr, int length, const MatchData& md)
-{
- const UChar* p = md.startSubject + md.offsetVector[offset];
-
-#ifdef DEBUG
- if (subjectPtr >= md.endSubject)
- printf("matching subject <null>");
- else {
- printf("matching subject ");
- pchars(subjectPtr, length, true, md);
- }
- printf(" against backref ");
- pchars(p, length, false, md);
- printf("\n");
-#endif
-
- /* Always fail if not enough characters left */
-
- if (length > md.endSubject - subjectPtr)
- return false;
-
- /* Separate the caselesss case for speed */
-
- if (md.ignoreCase) {
- while (length-- > 0) {
- UChar c = *p++;
- int othercase = jsc_pcre_ucp_othercase(c);
- UChar d = *subjectPtr++;
- if (c != d && othercase != d)
- return false;
- }
- }
- else {
- while (length-- > 0)
- if (*p++ != *subjectPtr++)
- return false;
- }
-
- return true;
-}
-
-#ifndef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION
-
-/* Use numbered labels and switch statement at the bottom of the match function. */
-
-#define RMATCH_WHERE(num) num
-#define RRETURN_LABEL RRETURN_SWITCH
-
-#else
-
-/* Use GCC's computed goto extension. */
-
-/* For one test case this is more than 40% faster than the switch statement.
-We could avoid the use of the num argument entirely by using local labels,
-but using it for the GCC case as well as the non-GCC case allows us to share
-a bit more code and notice if we use conflicting numbers.*/
-
-#define RMATCH_WHERE(num) &&RRETURN_##num
-#define RRETURN_LABEL *stack.currentFrame->returnLocation
-
-#endif
-
-#define RECURSIVE_MATCH_COMMON(num) \
- goto RECURSE;\
- RRETURN_##num: \
- stack.popCurrentFrame();
-
-#define RECURSIVE_MATCH(num, ra, rb) \
- do { \
- stack.pushNewFrame((ra), (rb), RMATCH_WHERE(num)); \
- RECURSIVE_MATCH_COMMON(num) \
- } while (0)
-
-#define RECURSIVE_MATCH_NEW_GROUP(num, ra, rb) \
- do { \
- stack.pushNewFrame((ra), (rb), RMATCH_WHERE(num)); \
- startNewGroup(stack.currentFrame); \
- RECURSIVE_MATCH_COMMON(num) \
- } while (0)
-
-#define RRETURN goto RRETURN_LABEL
-
-#define RRETURN_NO_MATCH do { isMatch = false; RRETURN; } while (0)
-
-/*************************************************
-* Match from current position *
-*************************************************/
-
-/* On entry instructionPtr points to the first opcode, and subjectPtr to the first character
-in the subject string, while substringStart holds the value of subjectPtr at the start of the
-last bracketed group - used for breaking infinite loops matching zero-length
-strings. This function is called recursively in many circumstances. Whenever it
-returns a negative (error) response, the outer match() call must also return the
-same response.
-
-Arguments:
- subjectPtr pointer in subject
- instructionPtr position in code
- offsetTop current top pointer
- md pointer to "static" info for the match
-
-Returns: 1 if matched ) these values are >= 0
- 0 if failed to match )
- a negative error value if aborted by an error condition
- (e.g. stopped by repeated call or recursion limit)
-*/
-
-static const unsigned numFramesOnStack = 16;
-
-struct MatchStack {
- MatchStack()
- : framesEnd(frames + numFramesOnStack)
- , currentFrame(frames)
- , size(1) // match() creates accesses the first frame w/o calling pushNewFrame
- {
- ASSERT((sizeof(frames) / sizeof(frames[0])) == numFramesOnStack);
- }
-
- MatchFrame frames[numFramesOnStack];
- MatchFrame* framesEnd;
- MatchFrame* currentFrame;
- unsigned size;
-
- inline bool canUseStackBufferForNextFrame()
- {
- return size < numFramesOnStack;
- }
-
- inline MatchFrame* allocateNextFrame()
- {
- if (canUseStackBufferForNextFrame())
- return currentFrame + 1;
- return new MatchFrame;
- }
-
- inline void pushNewFrame(const unsigned char* instructionPtr, BracketChainNode* bracketChain, ReturnLocation returnLocation)
- {
- MatchFrame* newframe = allocateNextFrame();
- newframe->previousFrame = currentFrame;
-
- newframe->args.subjectPtr = currentFrame->args.subjectPtr;
- newframe->args.offsetTop = currentFrame->args.offsetTop;
- newframe->args.instructionPtr = instructionPtr;
- newframe->args.bracketChain = bracketChain;
- newframe->returnLocation = returnLocation;
- size++;
-
- currentFrame = newframe;
- }
-
- inline void popCurrentFrame()
- {
- MatchFrame* oldFrame = currentFrame;
- currentFrame = currentFrame->previousFrame;
- if (size > numFramesOnStack)
- delete oldFrame;
- size--;
- }
-
- void popAllFrames()
- {
- while (size)
- popCurrentFrame();
- }
-};
-
-static int matchError(int errorCode, MatchStack& stack)
-{
- stack.popAllFrames();
- return errorCode;
-}
-
-/* Get the next UTF-8 character, not advancing the pointer, incrementing length
- if there are extra bytes. This is called when we know we are in UTF-8 mode. */
-
-static inline void getUTF8CharAndIncrementLength(int& c, const unsigned char* subjectPtr, int& len)
-{
- c = *subjectPtr;
- if ((c & 0xc0) == 0xc0) {
- int gcaa = jsc_pcre_utf8_table4[c & 0x3f]; /* Number of additional bytes */
- int gcss = 6 * gcaa;
- c = (c & jsc_pcre_utf8_table3[gcaa]) << gcss;
- for (int gcii = 1; gcii <= gcaa; gcii++) {
- gcss -= 6;
- c |= (subjectPtr[gcii] & 0x3f) << gcss;
- }
- len += gcaa;
- }
-}
-
-static inline void startNewGroup(MatchFrame* currentFrame)
-{
- /* At the start of a bracketed group, add the current subject pointer to the
- stack of such pointers, to be re-instated at the end of the group when we hit
- the closing ket. When match() is called in other circumstances, we don't add to
- this stack. */
-
- currentFrame->locals.bracketChainNode.previousBracket = currentFrame->args.bracketChain;
- currentFrame->locals.bracketChainNode.bracketStart = currentFrame->args.subjectPtr;
- currentFrame->args.bracketChain = ¤tFrame->locals.bracketChainNode;
-}
-
-// FIXME: "minimize" means "not greedy", we should invert the callers to ask for "greedy" to be less confusing
-static inline void repeatInformationFromInstructionOffset(short instructionOffset, bool& minimize, int& minimumRepeats, int& maximumRepeats)
-{
- // Instruction offsets are based off of OP_CRSTAR, OP_STAR, OP_TYPESTAR, OP_NOTSTAR
- static const char minimumRepeatsFromInstructionOffset[] = { 0, 0, 1, 1, 0, 0 };
- static const int maximumRepeatsFromInstructionOffset[] = { INT_MAX, INT_MAX, INT_MAX, INT_MAX, 1, 1 };
-
- ASSERT(instructionOffset >= 0);
- ASSERT(instructionOffset <= (OP_CRMINQUERY - OP_CRSTAR));
-
- minimize = (instructionOffset & 1); // this assumes ordering: Instruction, MinimizeInstruction, Instruction2, MinimizeInstruction2
- minimumRepeats = minimumRepeatsFromInstructionOffset[instructionOffset];
- maximumRepeats = maximumRepeatsFromInstructionOffset[instructionOffset];
-}
-
-static int match(const UChar* subjectPtr, const unsigned char* instructionPtr, int offsetTop, MatchData& md)
-{
- bool isMatch = false;
- int min;
- bool minimize = false; /* Initialization not really needed, but some compilers think so. */
- unsigned remainingMatchCount = matchLimit;
- int othercase; /* Declare here to avoid errors during jumps */
-
- MatchStack stack;
-
- /* The opcode jump table. */
-#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP
-#define EMIT_JUMP_TABLE_ENTRY(opcode) &&LABEL_OP_##opcode,
- static void* opcodeJumpTable[256] = { FOR_EACH_OPCODE(EMIT_JUMP_TABLE_ENTRY) };
-#undef EMIT_JUMP_TABLE_ENTRY
-#endif
-
- /* One-time setup of the opcode jump table. */
-#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP
- for (int i = 255; !opcodeJumpTable[i]; i--)
- opcodeJumpTable[i] = &&CAPTURING_BRACKET;
-#endif
-
-#ifdef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION
- // Shark shows this as a hot line
- // Using a static const here makes this line disappear, but makes later access hotter (not sure why)
- stack.currentFrame->returnLocation = &&RETURN;
-#else
- stack.currentFrame->returnLocation = 0;
-#endif
- stack.currentFrame->args.subjectPtr = subjectPtr;
- stack.currentFrame->args.instructionPtr = instructionPtr;
- stack.currentFrame->args.offsetTop = offsetTop;
- stack.currentFrame->args.bracketChain = 0;
- startNewGroup(stack.currentFrame);
-
- /* This is where control jumps back to to effect "recursion" */
-
-RECURSE:
- if (!--remainingMatchCount)
- return matchError(JSRegExpErrorHitLimit, stack);
-
- /* Now start processing the operations. */
-
-#ifndef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP
- while (true)
-#endif
- {
-
-#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP
-#define BEGIN_OPCODE(opcode) LABEL_OP_##opcode
-#define NEXT_OPCODE goto *opcodeJumpTable[*stack.currentFrame->args.instructionPtr]
-#else
-#define BEGIN_OPCODE(opcode) case OP_##opcode
-#define NEXT_OPCODE continue
-#endif
-
-#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP
- NEXT_OPCODE;
-#else
- switch (*stack.currentFrame->args.instructionPtr)
-#endif
- {
- /* Non-capturing bracket: optimized */
-
- BEGIN_OPCODE(BRA):
- NON_CAPTURING_BRACKET:
- DPRINTF(("start bracket 0\n"));
- do {
- RECURSIVE_MATCH_NEW_GROUP(2, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1);
- } while (*stack.currentFrame->args.instructionPtr == OP_ALT);
- DPRINTF(("bracket 0 failed\n"));
- RRETURN;
-
- /* Skip over large extraction number data if encountered. */
-
- BEGIN_OPCODE(BRANUMBER):
- stack.currentFrame->args.instructionPtr += 3;
- NEXT_OPCODE;
-
- /* End of the pattern. */
-
- BEGIN_OPCODE(END):
- md.endMatchPtr = stack.currentFrame->args.subjectPtr; /* Record where we ended */
- md.endOffsetTop = stack.currentFrame->args.offsetTop; /* and how many extracts were taken */
- isMatch = true;
- RRETURN;
-
- /* Assertion brackets. Check the alternative branches in turn - the
- matching won't pass the KET for an assertion. If any one branch matches,
- the assertion is true. Lookbehind assertions have an OP_REVERSE item at the
- start of each branch to move the current point backwards, so the code at
- this level is identical to the lookahead case. */
-
- BEGIN_OPCODE(ASSERT):
- do {
- RECURSIVE_MATCH_NEW_GROUP(6, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, NULL);
- if (isMatch)
- break;
- stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1);
- } while (*stack.currentFrame->args.instructionPtr == OP_ALT);
- if (*stack.currentFrame->args.instructionPtr == OP_KET)
- RRETURN_NO_MATCH;
-
- /* Continue from after the assertion, updating the offsets high water
- mark, since extracts may have been taken during the assertion. */
-
- advanceToEndOfBracket(stack.currentFrame->args.instructionPtr);
- stack.currentFrame->args.instructionPtr += 1 + LINK_SIZE;
- stack.currentFrame->args.offsetTop = md.endOffsetTop;
- NEXT_OPCODE;
-
- /* Negative assertion: all branches must fail to match */
-
- BEGIN_OPCODE(ASSERT_NOT):
- do {
- RECURSIVE_MATCH_NEW_GROUP(7, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, NULL);
- if (isMatch)
- RRETURN_NO_MATCH;
- stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1);
- } while (*stack.currentFrame->args.instructionPtr == OP_ALT);
-
- stack.currentFrame->args.instructionPtr += 1 + LINK_SIZE;
- NEXT_OPCODE;
-
- /* An alternation is the end of a branch; scan along to find the end of the
- bracketed group and go to there. */
-
- BEGIN_OPCODE(ALT):
- advanceToEndOfBracket(stack.currentFrame->args.instructionPtr);
- NEXT_OPCODE;
-
- /* BRAZERO and BRAMINZERO occur just before a bracket group, indicating
- that it may occur zero times. It may repeat infinitely, or not at all -
- i.e. it could be ()* or ()? in the pattern. Brackets with fixed upper
- repeat limits are compiled as a number of copies, with the optional ones
- preceded by BRAZERO or BRAMINZERO. */
-
- BEGIN_OPCODE(BRAZERO): {
- stack.currentFrame->locals.startOfRepeatingBracket = stack.currentFrame->args.instructionPtr + 1;
- RECURSIVE_MATCH_NEW_GROUP(14, stack.currentFrame->locals.startOfRepeatingBracket, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- advanceToEndOfBracket(stack.currentFrame->locals.startOfRepeatingBracket);
- stack.currentFrame->args.instructionPtr = stack.currentFrame->locals.startOfRepeatingBracket + 1 + LINK_SIZE;
- NEXT_OPCODE;
- }
-
- BEGIN_OPCODE(BRAMINZERO): {
- stack.currentFrame->locals.startOfRepeatingBracket = stack.currentFrame->args.instructionPtr + 1;
- advanceToEndOfBracket(stack.currentFrame->locals.startOfRepeatingBracket);
- RECURSIVE_MATCH_NEW_GROUP(15, stack.currentFrame->locals.startOfRepeatingBracket + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- stack.currentFrame->args.instructionPtr++;
- NEXT_OPCODE;
- }
-
- /* End of a group, repeated or non-repeating. If we are at the end of
- an assertion "group", stop matching and return 1, but record the
- current high water mark for use by positive assertions. Do this also
- for the "once" (not-backup up) groups. */
-
- BEGIN_OPCODE(KET):
- BEGIN_OPCODE(KETRMIN):
- BEGIN_OPCODE(KETRMAX):
- stack.currentFrame->locals.instructionPtrAtStartOfOnce = stack.currentFrame->args.instructionPtr - getLinkValue(stack.currentFrame->args.instructionPtr + 1);
- stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.bracketChain->bracketStart;
-
- /* Back up the stack of bracket start pointers. */
-
- stack.currentFrame->args.bracketChain = stack.currentFrame->args.bracketChain->previousBracket;
-
- if (*stack.currentFrame->locals.instructionPtrAtStartOfOnce == OP_ASSERT || *stack.currentFrame->locals.instructionPtrAtStartOfOnce == OP_ASSERT_NOT) {
- md.endOffsetTop = stack.currentFrame->args.offsetTop;
- isMatch = true;
- RRETURN;
- }
-
- /* In all other cases except a conditional group we have to check the
- group number back at the start and if necessary complete handling an
- extraction by setting the offsets and bumping the high water mark. */
-
- stack.currentFrame->locals.number = *stack.currentFrame->locals.instructionPtrAtStartOfOnce - OP_BRA;
-
- /* For extended extraction brackets (large number), we have to fish out
- the number from a dummy opcode at the start. */
-
- if (stack.currentFrame->locals.number > EXTRACT_BASIC_MAX)
- stack.currentFrame->locals.number = get2ByteValue(stack.currentFrame->locals.instructionPtrAtStartOfOnce + 2 + LINK_SIZE);
- stack.currentFrame->locals.offset = stack.currentFrame->locals.number << 1;
-
-#ifdef DEBUG
- printf("end bracket %d", stack.currentFrame->locals.number);
- printf("\n");
-#endif
-
- /* Test for a numbered group. This includes groups called as a result
- of recursion. Note that whole-pattern recursion is coded as a recurse
- into group 0, so it won't be picked up here. Instead, we catch it when
- the OP_END is reached. */
-
- if (stack.currentFrame->locals.number > 0) {
- if (stack.currentFrame->locals.offset >= md.offsetMax)
- md.offsetOverflow = true;
- else {
- md.offsetVector[stack.currentFrame->locals.offset] =
- md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number];
- md.offsetVector[stack.currentFrame->locals.offset+1] = stack.currentFrame->args.subjectPtr - md.startSubject;
- if (stack.currentFrame->args.offsetTop <= stack.currentFrame->locals.offset)
- stack.currentFrame->args.offsetTop = stack.currentFrame->locals.offset + 2;
- }
- }
-
- /* For a non-repeating ket, just continue at this level. This also
- happens for a repeating ket if no characters were matched in the group.
- This is the forcible breaking of infinite loops as implemented in Perl
- 5.005. If there is an options reset, it will get obeyed in the normal
- course of events. */
-
- if (*stack.currentFrame->args.instructionPtr == OP_KET || stack.currentFrame->args.subjectPtr == stack.currentFrame->locals.subjectPtrAtStartOfInstruction) {
- stack.currentFrame->args.instructionPtr += 1 + LINK_SIZE;
- NEXT_OPCODE;
- }
-
- /* The repeating kets try the rest of the pattern or restart from the
- preceding bracket, in the appropriate order. */
-
- if (*stack.currentFrame->args.instructionPtr == OP_KETRMIN) {
- RECURSIVE_MATCH(16, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- RECURSIVE_MATCH_NEW_GROUP(17, stack.currentFrame->locals.instructionPtrAtStartOfOnce, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- } else { /* OP_KETRMAX */
- RECURSIVE_MATCH_NEW_GROUP(18, stack.currentFrame->locals.instructionPtrAtStartOfOnce, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- RECURSIVE_MATCH(19, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- }
- RRETURN;
-
- /* Start of subject. */
-
- BEGIN_OPCODE(CIRC):
- if (stack.currentFrame->args.subjectPtr != md.startSubject)
- RRETURN_NO_MATCH;
- stack.currentFrame->args.instructionPtr++;
- NEXT_OPCODE;
-
- /* After internal newline if multiline. */
-
- BEGIN_OPCODE(BOL):
- if (stack.currentFrame->args.subjectPtr != md.startSubject && !isNewline(stack.currentFrame->args.subjectPtr[-1]))
- RRETURN_NO_MATCH;
- stack.currentFrame->args.instructionPtr++;
- NEXT_OPCODE;
-
- /* End of subject. */
-
- BEGIN_OPCODE(DOLL):
- if (stack.currentFrame->args.subjectPtr < md.endSubject)
- RRETURN_NO_MATCH;
- stack.currentFrame->args.instructionPtr++;
- NEXT_OPCODE;
-
- /* Before internal newline if multiline. */
-
- BEGIN_OPCODE(EOL):
- if (stack.currentFrame->args.subjectPtr < md.endSubject && !isNewline(*stack.currentFrame->args.subjectPtr))
- RRETURN_NO_MATCH;
- stack.currentFrame->args.instructionPtr++;
- NEXT_OPCODE;
-
- /* Word boundary assertions */
-
- BEGIN_OPCODE(NOT_WORD_BOUNDARY):
- BEGIN_OPCODE(WORD_BOUNDARY): {
- bool currentCharIsWordChar = false;
- bool previousCharIsWordChar = false;
-
- if (stack.currentFrame->args.subjectPtr > md.startSubject)
- previousCharIsWordChar = isWordChar(stack.currentFrame->args.subjectPtr[-1]);
- if (stack.currentFrame->args.subjectPtr < md.endSubject)
- currentCharIsWordChar = isWordChar(*stack.currentFrame->args.subjectPtr);
-
- /* Now see if the situation is what we want */
- bool wordBoundaryDesired = (*stack.currentFrame->args.instructionPtr++ == OP_WORD_BOUNDARY);
- if (wordBoundaryDesired ? currentCharIsWordChar == previousCharIsWordChar : currentCharIsWordChar != previousCharIsWordChar)
- RRETURN_NO_MATCH;
- NEXT_OPCODE;
- }
-
- /* Match a single character type; inline for speed */
-
- BEGIN_OPCODE(NOT_NEWLINE):
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN_NO_MATCH;
- if (isNewline(*stack.currentFrame->args.subjectPtr++))
- RRETURN_NO_MATCH;
- stack.currentFrame->args.instructionPtr++;
- NEXT_OPCODE;
-
- BEGIN_OPCODE(NOT_DIGIT):
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN_NO_MATCH;
- if (isASCIIDigit(*stack.currentFrame->args.subjectPtr++))
- RRETURN_NO_MATCH;
- stack.currentFrame->args.instructionPtr++;
- NEXT_OPCODE;
-
- BEGIN_OPCODE(DIGIT):
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN_NO_MATCH;
- if (!isASCIIDigit(*stack.currentFrame->args.subjectPtr++))
- RRETURN_NO_MATCH;
- stack.currentFrame->args.instructionPtr++;
- NEXT_OPCODE;
-
- BEGIN_OPCODE(NOT_WHITESPACE):
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN_NO_MATCH;
- if (isSpaceChar(*stack.currentFrame->args.subjectPtr++))
- RRETURN_NO_MATCH;
- stack.currentFrame->args.instructionPtr++;
- NEXT_OPCODE;
-
- BEGIN_OPCODE(WHITESPACE):
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN_NO_MATCH;
- if (!isSpaceChar(*stack.currentFrame->args.subjectPtr++))
- RRETURN_NO_MATCH;
- stack.currentFrame->args.instructionPtr++;
- NEXT_OPCODE;
-
- BEGIN_OPCODE(NOT_WORDCHAR):
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN_NO_MATCH;
- if (isWordChar(*stack.currentFrame->args.subjectPtr++))
- RRETURN_NO_MATCH;
- stack.currentFrame->args.instructionPtr++;
- NEXT_OPCODE;
-
- BEGIN_OPCODE(WORDCHAR):
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN_NO_MATCH;
- if (!isWordChar(*stack.currentFrame->args.subjectPtr++))
- RRETURN_NO_MATCH;
- stack.currentFrame->args.instructionPtr++;
- NEXT_OPCODE;
-
- /* Match a back reference, possibly repeatedly. Look past the end of the
- item to see if there is repeat information following. The code is similar
- to that for character classes, but repeated for efficiency. Then obey
- similar code to character type repeats - written out again for speed.
- However, if the referenced string is the empty string, always treat
- it as matched, any number of times (otherwise there could be infinite
- loops). */
-
- BEGIN_OPCODE(REF):
- stack.currentFrame->locals.offset = get2ByteValue(stack.currentFrame->args.instructionPtr + 1) << 1; /* Doubled ref number */
- stack.currentFrame->args.instructionPtr += 3; /* Advance past item */
-
- /* If the reference is unset, set the length to be longer than the amount
- of subject left; this ensures that every attempt at a match fails. We
- can't just fail here, because of the possibility of quantifiers with zero
- minima. */
-
- if (stack.currentFrame->locals.offset >= stack.currentFrame->args.offsetTop || md.offsetVector[stack.currentFrame->locals.offset] < 0)
- stack.currentFrame->locals.length = 0;
- else
- stack.currentFrame->locals.length = md.offsetVector[stack.currentFrame->locals.offset+1] - md.offsetVector[stack.currentFrame->locals.offset];
-
- /* Set up for repetition, or handle the non-repeated case */
-
- switch (*stack.currentFrame->args.instructionPtr) {
- case OP_CRSTAR:
- case OP_CRMINSTAR:
- case OP_CRPLUS:
- case OP_CRMINPLUS:
- case OP_CRQUERY:
- case OP_CRMINQUERY:
- repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_CRSTAR, minimize, min, stack.currentFrame->locals.max);
- break;
-
- case OP_CRRANGE:
- case OP_CRMINRANGE:
- minimize = (*stack.currentFrame->args.instructionPtr == OP_CRMINRANGE);
- min = get2ByteValue(stack.currentFrame->args.instructionPtr + 1);
- stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 3);
- if (stack.currentFrame->locals.max == 0)
- stack.currentFrame->locals.max = INT_MAX;
- stack.currentFrame->args.instructionPtr += 5;
- break;
-
- default: /* No repeat follows */
- if (!matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md))
- RRETURN_NO_MATCH;
- stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length;
- NEXT_OPCODE;
- }
-
- /* If the length of the reference is zero, just continue with the
- main loop. */
-
- if (stack.currentFrame->locals.length == 0)
- NEXT_OPCODE;
-
- /* First, ensure the minimum number of matches are present. */
-
- for (int i = 1; i <= min; i++) {
- if (!matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md))
- RRETURN_NO_MATCH;
- stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length;
- }
-
- /* If min = max, continue at the same level without recursion.
- They are not both allowed to be zero. */
-
- if (min == stack.currentFrame->locals.max)
- NEXT_OPCODE;
-
- /* If minimizing, keep trying and advancing the pointer */
-
- if (minimize) {
- for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) {
- RECURSIVE_MATCH(20, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || !matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md))
- RRETURN;
- stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length;
- }
- /* Control never reaches here */
- }
-
- /* If maximizing, find the longest string and work backwards */
-
- else {
- stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr;
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (!matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md))
- break;
- stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length;
- }
- while (stack.currentFrame->args.subjectPtr >= stack.currentFrame->locals.subjectPtrAtStartOfInstruction) {
- RECURSIVE_MATCH(21, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- stack.currentFrame->args.subjectPtr -= stack.currentFrame->locals.length;
- }
- RRETURN_NO_MATCH;
- }
- /* Control never reaches here */
-
- /* Match a bit-mapped character class, possibly repeatedly. This op code is
- used when all the characters in the class have values in the range 0-255,
- and either the matching is caseful, or the characters are in the range
- 0-127 when UTF-8 processing is enabled. The only difference between
- OP_CLASS and OP_NCLASS occurs when a data character outside the range is
- encountered.
-
- First, look past the end of the item to see if there is repeat information
- following. Then obey similar code to character type repeats - written out
- again for speed. */
-
- BEGIN_OPCODE(NCLASS):
- BEGIN_OPCODE(CLASS):
- stack.currentFrame->locals.data = stack.currentFrame->args.instructionPtr + 1; /* Save for matching */
- stack.currentFrame->args.instructionPtr += 33; /* Advance past the item */
-
- switch (*stack.currentFrame->args.instructionPtr) {
- case OP_CRSTAR:
- case OP_CRMINSTAR:
- case OP_CRPLUS:
- case OP_CRMINPLUS:
- case OP_CRQUERY:
- case OP_CRMINQUERY:
- repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_CRSTAR, minimize, min, stack.currentFrame->locals.max);
- break;
-
- case OP_CRRANGE:
- case OP_CRMINRANGE:
- minimize = (*stack.currentFrame->args.instructionPtr == OP_CRMINRANGE);
- min = get2ByteValue(stack.currentFrame->args.instructionPtr + 1);
- stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 3);
- if (stack.currentFrame->locals.max == 0)
- stack.currentFrame->locals.max = INT_MAX;
- stack.currentFrame->args.instructionPtr += 5;
- break;
-
- default: /* No repeat follows */
- min = stack.currentFrame->locals.max = 1;
- break;
- }
-
- /* First, ensure the minimum number of matches are present. */
-
- for (int i = 1; i <= min; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN_NO_MATCH;
- int c = *stack.currentFrame->args.subjectPtr++;
- if (c > 255) {
- if (stack.currentFrame->locals.data[-1] == OP_CLASS)
- RRETURN_NO_MATCH;
- } else {
- if (!(stack.currentFrame->locals.data[c / 8] & (1 << (c & 7))))
- RRETURN_NO_MATCH;
- }
- }
-
- /* If max == min we can continue with the main loop without the
- need to recurse. */
-
- if (min == stack.currentFrame->locals.max)
- NEXT_OPCODE;
-
- /* If minimizing, keep testing the rest of the expression and advancing
- the pointer while it matches the class. */
- if (minimize) {
- for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) {
- RECURSIVE_MATCH(22, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN;
- int c = *stack.currentFrame->args.subjectPtr++;
- if (c > 255) {
- if (stack.currentFrame->locals.data[-1] == OP_CLASS)
- RRETURN;
- } else {
- if ((stack.currentFrame->locals.data[c/8] & (1 << (c&7))) == 0)
- RRETURN;
- }
- }
- /* Control never reaches here */
- }
- /* If maximizing, find the longest possible run, then work backwards. */
- else {
- stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr;
-
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- break;
- int c = *stack.currentFrame->args.subjectPtr;
- if (c > 255) {
- if (stack.currentFrame->locals.data[-1] == OP_CLASS)
- break;
- } else {
- if (!(stack.currentFrame->locals.data[c / 8] & (1 << (c & 7))))
- break;
- }
- ++stack.currentFrame->args.subjectPtr;
- }
- for (;;) {
- RECURSIVE_MATCH(24, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction)
- break; /* Stop if tried at original pos */
- }
-
- RRETURN;
- }
- /* Control never reaches here */
-
- /* Match an extended character class. */
-
- BEGIN_OPCODE(XCLASS):
- stack.currentFrame->locals.data = stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE; /* Save for matching */
- stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1); /* Advance past the item */
-
- switch (*stack.currentFrame->args.instructionPtr) {
- case OP_CRSTAR:
- case OP_CRMINSTAR:
- case OP_CRPLUS:
- case OP_CRMINPLUS:
- case OP_CRQUERY:
- case OP_CRMINQUERY:
- repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_CRSTAR, minimize, min, stack.currentFrame->locals.max);
- break;
-
- case OP_CRRANGE:
- case OP_CRMINRANGE:
- minimize = (*stack.currentFrame->args.instructionPtr == OP_CRMINRANGE);
- min = get2ByteValue(stack.currentFrame->args.instructionPtr + 1);
- stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 3);
- if (stack.currentFrame->locals.max == 0)
- stack.currentFrame->locals.max = INT_MAX;
- stack.currentFrame->args.instructionPtr += 5;
- break;
-
- default: /* No repeat follows */
- min = stack.currentFrame->locals.max = 1;
- }
-
- /* First, ensure the minimum number of matches are present. */
-
- for (int i = 1; i <= min; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN_NO_MATCH;
- int c = *stack.currentFrame->args.subjectPtr++;
- if (!jsc_pcre_xclass(c, stack.currentFrame->locals.data))
- RRETURN_NO_MATCH;
- }
-
- /* If max == min we can continue with the main loop without the
- need to recurse. */
-
- if (min == stack.currentFrame->locals.max)
- NEXT_OPCODE;
-
- /* If minimizing, keep testing the rest of the expression and advancing
- the pointer while it matches the class. */
-
- if (minimize) {
- for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) {
- RECURSIVE_MATCH(26, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN;
- int c = *stack.currentFrame->args.subjectPtr++;
- if (!jsc_pcre_xclass(c, stack.currentFrame->locals.data))
- RRETURN;
- }
- /* Control never reaches here */
- }
-
- /* If maximizing, find the longest possible run, then work backwards. */
-
- else {
- stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr;
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- break;
- int c = *stack.currentFrame->args.subjectPtr;
- if (!jsc_pcre_xclass(c, stack.currentFrame->locals.data))
- break;
- ++stack.currentFrame->args.subjectPtr;
- }
- for(;;) {
- RECURSIVE_MATCH(27, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction)
- break; /* Stop if tried at original pos */
- }
- RRETURN;
- }
-
- /* Control never reaches here */
-
- /* Match a single character, casefully */
-
- BEGIN_OPCODE(CHAR):
- stack.currentFrame->locals.length = 1;
- stack.currentFrame->args.instructionPtr++;
- getUTF8CharAndIncrementLength(stack.currentFrame->locals.fc, stack.currentFrame->args.instructionPtr, stack.currentFrame->locals.length);
- stack.currentFrame->args.instructionPtr += stack.currentFrame->locals.length;
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN_NO_MATCH;
- if (stack.currentFrame->locals.fc != *stack.currentFrame->args.subjectPtr++)
- RRETURN_NO_MATCH;
- NEXT_OPCODE;
-
- /* Match a single character, caselessly */
-
- BEGIN_OPCODE(CHAR_IGNORING_CASE): {
- stack.currentFrame->locals.length = 1;
- stack.currentFrame->args.instructionPtr++;
- getUTF8CharAndIncrementLength(stack.currentFrame->locals.fc, stack.currentFrame->args.instructionPtr, stack.currentFrame->locals.length);
- stack.currentFrame->args.instructionPtr += stack.currentFrame->locals.length;
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN_NO_MATCH;
- int dc = *stack.currentFrame->args.subjectPtr++;
- if (stack.currentFrame->locals.fc != dc && jsc_pcre_ucp_othercase(stack.currentFrame->locals.fc) != dc)
- RRETURN_NO_MATCH;
- NEXT_OPCODE;
- }
-
- /* Match a single ASCII character. */
-
- BEGIN_OPCODE(ASCII_CHAR):
- if (md.endSubject == stack.currentFrame->args.subjectPtr)
- RRETURN_NO_MATCH;
- if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->args.instructionPtr[1])
- RRETURN_NO_MATCH;
- ++stack.currentFrame->args.subjectPtr;
- stack.currentFrame->args.instructionPtr += 2;
- NEXT_OPCODE;
-
- /* Match one of two cases of an ASCII letter. */
-
- BEGIN_OPCODE(ASCII_LETTER_IGNORING_CASE):
- if (md.endSubject == stack.currentFrame->args.subjectPtr)
- RRETURN_NO_MATCH;
- if ((*stack.currentFrame->args.subjectPtr | 0x20) != stack.currentFrame->args.instructionPtr[1])
- RRETURN_NO_MATCH;
- ++stack.currentFrame->args.subjectPtr;
- stack.currentFrame->args.instructionPtr += 2;
- NEXT_OPCODE;
-
- /* Match a single character repeatedly; different opcodes share code. */
-
- BEGIN_OPCODE(EXACT):
- min = stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1);
- minimize = false;
- stack.currentFrame->args.instructionPtr += 3;
- goto REPEATCHAR;
-
- BEGIN_OPCODE(UPTO):
- BEGIN_OPCODE(MINUPTO):
- min = 0;
- stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1);
- minimize = *stack.currentFrame->args.instructionPtr == OP_MINUPTO;
- stack.currentFrame->args.instructionPtr += 3;
- goto REPEATCHAR;
-
- BEGIN_OPCODE(STAR):
- BEGIN_OPCODE(MINSTAR):
- BEGIN_OPCODE(PLUS):
- BEGIN_OPCODE(MINPLUS):
- BEGIN_OPCODE(QUERY):
- BEGIN_OPCODE(MINQUERY):
- repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_STAR, minimize, min, stack.currentFrame->locals.max);
-
- /* Common code for all repeated single-character matches. We can give
- up quickly if there are fewer than the minimum number of characters left in
- the subject. */
-
- REPEATCHAR:
-
- stack.currentFrame->locals.length = 1;
- getUTF8CharAndIncrementLength(stack.currentFrame->locals.fc, stack.currentFrame->args.instructionPtr, stack.currentFrame->locals.length);
- if (min * (stack.currentFrame->locals.fc > 0xFFFF ? 2 : 1) > md.endSubject - stack.currentFrame->args.subjectPtr)
- RRETURN_NO_MATCH;
- stack.currentFrame->args.instructionPtr += stack.currentFrame->locals.length;
-
- if (stack.currentFrame->locals.fc <= 0xFFFF) {
- othercase = md.ignoreCase ? jsc_pcre_ucp_othercase(stack.currentFrame->locals.fc) : -1;
-
- for (int i = 1; i <= min; i++) {
- if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc && *stack.currentFrame->args.subjectPtr != othercase)
- RRETURN_NO_MATCH;
- ++stack.currentFrame->args.subjectPtr;
- }
-
- if (min == stack.currentFrame->locals.max)
- NEXT_OPCODE;
-
- if (minimize) {
- stack.currentFrame->locals.repeatOthercase = othercase;
- for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) {
- RECURSIVE_MATCH(28, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN;
- if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc && *stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.repeatOthercase)
- RRETURN;
- ++stack.currentFrame->args.subjectPtr;
- }
- /* Control never reaches here */
- } else {
- stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr;
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- break;
- if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc && *stack.currentFrame->args.subjectPtr != othercase)
- break;
- ++stack.currentFrame->args.subjectPtr;
- }
- while (stack.currentFrame->args.subjectPtr >= stack.currentFrame->locals.subjectPtrAtStartOfInstruction) {
- RECURSIVE_MATCH(29, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- --stack.currentFrame->args.subjectPtr;
- }
- RRETURN_NO_MATCH;
- }
- /* Control never reaches here */
- } else {
- /* No case on surrogate pairs, so no need to bother with "othercase". */
-
- for (int i = 1; i <= min; i++) {
- if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc)
- RRETURN_NO_MATCH;
- stack.currentFrame->args.subjectPtr += 2;
- }
-
- if (min == stack.currentFrame->locals.max)
- NEXT_OPCODE;
-
- if (minimize) {
- for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) {
- RECURSIVE_MATCH(30, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN;
- if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc)
- RRETURN;
- stack.currentFrame->args.subjectPtr += 2;
- }
- /* Control never reaches here */
- } else {
- stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr;
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (stack.currentFrame->args.subjectPtr > md.endSubject - 2)
- break;
- if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc)
- break;
- stack.currentFrame->args.subjectPtr += 2;
- }
- while (stack.currentFrame->args.subjectPtr >= stack.currentFrame->locals.subjectPtrAtStartOfInstruction) {
- RECURSIVE_MATCH(31, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- stack.currentFrame->args.subjectPtr -= 2;
- }
- RRETURN_NO_MATCH;
- }
- /* Control never reaches here */
- }
- /* Control never reaches here */
-
- /* Match a negated single one-byte character. */
-
- BEGIN_OPCODE(NOT): {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN_NO_MATCH;
- int b = stack.currentFrame->args.instructionPtr[1];
- int c = *stack.currentFrame->args.subjectPtr++;
- stack.currentFrame->args.instructionPtr += 2;
- if (md.ignoreCase) {
- if (c < 128)
- c = toLowerCase(c);
- if (toLowerCase(b) == c)
- RRETURN_NO_MATCH;
- } else {
- if (b == c)
- RRETURN_NO_MATCH;
- }
- NEXT_OPCODE;
- }
-
- /* Match a negated single one-byte character repeatedly. This is almost a
- repeat of the code for a repeated single character, but I haven't found a
- nice way of commoning these up that doesn't require a test of the
- positive/negative option for each character match. Maybe that wouldn't add
- very much to the time taken, but character matching *is* what this is all
- about... */
-
- BEGIN_OPCODE(NOTEXACT):
- min = stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1);
- minimize = false;
- stack.currentFrame->args.instructionPtr += 3;
- goto REPEATNOTCHAR;
-
- BEGIN_OPCODE(NOTUPTO):
- BEGIN_OPCODE(NOTMINUPTO):
- min = 0;
- stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1);
- minimize = *stack.currentFrame->args.instructionPtr == OP_NOTMINUPTO;
- stack.currentFrame->args.instructionPtr += 3;
- goto REPEATNOTCHAR;
-
- BEGIN_OPCODE(NOTSTAR):
- BEGIN_OPCODE(NOTMINSTAR):
- BEGIN_OPCODE(NOTPLUS):
- BEGIN_OPCODE(NOTMINPLUS):
- BEGIN_OPCODE(NOTQUERY):
- BEGIN_OPCODE(NOTMINQUERY):
- repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_NOTSTAR, minimize, min, stack.currentFrame->locals.max);
-
- /* Common code for all repeated single-byte matches. We can give up quickly
- if there are fewer than the minimum number of bytes left in the
- subject. */
-
- REPEATNOTCHAR:
- if (min > md.endSubject - stack.currentFrame->args.subjectPtr)
- RRETURN_NO_MATCH;
- stack.currentFrame->locals.fc = *stack.currentFrame->args.instructionPtr++;
-
- /* The code is duplicated for the caseless and caseful cases, for speed,
- since matching characters is likely to be quite common. First, ensure the
- minimum number of matches are present. If min = max, continue at the same
- level without recursing. Otherwise, if minimizing, keep trying the rest of
- the expression and advancing one matching character if failing, up to the
- maximum. Alternatively, if maximizing, find the maximum number of
- characters and work backwards. */
-
- DPRINTF(("negative matching %c{%d,%d}\n", stack.currentFrame->locals.fc, min, stack.currentFrame->locals.max));
-
- if (md.ignoreCase) {
- if (stack.currentFrame->locals.fc < 128)
- stack.currentFrame->locals.fc = toLowerCase(stack.currentFrame->locals.fc);
-
- for (int i = 1; i <= min; i++) {
- int d = *stack.currentFrame->args.subjectPtr++;
- if (d < 128)
- d = toLowerCase(d);
- if (stack.currentFrame->locals.fc == d)
- RRETURN_NO_MATCH;
- }
-
- if (min == stack.currentFrame->locals.max)
- NEXT_OPCODE;
-
- if (minimize) {
- for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) {
- RECURSIVE_MATCH(38, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- int d = *stack.currentFrame->args.subjectPtr++;
- if (d < 128)
- d = toLowerCase(d);
- if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject || stack.currentFrame->locals.fc == d)
- RRETURN;
- }
- /* Control never reaches here */
- }
-
- /* Maximize case */
-
- else {
- stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr;
-
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- break;
- int d = *stack.currentFrame->args.subjectPtr;
- if (d < 128)
- d = toLowerCase(d);
- if (stack.currentFrame->locals.fc == d)
- break;
- ++stack.currentFrame->args.subjectPtr;
- }
- for (;;) {
- RECURSIVE_MATCH(40, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction)
- break; /* Stop if tried at original pos */
- }
-
- RRETURN;
- }
- /* Control never reaches here */
- }
-
- /* Caseful comparisons */
-
- else {
- for (int i = 1; i <= min; i++) {
- int d = *stack.currentFrame->args.subjectPtr++;
- if (stack.currentFrame->locals.fc == d)
- RRETURN_NO_MATCH;
- }
-
- if (min == stack.currentFrame->locals.max)
- NEXT_OPCODE;
-
- if (minimize) {
- for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) {
- RECURSIVE_MATCH(42, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- int d = *stack.currentFrame->args.subjectPtr++;
- if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject || stack.currentFrame->locals.fc == d)
- RRETURN;
- }
- /* Control never reaches here */
- }
-
- /* Maximize case */
-
- else {
- stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr;
-
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- break;
- int d = *stack.currentFrame->args.subjectPtr;
- if (stack.currentFrame->locals.fc == d)
- break;
- ++stack.currentFrame->args.subjectPtr;
- }
- for (;;) {
- RECURSIVE_MATCH(44, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction)
- break; /* Stop if tried at original pos */
- }
-
- RRETURN;
- }
- }
- /* Control never reaches here */
-
- /* Match a single character type repeatedly; several different opcodes
- share code. This is very similar to the code for single characters, but we
- repeat it in the interests of efficiency. */
-
- BEGIN_OPCODE(TYPEEXACT):
- min = stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1);
- minimize = true;
- stack.currentFrame->args.instructionPtr += 3;
- goto REPEATTYPE;
-
- BEGIN_OPCODE(TYPEUPTO):
- BEGIN_OPCODE(TYPEMINUPTO):
- min = 0;
- stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1);
- minimize = *stack.currentFrame->args.instructionPtr == OP_TYPEMINUPTO;
- stack.currentFrame->args.instructionPtr += 3;
- goto REPEATTYPE;
-
- BEGIN_OPCODE(TYPESTAR):
- BEGIN_OPCODE(TYPEMINSTAR):
- BEGIN_OPCODE(TYPEPLUS):
- BEGIN_OPCODE(TYPEMINPLUS):
- BEGIN_OPCODE(TYPEQUERY):
- BEGIN_OPCODE(TYPEMINQUERY):
- repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_TYPESTAR, minimize, min, stack.currentFrame->locals.max);
-
- /* Common code for all repeated single character type matches. Note that
- in UTF-8 mode, '.' matches a character of any length, but for the other
- character types, the valid characters are all one-byte long. */
-
- REPEATTYPE:
- stack.currentFrame->locals.ctype = *stack.currentFrame->args.instructionPtr++; /* Code for the character type */
-
- /* First, ensure the minimum number of matches are present. Use inline
- code for maximizing the speed, and do the type test once at the start
- (i.e. keep it out of the loop). Also we can test that there are at least
- the minimum number of characters before we start. */
-
- if (min > md.endSubject - stack.currentFrame->args.subjectPtr)
- RRETURN_NO_MATCH;
- if (min > 0) {
- switch (stack.currentFrame->locals.ctype) {
- case OP_NOT_NEWLINE:
- for (int i = 1; i <= min; i++) {
- if (isNewline(*stack.currentFrame->args.subjectPtr))
- RRETURN_NO_MATCH;
- ++stack.currentFrame->args.subjectPtr;
- }
- break;
-
- case OP_NOT_DIGIT:
- for (int i = 1; i <= min; i++) {
- if (isASCIIDigit(*stack.currentFrame->args.subjectPtr))
- RRETURN_NO_MATCH;
- ++stack.currentFrame->args.subjectPtr;
- }
- break;
-
- case OP_DIGIT:
- for (int i = 1; i <= min; i++) {
- if (!isASCIIDigit(*stack.currentFrame->args.subjectPtr))
- RRETURN_NO_MATCH;
- ++stack.currentFrame->args.subjectPtr;
- }
- break;
-
- case OP_NOT_WHITESPACE:
- for (int i = 1; i <= min; i++) {
- if (isSpaceChar(*stack.currentFrame->args.subjectPtr))
- RRETURN_NO_MATCH;
- ++stack.currentFrame->args.subjectPtr;
- }
- break;
-
- case OP_WHITESPACE:
- for (int i = 1; i <= min; i++) {
- if (!isSpaceChar(*stack.currentFrame->args.subjectPtr))
- RRETURN_NO_MATCH;
- ++stack.currentFrame->args.subjectPtr;
- }
- break;
-
- case OP_NOT_WORDCHAR:
- for (int i = 1; i <= min; i++) {
- if (isWordChar(*stack.currentFrame->args.subjectPtr))
- RRETURN_NO_MATCH;
- ++stack.currentFrame->args.subjectPtr;
- }
- break;
-
- case OP_WORDCHAR:
- for (int i = 1; i <= min; i++) {
- if (!isWordChar(*stack.currentFrame->args.subjectPtr))
- RRETURN_NO_MATCH;
- ++stack.currentFrame->args.subjectPtr;
- }
- break;
-
- default:
- ASSERT_NOT_REACHED();
- return matchError(JSRegExpErrorInternal, stack);
- } /* End switch(stack.currentFrame->locals.ctype) */
- }
-
- /* If min = max, continue at the same level without recursing */
-
- if (min == stack.currentFrame->locals.max)
- NEXT_OPCODE;
-
- /* If minimizing, we have to test the rest of the pattern before each
- subsequent match. */
-
- if (minimize) {
- for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) {
- RECURSIVE_MATCH(48, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN;
-
- int c = *stack.currentFrame->args.subjectPtr++;
- switch (stack.currentFrame->locals.ctype) {
- case OP_NOT_NEWLINE:
- if (isNewline(c))
- RRETURN;
- break;
-
- case OP_NOT_DIGIT:
- if (isASCIIDigit(c))
- RRETURN;
- break;
-
- case OP_DIGIT:
- if (!isASCIIDigit(c))
- RRETURN;
- break;
-
- case OP_NOT_WHITESPACE:
- if (isSpaceChar(c))
- RRETURN;
- break;
-
- case OP_WHITESPACE:
- if (!isSpaceChar(c))
- RRETURN;
- break;
-
- case OP_NOT_WORDCHAR:
- if (isWordChar(c))
- RRETURN;
- break;
-
- case OP_WORDCHAR:
- if (!isWordChar(c))
- RRETURN;
- break;
-
- default:
- ASSERT_NOT_REACHED();
- return matchError(JSRegExpErrorInternal, stack);
- }
- }
- /* Control never reaches here */
- }
-
- /* If maximizing it is worth using inline code for speed, doing the type
- test once at the start (i.e. keep it out of the loop). */
-
- else {
- stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; /* Remember where we started */
-
- switch (stack.currentFrame->locals.ctype) {
- case OP_NOT_NEWLINE:
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject || isNewline(*stack.currentFrame->args.subjectPtr))
- break;
- stack.currentFrame->args.subjectPtr++;
- }
- break;
-
- case OP_NOT_DIGIT:
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- break;
- int c = *stack.currentFrame->args.subjectPtr;
- if (isASCIIDigit(c))
- break;
- ++stack.currentFrame->args.subjectPtr;
- }
- break;
-
- case OP_DIGIT:
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- break;
- int c = *stack.currentFrame->args.subjectPtr;
- if (!isASCIIDigit(c))
- break;
- ++stack.currentFrame->args.subjectPtr;
- }
- break;
-
- case OP_NOT_WHITESPACE:
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- break;
- int c = *stack.currentFrame->args.subjectPtr;
- if (isSpaceChar(c))
- break;
- ++stack.currentFrame->args.subjectPtr;
- }
- break;
-
- case OP_WHITESPACE:
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- break;
- int c = *stack.currentFrame->args.subjectPtr;
- if (!isSpaceChar(c))
- break;
- ++stack.currentFrame->args.subjectPtr;
- }
- break;
-
- case OP_NOT_WORDCHAR:
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- break;
- int c = *stack.currentFrame->args.subjectPtr;
- if (isWordChar(c))
- break;
- ++stack.currentFrame->args.subjectPtr;
- }
- break;
-
- case OP_WORDCHAR:
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- break;
- int c = *stack.currentFrame->args.subjectPtr;
- if (!isWordChar(c))
- break;
- ++stack.currentFrame->args.subjectPtr;
- }
- break;
-
- default:
- ASSERT_NOT_REACHED();
- return matchError(JSRegExpErrorInternal, stack);
- }
-
- /* stack.currentFrame->args.subjectPtr is now past the end of the maximum run */
-
- for (;;) {
- RECURSIVE_MATCH(52, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction)
- break; /* Stop if tried at original pos */
- }
-
- /* Get here if we can't make it match with any permitted repetitions */
-
- RRETURN;
- }
- /* Control never reaches here */
-
- BEGIN_OPCODE(CRMINPLUS):
- BEGIN_OPCODE(CRMINQUERY):
- BEGIN_OPCODE(CRMINRANGE):
- BEGIN_OPCODE(CRMINSTAR):
- BEGIN_OPCODE(CRPLUS):
- BEGIN_OPCODE(CRQUERY):
- BEGIN_OPCODE(CRRANGE):
- BEGIN_OPCODE(CRSTAR):
- ASSERT_NOT_REACHED();
- return matchError(JSRegExpErrorInternal, stack);
-
-#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP
- CAPTURING_BRACKET:
-#else
- default:
-#endif
- /* Opening capturing bracket. If there is space in the offset vector, save
- the current subject position in the working slot at the top of the vector. We
- mustn't change the current values of the data slot, because they may be set
- from a previous iteration of this group, and be referred to by a reference
- inside the group.
-
- If the bracket fails to match, we need to restore this value and also the
- values of the final offsets, in case they were set by a previous iteration of
- the same bracket.
-
- If there isn't enough space in the offset vector, treat this as if it were a
- non-capturing bracket. Don't worry about setting the flag for the error case
- here; that is handled in the code for KET. */
-
- ASSERT(*stack.currentFrame->args.instructionPtr > OP_BRA);
-
- stack.currentFrame->locals.number = *stack.currentFrame->args.instructionPtr - OP_BRA;
-
- /* For extended extraction brackets (large number), we have to fish out the
- number from a dummy opcode at the start. */
-
- if (stack.currentFrame->locals.number > EXTRACT_BASIC_MAX)
- stack.currentFrame->locals.number = get2ByteValue(stack.currentFrame->args.instructionPtr + 2 + LINK_SIZE);
- stack.currentFrame->locals.offset = stack.currentFrame->locals.number << 1;
-
-#ifdef DEBUG
- printf("start bracket %d subject=", stack.currentFrame->locals.number);
- pchars(stack.currentFrame->args.subjectPtr, 16, true, md);
- printf("\n");
-#endif
-
- if (stack.currentFrame->locals.offset < md.offsetMax) {
- stack.currentFrame->locals.saveOffset1 = md.offsetVector[stack.currentFrame->locals.offset];
- stack.currentFrame->locals.saveOffset2 = md.offsetVector[stack.currentFrame->locals.offset + 1];
- stack.currentFrame->locals.saveOffset3 = md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number];
-
- DPRINTF(("saving %d %d %d\n", stack.currentFrame->locals.saveOffset1, stack.currentFrame->locals.saveOffset2, stack.currentFrame->locals.saveOffset3));
- md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number] = stack.currentFrame->args.subjectPtr - md.startSubject;
-
- do {
- RECURSIVE_MATCH_NEW_GROUP(1, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1);
- } while (*stack.currentFrame->args.instructionPtr == OP_ALT);
-
- DPRINTF(("bracket %d failed\n", stack.currentFrame->locals.number));
-
- md.offsetVector[stack.currentFrame->locals.offset] = stack.currentFrame->locals.saveOffset1;
- md.offsetVector[stack.currentFrame->locals.offset + 1] = stack.currentFrame->locals.saveOffset2;
- md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number] = stack.currentFrame->locals.saveOffset3;
-
- RRETURN;
- }
-
- /* Insufficient room for saving captured contents */
-
- goto NON_CAPTURING_BRACKET;
- }
-
- /* Do not stick any code in here without much thought; it is assumed
- that "continue" in the code above comes out to here to repeat the main
- loop. */
-
- } /* End of main loop */
-
- ASSERT_NOT_REACHED();
-
-#ifndef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION
-
-RRETURN_SWITCH:
- switch (stack.currentFrame->returnLocation) {
- case 0: goto RETURN;
- case 1: goto RRETURN_1;
- case 2: goto RRETURN_2;
- case 6: goto RRETURN_6;
- case 7: goto RRETURN_7;
- case 14: goto RRETURN_14;
- case 15: goto RRETURN_15;
- case 16: goto RRETURN_16;
- case 17: goto RRETURN_17;
- case 18: goto RRETURN_18;
- case 19: goto RRETURN_19;
- case 20: goto RRETURN_20;
- case 21: goto RRETURN_21;
- case 22: goto RRETURN_22;
- case 24: goto RRETURN_24;
- case 26: goto RRETURN_26;
- case 27: goto RRETURN_27;
- case 28: goto RRETURN_28;
- case 29: goto RRETURN_29;
- case 30: goto RRETURN_30;
- case 31: goto RRETURN_31;
- case 38: goto RRETURN_38;
- case 40: goto RRETURN_40;
- case 42: goto RRETURN_42;
- case 44: goto RRETURN_44;
- case 48: goto RRETURN_48;
- case 52: goto RRETURN_52;
- }
-
- ASSERT_NOT_REACHED();
- return matchError(JSRegExpErrorInternal, stack);
-
-#endif
-
-RETURN:
- return isMatch;
-}
-
-
-/*************************************************
-* Execute a Regular Expression *
-*************************************************/
-
-/* This function applies a compiled re to a subject string and picks out
-portions of the string if it matches. Two elements in the vector are set for
-each substring: the offsets to the start and end of the substring.
-
-Arguments:
- re points to the compiled expression
- extra_data points to extra data or is NULL
- subject points to the subject string
- length length of subject string (may contain binary zeros)
- start_offset where to start in the subject string
- options option bits
- offsets points to a vector of ints to be filled in with offsets
- offsetCount the number of elements in the vector
-
-Returns: > 0 => success; value is the number of elements filled in
- = 0 => success, but offsets is not big enough
- -1 => failed to match
- < -1 => some kind of unexpected problem
-*/
-
-static void tryFirstByteOptimization(const UChar*& subjectPtr, const UChar* endSubject, int firstByte, bool firstByteIsCaseless, bool useMultiLineFirstCharOptimization, const UChar* originalSubjectStart)
-{
- // If firstByte is set, try scanning to the first instance of that byte
- // no need to try and match against any earlier part of the subject string.
- if (firstByte >= 0) {
- UChar firstChar = firstByte;
- if (firstByteIsCaseless)
- while (subjectPtr < endSubject) {
- int c = *subjectPtr;
- if (c > 127)
- break;
- if (toLowerCase(c) == firstChar)
- break;
- subjectPtr++;
- }
- else {
- while (subjectPtr < endSubject && *subjectPtr != firstChar)
- subjectPtr++;
- }
- } else if (useMultiLineFirstCharOptimization) {
- /* Or to just after \n for a multiline match if possible */
- // I'm not sure why this != originalSubjectStart check is necessary -- ecs 11/18/07
- if (subjectPtr > originalSubjectStart) {
- while (subjectPtr < endSubject && !isNewline(subjectPtr[-1]))
- subjectPtr++;
- }
- }
-}
-
-static bool tryRequiredByteOptimization(const UChar*& subjectPtr, const UChar* endSubject, int reqByte, int reqByte2, bool reqByteIsCaseless, bool hasFirstByte, const UChar*& reqBytePtr)
-{
- /* If reqByte is set, we know that that character must appear in the subject
- for the match to succeed. If the first character is set, reqByte must be
- later in the subject; otherwise the test starts at the match point. This
- optimization can save a huge amount of backtracking in patterns with nested
- unlimited repeats that aren't going to match. Writing separate code for
- cased/caseless versions makes it go faster, as does using an autoincrement
- and backing off on a match.
-
- HOWEVER: when the subject string is very, very long, searching to its end can
- take a long time, and give bad performance on quite ordinary patterns. This
- showed up when somebody was matching /^C/ on a 32-megabyte string... so we
- don't do this when the string is sufficiently long.
- */
-
- if (reqByte >= 0 && endSubject - subjectPtr < REQ_BYTE_MAX) {
- const UChar* p = subjectPtr + (hasFirstByte ? 1 : 0);
-
- /* We don't need to repeat the search if we haven't yet reached the
- place we found it at last time. */
-
- if (p > reqBytePtr) {
- if (reqByteIsCaseless) {
- while (p < endSubject) {
- int pp = *p++;
- if (pp == reqByte || pp == reqByte2) {
- p--;
- break;
- }
- }
- } else {
- while (p < endSubject) {
- if (*p++ == reqByte) {
- p--;
- break;
- }
- }
- }
-
- /* If we can't find the required character, break the matching loop */
-
- if (p >= endSubject)
- return true;
-
- /* If we have found the required character, save the point where we
- found it, so that we don't search again next time round the loop if
- the start hasn't passed this character yet. */
-
- reqBytePtr = p;
- }
- }
- return false;
-}
-
-int jsRegExpExecute(const JSRegExp* re,
- const UChar* subject, int length, int start_offset, int* offsets,
- int offsetCount)
-{
- ASSERT(re);
- ASSERT(subject || !length);
- ASSERT(offsetCount >= 0);
- ASSERT(offsets || offsetCount == 0);
-
- HistogramTimeLogger logger(re);
-
- MatchData matchBlock;
- matchBlock.startSubject = subject;
- matchBlock.endSubject = matchBlock.startSubject + length;
- const UChar* endSubject = matchBlock.endSubject;
-
- matchBlock.multiline = (re->options & MatchAcrossMultipleLinesOption);
- matchBlock.ignoreCase = (re->options & IgnoreCaseOption);
-
- /* If the expression has got more back references than the offsets supplied can
- hold, we get a temporary chunk of working store to use during the matching.
- Otherwise, we can use the vector supplied, rounding down its size to a multiple
- of 3. */
-
- int ocount = offsetCount - (offsetCount % 3);
-
- // FIXME: This is lame that we have to second-guess our caller here.
- // The API should change to either fail-hard when we don't have enough offset space
- // or that we shouldn't ask our callers to pre-allocate in the first place.
- bool usingTemporaryOffsets = false;
- if (re->topBackref > 0 && re->topBackref >= ocount/3) {
- ocount = re->topBackref * 3 + 3;
- matchBlock.offsetVector = new int[ocount];
- if (!matchBlock.offsetVector)
- return JSRegExpErrorNoMemory;
- usingTemporaryOffsets = true;
- } else
- matchBlock.offsetVector = offsets;
-
- matchBlock.offsetEnd = ocount;
- matchBlock.offsetMax = (2*ocount)/3;
- matchBlock.offsetOverflow = false;
-
- /* Compute the minimum number of offsets that we need to reset each time. Doing
- this makes a huge difference to execution time when there aren't many brackets
- in the pattern. */
-
- int resetCount = 2 + re->topBracket * 2;
- if (resetCount > offsetCount)
- resetCount = ocount;
-
- /* Reset the working variable associated with each extraction. These should
- never be used unless previously set, but they get saved and restored, and so we
- initialize them to avoid reading uninitialized locations. */
-
- if (matchBlock.offsetVector) {
- int* iptr = matchBlock.offsetVector + ocount;
- int* iend = iptr - resetCount/2 + 1;
- while (--iptr >= iend)
- *iptr = -1;
- }
-
- /* Set up the first character to match, if available. The firstByte value is
- never set for an anchored regular expression, but the anchoring may be forced
- at run time, so we have to test for anchoring. The first char may be unset for
- an unanchored pattern, of course. If there's no first char and the pattern was
- studied, there may be a bitmap of possible first characters. */
-
- bool firstByteIsCaseless = false;
- int firstByte = -1;
- if (re->options & UseFirstByteOptimizationOption) {
- firstByte = re->firstByte & 255;
- if ((firstByteIsCaseless = (re->firstByte & REQ_IGNORE_CASE)))
- firstByte = toLowerCase(firstByte);
- }
-
- /* For anchored or unanchored matches, there may be a "last known required
- character" set. */
-
- bool reqByteIsCaseless = false;
- int reqByte = -1;
- int reqByte2 = -1;
- if (re->options & UseRequiredByteOptimizationOption) {
- reqByte = re->reqByte & 255; // FIXME: This optimization could be made to work for UTF16 chars as well...
- reqByteIsCaseless = (re->reqByte & REQ_IGNORE_CASE);
- reqByte2 = flipCase(reqByte);
- }
-
- /* Loop for handling unanchored repeated matching attempts; for anchored regexs
- the loop runs just once. */
-
- const UChar* startMatch = subject + start_offset;
- const UChar* reqBytePtr = startMatch - 1;
- bool useMultiLineFirstCharOptimization = re->options & UseMultiLineFirstByteOptimizationOption;
-
- do {
- /* Reset the maximum number of extractions we might see. */
- if (matchBlock.offsetVector) {
- int* iptr = matchBlock.offsetVector;
- int* iend = iptr + resetCount;
- while (iptr < iend)
- *iptr++ = -1;
- }
-
- tryFirstByteOptimization(startMatch, endSubject, firstByte, firstByteIsCaseless, useMultiLineFirstCharOptimization, matchBlock.startSubject + start_offset);
- if (tryRequiredByteOptimization(startMatch, endSubject, reqByte, reqByte2, reqByteIsCaseless, firstByte >= 0, reqBytePtr))
- break;
-
- /* When a match occurs, substrings will be set for all internal extractions;
- we just need to set up the whole thing as substring 0 before returning. If
- there were too many extractions, set the return code to zero. In the case
- where we had to get some local store to hold offsets for backreferences, copy
- those back references that we can. In this case there need not be overflow
- if certain parts of the pattern were not used. */
-
- /* The code starts after the JSRegExp block and the capture name table. */
- const unsigned char* start_code = (const unsigned char*)(re + 1);
-
- int returnCode = match(startMatch, start_code, 2, matchBlock);
-
- /* When the result is no match, advance the pointer to the next character
- and continue. */
- if (returnCode == 0) {
- startMatch++;
- continue;
- }
-
- if (returnCode != 1) {
- ASSERT(returnCode == JSRegExpErrorHitLimit || returnCode == JSRegExpErrorNoMemory);
- DPRINTF((">>>> error: returning %d\n", returnCode));
- return returnCode;
- }
-
- /* We have a match! Copy the offset information from temporary store if
- necessary */
-
- if (usingTemporaryOffsets) {
- if (offsetCount >= 4) {
- memcpy(offsets + 2, matchBlock.offsetVector + 2, (offsetCount - 2) * sizeof(int));
- DPRINTF(("Copied offsets from temporary memory\n"));
- }
- if (matchBlock.endOffsetTop > offsetCount)
- matchBlock.offsetOverflow = true;
-
- DPRINTF(("Freeing temporary memory\n"));
- delete [] matchBlock.offsetVector;
- }
-
- returnCode = matchBlock.offsetOverflow ? 0 : matchBlock.endOffsetTop / 2;
-
- if (offsetCount < 2)
- returnCode = 0;
- else {
- offsets[0] = startMatch - matchBlock.startSubject;
- offsets[1] = matchBlock.endMatchPtr - matchBlock.startSubject;
- }
-
- DPRINTF((">>>> returning %d\n", returnCode));
- return returnCode;
- } while (!(re->options & IsAnchoredOption) && startMatch <= endSubject);
-
- if (usingTemporaryOffsets) {
- DPRINTF(("Freeing temporary memory\n"));
- delete [] matchBlock.offsetVector;
- }
-
- DPRINTF((">>>> returning PCRE_ERROR_NOMATCH\n"));
- return JSRegExpErrorNoMatch;
-}
-
-#if REGEXP_HISTOGRAM
-
-class CompareHistogramEntries {
-public:
- bool operator()(const pair<UString, double>& a, const pair<UString, double>& b)
- {
- if (a.second == b.second)
- return a.first < b.first;
- return a.second < b.second;
- }
-};
-
-Histogram::~Histogram()
-{
- Vector<pair<UString, double> > values;
- Map::iterator end = times.end();
- for (Map::iterator it = times.begin(); it != end; ++it)
- values.append(*it);
- sort(values.begin(), values.end(), CompareHistogramEntries());
- size_t size = values.size();
- printf("Regular Expressions, sorted by time spent evaluating them:\n");
- for (size_t i = 0; i < size; ++i)
- printf(" %f - %s\n", values[size - i - 1].second, values[size - i - 1].first.UTF8String().c_str());
-}
-
-void Histogram::add(const JSRegExp* re, double elapsedTime)
-{
- UString string(reinterpret_cast<const UChar*>(reinterpret_cast<const char*>(re) + re->stringOffset), re->stringLength);
- if (re->options & IgnoreCaseOption && re->options & MatchAcrossMultipleLinesOption)
- string += " (multi-line, ignore case)";
- else {
- if (re->options & IgnoreCaseOption)
- string += " (ignore case)";
- if (re->options & MatchAcrossMultipleLinesOption)
- string += " (multi-line)";
- }
- pair<Map::iterator, bool> result = times.add(string.rep(), elapsedTime);
- if (!result.second)
- result.first->second += elapsedTime;
-}
-
-HistogramTimeLogger::HistogramTimeLogger(const JSRegExp* re)
- : m_re(re)
- , m_startTime(currentTimeMS())
-{
-}
-
-HistogramTimeLogger::~HistogramTimeLogger()
-{
- static Histogram histogram;
- histogram.add(m_re, currentTimeMS() - m_startTime);
-}
-
-#endif
+++ /dev/null
-/* This is JavaScriptCore's variant of the PCRE library. While this library
-started out as a copy of PCRE, many of the features of PCRE have been
-removed. This library now supports only the regular expression features
-required by the JavaScript language specification, and has only the functions
-needed by JavaScriptCore and the rest of WebKit.
-
- Originally written by Philip Hazel
- Copyright (c) 1997-2006 University of Cambridge
- Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-/* This header contains definitions that are shared between the different
-modules, but which are not relevant to the exported API. This includes some
-functions whose names all begin with "_pcre_". */
-
-#ifndef PCRE_INTERNAL_H
-#define PCRE_INTERNAL_H
-
-/* Bit definitions for entries in the pcre_ctypes table. */
-
-#define ctype_space 0x01
-#define ctype_xdigit 0x08
-#define ctype_word 0x10 /* alphameric or '_' */
-
-/* Offsets for the bitmap tables in pcre_cbits. Each table contains a set
-of bits for a class map. Some classes are built by combining these tables. */
-
-#define cbit_space 0 /* \s */
-#define cbit_digit 32 /* \d */
-#define cbit_word 64 /* \w */
-#define cbit_length 96 /* Length of the cbits table */
-
-/* Offsets of the various tables from the base tables pointer, and
-total length. */
-
-#define lcc_offset 0
-#define fcc_offset 128
-#define cbits_offset 256
-#define ctypes_offset (cbits_offset + cbit_length)
-#define tables_length (ctypes_offset + 128)
-
-#ifndef DFTABLES
-
-// Change the following to 1 to dump used regular expressions at process exit time.
-#define REGEXP_HISTOGRAM 0
-
-#include "Assertions.h"
-
-#if COMPILER(MSVC)
-#pragma warning(disable: 4232)
-#pragma warning(disable: 4244)
-#endif
-
-#include "pcre.h"
-
-/* The value of LINK_SIZE determines the number of bytes used to store links as
-offsets within the compiled regex. The default is 2, which allows for compiled
-patterns up to 64K long. */
-
-#define LINK_SIZE 3
-
-/* Define DEBUG to get debugging output on stdout. */
-
-#if 0
-#define DEBUG
-#endif
-
-/* Use a macro for debugging printing, 'cause that eliminates the use of #ifdef
-inline, and there are *still* stupid compilers about that don't like indented
-pre-processor statements, or at least there were when I first wrote this. After
-all, it had only been about 10 years then... */
-
-#ifdef DEBUG
-#define DPRINTF(p) printf p
-#else
-#define DPRINTF(p) /*nothing*/
-#endif
-
-/* PCRE keeps offsets in its compiled code as 2-byte quantities (always stored
-in big-endian order) by default. These are used, for example, to link from the
-start of a subpattern to its alternatives and its end. The use of 2 bytes per
-offset limits the size of the compiled regex to around 64K, which is big enough
-for almost everybody. However, I received a request for an even bigger limit.
-For this reason, and also to make the code easier to maintain, the storing and
-loading of offsets from the byte string is now handled by the functions that are
-defined here. */
-
-/* PCRE uses some other 2-byte quantities that do not change when the size of
-offsets changes. There are used for repeat counts and for other things such as
-capturing parenthesis numbers in back references. */
-
-static inline void put2ByteValue(unsigned char* opcodePtr, int value)
-{
- ASSERT(value >= 0 && value <= 0xFFFF);
- opcodePtr[0] = value >> 8;
- opcodePtr[1] = value;
-}
-
-static inline void put3ByteValue(unsigned char* opcodePtr, int value)
-{
- ASSERT(value >= 0 && value <= 0xFFFFFF);
- opcodePtr[0] = value >> 16;
- opcodePtr[1] = value >> 8;
- opcodePtr[2] = value;
-}
-
-static inline int get2ByteValue(const unsigned char* opcodePtr)
-{
- return (opcodePtr[0] << 8) | opcodePtr[1];
-}
-
-static inline int get3ByteValue(const unsigned char* opcodePtr)
-{
- return (opcodePtr[0] << 16) | (opcodePtr[1] << 8) | opcodePtr[2];
-}
-
-static inline void put2ByteValueAndAdvance(unsigned char*& opcodePtr, int value)
-{
- put2ByteValue(opcodePtr, value);
- opcodePtr += 2;
-}
-
-static inline void put3ByteValueAndAdvance(unsigned char*& opcodePtr, int value)
-{
- put3ByteValue(opcodePtr, value);
- opcodePtr += 3;
-}
-
-static inline void putLinkValueAllowZero(unsigned char* opcodePtr, int value)
-{
-#if LINK_SIZE == 3
- put3ByteValue(opcodePtr, value);
-#elif LINK_SIZE == 2
- put2ByteValue(opcodePtr, value);
-#else
-# error LINK_SIZE not supported.
-#endif
-}
-
-static inline int getLinkValueAllowZero(const unsigned char* opcodePtr)
-{
-#if LINK_SIZE == 3
- return get3ByteValue(opcodePtr);
-#elif LINK_SIZE == 2
- return get2ByteValue(opcodePtr);
-#else
-# error LINK_SIZE not supported.
-#endif
-}
-
-#define MAX_PATTERN_SIZE 1024 * 1024 // Derived by empirical testing of compile time in PCRE and WREC.
-COMPILE_ASSERT(MAX_PATTERN_SIZE < (1 << (8 * LINK_SIZE)), pcre_max_pattern_fits_in_bytecode);
-
-static inline void putLinkValue(unsigned char* opcodePtr, int value)
-{
- ASSERT(value);
- putLinkValueAllowZero(opcodePtr, value);
-}
-
-static inline int getLinkValue(const unsigned char* opcodePtr)
-{
- int value = getLinkValueAllowZero(opcodePtr);
- ASSERT(value);
- return value;
-}
-
-static inline void putLinkValueAndAdvance(unsigned char*& opcodePtr, int value)
-{
- putLinkValue(opcodePtr, value);
- opcodePtr += LINK_SIZE;
-}
-
-static inline void putLinkValueAllowZeroAndAdvance(unsigned char*& opcodePtr, int value)
-{
- putLinkValueAllowZero(opcodePtr, value);
- opcodePtr += LINK_SIZE;
-}
-
-// FIXME: These are really more of a "compiled regexp state" than "regexp options"
-enum RegExpOptions {
- UseFirstByteOptimizationOption = 0x40000000, /* firstByte is set */
- UseRequiredByteOptimizationOption = 0x20000000, /* reqByte is set */
- UseMultiLineFirstByteOptimizationOption = 0x10000000, /* start after \n for multiline */
- IsAnchoredOption = 0x02000000, /* can't use partial with this regex */
- IgnoreCaseOption = 0x00000001,
- MatchAcrossMultipleLinesOption = 0x00000002
-};
-
-/* Flags added to firstByte or reqByte; a "non-literal" item is either a
-variable-length repeat, or a anything other than literal characters. */
-
-#define REQ_IGNORE_CASE 0x0100 /* indicates should ignore case */
-#define REQ_VARY 0x0200 /* reqByte followed non-literal item */
-
-/* Miscellaneous definitions */
-
-/* Flag bits and data types for the extended class (OP_XCLASS) for classes that
-contain UTF-8 characters with values greater than 255. */
-
-#define XCL_NOT 0x01 /* Flag: this is a negative class */
-#define XCL_MAP 0x02 /* Flag: a 32-byte map is present */
-
-#define XCL_END 0 /* Marks end of individual items */
-#define XCL_SINGLE 1 /* Single item (one multibyte char) follows */
-#define XCL_RANGE 2 /* A range (two multibyte chars) follows */
-
-/* These are escaped items that aren't just an encoding of a particular data
-value such as \n. They must have non-zero values, as check_escape() returns
-their negation. Also, they must appear in the same order as in the opcode
-definitions below, up to ESC_w. The final one must be
-ESC_REF as subsequent values are used for \1, \2, \3, etc. There is are two
-tests in the code for an escape > ESC_b and <= ESC_w to
-detect the types that may be repeated. These are the types that consume
-characters. If any new escapes are put in between that don't consume a
-character, that code will have to change. */
-
-enum { ESC_B = 1, ESC_b, ESC_D, ESC_d, ESC_S, ESC_s, ESC_W, ESC_w, ESC_REF };
-
-/* Opcode table: OP_BRA must be last, as all values >= it are used for brackets
-that extract substrings. Starting from 1 (i.e. after OP_END), the values up to
-OP_EOD must correspond in order to the list of escapes immediately above.
-Note that whenever this list is updated, the two macro definitions that follow
-must also be updated to match. */
-
-#define FOR_EACH_OPCODE(macro) \
- macro(END) \
- \
- macro(NOT_WORD_BOUNDARY) \
- macro(WORD_BOUNDARY) \
- macro(NOT_DIGIT) \
- macro(DIGIT) \
- macro(NOT_WHITESPACE) \
- macro(WHITESPACE) \
- macro(NOT_WORDCHAR) \
- macro(WORDCHAR) \
- \
- macro(NOT_NEWLINE) \
- \
- macro(CIRC) \
- macro(DOLL) \
- macro(BOL) \
- macro(EOL) \
- macro(CHAR) \
- macro(CHAR_IGNORING_CASE) \
- macro(ASCII_CHAR) \
- macro(ASCII_LETTER_IGNORING_CASE) \
- macro(NOT) \
- \
- macro(STAR) \
- macro(MINSTAR) \
- macro(PLUS) \
- macro(MINPLUS) \
- macro(QUERY) \
- macro(MINQUERY) \
- macro(UPTO) \
- macro(MINUPTO) \
- macro(EXACT) \
- \
- macro(NOTSTAR) \
- macro(NOTMINSTAR) \
- macro(NOTPLUS) \
- macro(NOTMINPLUS) \
- macro(NOTQUERY) \
- macro(NOTMINQUERY) \
- macro(NOTUPTO) \
- macro(NOTMINUPTO) \
- macro(NOTEXACT) \
- \
- macro(TYPESTAR) \
- macro(TYPEMINSTAR) \
- macro(TYPEPLUS) \
- macro(TYPEMINPLUS) \
- macro(TYPEQUERY) \
- macro(TYPEMINQUERY) \
- macro(TYPEUPTO) \
- macro(TYPEMINUPTO) \
- macro(TYPEEXACT) \
- \
- macro(CRSTAR) \
- macro(CRMINSTAR) \
- macro(CRPLUS) \
- macro(CRMINPLUS) \
- macro(CRQUERY) \
- macro(CRMINQUERY) \
- macro(CRRANGE) \
- macro(CRMINRANGE) \
- \
- macro(CLASS) \
- macro(NCLASS) \
- macro(XCLASS) \
- \
- macro(REF) \
- \
- macro(ALT) \
- macro(KET) \
- macro(KETRMAX) \
- macro(KETRMIN) \
- \
- macro(ASSERT) \
- macro(ASSERT_NOT) \
- \
- macro(BRAZERO) \
- macro(BRAMINZERO) \
- macro(BRANUMBER) \
- macro(BRA)
-
-#define OPCODE_ENUM_VALUE(opcode) OP_##opcode,
-enum { FOR_EACH_OPCODE(OPCODE_ENUM_VALUE) };
-
-/* WARNING WARNING WARNING: There is an implicit assumption in pcre.c and
-study.c that all opcodes are less than 128 in value. This makes handling UTF-8
-character sequences easier. */
-
-/* The highest extraction number before we have to start using additional
-bytes. (Originally PCRE didn't have support for extraction counts higher than
-this number.) The value is limited by the number of opcodes left after OP_BRA,
-i.e. 255 - OP_BRA. We actually set it a bit lower to leave room for additional
-opcodes. */
-
-/* FIXME: Note that OP_BRA + 100 is > 128, so the two comments above
-are in conflict! */
-
-#define EXTRACT_BASIC_MAX 100
-
-/* The code vector runs on as long as necessary after the end. */
-
-struct JSRegExp {
- unsigned options;
-
- unsigned short topBracket;
- unsigned short topBackref;
-
- unsigned short firstByte;
- unsigned short reqByte;
-
-#if REGEXP_HISTOGRAM
- size_t stringOffset;
- size_t stringLength;
-#endif
-};
-
-/* Internal shared data tables. These are tables that are used by more than one
- of the exported public functions. They have to be "external" in the C sense,
- but are not part of the PCRE public API. The data for these tables is in the
- pcre_tables.c module. */
-
-#define jsc_pcre_utf8_table1_size 6
-
-extern const int jsc_pcre_utf8_table1[6];
-extern const int jsc_pcre_utf8_table2[6];
-extern const int jsc_pcre_utf8_table3[6];
-extern const unsigned char jsc_pcre_utf8_table4[0x40];
-
-extern const unsigned char jsc_pcre_default_tables[tables_length];
-
-static inline unsigned char toLowerCase(unsigned char c)
-{
- static const unsigned char* lowerCaseChars = jsc_pcre_default_tables + lcc_offset;
- return lowerCaseChars[c];
-}
-
-static inline unsigned char flipCase(unsigned char c)
-{
- static const unsigned char* flippedCaseChars = jsc_pcre_default_tables + fcc_offset;
- return flippedCaseChars[c];
-}
-
-static inline unsigned char classBitmapForChar(unsigned char c)
-{
- static const unsigned char* charClassBitmaps = jsc_pcre_default_tables + cbits_offset;
- return charClassBitmaps[c];
-}
-
-static inline unsigned char charTypeForChar(unsigned char c)
-{
- const unsigned char* charTypeMap = jsc_pcre_default_tables + ctypes_offset;
- return charTypeMap[c];
-}
-
-static inline bool isWordChar(UChar c)
-{
- return c < 128 && (charTypeForChar(c) & ctype_word);
-}
-
-static inline bool isSpaceChar(UChar c)
-{
- return (c < 128 && (charTypeForChar(c) & ctype_space)) || c == 0x00A0;
-}
-
-static inline bool isNewline(UChar nl)
-{
- return (nl == 0xA || nl == 0xD || nl == 0x2028 || nl == 0x2029);
-}
-
-static inline bool isBracketStartOpcode(unsigned char opcode)
-{
- if (opcode >= OP_BRA)
- return true;
- switch (opcode) {
- case OP_ASSERT:
- case OP_ASSERT_NOT:
- return true;
- default:
- return false;
- }
-}
-
-static inline void advanceToEndOfBracket(const unsigned char*& opcodePtr)
-{
- ASSERT(isBracketStartOpcode(*opcodePtr) || *opcodePtr == OP_ALT);
- do
- opcodePtr += getLinkValue(opcodePtr + 1);
- while (*opcodePtr == OP_ALT);
-}
-
-/* Internal shared functions. These are functions that are used in more
-that one of the source files. They have to have external linkage, but
-but are not part of the public API and so not exported from the library. */
-
-extern int jsc_pcre_ucp_othercase(unsigned);
-extern bool jsc_pcre_xclass(int, const unsigned char*);
-
-#endif
-
-#endif
-
-/* End of pcre_internal.h */
+++ /dev/null
-/* This is JavaScriptCore's variant of the PCRE library. While this library
-started out as a copy of PCRE, many of the features of PCRE have been
-removed. This library now supports only the regular expression features
-required by the JavaScript language specification, and has only the functions
-needed by JavaScriptCore and the rest of WebKit.
-
- Originally written by Philip Hazel
- Copyright (c) 1997-2006 University of Cambridge
- Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-/* This module contains some fixed tables that are used by more than one of the
-PCRE code modules. */
-
-#include "config.h"
-#include "pcre_internal.h"
-
-/*************************************************
-* Tables for UTF-8 support *
-*************************************************/
-
-/* These are the breakpoints for different numbers of bytes in a UTF-8
-character. */
-
-const int jsc_pcre_utf8_table1[6] =
- { 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff};
-
-/* These are the indicator bits and the mask for the data bits to set in the
-first byte of a character, indexed by the number of additional bytes. */
-
-const int jsc_pcre_utf8_table2[6] = { 0, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc};
-const int jsc_pcre_utf8_table3[6] = { 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01};
-
-/* Table of the number of extra characters, indexed by the first character
-masked with 0x3f. The highest number for a valid UTF-8 character is in fact
-0x3d. */
-
-const unsigned char jsc_pcre_utf8_table4[0x40] = {
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
- 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 };
-
-#include "chartables.c"
+++ /dev/null
-/* This is JavaScriptCore's variant of the PCRE library. While this library
-started out as a copy of PCRE, many of the features of PCRE have been
-removed. This library now supports only the regular expression features
-required by the JavaScript language specification, and has only the functions
-needed by JavaScriptCore and the rest of WebKit.
-
- Originally written by Philip Hazel
- Copyright (c) 1997-2006 University of Cambridge
- Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-
-/* This module contains code for searching the table of Unicode character
-properties. */
-
-#include "config.h"
-#include "pcre_internal.h"
-
-#include "ucpinternal.h" /* Internal table details */
-#include "ucptable.cpp" /* The table itself */
-
-/*************************************************
-* Search table and return other case *
-*************************************************/
-
-/* If the given character is a letter, and there is another case for the
-letter, return the other case. Otherwise, return -1.
-
-Arguments:
- c the character value
-
-Returns: the other case or -1 if none
-*/
-
-int jsc_pcre_ucp_othercase(unsigned c)
-{
- int bot = 0;
- int top = sizeof(ucp_table) / sizeof(cnode);
- int mid;
-
- /* The table is searched using a binary chop. You might think that using
- intermediate variables to hold some of the common expressions would speed
- things up, but tests with gcc 3.4.4 on Linux showed that, on the contrary, it
- makes things a lot slower. */
-
- for (;;) {
- if (top <= bot)
- return -1;
- mid = (bot + top) >> 1;
- if (c == (ucp_table[mid].f0 & f0_charmask))
- break;
- if (c < (ucp_table[mid].f0 & f0_charmask))
- top = mid;
- else {
- if ((ucp_table[mid].f0 & f0_rangeflag) && (c <= (ucp_table[mid].f0 & f0_charmask) + (ucp_table[mid].f1 & f1_rangemask)))
- break;
- bot = mid + 1;
- }
- }
-
- /* Found an entry in the table. Return -1 for a range entry. Otherwise return
- the other case if there is one, else -1. */
-
- if (ucp_table[mid].f0 & f0_rangeflag)
- return -1;
-
- int offset = ucp_table[mid].f1 & f1_casemask;
- if (offset & f1_caseneg)
- offset |= f1_caseneg;
- return !offset ? -1 : c + offset;
-}
+++ /dev/null
-/* This is JavaScriptCore's variant of the PCRE library. While this library
-started out as a copy of PCRE, many of the features of PCRE have been
-removed. This library now supports only the regular expression features
-required by the JavaScript language specification, and has only the functions
-needed by JavaScriptCore and the rest of WebKit.
-
- Originally written by Philip Hazel
- Copyright (c) 1997-2006 University of Cambridge
- Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-/* This module contains an internal function that is used to match an extended
-class (one that contains characters whose values are > 255). */
-
-#include "config.h"
-#include "pcre_internal.h"
-
-/*************************************************
-* Match character against an XCLASS *
-*************************************************/
-
-/* This function is called to match a character against an extended class that
-might contain values > 255.
-
-Arguments:
- c the character
- data points to the flag byte of the XCLASS data
-
-Returns: true if character matches, else false
-*/
-
-/* Get the next UTF-8 character, advancing the pointer. This is called when we
- know we are in UTF-8 mode. */
-
-static inline void getUTF8CharAndAdvancePointer(int& c, const unsigned char*& subjectPtr)
-{
- c = *subjectPtr++;
- if ((c & 0xc0) == 0xc0) {
- int gcaa = jsc_pcre_utf8_table4[c & 0x3f]; /* Number of additional bytes */
- int gcss = 6 * gcaa;
- c = (c & jsc_pcre_utf8_table3[gcaa]) << gcss;
- while (gcaa-- > 0) {
- gcss -= 6;
- c |= (*subjectPtr++ & 0x3f) << gcss;
- }
- }
-}
-
-bool jsc_pcre_xclass(int c, const unsigned char* data)
-{
- bool negated = (*data & XCL_NOT);
-
- /* Character values < 256 are matched against a bitmap, if one is present. If
- not, we still carry on, because there may be ranges that start below 256 in the
- additional data. */
-
- if (c < 256) {
- if ((*data & XCL_MAP) != 0 && (data[1 + c/8] & (1 << (c&7))) != 0)
- return !negated; /* char found */
- }
-
- /* First skip the bit map if present. Then match against the list of Unicode
- properties or large chars or ranges that end with a large char. We won't ever
- encounter XCL_PROP or XCL_NOTPROP when UCP support is not compiled. */
-
- if ((*data++ & XCL_MAP) != 0)
- data += 32;
-
- int t;
- while ((t = *data++) != XCL_END) {
- if (t == XCL_SINGLE) {
- int x;
- getUTF8CharAndAdvancePointer(x, data);
- if (c == x)
- return !negated;
- }
- else if (t == XCL_RANGE) {
- int x, y;
- getUTF8CharAndAdvancePointer(x, data);
- getUTF8CharAndAdvancePointer(y, data);
- if (c >= x && c <= y)
- return !negated;
- }
- }
-
- return negated; /* char did not match */
-}
+++ /dev/null
-/* This is JavaScriptCore's variant of the PCRE library. While this library
-started out as a copy of PCRE, many of the features of PCRE have been
-removed. This library now supports only the regular expression features
-required by the JavaScript language specification, and has only the functions
-needed by JavaScriptCore and the rest of WebKit.
-
- Originally written by Philip Hazel
- Copyright (c) 1997-2006 University of Cambridge
- Copyright (C) 2002, 2004, 2006, 2007 Apple Inc. All rights reserved.
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-/*************************************************
-* Unicode Property Table handler *
-*************************************************/
-
-/* Internal header file defining the layout of the bits in each pair of 32-bit
-words that form a data item in the table. */
-
-typedef struct cnode {
- unsigned f0;
- unsigned f1;
-} cnode;
-
-/* Things for the f0 field */
-
-#define f0_scriptmask 0xff000000 /* Mask for script field */
-#define f0_scriptshift 24 /* Shift for script value */
-#define f0_rangeflag 0x00f00000 /* Flag for a range item */
-#define f0_charmask 0x001fffff /* Mask for code point value */
-
-/* Things for the f1 field */
-
-#define f1_typemask 0xfc000000 /* Mask for char type field */
-#define f1_typeshift 26 /* Shift for the type field */
-#define f1_rangemask 0x0000ffff /* Mask for a range offset */
-#define f1_casemask 0x0000ffff /* Mask for a case offset */
-#define f1_caseneg 0xffff8000 /* Bits for negation */
-
-/* The data consists of a vector of structures of type cnode. The two unsigned
-32-bit integers are used as follows:
-
-(f0) (1) The most significant byte holds the script number. The numbers are
- defined by the enum in ucp.h.
-
- (2) The 0x00800000 bit is set if this entry defines a range of characters.
- It is not set if this entry defines a single character
-
- (3) The 0x00600000 bits are spare.
-
- (4) The 0x001fffff bits contain the code point. No Unicode code point will
- ever be greater than 0x0010ffff, so this should be OK for ever.
-
-(f1) (1) The 0xfc000000 bits contain the character type number. The numbers are
- defined by an enum in ucp.h.
-
- (2) The 0x03ff0000 bits are spare.
-
- (3) The 0x0000ffff bits contain EITHER the unsigned offset to the top of
- range if this entry defines a range, OR the *signed* offset to the
- character's "other case" partner if this entry defines a single
- character. There is no partner if the value is zero.
-
--------------------------------------------------------------------------------
-| script (8) |.|.|.| codepoint (21) || type (6) |.|.| spare (8) | offset (16) |
--------------------------------------------------------------------------------
- | | | | |
- | | |-> spare | |-> spare
- | | |
- | |-> spare |-> spare
- |
- |-> range flag
-
-The upper/lower casing information is set only for characters that come in
-pairs. The non-one-to-one mappings in the Unicode data are ignored.
-
-When searching the data, proceed as follows:
-
-(1) Set up for a binary chop search.
-
-(2) If the top is not greater than the bottom, the character is not in the
- table. Its type must therefore be "Cn" ("Undefined").
-
-(3) Find the middle vector element.
-
-(4) Extract the code point and compare. If equal, we are done.
-
-(5) If the test character is smaller, set the top to the current point, and
- goto (2).
-
-(6) If the current entry defines a range, compute the last character by adding
- the offset, and see if the test character is within the range. If it is,
- we are done.
-
-(7) Otherwise, set the bottom to one element past the current point and goto
- (2).
-*/
-
-/* End of ucpinternal.h */
+++ /dev/null
-/* This source module is automatically generated from the Unicode
-property table. See ucpinternal.h for a description of the layout. */
-
-static const cnode ucp_table[] = {
- { 0x09800000, 0x0000001f },
- { 0x09000020, 0x74000000 },
- { 0x09800021, 0x54000002 },
- { 0x09000024, 0x5c000000 },
- { 0x09800025, 0x54000002 },
- { 0x09000028, 0x58000000 },
- { 0x09000029, 0x48000000 },
- { 0x0900002a, 0x54000000 },
- { 0x0900002b, 0x64000000 },
- { 0x0900002c, 0x54000000 },
- { 0x0900002d, 0x44000000 },
- { 0x0980002e, 0x54000001 },
- { 0x09800030, 0x34000009 },
- { 0x0980003a, 0x54000001 },
- { 0x0980003c, 0x64000002 },
- { 0x0980003f, 0x54000001 },
- { 0x21000041, 0x24000020 },
- { 0x21000042, 0x24000020 },
- { 0x21000043, 0x24000020 },
- { 0x21000044, 0x24000020 },
- { 0x21000045, 0x24000020 },
- { 0x21000046, 0x24000020 },
- { 0x21000047, 0x24000020 },
- { 0x21000048, 0x24000020 },
- { 0x21000049, 0x24000020 },
- { 0x2100004a, 0x24000020 },
- { 0x2100004b, 0x24000020 },
- { 0x2100004c, 0x24000020 },
- { 0x2100004d, 0x24000020 },
- { 0x2100004e, 0x24000020 },
- { 0x2100004f, 0x24000020 },
- { 0x21000050, 0x24000020 },
- { 0x21000051, 0x24000020 },
- { 0x21000052, 0x24000020 },
- { 0x21000053, 0x24000020 },
- { 0x21000054, 0x24000020 },
- { 0x21000055, 0x24000020 },
- { 0x21000056, 0x24000020 },
- { 0x21000057, 0x24000020 },
- { 0x21000058, 0x24000020 },
- { 0x21000059, 0x24000020 },
- { 0x2100005a, 0x24000020 },
- { 0x0900005b, 0x58000000 },
- { 0x0900005c, 0x54000000 },
- { 0x0900005d, 0x48000000 },
- { 0x0900005e, 0x60000000 },
- { 0x0900005f, 0x40000000 },
- { 0x09000060, 0x60000000 },
- { 0x21000061, 0x1400ffe0 },
- { 0x21000062, 0x1400ffe0 },
- { 0x21000063, 0x1400ffe0 },
- { 0x21000064, 0x1400ffe0 },
- { 0x21000065, 0x1400ffe0 },
- { 0x21000066, 0x1400ffe0 },
- { 0x21000067, 0x1400ffe0 },
- { 0x21000068, 0x1400ffe0 },
- { 0x21000069, 0x1400ffe0 },
- { 0x2100006a, 0x1400ffe0 },
- { 0x2100006b, 0x1400ffe0 },
- { 0x2100006c, 0x1400ffe0 },
- { 0x2100006d, 0x1400ffe0 },
- { 0x2100006e, 0x1400ffe0 },
- { 0x2100006f, 0x1400ffe0 },
- { 0x21000070, 0x1400ffe0 },
- { 0x21000071, 0x1400ffe0 },
- { 0x21000072, 0x1400ffe0 },
- { 0x21000073, 0x1400ffe0 },
- { 0x21000074, 0x1400ffe0 },
- { 0x21000075, 0x1400ffe0 },
- { 0x21000076, 0x1400ffe0 },
- { 0x21000077, 0x1400ffe0 },
- { 0x21000078, 0x1400ffe0 },
- { 0x21000079, 0x1400ffe0 },
- { 0x2100007a, 0x1400ffe0 },
- { 0x0900007b, 0x58000000 },
- { 0x0900007c, 0x64000000 },
- { 0x0900007d, 0x48000000 },
- { 0x0900007e, 0x64000000 },
- { 0x0980007f, 0x00000020 },
- { 0x090000a0, 0x74000000 },
- { 0x090000a1, 0x54000000 },
- { 0x098000a2, 0x5c000003 },
- { 0x098000a6, 0x68000001 },
- { 0x090000a8, 0x60000000 },
- { 0x090000a9, 0x68000000 },
- { 0x210000aa, 0x14000000 },
- { 0x090000ab, 0x50000000 },
- { 0x090000ac, 0x64000000 },
- { 0x090000ad, 0x04000000 },
- { 0x090000ae, 0x68000000 },
- { 0x090000af, 0x60000000 },
- { 0x090000b0, 0x68000000 },
- { 0x090000b1, 0x64000000 },
- { 0x098000b2, 0x3c000001 },
- { 0x090000b4, 0x60000000 },
- { 0x090000b5, 0x140002e7 },
- { 0x090000b6, 0x68000000 },
- { 0x090000b7, 0x54000000 },
- { 0x090000b8, 0x60000000 },
- { 0x090000b9, 0x3c000000 },
- { 0x210000ba, 0x14000000 },
- { 0x090000bb, 0x4c000000 },
- { 0x098000bc, 0x3c000002 },
- { 0x090000bf, 0x54000000 },
- { 0x210000c0, 0x24000020 },
- { 0x210000c1, 0x24000020 },
- { 0x210000c2, 0x24000020 },
- { 0x210000c3, 0x24000020 },
- { 0x210000c4, 0x24000020 },
- { 0x210000c5, 0x24000020 },
- { 0x210000c6, 0x24000020 },
- { 0x210000c7, 0x24000020 },
- { 0x210000c8, 0x24000020 },
- { 0x210000c9, 0x24000020 },
- { 0x210000ca, 0x24000020 },
- { 0x210000cb, 0x24000020 },
- { 0x210000cc, 0x24000020 },
- { 0x210000cd, 0x24000020 },
- { 0x210000ce, 0x24000020 },
- { 0x210000cf, 0x24000020 },
- { 0x210000d0, 0x24000020 },
- { 0x210000d1, 0x24000020 },
- { 0x210000d2, 0x24000020 },
- { 0x210000d3, 0x24000020 },
- { 0x210000d4, 0x24000020 },
- { 0x210000d5, 0x24000020 },
- { 0x210000d6, 0x24000020 },
- { 0x090000d7, 0x64000000 },
- { 0x210000d8, 0x24000020 },
- { 0x210000d9, 0x24000020 },
- { 0x210000da, 0x24000020 },
- { 0x210000db, 0x24000020 },
- { 0x210000dc, 0x24000020 },
- { 0x210000dd, 0x24000020 },
- { 0x210000de, 0x24000020 },
- { 0x210000df, 0x14000000 },
- { 0x210000e0, 0x1400ffe0 },
- { 0x210000e1, 0x1400ffe0 },
- { 0x210000e2, 0x1400ffe0 },
- { 0x210000e3, 0x1400ffe0 },
- { 0x210000e4, 0x1400ffe0 },
- { 0x210000e5, 0x1400ffe0 },
- { 0x210000e6, 0x1400ffe0 },
- { 0x210000e7, 0x1400ffe0 },
- { 0x210000e8, 0x1400ffe0 },
- { 0x210000e9, 0x1400ffe0 },
- { 0x210000ea, 0x1400ffe0 },
- { 0x210000eb, 0x1400ffe0 },
- { 0x210000ec, 0x1400ffe0 },
- { 0x210000ed, 0x1400ffe0 },
- { 0x210000ee, 0x1400ffe0 },
- { 0x210000ef, 0x1400ffe0 },
- { 0x210000f0, 0x1400ffe0 },
- { 0x210000f1, 0x1400ffe0 },
- { 0x210000f2, 0x1400ffe0 },
- { 0x210000f3, 0x1400ffe0 },
- { 0x210000f4, 0x1400ffe0 },
- { 0x210000f5, 0x1400ffe0 },
- { 0x210000f6, 0x1400ffe0 },
- { 0x090000f7, 0x64000000 },
- { 0x210000f8, 0x1400ffe0 },
- { 0x210000f9, 0x1400ffe0 },
- { 0x210000fa, 0x1400ffe0 },
- { 0x210000fb, 0x1400ffe0 },
- { 0x210000fc, 0x1400ffe0 },
- { 0x210000fd, 0x1400ffe0 },
- { 0x210000fe, 0x1400ffe0 },
- { 0x210000ff, 0x14000079 },
- { 0x21000100, 0x24000001 },
- { 0x21000101, 0x1400ffff },
- { 0x21000102, 0x24000001 },
- { 0x21000103, 0x1400ffff },
- { 0x21000104, 0x24000001 },
- { 0x21000105, 0x1400ffff },
- { 0x21000106, 0x24000001 },
- { 0x21000107, 0x1400ffff },
- { 0x21000108, 0x24000001 },
- { 0x21000109, 0x1400ffff },
- { 0x2100010a, 0x24000001 },
- { 0x2100010b, 0x1400ffff },
- { 0x2100010c, 0x24000001 },
- { 0x2100010d, 0x1400ffff },
- { 0x2100010e, 0x24000001 },
- { 0x2100010f, 0x1400ffff },
- { 0x21000110, 0x24000001 },
- { 0x21000111, 0x1400ffff },
- { 0x21000112, 0x24000001 },
- { 0x21000113, 0x1400ffff },
- { 0x21000114, 0x24000001 },
- { 0x21000115, 0x1400ffff },
- { 0x21000116, 0x24000001 },
- { 0x21000117, 0x1400ffff },
- { 0x21000118, 0x24000001 },
- { 0x21000119, 0x1400ffff },
- { 0x2100011a, 0x24000001 },
- { 0x2100011b, 0x1400ffff },
- { 0x2100011c, 0x24000001 },
- { 0x2100011d, 0x1400ffff },
- { 0x2100011e, 0x24000001 },
- { 0x2100011f, 0x1400ffff },
- { 0x21000120, 0x24000001 },
- { 0x21000121, 0x1400ffff },
- { 0x21000122, 0x24000001 },
- { 0x21000123, 0x1400ffff },
- { 0x21000124, 0x24000001 },
- { 0x21000125, 0x1400ffff },
- { 0x21000126, 0x24000001 },
- { 0x21000127, 0x1400ffff },
- { 0x21000128, 0x24000001 },
- { 0x21000129, 0x1400ffff },
- { 0x2100012a, 0x24000001 },
- { 0x2100012b, 0x1400ffff },
- { 0x2100012c, 0x24000001 },
- { 0x2100012d, 0x1400ffff },
- { 0x2100012e, 0x24000001 },
- { 0x2100012f, 0x1400ffff },
- { 0x21000130, 0x2400ff39 },
- { 0x21000131, 0x1400ff18 },
- { 0x21000132, 0x24000001 },
- { 0x21000133, 0x1400ffff },
- { 0x21000134, 0x24000001 },
- { 0x21000135, 0x1400ffff },
- { 0x21000136, 0x24000001 },
- { 0x21000137, 0x1400ffff },
- { 0x21000138, 0x14000000 },
- { 0x21000139, 0x24000001 },
- { 0x2100013a, 0x1400ffff },
- { 0x2100013b, 0x24000001 },
- { 0x2100013c, 0x1400ffff },
- { 0x2100013d, 0x24000001 },
- { 0x2100013e, 0x1400ffff },
- { 0x2100013f, 0x24000001 },
- { 0x21000140, 0x1400ffff },
- { 0x21000141, 0x24000001 },
- { 0x21000142, 0x1400ffff },
- { 0x21000143, 0x24000001 },
- { 0x21000144, 0x1400ffff },
- { 0x21000145, 0x24000001 },
- { 0x21000146, 0x1400ffff },
- { 0x21000147, 0x24000001 },
- { 0x21000148, 0x1400ffff },
- { 0x21000149, 0x14000000 },
- { 0x2100014a, 0x24000001 },
- { 0x2100014b, 0x1400ffff },
- { 0x2100014c, 0x24000001 },
- { 0x2100014d, 0x1400ffff },
- { 0x2100014e, 0x24000001 },
- { 0x2100014f, 0x1400ffff },
- { 0x21000150, 0x24000001 },
- { 0x21000151, 0x1400ffff },
- { 0x21000152, 0x24000001 },
- { 0x21000153, 0x1400ffff },
- { 0x21000154, 0x24000001 },
- { 0x21000155, 0x1400ffff },
- { 0x21000156, 0x24000001 },
- { 0x21000157, 0x1400ffff },
- { 0x21000158, 0x24000001 },
- { 0x21000159, 0x1400ffff },
- { 0x2100015a, 0x24000001 },
- { 0x2100015b, 0x1400ffff },
- { 0x2100015c, 0x24000001 },
- { 0x2100015d, 0x1400ffff },
- { 0x2100015e, 0x24000001 },
- { 0x2100015f, 0x1400ffff },
- { 0x21000160, 0x24000001 },
- { 0x21000161, 0x1400ffff },
- { 0x21000162, 0x24000001 },
- { 0x21000163, 0x1400ffff },
- { 0x21000164, 0x24000001 },
- { 0x21000165, 0x1400ffff },
- { 0x21000166, 0x24000001 },
- { 0x21000167, 0x1400ffff },
- { 0x21000168, 0x24000001 },
- { 0x21000169, 0x1400ffff },
- { 0x2100016a, 0x24000001 },
- { 0x2100016b, 0x1400ffff },
- { 0x2100016c, 0x24000001 },
- { 0x2100016d, 0x1400ffff },
- { 0x2100016e, 0x24000001 },
- { 0x2100016f, 0x1400ffff },
- { 0x21000170, 0x24000001 },
- { 0x21000171, 0x1400ffff },
- { 0x21000172, 0x24000001 },
- { 0x21000173, 0x1400ffff },
- { 0x21000174, 0x24000001 },
- { 0x21000175, 0x1400ffff },
- { 0x21000176, 0x24000001 },
- { 0x21000177, 0x1400ffff },
- { 0x21000178, 0x2400ff87 },
- { 0x21000179, 0x24000001 },
- { 0x2100017a, 0x1400ffff },
- { 0x2100017b, 0x24000001 },
- { 0x2100017c, 0x1400ffff },
- { 0x2100017d, 0x24000001 },
- { 0x2100017e, 0x1400ffff },
- { 0x2100017f, 0x1400fed4 },
- { 0x21000180, 0x14000000 },
- { 0x21000181, 0x240000d2 },
- { 0x21000182, 0x24000001 },
- { 0x21000183, 0x1400ffff },
- { 0x21000184, 0x24000001 },
- { 0x21000185, 0x1400ffff },
- { 0x21000186, 0x240000ce },
- { 0x21000187, 0x24000001 },
- { 0x21000188, 0x1400ffff },
- { 0x21000189, 0x240000cd },
- { 0x2100018a, 0x240000cd },
- { 0x2100018b, 0x24000001 },
- { 0x2100018c, 0x1400ffff },
- { 0x2100018d, 0x14000000 },
- { 0x2100018e, 0x2400004f },
- { 0x2100018f, 0x240000ca },
- { 0x21000190, 0x240000cb },
- { 0x21000191, 0x24000001 },
- { 0x21000192, 0x1400ffff },
- { 0x21000193, 0x240000cd },
- { 0x21000194, 0x240000cf },
- { 0x21000195, 0x14000061 },
- { 0x21000196, 0x240000d3 },
- { 0x21000197, 0x240000d1 },
- { 0x21000198, 0x24000001 },
- { 0x21000199, 0x1400ffff },
- { 0x2100019a, 0x140000a3 },
- { 0x2100019b, 0x14000000 },
- { 0x2100019c, 0x240000d3 },
- { 0x2100019d, 0x240000d5 },
- { 0x2100019e, 0x14000082 },
- { 0x2100019f, 0x240000d6 },
- { 0x210001a0, 0x24000001 },
- { 0x210001a1, 0x1400ffff },
- { 0x210001a2, 0x24000001 },
- { 0x210001a3, 0x1400ffff },
- { 0x210001a4, 0x24000001 },
- { 0x210001a5, 0x1400ffff },
- { 0x210001a6, 0x240000da },
- { 0x210001a7, 0x24000001 },
- { 0x210001a8, 0x1400ffff },
- { 0x210001a9, 0x240000da },
- { 0x218001aa, 0x14000001 },
- { 0x210001ac, 0x24000001 },
- { 0x210001ad, 0x1400ffff },
- { 0x210001ae, 0x240000da },
- { 0x210001af, 0x24000001 },
- { 0x210001b0, 0x1400ffff },
- { 0x210001b1, 0x240000d9 },
- { 0x210001b2, 0x240000d9 },
- { 0x210001b3, 0x24000001 },
- { 0x210001b4, 0x1400ffff },
- { 0x210001b5, 0x24000001 },
- { 0x210001b6, 0x1400ffff },
- { 0x210001b7, 0x240000db },
- { 0x210001b8, 0x24000001 },
- { 0x210001b9, 0x1400ffff },
- { 0x210001ba, 0x14000000 },
- { 0x210001bb, 0x1c000000 },
- { 0x210001bc, 0x24000001 },
- { 0x210001bd, 0x1400ffff },
- { 0x210001be, 0x14000000 },
- { 0x210001bf, 0x14000038 },
- { 0x218001c0, 0x1c000003 },
- { 0x210001c4, 0x24000002 },
- { 0x210001c5, 0x2000ffff },
- { 0x210001c6, 0x1400fffe },
- { 0x210001c7, 0x24000002 },
- { 0x210001c8, 0x2000ffff },
- { 0x210001c9, 0x1400fffe },
- { 0x210001ca, 0x24000002 },
- { 0x210001cb, 0x2000ffff },
- { 0x210001cc, 0x1400fffe },
- { 0x210001cd, 0x24000001 },
- { 0x210001ce, 0x1400ffff },
- { 0x210001cf, 0x24000001 },
- { 0x210001d0, 0x1400ffff },
- { 0x210001d1, 0x24000001 },
- { 0x210001d2, 0x1400ffff },
- { 0x210001d3, 0x24000001 },
- { 0x210001d4, 0x1400ffff },
- { 0x210001d5, 0x24000001 },
- { 0x210001d6, 0x1400ffff },
- { 0x210001d7, 0x24000001 },
- { 0x210001d8, 0x1400ffff },
- { 0x210001d9, 0x24000001 },
- { 0x210001da, 0x1400ffff },
- { 0x210001db, 0x24000001 },
- { 0x210001dc, 0x1400ffff },
- { 0x210001dd, 0x1400ffb1 },
- { 0x210001de, 0x24000001 },
- { 0x210001df, 0x1400ffff },
- { 0x210001e0, 0x24000001 },
- { 0x210001e1, 0x1400ffff },
- { 0x210001e2, 0x24000001 },
- { 0x210001e3, 0x1400ffff },
- { 0x210001e4, 0x24000001 },
- { 0x210001e5, 0x1400ffff },
- { 0x210001e6, 0x24000001 },
- { 0x210001e7, 0x1400ffff },
- { 0x210001e8, 0x24000001 },
- { 0x210001e9, 0x1400ffff },
- { 0x210001ea, 0x24000001 },
- { 0x210001eb, 0x1400ffff },
- { 0x210001ec, 0x24000001 },
- { 0x210001ed, 0x1400ffff },
- { 0x210001ee, 0x24000001 },
- { 0x210001ef, 0x1400ffff },
- { 0x210001f0, 0x14000000 },
- { 0x210001f1, 0x24000002 },
- { 0x210001f2, 0x2000ffff },
- { 0x210001f3, 0x1400fffe },
- { 0x210001f4, 0x24000001 },
- { 0x210001f5, 0x1400ffff },
- { 0x210001f6, 0x2400ff9f },
- { 0x210001f7, 0x2400ffc8 },
- { 0x210001f8, 0x24000001 },
- { 0x210001f9, 0x1400ffff },
- { 0x210001fa, 0x24000001 },
- { 0x210001fb, 0x1400ffff },
- { 0x210001fc, 0x24000001 },
- { 0x210001fd, 0x1400ffff },
- { 0x210001fe, 0x24000001 },
- { 0x210001ff, 0x1400ffff },
- { 0x21000200, 0x24000001 },
- { 0x21000201, 0x1400ffff },
- { 0x21000202, 0x24000001 },
- { 0x21000203, 0x1400ffff },
- { 0x21000204, 0x24000001 },
- { 0x21000205, 0x1400ffff },
- { 0x21000206, 0x24000001 },
- { 0x21000207, 0x1400ffff },
- { 0x21000208, 0x24000001 },
- { 0x21000209, 0x1400ffff },
- { 0x2100020a, 0x24000001 },
- { 0x2100020b, 0x1400ffff },
- { 0x2100020c, 0x24000001 },
- { 0x2100020d, 0x1400ffff },
- { 0x2100020e, 0x24000001 },
- { 0x2100020f, 0x1400ffff },
- { 0x21000210, 0x24000001 },
- { 0x21000211, 0x1400ffff },
- { 0x21000212, 0x24000001 },
- { 0x21000213, 0x1400ffff },
- { 0x21000214, 0x24000001 },
- { 0x21000215, 0x1400ffff },
- { 0x21000216, 0x24000001 },
- { 0x21000217, 0x1400ffff },
- { 0x21000218, 0x24000001 },
- { 0x21000219, 0x1400ffff },
- { 0x2100021a, 0x24000001 },
- { 0x2100021b, 0x1400ffff },
- { 0x2100021c, 0x24000001 },
- { 0x2100021d, 0x1400ffff },
- { 0x2100021e, 0x24000001 },
- { 0x2100021f, 0x1400ffff },
- { 0x21000220, 0x2400ff7e },
- { 0x21000221, 0x14000000 },
- { 0x21000222, 0x24000001 },
- { 0x21000223, 0x1400ffff },
- { 0x21000224, 0x24000001 },
- { 0x21000225, 0x1400ffff },
- { 0x21000226, 0x24000001 },
- { 0x21000227, 0x1400ffff },
- { 0x21000228, 0x24000001 },
- { 0x21000229, 0x1400ffff },
- { 0x2100022a, 0x24000001 },
- { 0x2100022b, 0x1400ffff },
- { 0x2100022c, 0x24000001 },
- { 0x2100022d, 0x1400ffff },
- { 0x2100022e, 0x24000001 },
- { 0x2100022f, 0x1400ffff },
- { 0x21000230, 0x24000001 },
- { 0x21000231, 0x1400ffff },
- { 0x21000232, 0x24000001 },
- { 0x21000233, 0x1400ffff },
- { 0x21800234, 0x14000005 },
- { 0x2100023a, 0x24000000 },
- { 0x2100023b, 0x24000001 },
- { 0x2100023c, 0x1400ffff },
- { 0x2100023d, 0x2400ff5d },
- { 0x2100023e, 0x24000000 },
- { 0x2180023f, 0x14000001 },
- { 0x21000241, 0x24000053 },
- { 0x21800250, 0x14000002 },
- { 0x21000253, 0x1400ff2e },
- { 0x21000254, 0x1400ff32 },
- { 0x21000255, 0x14000000 },
- { 0x21000256, 0x1400ff33 },
- { 0x21000257, 0x1400ff33 },
- { 0x21000258, 0x14000000 },
- { 0x21000259, 0x1400ff36 },
- { 0x2100025a, 0x14000000 },
- { 0x2100025b, 0x1400ff35 },
- { 0x2180025c, 0x14000003 },
- { 0x21000260, 0x1400ff33 },
- { 0x21800261, 0x14000001 },
- { 0x21000263, 0x1400ff31 },
- { 0x21800264, 0x14000003 },
- { 0x21000268, 0x1400ff2f },
- { 0x21000269, 0x1400ff2d },
- { 0x2180026a, 0x14000004 },
- { 0x2100026f, 0x1400ff2d },
- { 0x21800270, 0x14000001 },
- { 0x21000272, 0x1400ff2b },
- { 0x21800273, 0x14000001 },
- { 0x21000275, 0x1400ff2a },
- { 0x21800276, 0x14000009 },
- { 0x21000280, 0x1400ff26 },
- { 0x21800281, 0x14000001 },
- { 0x21000283, 0x1400ff26 },
- { 0x21800284, 0x14000003 },
- { 0x21000288, 0x1400ff26 },
- { 0x21000289, 0x14000000 },
- { 0x2100028a, 0x1400ff27 },
- { 0x2100028b, 0x1400ff27 },
- { 0x2180028c, 0x14000005 },
- { 0x21000292, 0x1400ff25 },
- { 0x21000293, 0x14000000 },
- { 0x21000294, 0x1400ffad },
- { 0x21800295, 0x1400001a },
- { 0x218002b0, 0x18000011 },
- { 0x098002c2, 0x60000003 },
- { 0x098002c6, 0x1800000b },
- { 0x098002d2, 0x6000000d },
- { 0x218002e0, 0x18000004 },
- { 0x098002e5, 0x60000008 },
- { 0x090002ee, 0x18000000 },
- { 0x098002ef, 0x60000010 },
- { 0x1b800300, 0x30000044 },
- { 0x1b000345, 0x30000054 },
- { 0x1b800346, 0x30000029 },
- { 0x13800374, 0x60000001 },
- { 0x1300037a, 0x18000000 },
- { 0x0900037e, 0x54000000 },
- { 0x13800384, 0x60000001 },
- { 0x13000386, 0x24000026 },
- { 0x09000387, 0x54000000 },
- { 0x13000388, 0x24000025 },
- { 0x13000389, 0x24000025 },
- { 0x1300038a, 0x24000025 },
- { 0x1300038c, 0x24000040 },
- { 0x1300038e, 0x2400003f },
- { 0x1300038f, 0x2400003f },
- { 0x13000390, 0x14000000 },
- { 0x13000391, 0x24000020 },
- { 0x13000392, 0x24000020 },
- { 0x13000393, 0x24000020 },
- { 0x13000394, 0x24000020 },
- { 0x13000395, 0x24000020 },
- { 0x13000396, 0x24000020 },
- { 0x13000397, 0x24000020 },
- { 0x13000398, 0x24000020 },
- { 0x13000399, 0x24000020 },
- { 0x1300039a, 0x24000020 },
- { 0x1300039b, 0x24000020 },
- { 0x1300039c, 0x24000020 },
- { 0x1300039d, 0x24000020 },
- { 0x1300039e, 0x24000020 },
- { 0x1300039f, 0x24000020 },
- { 0x130003a0, 0x24000020 },
- { 0x130003a1, 0x24000020 },
- { 0x130003a3, 0x24000020 },
- { 0x130003a4, 0x24000020 },
- { 0x130003a5, 0x24000020 },
- { 0x130003a6, 0x24000020 },
- { 0x130003a7, 0x24000020 },
- { 0x130003a8, 0x24000020 },
- { 0x130003a9, 0x24000020 },
- { 0x130003aa, 0x24000020 },
- { 0x130003ab, 0x24000020 },
- { 0x130003ac, 0x1400ffda },
- { 0x130003ad, 0x1400ffdb },
- { 0x130003ae, 0x1400ffdb },
- { 0x130003af, 0x1400ffdb },
- { 0x130003b0, 0x14000000 },
- { 0x130003b1, 0x1400ffe0 },
- { 0x130003b2, 0x1400ffe0 },
- { 0x130003b3, 0x1400ffe0 },
- { 0x130003b4, 0x1400ffe0 },
- { 0x130003b5, 0x1400ffe0 },
- { 0x130003b6, 0x1400ffe0 },
- { 0x130003b7, 0x1400ffe0 },
- { 0x130003b8, 0x1400ffe0 },
- { 0x130003b9, 0x1400ffe0 },
- { 0x130003ba, 0x1400ffe0 },
- { 0x130003bb, 0x1400ffe0 },
- { 0x130003bc, 0x1400ffe0 },
- { 0x130003bd, 0x1400ffe0 },
- { 0x130003be, 0x1400ffe0 },
- { 0x130003bf, 0x1400ffe0 },
- { 0x130003c0, 0x1400ffe0 },
- { 0x130003c1, 0x1400ffe0 },
- { 0x130003c2, 0x1400ffe1 },
- { 0x130003c3, 0x1400ffe0 },
- { 0x130003c4, 0x1400ffe0 },
- { 0x130003c5, 0x1400ffe0 },
- { 0x130003c6, 0x1400ffe0 },
- { 0x130003c7, 0x1400ffe0 },
- { 0x130003c8, 0x1400ffe0 },
- { 0x130003c9, 0x1400ffe0 },
- { 0x130003ca, 0x1400ffe0 },
- { 0x130003cb, 0x1400ffe0 },
- { 0x130003cc, 0x1400ffc0 },
- { 0x130003cd, 0x1400ffc1 },
- { 0x130003ce, 0x1400ffc1 },
- { 0x130003d0, 0x1400ffc2 },
- { 0x130003d1, 0x1400ffc7 },
- { 0x138003d2, 0x24000002 },
- { 0x130003d5, 0x1400ffd1 },
- { 0x130003d6, 0x1400ffca },
- { 0x130003d7, 0x14000000 },
- { 0x130003d8, 0x24000001 },
- { 0x130003d9, 0x1400ffff },
- { 0x130003da, 0x24000001 },
- { 0x130003db, 0x1400ffff },
- { 0x130003dc, 0x24000001 },
- { 0x130003dd, 0x1400ffff },
- { 0x130003de, 0x24000001 },
- { 0x130003df, 0x1400ffff },
- { 0x130003e0, 0x24000001 },
- { 0x130003e1, 0x1400ffff },
- { 0x0a0003e2, 0x24000001 },
- { 0x0a0003e3, 0x1400ffff },
- { 0x0a0003e4, 0x24000001 },
- { 0x0a0003e5, 0x1400ffff },
- { 0x0a0003e6, 0x24000001 },
- { 0x0a0003e7, 0x1400ffff },
- { 0x0a0003e8, 0x24000001 },
- { 0x0a0003e9, 0x1400ffff },
- { 0x0a0003ea, 0x24000001 },
- { 0x0a0003eb, 0x1400ffff },
- { 0x0a0003ec, 0x24000001 },
- { 0x0a0003ed, 0x1400ffff },
- { 0x0a0003ee, 0x24000001 },
- { 0x0a0003ef, 0x1400ffff },
- { 0x130003f0, 0x1400ffaa },
- { 0x130003f1, 0x1400ffb0 },
- { 0x130003f2, 0x14000007 },
- { 0x130003f3, 0x14000000 },
- { 0x130003f4, 0x2400ffc4 },
- { 0x130003f5, 0x1400ffa0 },
- { 0x130003f6, 0x64000000 },
- { 0x130003f7, 0x24000001 },
- { 0x130003f8, 0x1400ffff },
- { 0x130003f9, 0x2400fff9 },
- { 0x130003fa, 0x24000001 },
- { 0x130003fb, 0x1400ffff },
- { 0x130003fc, 0x14000000 },
- { 0x138003fd, 0x24000002 },
- { 0x0c000400, 0x24000050 },
- { 0x0c000401, 0x24000050 },
- { 0x0c000402, 0x24000050 },
- { 0x0c000403, 0x24000050 },
- { 0x0c000404, 0x24000050 },
- { 0x0c000405, 0x24000050 },
- { 0x0c000406, 0x24000050 },
- { 0x0c000407, 0x24000050 },
- { 0x0c000408, 0x24000050 },
- { 0x0c000409, 0x24000050 },
- { 0x0c00040a, 0x24000050 },
- { 0x0c00040b, 0x24000050 },
- { 0x0c00040c, 0x24000050 },
- { 0x0c00040d, 0x24000050 },
- { 0x0c00040e, 0x24000050 },
- { 0x0c00040f, 0x24000050 },
- { 0x0c000410, 0x24000020 },
- { 0x0c000411, 0x24000020 },
- { 0x0c000412, 0x24000020 },
- { 0x0c000413, 0x24000020 },
- { 0x0c000414, 0x24000020 },
- { 0x0c000415, 0x24000020 },
- { 0x0c000416, 0x24000020 },
- { 0x0c000417, 0x24000020 },
- { 0x0c000418, 0x24000020 },
- { 0x0c000419, 0x24000020 },
- { 0x0c00041a, 0x24000020 },
- { 0x0c00041b, 0x24000020 },
- { 0x0c00041c, 0x24000020 },
- { 0x0c00041d, 0x24000020 },
- { 0x0c00041e, 0x24000020 },
- { 0x0c00041f, 0x24000020 },
- { 0x0c000420, 0x24000020 },
- { 0x0c000421, 0x24000020 },
- { 0x0c000422, 0x24000020 },
- { 0x0c000423, 0x24000020 },
- { 0x0c000424, 0x24000020 },
- { 0x0c000425, 0x24000020 },
- { 0x0c000426, 0x24000020 },
- { 0x0c000427, 0x24000020 },
- { 0x0c000428, 0x24000020 },
- { 0x0c000429, 0x24000020 },
- { 0x0c00042a, 0x24000020 },
- { 0x0c00042b, 0x24000020 },
- { 0x0c00042c, 0x24000020 },
- { 0x0c00042d, 0x24000020 },
- { 0x0c00042e, 0x24000020 },
- { 0x0c00042f, 0x24000020 },
- { 0x0c000430, 0x1400ffe0 },
- { 0x0c000431, 0x1400ffe0 },
- { 0x0c000432, 0x1400ffe0 },
- { 0x0c000433, 0x1400ffe0 },
- { 0x0c000434, 0x1400ffe0 },
- { 0x0c000435, 0x1400ffe0 },
- { 0x0c000436, 0x1400ffe0 },
- { 0x0c000437, 0x1400ffe0 },
- { 0x0c000438, 0x1400ffe0 },
- { 0x0c000439, 0x1400ffe0 },
- { 0x0c00043a, 0x1400ffe0 },
- { 0x0c00043b, 0x1400ffe0 },
- { 0x0c00043c, 0x1400ffe0 },
- { 0x0c00043d, 0x1400ffe0 },
- { 0x0c00043e, 0x1400ffe0 },
- { 0x0c00043f, 0x1400ffe0 },
- { 0x0c000440, 0x1400ffe0 },
- { 0x0c000441, 0x1400ffe0 },
- { 0x0c000442, 0x1400ffe0 },
- { 0x0c000443, 0x1400ffe0 },
- { 0x0c000444, 0x1400ffe0 },
- { 0x0c000445, 0x1400ffe0 },
- { 0x0c000446, 0x1400ffe0 },
- { 0x0c000447, 0x1400ffe0 },
- { 0x0c000448, 0x1400ffe0 },
- { 0x0c000449, 0x1400ffe0 },
- { 0x0c00044a, 0x1400ffe0 },
- { 0x0c00044b, 0x1400ffe0 },
- { 0x0c00044c, 0x1400ffe0 },
- { 0x0c00044d, 0x1400ffe0 },
- { 0x0c00044e, 0x1400ffe0 },
- { 0x0c00044f, 0x1400ffe0 },
- { 0x0c000450, 0x1400ffb0 },
- { 0x0c000451, 0x1400ffb0 },
- { 0x0c000452, 0x1400ffb0 },
- { 0x0c000453, 0x1400ffb0 },
- { 0x0c000454, 0x1400ffb0 },
- { 0x0c000455, 0x1400ffb0 },
- { 0x0c000456, 0x1400ffb0 },
- { 0x0c000457, 0x1400ffb0 },
- { 0x0c000458, 0x1400ffb0 },
- { 0x0c000459, 0x1400ffb0 },
- { 0x0c00045a, 0x1400ffb0 },
- { 0x0c00045b, 0x1400ffb0 },
- { 0x0c00045c, 0x1400ffb0 },
- { 0x0c00045d, 0x1400ffb0 },
- { 0x0c00045e, 0x1400ffb0 },
- { 0x0c00045f, 0x1400ffb0 },
- { 0x0c000460, 0x24000001 },
- { 0x0c000461, 0x1400ffff },
- { 0x0c000462, 0x24000001 },
- { 0x0c000463, 0x1400ffff },
- { 0x0c000464, 0x24000001 },
- { 0x0c000465, 0x1400ffff },
- { 0x0c000466, 0x24000001 },
- { 0x0c000467, 0x1400ffff },
- { 0x0c000468, 0x24000001 },
- { 0x0c000469, 0x1400ffff },
- { 0x0c00046a, 0x24000001 },
- { 0x0c00046b, 0x1400ffff },
- { 0x0c00046c, 0x24000001 },
- { 0x0c00046d, 0x1400ffff },
- { 0x0c00046e, 0x24000001 },
- { 0x0c00046f, 0x1400ffff },
- { 0x0c000470, 0x24000001 },
- { 0x0c000471, 0x1400ffff },
- { 0x0c000472, 0x24000001 },
- { 0x0c000473, 0x1400ffff },
- { 0x0c000474, 0x24000001 },
- { 0x0c000475, 0x1400ffff },
- { 0x0c000476, 0x24000001 },
- { 0x0c000477, 0x1400ffff },
- { 0x0c000478, 0x24000001 },
- { 0x0c000479, 0x1400ffff },
- { 0x0c00047a, 0x24000001 },
- { 0x0c00047b, 0x1400ffff },
- { 0x0c00047c, 0x24000001 },
- { 0x0c00047d, 0x1400ffff },
- { 0x0c00047e, 0x24000001 },
- { 0x0c00047f, 0x1400ffff },
- { 0x0c000480, 0x24000001 },
- { 0x0c000481, 0x1400ffff },
- { 0x0c000482, 0x68000000 },
- { 0x0c800483, 0x30000003 },
- { 0x0c800488, 0x2c000001 },
- { 0x0c00048a, 0x24000001 },
- { 0x0c00048b, 0x1400ffff },
- { 0x0c00048c, 0x24000001 },
- { 0x0c00048d, 0x1400ffff },
- { 0x0c00048e, 0x24000001 },
- { 0x0c00048f, 0x1400ffff },
- { 0x0c000490, 0x24000001 },
- { 0x0c000491, 0x1400ffff },
- { 0x0c000492, 0x24000001 },
- { 0x0c000493, 0x1400ffff },
- { 0x0c000494, 0x24000001 },
- { 0x0c000495, 0x1400ffff },
- { 0x0c000496, 0x24000001 },
- { 0x0c000497, 0x1400ffff },
- { 0x0c000498, 0x24000001 },
- { 0x0c000499, 0x1400ffff },
- { 0x0c00049a, 0x24000001 },
- { 0x0c00049b, 0x1400ffff },
- { 0x0c00049c, 0x24000001 },
- { 0x0c00049d, 0x1400ffff },
- { 0x0c00049e, 0x24000001 },
- { 0x0c00049f, 0x1400ffff },
- { 0x0c0004a0, 0x24000001 },
- { 0x0c0004a1, 0x1400ffff },
- { 0x0c0004a2, 0x24000001 },
- { 0x0c0004a3, 0x1400ffff },
- { 0x0c0004a4, 0x24000001 },
- { 0x0c0004a5, 0x1400ffff },
- { 0x0c0004a6, 0x24000001 },
- { 0x0c0004a7, 0x1400ffff },
- { 0x0c0004a8, 0x24000001 },
- { 0x0c0004a9, 0x1400ffff },
- { 0x0c0004aa, 0x24000001 },
- { 0x0c0004ab, 0x1400ffff },
- { 0x0c0004ac, 0x24000001 },
- { 0x0c0004ad, 0x1400ffff },
- { 0x0c0004ae, 0x24000001 },
- { 0x0c0004af, 0x1400ffff },
- { 0x0c0004b0, 0x24000001 },
- { 0x0c0004b1, 0x1400ffff },
- { 0x0c0004b2, 0x24000001 },
- { 0x0c0004b3, 0x1400ffff },
- { 0x0c0004b4, 0x24000001 },
- { 0x0c0004b5, 0x1400ffff },
- { 0x0c0004b6, 0x24000001 },
- { 0x0c0004b7, 0x1400ffff },
- { 0x0c0004b8, 0x24000001 },
- { 0x0c0004b9, 0x1400ffff },
- { 0x0c0004ba, 0x24000001 },
- { 0x0c0004bb, 0x1400ffff },
- { 0x0c0004bc, 0x24000001 },
- { 0x0c0004bd, 0x1400ffff },
- { 0x0c0004be, 0x24000001 },
- { 0x0c0004bf, 0x1400ffff },
- { 0x0c0004c0, 0x24000000 },
- { 0x0c0004c1, 0x24000001 },
- { 0x0c0004c2, 0x1400ffff },
- { 0x0c0004c3, 0x24000001 },
- { 0x0c0004c4, 0x1400ffff },
- { 0x0c0004c5, 0x24000001 },
- { 0x0c0004c6, 0x1400ffff },
- { 0x0c0004c7, 0x24000001 },
- { 0x0c0004c8, 0x1400ffff },
- { 0x0c0004c9, 0x24000001 },
- { 0x0c0004ca, 0x1400ffff },
- { 0x0c0004cb, 0x24000001 },
- { 0x0c0004cc, 0x1400ffff },
- { 0x0c0004cd, 0x24000001 },
- { 0x0c0004ce, 0x1400ffff },
- { 0x0c0004d0, 0x24000001 },
- { 0x0c0004d1, 0x1400ffff },
- { 0x0c0004d2, 0x24000001 },
- { 0x0c0004d3, 0x1400ffff },
- { 0x0c0004d4, 0x24000001 },
- { 0x0c0004d5, 0x1400ffff },
- { 0x0c0004d6, 0x24000001 },
- { 0x0c0004d7, 0x1400ffff },
- { 0x0c0004d8, 0x24000001 },
- { 0x0c0004d9, 0x1400ffff },
- { 0x0c0004da, 0x24000001 },
- { 0x0c0004db, 0x1400ffff },
- { 0x0c0004dc, 0x24000001 },
- { 0x0c0004dd, 0x1400ffff },
- { 0x0c0004de, 0x24000001 },
- { 0x0c0004df, 0x1400ffff },
- { 0x0c0004e0, 0x24000001 },
- { 0x0c0004e1, 0x1400ffff },
- { 0x0c0004e2, 0x24000001 },
- { 0x0c0004e3, 0x1400ffff },
- { 0x0c0004e4, 0x24000001 },
- { 0x0c0004e5, 0x1400ffff },
- { 0x0c0004e6, 0x24000001 },
- { 0x0c0004e7, 0x1400ffff },
- { 0x0c0004e8, 0x24000001 },
- { 0x0c0004e9, 0x1400ffff },
- { 0x0c0004ea, 0x24000001 },
- { 0x0c0004eb, 0x1400ffff },
- { 0x0c0004ec, 0x24000001 },
- { 0x0c0004ed, 0x1400ffff },
- { 0x0c0004ee, 0x24000001 },
- { 0x0c0004ef, 0x1400ffff },
- { 0x0c0004f0, 0x24000001 },
- { 0x0c0004f1, 0x1400ffff },
- { 0x0c0004f2, 0x24000001 },
- { 0x0c0004f3, 0x1400ffff },
- { 0x0c0004f4, 0x24000001 },
- { 0x0c0004f5, 0x1400ffff },
- { 0x0c0004f6, 0x24000001 },
- { 0x0c0004f7, 0x1400ffff },
- { 0x0c0004f8, 0x24000001 },
- { 0x0c0004f9, 0x1400ffff },
- { 0x0c000500, 0x24000001 },
- { 0x0c000501, 0x1400ffff },
- { 0x0c000502, 0x24000001 },
- { 0x0c000503, 0x1400ffff },
- { 0x0c000504, 0x24000001 },
- { 0x0c000505, 0x1400ffff },
- { 0x0c000506, 0x24000001 },
- { 0x0c000507, 0x1400ffff },
- { 0x0c000508, 0x24000001 },
- { 0x0c000509, 0x1400ffff },
- { 0x0c00050a, 0x24000001 },
- { 0x0c00050b, 0x1400ffff },
- { 0x0c00050c, 0x24000001 },
- { 0x0c00050d, 0x1400ffff },
- { 0x0c00050e, 0x24000001 },
- { 0x0c00050f, 0x1400ffff },
- { 0x01000531, 0x24000030 },
- { 0x01000532, 0x24000030 },
- { 0x01000533, 0x24000030 },
- { 0x01000534, 0x24000030 },
- { 0x01000535, 0x24000030 },
- { 0x01000536, 0x24000030 },
- { 0x01000537, 0x24000030 },
- { 0x01000538, 0x24000030 },
- { 0x01000539, 0x24000030 },
- { 0x0100053a, 0x24000030 },
- { 0x0100053b, 0x24000030 },
- { 0x0100053c, 0x24000030 },
- { 0x0100053d, 0x24000030 },
- { 0x0100053e, 0x24000030 },
- { 0x0100053f, 0x24000030 },
- { 0x01000540, 0x24000030 },
- { 0x01000541, 0x24000030 },
- { 0x01000542, 0x24000030 },
- { 0x01000543, 0x24000030 },
- { 0x01000544, 0x24000030 },
- { 0x01000545, 0x24000030 },
- { 0x01000546, 0x24000030 },
- { 0x01000547, 0x24000030 },
- { 0x01000548, 0x24000030 },
- { 0x01000549, 0x24000030 },
- { 0x0100054a, 0x24000030 },
- { 0x0100054b, 0x24000030 },
- { 0x0100054c, 0x24000030 },
- { 0x0100054d, 0x24000030 },
- { 0x0100054e, 0x24000030 },
- { 0x0100054f, 0x24000030 },
- { 0x01000550, 0x24000030 },
- { 0x01000551, 0x24000030 },
- { 0x01000552, 0x24000030 },
- { 0x01000553, 0x24000030 },
- { 0x01000554, 0x24000030 },
- { 0x01000555, 0x24000030 },
- { 0x01000556, 0x24000030 },
- { 0x01000559, 0x18000000 },
- { 0x0180055a, 0x54000005 },
- { 0x01000561, 0x1400ffd0 },
- { 0x01000562, 0x1400ffd0 },
- { 0x01000563, 0x1400ffd0 },
- { 0x01000564, 0x1400ffd0 },
- { 0x01000565, 0x1400ffd0 },
- { 0x01000566, 0x1400ffd0 },
- { 0x01000567, 0x1400ffd0 },
- { 0x01000568, 0x1400ffd0 },
- { 0x01000569, 0x1400ffd0 },
- { 0x0100056a, 0x1400ffd0 },
- { 0x0100056b, 0x1400ffd0 },
- { 0x0100056c, 0x1400ffd0 },
- { 0x0100056d, 0x1400ffd0 },
- { 0x0100056e, 0x1400ffd0 },
- { 0x0100056f, 0x1400ffd0 },
- { 0x01000570, 0x1400ffd0 },
- { 0x01000571, 0x1400ffd0 },
- { 0x01000572, 0x1400ffd0 },
- { 0x01000573, 0x1400ffd0 },
- { 0x01000574, 0x1400ffd0 },
- { 0x01000575, 0x1400ffd0 },
- { 0x01000576, 0x1400ffd0 },
- { 0x01000577, 0x1400ffd0 },
- { 0x01000578, 0x1400ffd0 },
- { 0x01000579, 0x1400ffd0 },
- { 0x0100057a, 0x1400ffd0 },
- { 0x0100057b, 0x1400ffd0 },
- { 0x0100057c, 0x1400ffd0 },
- { 0x0100057d, 0x1400ffd0 },
- { 0x0100057e, 0x1400ffd0 },
- { 0x0100057f, 0x1400ffd0 },
- { 0x01000580, 0x1400ffd0 },
- { 0x01000581, 0x1400ffd0 },
- { 0x01000582, 0x1400ffd0 },
- { 0x01000583, 0x1400ffd0 },
- { 0x01000584, 0x1400ffd0 },
- { 0x01000585, 0x1400ffd0 },
- { 0x01000586, 0x1400ffd0 },
- { 0x01000587, 0x14000000 },
- { 0x09000589, 0x54000000 },
- { 0x0100058a, 0x44000000 },
- { 0x19800591, 0x30000028 },
- { 0x198005bb, 0x30000002 },
- { 0x190005be, 0x54000000 },
- { 0x190005bf, 0x30000000 },
- { 0x190005c0, 0x54000000 },
- { 0x198005c1, 0x30000001 },
- { 0x190005c3, 0x54000000 },
- { 0x198005c4, 0x30000001 },
- { 0x190005c6, 0x54000000 },
- { 0x190005c7, 0x30000000 },
- { 0x198005d0, 0x1c00001a },
- { 0x198005f0, 0x1c000002 },
- { 0x198005f3, 0x54000001 },
- { 0x09800600, 0x04000003 },
- { 0x0000060b, 0x5c000000 },
- { 0x0980060c, 0x54000001 },
- { 0x0080060e, 0x68000001 },
- { 0x00800610, 0x30000005 },
- { 0x0900061b, 0x54000000 },
- { 0x0080061e, 0x54000001 },
- { 0x00800621, 0x1c000019 },
- { 0x09000640, 0x18000000 },
- { 0x00800641, 0x1c000009 },
- { 0x1b80064b, 0x30000013 },
- { 0x09800660, 0x34000009 },
- { 0x0080066a, 0x54000003 },
- { 0x0080066e, 0x1c000001 },
- { 0x1b000670, 0x30000000 },
- { 0x00800671, 0x1c000062 },
- { 0x000006d4, 0x54000000 },
- { 0x000006d5, 0x1c000000 },
- { 0x008006d6, 0x30000006 },
- { 0x090006dd, 0x04000000 },
- { 0x000006de, 0x2c000000 },
- { 0x008006df, 0x30000005 },
- { 0x008006e5, 0x18000001 },
- { 0x008006e7, 0x30000001 },
- { 0x000006e9, 0x68000000 },
- { 0x008006ea, 0x30000003 },
- { 0x008006ee, 0x1c000001 },
- { 0x008006f0, 0x34000009 },
- { 0x008006fa, 0x1c000002 },
- { 0x008006fd, 0x68000001 },
- { 0x000006ff, 0x1c000000 },
- { 0x31800700, 0x5400000d },
- { 0x3100070f, 0x04000000 },
- { 0x31000710, 0x1c000000 },
- { 0x31000711, 0x30000000 },
- { 0x31800712, 0x1c00001d },
- { 0x31800730, 0x3000001a },
- { 0x3180074d, 0x1c000020 },
- { 0x37800780, 0x1c000025 },
- { 0x378007a6, 0x3000000a },
- { 0x370007b1, 0x1c000000 },
- { 0x0e800901, 0x30000001 },
- { 0x0e000903, 0x28000000 },
- { 0x0e800904, 0x1c000035 },
- { 0x0e00093c, 0x30000000 },
- { 0x0e00093d, 0x1c000000 },
- { 0x0e80093e, 0x28000002 },
- { 0x0e800941, 0x30000007 },
- { 0x0e800949, 0x28000003 },
- { 0x0e00094d, 0x30000000 },
- { 0x0e000950, 0x1c000000 },
- { 0x0e800951, 0x30000003 },
- { 0x0e800958, 0x1c000009 },
- { 0x0e800962, 0x30000001 },
- { 0x09800964, 0x54000001 },
- { 0x0e800966, 0x34000009 },
- { 0x09000970, 0x54000000 },
- { 0x0e00097d, 0x1c000000 },
- { 0x02000981, 0x30000000 },
- { 0x02800982, 0x28000001 },
- { 0x02800985, 0x1c000007 },
- { 0x0280098f, 0x1c000001 },
- { 0x02800993, 0x1c000015 },
- { 0x028009aa, 0x1c000006 },
- { 0x020009b2, 0x1c000000 },
- { 0x028009b6, 0x1c000003 },
- { 0x020009bc, 0x30000000 },
- { 0x020009bd, 0x1c000000 },
- { 0x028009be, 0x28000002 },
- { 0x028009c1, 0x30000003 },
- { 0x028009c7, 0x28000001 },
- { 0x028009cb, 0x28000001 },
- { 0x020009cd, 0x30000000 },
- { 0x020009ce, 0x1c000000 },
- { 0x020009d7, 0x28000000 },
- { 0x028009dc, 0x1c000001 },
- { 0x028009df, 0x1c000002 },
- { 0x028009e2, 0x30000001 },
- { 0x028009e6, 0x34000009 },
- { 0x028009f0, 0x1c000001 },
- { 0x028009f2, 0x5c000001 },
- { 0x028009f4, 0x3c000005 },
- { 0x020009fa, 0x68000000 },
- { 0x15800a01, 0x30000001 },
- { 0x15000a03, 0x28000000 },
- { 0x15800a05, 0x1c000005 },
- { 0x15800a0f, 0x1c000001 },
- { 0x15800a13, 0x1c000015 },
- { 0x15800a2a, 0x1c000006 },
- { 0x15800a32, 0x1c000001 },
- { 0x15800a35, 0x1c000001 },
- { 0x15800a38, 0x1c000001 },
- { 0x15000a3c, 0x30000000 },
- { 0x15800a3e, 0x28000002 },
- { 0x15800a41, 0x30000001 },
- { 0x15800a47, 0x30000001 },
- { 0x15800a4b, 0x30000002 },
- { 0x15800a59, 0x1c000003 },
- { 0x15000a5e, 0x1c000000 },
- { 0x15800a66, 0x34000009 },
- { 0x15800a70, 0x30000001 },
- { 0x15800a72, 0x1c000002 },
- { 0x14800a81, 0x30000001 },
- { 0x14000a83, 0x28000000 },
- { 0x14800a85, 0x1c000008 },
- { 0x14800a8f, 0x1c000002 },
- { 0x14800a93, 0x1c000015 },
- { 0x14800aaa, 0x1c000006 },
- { 0x14800ab2, 0x1c000001 },
- { 0x14800ab5, 0x1c000004 },
- { 0x14000abc, 0x30000000 },
- { 0x14000abd, 0x1c000000 },
- { 0x14800abe, 0x28000002 },
- { 0x14800ac1, 0x30000004 },
- { 0x14800ac7, 0x30000001 },
- { 0x14000ac9, 0x28000000 },
- { 0x14800acb, 0x28000001 },
- { 0x14000acd, 0x30000000 },
- { 0x14000ad0, 0x1c000000 },
- { 0x14800ae0, 0x1c000001 },
- { 0x14800ae2, 0x30000001 },
- { 0x14800ae6, 0x34000009 },
- { 0x14000af1, 0x5c000000 },
- { 0x2b000b01, 0x30000000 },
- { 0x2b800b02, 0x28000001 },
- { 0x2b800b05, 0x1c000007 },
- { 0x2b800b0f, 0x1c000001 },
- { 0x2b800b13, 0x1c000015 },
- { 0x2b800b2a, 0x1c000006 },
- { 0x2b800b32, 0x1c000001 },
- { 0x2b800b35, 0x1c000004 },
- { 0x2b000b3c, 0x30000000 },
- { 0x2b000b3d, 0x1c000000 },
- { 0x2b000b3e, 0x28000000 },
- { 0x2b000b3f, 0x30000000 },
- { 0x2b000b40, 0x28000000 },
- { 0x2b800b41, 0x30000002 },
- { 0x2b800b47, 0x28000001 },
- { 0x2b800b4b, 0x28000001 },
- { 0x2b000b4d, 0x30000000 },
- { 0x2b000b56, 0x30000000 },
- { 0x2b000b57, 0x28000000 },
- { 0x2b800b5c, 0x1c000001 },
- { 0x2b800b5f, 0x1c000002 },
- { 0x2b800b66, 0x34000009 },
- { 0x2b000b70, 0x68000000 },
- { 0x2b000b71, 0x1c000000 },
- { 0x35000b82, 0x30000000 },
- { 0x35000b83, 0x1c000000 },
- { 0x35800b85, 0x1c000005 },
- { 0x35800b8e, 0x1c000002 },
- { 0x35800b92, 0x1c000003 },
- { 0x35800b99, 0x1c000001 },
- { 0x35000b9c, 0x1c000000 },
- { 0x35800b9e, 0x1c000001 },
- { 0x35800ba3, 0x1c000001 },
- { 0x35800ba8, 0x1c000002 },
- { 0x35800bae, 0x1c00000b },
- { 0x35800bbe, 0x28000001 },
- { 0x35000bc0, 0x30000000 },
- { 0x35800bc1, 0x28000001 },
- { 0x35800bc6, 0x28000002 },
- { 0x35800bca, 0x28000002 },
- { 0x35000bcd, 0x30000000 },
- { 0x35000bd7, 0x28000000 },
- { 0x35800be6, 0x34000009 },
- { 0x35800bf0, 0x3c000002 },
- { 0x35800bf3, 0x68000005 },
- { 0x35000bf9, 0x5c000000 },
- { 0x35000bfa, 0x68000000 },
- { 0x36800c01, 0x28000002 },
- { 0x36800c05, 0x1c000007 },
- { 0x36800c0e, 0x1c000002 },
- { 0x36800c12, 0x1c000016 },
- { 0x36800c2a, 0x1c000009 },
- { 0x36800c35, 0x1c000004 },
- { 0x36800c3e, 0x30000002 },
- { 0x36800c41, 0x28000003 },
- { 0x36800c46, 0x30000002 },
- { 0x36800c4a, 0x30000003 },
- { 0x36800c55, 0x30000001 },
- { 0x36800c60, 0x1c000001 },
- { 0x36800c66, 0x34000009 },
- { 0x1c800c82, 0x28000001 },
- { 0x1c800c85, 0x1c000007 },
- { 0x1c800c8e, 0x1c000002 },
- { 0x1c800c92, 0x1c000016 },
- { 0x1c800caa, 0x1c000009 },
- { 0x1c800cb5, 0x1c000004 },
- { 0x1c000cbc, 0x30000000 },
- { 0x1c000cbd, 0x1c000000 },
- { 0x1c000cbe, 0x28000000 },
- { 0x1c000cbf, 0x30000000 },
- { 0x1c800cc0, 0x28000004 },
- { 0x1c000cc6, 0x30000000 },
- { 0x1c800cc7, 0x28000001 },
- { 0x1c800cca, 0x28000001 },
- { 0x1c800ccc, 0x30000001 },
- { 0x1c800cd5, 0x28000001 },
- { 0x1c000cde, 0x1c000000 },
- { 0x1c800ce0, 0x1c000001 },
- { 0x1c800ce6, 0x34000009 },
- { 0x24800d02, 0x28000001 },
- { 0x24800d05, 0x1c000007 },
- { 0x24800d0e, 0x1c000002 },
- { 0x24800d12, 0x1c000016 },
- { 0x24800d2a, 0x1c00000f },
- { 0x24800d3e, 0x28000002 },
- { 0x24800d41, 0x30000002 },
- { 0x24800d46, 0x28000002 },
- { 0x24800d4a, 0x28000002 },
- { 0x24000d4d, 0x30000000 },
- { 0x24000d57, 0x28000000 },
- { 0x24800d60, 0x1c000001 },
- { 0x24800d66, 0x34000009 },
- { 0x2f800d82, 0x28000001 },
- { 0x2f800d85, 0x1c000011 },
- { 0x2f800d9a, 0x1c000017 },
- { 0x2f800db3, 0x1c000008 },
- { 0x2f000dbd, 0x1c000000 },
- { 0x2f800dc0, 0x1c000006 },
- { 0x2f000dca, 0x30000000 },
- { 0x2f800dcf, 0x28000002 },
- { 0x2f800dd2, 0x30000002 },
- { 0x2f000dd6, 0x30000000 },
- { 0x2f800dd8, 0x28000007 },
- { 0x2f800df2, 0x28000001 },
- { 0x2f000df4, 0x54000000 },
- { 0x38800e01, 0x1c00002f },
- { 0x38000e31, 0x30000000 },
- { 0x38800e32, 0x1c000001 },
- { 0x38800e34, 0x30000006 },
- { 0x09000e3f, 0x5c000000 },
- { 0x38800e40, 0x1c000005 },
- { 0x38000e46, 0x18000000 },
- { 0x38800e47, 0x30000007 },
- { 0x38000e4f, 0x54000000 },
- { 0x38800e50, 0x34000009 },
- { 0x38800e5a, 0x54000001 },
- { 0x20800e81, 0x1c000001 },
- { 0x20000e84, 0x1c000000 },
- { 0x20800e87, 0x1c000001 },
- { 0x20000e8a, 0x1c000000 },
- { 0x20000e8d, 0x1c000000 },
- { 0x20800e94, 0x1c000003 },
- { 0x20800e99, 0x1c000006 },
- { 0x20800ea1, 0x1c000002 },
- { 0x20000ea5, 0x1c000000 },
- { 0x20000ea7, 0x1c000000 },
- { 0x20800eaa, 0x1c000001 },
- { 0x20800ead, 0x1c000003 },
- { 0x20000eb1, 0x30000000 },
- { 0x20800eb2, 0x1c000001 },
- { 0x20800eb4, 0x30000005 },
- { 0x20800ebb, 0x30000001 },
- { 0x20000ebd, 0x1c000000 },
- { 0x20800ec0, 0x1c000004 },
- { 0x20000ec6, 0x18000000 },
- { 0x20800ec8, 0x30000005 },
- { 0x20800ed0, 0x34000009 },
- { 0x20800edc, 0x1c000001 },
- { 0x39000f00, 0x1c000000 },
- { 0x39800f01, 0x68000002 },
- { 0x39800f04, 0x5400000e },
- { 0x39800f13, 0x68000004 },
- { 0x39800f18, 0x30000001 },
- { 0x39800f1a, 0x68000005 },
- { 0x39800f20, 0x34000009 },
- { 0x39800f2a, 0x3c000009 },
- { 0x39000f34, 0x68000000 },
- { 0x39000f35, 0x30000000 },
- { 0x39000f36, 0x68000000 },
- { 0x39000f37, 0x30000000 },
- { 0x39000f38, 0x68000000 },
- { 0x39000f39, 0x30000000 },
- { 0x39000f3a, 0x58000000 },
- { 0x39000f3b, 0x48000000 },
- { 0x39000f3c, 0x58000000 },
- { 0x39000f3d, 0x48000000 },
- { 0x39800f3e, 0x28000001 },
- { 0x39800f40, 0x1c000007 },
- { 0x39800f49, 0x1c000021 },
- { 0x39800f71, 0x3000000d },
- { 0x39000f7f, 0x28000000 },
- { 0x39800f80, 0x30000004 },
- { 0x39000f85, 0x54000000 },
- { 0x39800f86, 0x30000001 },
- { 0x39800f88, 0x1c000003 },
- { 0x39800f90, 0x30000007 },
- { 0x39800f99, 0x30000023 },
- { 0x39800fbe, 0x68000007 },
- { 0x39000fc6, 0x30000000 },
- { 0x39800fc7, 0x68000005 },
- { 0x39000fcf, 0x68000000 },
- { 0x39800fd0, 0x54000001 },
- { 0x26801000, 0x1c000021 },
- { 0x26801023, 0x1c000004 },
- { 0x26801029, 0x1c000001 },
- { 0x2600102c, 0x28000000 },
- { 0x2680102d, 0x30000003 },
- { 0x26001031, 0x28000000 },
- { 0x26001032, 0x30000000 },
- { 0x26801036, 0x30000001 },
- { 0x26001038, 0x28000000 },
- { 0x26001039, 0x30000000 },
- { 0x26801040, 0x34000009 },
- { 0x2680104a, 0x54000005 },
- { 0x26801050, 0x1c000005 },
- { 0x26801056, 0x28000001 },
- { 0x26801058, 0x30000001 },
- { 0x100010a0, 0x24001c60 },
- { 0x100010a1, 0x24001c60 },
- { 0x100010a2, 0x24001c60 },
- { 0x100010a3, 0x24001c60 },
- { 0x100010a4, 0x24001c60 },
- { 0x100010a5, 0x24001c60 },
- { 0x100010a6, 0x24001c60 },
- { 0x100010a7, 0x24001c60 },
- { 0x100010a8, 0x24001c60 },
- { 0x100010a9, 0x24001c60 },
- { 0x100010aa, 0x24001c60 },
- { 0x100010ab, 0x24001c60 },
- { 0x100010ac, 0x24001c60 },
- { 0x100010ad, 0x24001c60 },
- { 0x100010ae, 0x24001c60 },
- { 0x100010af, 0x24001c60 },
- { 0x100010b0, 0x24001c60 },
- { 0x100010b1, 0x24001c60 },
- { 0x100010b2, 0x24001c60 },
- { 0x100010b3, 0x24001c60 },
- { 0x100010b4, 0x24001c60 },
- { 0x100010b5, 0x24001c60 },
- { 0x100010b6, 0x24001c60 },
- { 0x100010b7, 0x24001c60 },
- { 0x100010b8, 0x24001c60 },
- { 0x100010b9, 0x24001c60 },
- { 0x100010ba, 0x24001c60 },
- { 0x100010bb, 0x24001c60 },
- { 0x100010bc, 0x24001c60 },
- { 0x100010bd, 0x24001c60 },
- { 0x100010be, 0x24001c60 },
- { 0x100010bf, 0x24001c60 },
- { 0x100010c0, 0x24001c60 },
- { 0x100010c1, 0x24001c60 },
- { 0x100010c2, 0x24001c60 },
- { 0x100010c3, 0x24001c60 },
- { 0x100010c4, 0x24001c60 },
- { 0x100010c5, 0x24001c60 },
- { 0x108010d0, 0x1c00002a },
- { 0x090010fb, 0x54000000 },
- { 0x100010fc, 0x18000000 },
- { 0x17801100, 0x1c000059 },
- { 0x1780115f, 0x1c000043 },
- { 0x178011a8, 0x1c000051 },
- { 0x0f801200, 0x1c000048 },
- { 0x0f80124a, 0x1c000003 },
- { 0x0f801250, 0x1c000006 },
- { 0x0f001258, 0x1c000000 },
- { 0x0f80125a, 0x1c000003 },
- { 0x0f801260, 0x1c000028 },
- { 0x0f80128a, 0x1c000003 },
- { 0x0f801290, 0x1c000020 },
- { 0x0f8012b2, 0x1c000003 },
- { 0x0f8012b8, 0x1c000006 },
- { 0x0f0012c0, 0x1c000000 },
- { 0x0f8012c2, 0x1c000003 },
- { 0x0f8012c8, 0x1c00000e },
- { 0x0f8012d8, 0x1c000038 },
- { 0x0f801312, 0x1c000003 },
- { 0x0f801318, 0x1c000042 },
- { 0x0f00135f, 0x30000000 },
- { 0x0f001360, 0x68000000 },
- { 0x0f801361, 0x54000007 },
- { 0x0f801369, 0x3c000013 },
- { 0x0f801380, 0x1c00000f },
- { 0x0f801390, 0x68000009 },
- { 0x088013a0, 0x1c000054 },
- { 0x07801401, 0x1c00026b },
- { 0x0780166d, 0x54000001 },
- { 0x0780166f, 0x1c000007 },
- { 0x28001680, 0x74000000 },
- { 0x28801681, 0x1c000019 },
- { 0x2800169b, 0x58000000 },
- { 0x2800169c, 0x48000000 },
- { 0x2d8016a0, 0x1c00004a },
- { 0x098016eb, 0x54000002 },
- { 0x2d8016ee, 0x38000002 },
- { 0x32801700, 0x1c00000c },
- { 0x3280170e, 0x1c000003 },
- { 0x32801712, 0x30000002 },
- { 0x18801720, 0x1c000011 },
- { 0x18801732, 0x30000002 },
- { 0x09801735, 0x54000001 },
- { 0x06801740, 0x1c000011 },
- { 0x06801752, 0x30000001 },
- { 0x33801760, 0x1c00000c },
- { 0x3380176e, 0x1c000002 },
- { 0x33801772, 0x30000001 },
- { 0x1f801780, 0x1c000033 },
- { 0x1f8017b4, 0x04000001 },
- { 0x1f0017b6, 0x28000000 },
- { 0x1f8017b7, 0x30000006 },
- { 0x1f8017be, 0x28000007 },
- { 0x1f0017c6, 0x30000000 },
- { 0x1f8017c7, 0x28000001 },
- { 0x1f8017c9, 0x3000000a },
- { 0x1f8017d4, 0x54000002 },
- { 0x1f0017d7, 0x18000000 },
- { 0x1f8017d8, 0x54000002 },
- { 0x1f0017db, 0x5c000000 },
- { 0x1f0017dc, 0x1c000000 },
- { 0x1f0017dd, 0x30000000 },
- { 0x1f8017e0, 0x34000009 },
- { 0x1f8017f0, 0x3c000009 },
- { 0x25801800, 0x54000005 },
- { 0x25001806, 0x44000000 },
- { 0x25801807, 0x54000003 },
- { 0x2580180b, 0x30000002 },
- { 0x2500180e, 0x74000000 },
- { 0x25801810, 0x34000009 },
- { 0x25801820, 0x1c000022 },
- { 0x25001843, 0x18000000 },
- { 0x25801844, 0x1c000033 },
- { 0x25801880, 0x1c000028 },
- { 0x250018a9, 0x30000000 },
- { 0x22801900, 0x1c00001c },
- { 0x22801920, 0x30000002 },
- { 0x22801923, 0x28000003 },
- { 0x22801927, 0x30000001 },
- { 0x22801929, 0x28000002 },
- { 0x22801930, 0x28000001 },
- { 0x22001932, 0x30000000 },
- { 0x22801933, 0x28000005 },
- { 0x22801939, 0x30000002 },
- { 0x22001940, 0x68000000 },
- { 0x22801944, 0x54000001 },
- { 0x22801946, 0x34000009 },
- { 0x34801950, 0x1c00001d },
- { 0x34801970, 0x1c000004 },
- { 0x27801980, 0x1c000029 },
- { 0x278019b0, 0x28000010 },
- { 0x278019c1, 0x1c000006 },
- { 0x278019c8, 0x28000001 },
- { 0x278019d0, 0x34000009 },
- { 0x278019de, 0x54000001 },
- { 0x1f8019e0, 0x6800001f },
- { 0x05801a00, 0x1c000016 },
- { 0x05801a17, 0x30000001 },
- { 0x05801a19, 0x28000002 },
- { 0x05801a1e, 0x54000001 },
- { 0x21801d00, 0x1400002b },
- { 0x21801d2c, 0x18000035 },
- { 0x21801d62, 0x14000015 },
- { 0x0c001d78, 0x18000000 },
- { 0x21801d79, 0x14000021 },
- { 0x21801d9b, 0x18000024 },
- { 0x1b801dc0, 0x30000003 },
- { 0x21001e00, 0x24000001 },
- { 0x21001e01, 0x1400ffff },
- { 0x21001e02, 0x24000001 },
- { 0x21001e03, 0x1400ffff },
- { 0x21001e04, 0x24000001 },
- { 0x21001e05, 0x1400ffff },
- { 0x21001e06, 0x24000001 },
- { 0x21001e07, 0x1400ffff },
- { 0x21001e08, 0x24000001 },
- { 0x21001e09, 0x1400ffff },
- { 0x21001e0a, 0x24000001 },
- { 0x21001e0b, 0x1400ffff },
- { 0x21001e0c, 0x24000001 },
- { 0x21001e0d, 0x1400ffff },
- { 0x21001e0e, 0x24000001 },
- { 0x21001e0f, 0x1400ffff },
- { 0x21001e10, 0x24000001 },
- { 0x21001e11, 0x1400ffff },
- { 0x21001e12, 0x24000001 },
- { 0x21001e13, 0x1400ffff },
- { 0x21001e14, 0x24000001 },
- { 0x21001e15, 0x1400ffff },
- { 0x21001e16, 0x24000001 },
- { 0x21001e17, 0x1400ffff },
- { 0x21001e18, 0x24000001 },
- { 0x21001e19, 0x1400ffff },
- { 0x21001e1a, 0x24000001 },
- { 0x21001e1b, 0x1400ffff },
- { 0x21001e1c, 0x24000001 },
- { 0x21001e1d, 0x1400ffff },
- { 0x21001e1e, 0x24000001 },
- { 0x21001e1f, 0x1400ffff },
- { 0x21001e20, 0x24000001 },
- { 0x21001e21, 0x1400ffff },
- { 0x21001e22, 0x24000001 },
- { 0x21001e23, 0x1400ffff },
- { 0x21001e24, 0x24000001 },
- { 0x21001e25, 0x1400ffff },
- { 0x21001e26, 0x24000001 },
- { 0x21001e27, 0x1400ffff },
- { 0x21001e28, 0x24000001 },
- { 0x21001e29, 0x1400ffff },
- { 0x21001e2a, 0x24000001 },
- { 0x21001e2b, 0x1400ffff },
- { 0x21001e2c, 0x24000001 },
- { 0x21001e2d, 0x1400ffff },
- { 0x21001e2e, 0x24000001 },
- { 0x21001e2f, 0x1400ffff },
- { 0x21001e30, 0x24000001 },
- { 0x21001e31, 0x1400ffff },
- { 0x21001e32, 0x24000001 },
- { 0x21001e33, 0x1400ffff },
- { 0x21001e34, 0x24000001 },
- { 0x21001e35, 0x1400ffff },
- { 0x21001e36, 0x24000001 },
- { 0x21001e37, 0x1400ffff },
- { 0x21001e38, 0x24000001 },
- { 0x21001e39, 0x1400ffff },
- { 0x21001e3a, 0x24000001 },
- { 0x21001e3b, 0x1400ffff },
- { 0x21001e3c, 0x24000001 },
- { 0x21001e3d, 0x1400ffff },
- { 0x21001e3e, 0x24000001 },
- { 0x21001e3f, 0x1400ffff },
- { 0x21001e40, 0x24000001 },
- { 0x21001e41, 0x1400ffff },
- { 0x21001e42, 0x24000001 },
- { 0x21001e43, 0x1400ffff },
- { 0x21001e44, 0x24000001 },
- { 0x21001e45, 0x1400ffff },
- { 0x21001e46, 0x24000001 },
- { 0x21001e47, 0x1400ffff },
- { 0x21001e48, 0x24000001 },
- { 0x21001e49, 0x1400ffff },
- { 0x21001e4a, 0x24000001 },
- { 0x21001e4b, 0x1400ffff },
- { 0x21001e4c, 0x24000001 },
- { 0x21001e4d, 0x1400ffff },
- { 0x21001e4e, 0x24000001 },
- { 0x21001e4f, 0x1400ffff },
- { 0x21001e50, 0x24000001 },
- { 0x21001e51, 0x1400ffff },
- { 0x21001e52, 0x24000001 },
- { 0x21001e53, 0x1400ffff },
- { 0x21001e54, 0x24000001 },
- { 0x21001e55, 0x1400ffff },
- { 0x21001e56, 0x24000001 },
- { 0x21001e57, 0x1400ffff },
- { 0x21001e58, 0x24000001 },
- { 0x21001e59, 0x1400ffff },
- { 0x21001e5a, 0x24000001 },
- { 0x21001e5b, 0x1400ffff },
- { 0x21001e5c, 0x24000001 },
- { 0x21001e5d, 0x1400ffff },
- { 0x21001e5e, 0x24000001 },
- { 0x21001e5f, 0x1400ffff },
- { 0x21001e60, 0x24000001 },
- { 0x21001e61, 0x1400ffff },
- { 0x21001e62, 0x24000001 },
- { 0x21001e63, 0x1400ffff },
- { 0x21001e64, 0x24000001 },
- { 0x21001e65, 0x1400ffff },
- { 0x21001e66, 0x24000001 },
- { 0x21001e67, 0x1400ffff },
- { 0x21001e68, 0x24000001 },
- { 0x21001e69, 0x1400ffff },
- { 0x21001e6a, 0x24000001 },
- { 0x21001e6b, 0x1400ffff },
- { 0x21001e6c, 0x24000001 },
- { 0x21001e6d, 0x1400ffff },
- { 0x21001e6e, 0x24000001 },
- { 0x21001e6f, 0x1400ffff },
- { 0x21001e70, 0x24000001 },
- { 0x21001e71, 0x1400ffff },
- { 0x21001e72, 0x24000001 },
- { 0x21001e73, 0x1400ffff },
- { 0x21001e74, 0x24000001 },
- { 0x21001e75, 0x1400ffff },
- { 0x21001e76, 0x24000001 },
- { 0x21001e77, 0x1400ffff },
- { 0x21001e78, 0x24000001 },
- { 0x21001e79, 0x1400ffff },
- { 0x21001e7a, 0x24000001 },
- { 0x21001e7b, 0x1400ffff },
- { 0x21001e7c, 0x24000001 },
- { 0x21001e7d, 0x1400ffff },
- { 0x21001e7e, 0x24000001 },
- { 0x21001e7f, 0x1400ffff },
- { 0x21001e80, 0x24000001 },
- { 0x21001e81, 0x1400ffff },
- { 0x21001e82, 0x24000001 },
- { 0x21001e83, 0x1400ffff },
- { 0x21001e84, 0x24000001 },
- { 0x21001e85, 0x1400ffff },
- { 0x21001e86, 0x24000001 },
- { 0x21001e87, 0x1400ffff },
- { 0x21001e88, 0x24000001 },
- { 0x21001e89, 0x1400ffff },
- { 0x21001e8a, 0x24000001 },
- { 0x21001e8b, 0x1400ffff },
- { 0x21001e8c, 0x24000001 },
- { 0x21001e8d, 0x1400ffff },
- { 0x21001e8e, 0x24000001 },
- { 0x21001e8f, 0x1400ffff },
- { 0x21001e90, 0x24000001 },
- { 0x21001e91, 0x1400ffff },
- { 0x21001e92, 0x24000001 },
- { 0x21001e93, 0x1400ffff },
- { 0x21001e94, 0x24000001 },
- { 0x21001e95, 0x1400ffff },
- { 0x21801e96, 0x14000004 },
- { 0x21001e9b, 0x1400ffc5 },
- { 0x21001ea0, 0x24000001 },
- { 0x21001ea1, 0x1400ffff },
- { 0x21001ea2, 0x24000001 },
- { 0x21001ea3, 0x1400ffff },
- { 0x21001ea4, 0x24000001 },
- { 0x21001ea5, 0x1400ffff },
- { 0x21001ea6, 0x24000001 },
- { 0x21001ea7, 0x1400ffff },
- { 0x21001ea8, 0x24000001 },
- { 0x21001ea9, 0x1400ffff },
- { 0x21001eaa, 0x24000001 },
- { 0x21001eab, 0x1400ffff },
- { 0x21001eac, 0x24000001 },
- { 0x21001ead, 0x1400ffff },
- { 0x21001eae, 0x24000001 },
- { 0x21001eaf, 0x1400ffff },
- { 0x21001eb0, 0x24000001 },
- { 0x21001eb1, 0x1400ffff },
- { 0x21001eb2, 0x24000001 },
- { 0x21001eb3, 0x1400ffff },
- { 0x21001eb4, 0x24000001 },
- { 0x21001eb5, 0x1400ffff },
- { 0x21001eb6, 0x24000001 },
- { 0x21001eb7, 0x1400ffff },
- { 0x21001eb8, 0x24000001 },
- { 0x21001eb9, 0x1400ffff },
- { 0x21001eba, 0x24000001 },
- { 0x21001ebb, 0x1400ffff },
- { 0x21001ebc, 0x24000001 },
- { 0x21001ebd, 0x1400ffff },
- { 0x21001ebe, 0x24000001 },
- { 0x21001ebf, 0x1400ffff },
- { 0x21001ec0, 0x24000001 },
- { 0x21001ec1, 0x1400ffff },
- { 0x21001ec2, 0x24000001 },
- { 0x21001ec3, 0x1400ffff },
- { 0x21001ec4, 0x24000001 },
- { 0x21001ec5, 0x1400ffff },
- { 0x21001ec6, 0x24000001 },
- { 0x21001ec7, 0x1400ffff },
- { 0x21001ec8, 0x24000001 },
- { 0x21001ec9, 0x1400ffff },
- { 0x21001eca, 0x24000001 },
- { 0x21001ecb, 0x1400ffff },
- { 0x21001ecc, 0x24000001 },
- { 0x21001ecd, 0x1400ffff },
- { 0x21001ece, 0x24000001 },
- { 0x21001ecf, 0x1400ffff },
- { 0x21001ed0, 0x24000001 },
- { 0x21001ed1, 0x1400ffff },
- { 0x21001ed2, 0x24000001 },
- { 0x21001ed3, 0x1400ffff },
- { 0x21001ed4, 0x24000001 },
- { 0x21001ed5, 0x1400ffff },
- { 0x21001ed6, 0x24000001 },
- { 0x21001ed7, 0x1400ffff },
- { 0x21001ed8, 0x24000001 },
- { 0x21001ed9, 0x1400ffff },
- { 0x21001eda, 0x24000001 },
- { 0x21001edb, 0x1400ffff },
- { 0x21001edc, 0x24000001 },
- { 0x21001edd, 0x1400ffff },
- { 0x21001ede, 0x24000001 },
- { 0x21001edf, 0x1400ffff },
- { 0x21001ee0, 0x24000001 },
- { 0x21001ee1, 0x1400ffff },
- { 0x21001ee2, 0x24000001 },
- { 0x21001ee3, 0x1400ffff },
- { 0x21001ee4, 0x24000001 },
- { 0x21001ee5, 0x1400ffff },
- { 0x21001ee6, 0x24000001 },
- { 0x21001ee7, 0x1400ffff },
- { 0x21001ee8, 0x24000001 },
- { 0x21001ee9, 0x1400ffff },
- { 0x21001eea, 0x24000001 },
- { 0x21001eeb, 0x1400ffff },
- { 0x21001eec, 0x24000001 },
- { 0x21001eed, 0x1400ffff },
- { 0x21001eee, 0x24000001 },
- { 0x21001eef, 0x1400ffff },
- { 0x21001ef0, 0x24000001 },
- { 0x21001ef1, 0x1400ffff },
- { 0x21001ef2, 0x24000001 },
- { 0x21001ef3, 0x1400ffff },
- { 0x21001ef4, 0x24000001 },
- { 0x21001ef5, 0x1400ffff },
- { 0x21001ef6, 0x24000001 },
- { 0x21001ef7, 0x1400ffff },
- { 0x21001ef8, 0x24000001 },
- { 0x21001ef9, 0x1400ffff },
- { 0x13001f00, 0x14000008 },
- { 0x13001f01, 0x14000008 },
- { 0x13001f02, 0x14000008 },
- { 0x13001f03, 0x14000008 },
- { 0x13001f04, 0x14000008 },
- { 0x13001f05, 0x14000008 },
- { 0x13001f06, 0x14000008 },
- { 0x13001f07, 0x14000008 },
- { 0x13001f08, 0x2400fff8 },
- { 0x13001f09, 0x2400fff8 },
- { 0x13001f0a, 0x2400fff8 },
- { 0x13001f0b, 0x2400fff8 },
- { 0x13001f0c, 0x2400fff8 },
- { 0x13001f0d, 0x2400fff8 },
- { 0x13001f0e, 0x2400fff8 },
- { 0x13001f0f, 0x2400fff8 },
- { 0x13001f10, 0x14000008 },
- { 0x13001f11, 0x14000008 },
- { 0x13001f12, 0x14000008 },
- { 0x13001f13, 0x14000008 },
- { 0x13001f14, 0x14000008 },
- { 0x13001f15, 0x14000008 },
- { 0x13001f18, 0x2400fff8 },
- { 0x13001f19, 0x2400fff8 },
- { 0x13001f1a, 0x2400fff8 },
- { 0x13001f1b, 0x2400fff8 },
- { 0x13001f1c, 0x2400fff8 },
- { 0x13001f1d, 0x2400fff8 },
- { 0x13001f20, 0x14000008 },
- { 0x13001f21, 0x14000008 },
- { 0x13001f22, 0x14000008 },
- { 0x13001f23, 0x14000008 },
- { 0x13001f24, 0x14000008 },
- { 0x13001f25, 0x14000008 },
- { 0x13001f26, 0x14000008 },
- { 0x13001f27, 0x14000008 },
- { 0x13001f28, 0x2400fff8 },
- { 0x13001f29, 0x2400fff8 },
- { 0x13001f2a, 0x2400fff8 },
- { 0x13001f2b, 0x2400fff8 },
- { 0x13001f2c, 0x2400fff8 },
- { 0x13001f2d, 0x2400fff8 },
- { 0x13001f2e, 0x2400fff8 },
- { 0x13001f2f, 0x2400fff8 },
- { 0x13001f30, 0x14000008 },
- { 0x13001f31, 0x14000008 },
- { 0x13001f32, 0x14000008 },
- { 0x13001f33, 0x14000008 },
- { 0x13001f34, 0x14000008 },
- { 0x13001f35, 0x14000008 },
- { 0x13001f36, 0x14000008 },
- { 0x13001f37, 0x14000008 },
- { 0x13001f38, 0x2400fff8 },
- { 0x13001f39, 0x2400fff8 },
- { 0x13001f3a, 0x2400fff8 },
- { 0x13001f3b, 0x2400fff8 },
- { 0x13001f3c, 0x2400fff8 },
- { 0x13001f3d, 0x2400fff8 },
- { 0x13001f3e, 0x2400fff8 },
- { 0x13001f3f, 0x2400fff8 },
- { 0x13001f40, 0x14000008 },
- { 0x13001f41, 0x14000008 },
- { 0x13001f42, 0x14000008 },
- { 0x13001f43, 0x14000008 },
- { 0x13001f44, 0x14000008 },
- { 0x13001f45, 0x14000008 },
- { 0x13001f48, 0x2400fff8 },
- { 0x13001f49, 0x2400fff8 },
- { 0x13001f4a, 0x2400fff8 },
- { 0x13001f4b, 0x2400fff8 },
- { 0x13001f4c, 0x2400fff8 },
- { 0x13001f4d, 0x2400fff8 },
- { 0x13001f50, 0x14000000 },
- { 0x13001f51, 0x14000008 },
- { 0x13001f52, 0x14000000 },
- { 0x13001f53, 0x14000008 },
- { 0x13001f54, 0x14000000 },
- { 0x13001f55, 0x14000008 },
- { 0x13001f56, 0x14000000 },
- { 0x13001f57, 0x14000008 },
- { 0x13001f59, 0x2400fff8 },
- { 0x13001f5b, 0x2400fff8 },
- { 0x13001f5d, 0x2400fff8 },
- { 0x13001f5f, 0x2400fff8 },
- { 0x13001f60, 0x14000008 },
- { 0x13001f61, 0x14000008 },
- { 0x13001f62, 0x14000008 },
- { 0x13001f63, 0x14000008 },
- { 0x13001f64, 0x14000008 },
- { 0x13001f65, 0x14000008 },
- { 0x13001f66, 0x14000008 },
- { 0x13001f67, 0x14000008 },
- { 0x13001f68, 0x2400fff8 },
- { 0x13001f69, 0x2400fff8 },
- { 0x13001f6a, 0x2400fff8 },
- { 0x13001f6b, 0x2400fff8 },
- { 0x13001f6c, 0x2400fff8 },
- { 0x13001f6d, 0x2400fff8 },
- { 0x13001f6e, 0x2400fff8 },
- { 0x13001f6f, 0x2400fff8 },
- { 0x13001f70, 0x1400004a },
- { 0x13001f71, 0x1400004a },
- { 0x13001f72, 0x14000056 },
- { 0x13001f73, 0x14000056 },
- { 0x13001f74, 0x14000056 },
- { 0x13001f75, 0x14000056 },
- { 0x13001f76, 0x14000064 },
- { 0x13001f77, 0x14000064 },
- { 0x13001f78, 0x14000080 },
- { 0x13001f79, 0x14000080 },
- { 0x13001f7a, 0x14000070 },
- { 0x13001f7b, 0x14000070 },
- { 0x13001f7c, 0x1400007e },
- { 0x13001f7d, 0x1400007e },
- { 0x13001f80, 0x14000008 },
- { 0x13001f81, 0x14000008 },
- { 0x13001f82, 0x14000008 },
- { 0x13001f83, 0x14000008 },
- { 0x13001f84, 0x14000008 },
- { 0x13001f85, 0x14000008 },
- { 0x13001f86, 0x14000008 },
- { 0x13001f87, 0x14000008 },
- { 0x13001f88, 0x2000fff8 },
- { 0x13001f89, 0x2000fff8 },
- { 0x13001f8a, 0x2000fff8 },
- { 0x13001f8b, 0x2000fff8 },
- { 0x13001f8c, 0x2000fff8 },
- { 0x13001f8d, 0x2000fff8 },
- { 0x13001f8e, 0x2000fff8 },
- { 0x13001f8f, 0x2000fff8 },
- { 0x13001f90, 0x14000008 },
- { 0x13001f91, 0x14000008 },
- { 0x13001f92, 0x14000008 },
- { 0x13001f93, 0x14000008 },
- { 0x13001f94, 0x14000008 },
- { 0x13001f95, 0x14000008 },
- { 0x13001f96, 0x14000008 },
- { 0x13001f97, 0x14000008 },
- { 0x13001f98, 0x2000fff8 },
- { 0x13001f99, 0x2000fff8 },
- { 0x13001f9a, 0x2000fff8 },
- { 0x13001f9b, 0x2000fff8 },
- { 0x13001f9c, 0x2000fff8 },
- { 0x13001f9d, 0x2000fff8 },
- { 0x13001f9e, 0x2000fff8 },
- { 0x13001f9f, 0x2000fff8 },
- { 0x13001fa0, 0x14000008 },
- { 0x13001fa1, 0x14000008 },
- { 0x13001fa2, 0x14000008 },
- { 0x13001fa3, 0x14000008 },
- { 0x13001fa4, 0x14000008 },
- { 0x13001fa5, 0x14000008 },
- { 0x13001fa6, 0x14000008 },
- { 0x13001fa7, 0x14000008 },
- { 0x13001fa8, 0x2000fff8 },
- { 0x13001fa9, 0x2000fff8 },
- { 0x13001faa, 0x2000fff8 },
- { 0x13001fab, 0x2000fff8 },
- { 0x13001fac, 0x2000fff8 },
- { 0x13001fad, 0x2000fff8 },
- { 0x13001fae, 0x2000fff8 },
- { 0x13001faf, 0x2000fff8 },
- { 0x13001fb0, 0x14000008 },
- { 0x13001fb1, 0x14000008 },
- { 0x13001fb2, 0x14000000 },
- { 0x13001fb3, 0x14000009 },
- { 0x13001fb4, 0x14000000 },
- { 0x13801fb6, 0x14000001 },
- { 0x13001fb8, 0x2400fff8 },
- { 0x13001fb9, 0x2400fff8 },
- { 0x13001fba, 0x2400ffb6 },
- { 0x13001fbb, 0x2400ffb6 },
- { 0x13001fbc, 0x2000fff7 },
- { 0x13001fbd, 0x60000000 },
- { 0x13001fbe, 0x1400e3db },
- { 0x13801fbf, 0x60000002 },
- { 0x13001fc2, 0x14000000 },
- { 0x13001fc3, 0x14000009 },
- { 0x13001fc4, 0x14000000 },
- { 0x13801fc6, 0x14000001 },
- { 0x13001fc8, 0x2400ffaa },
- { 0x13001fc9, 0x2400ffaa },
- { 0x13001fca, 0x2400ffaa },
- { 0x13001fcb, 0x2400ffaa },
- { 0x13001fcc, 0x2000fff7 },
- { 0x13801fcd, 0x60000002 },
- { 0x13001fd0, 0x14000008 },
- { 0x13001fd1, 0x14000008 },
- { 0x13801fd2, 0x14000001 },
- { 0x13801fd6, 0x14000001 },
- { 0x13001fd8, 0x2400fff8 },
- { 0x13001fd9, 0x2400fff8 },
- { 0x13001fda, 0x2400ff9c },
- { 0x13001fdb, 0x2400ff9c },
- { 0x13801fdd, 0x60000002 },
- { 0x13001fe0, 0x14000008 },
- { 0x13001fe1, 0x14000008 },
- { 0x13801fe2, 0x14000002 },
- { 0x13001fe5, 0x14000007 },
- { 0x13801fe6, 0x14000001 },
- { 0x13001fe8, 0x2400fff8 },
- { 0x13001fe9, 0x2400fff8 },
- { 0x13001fea, 0x2400ff90 },
- { 0x13001feb, 0x2400ff90 },
- { 0x13001fec, 0x2400fff9 },
- { 0x13801fed, 0x60000002 },
- { 0x13001ff2, 0x14000000 },
- { 0x13001ff3, 0x14000009 },
- { 0x13001ff4, 0x14000000 },
- { 0x13801ff6, 0x14000001 },
- { 0x13001ff8, 0x2400ff80 },
- { 0x13001ff9, 0x2400ff80 },
- { 0x13001ffa, 0x2400ff82 },
- { 0x13001ffb, 0x2400ff82 },
- { 0x13001ffc, 0x2000fff7 },
- { 0x13801ffd, 0x60000001 },
- { 0x09802000, 0x7400000a },
- { 0x0980200b, 0x04000004 },
- { 0x09802010, 0x44000005 },
- { 0x09802016, 0x54000001 },
- { 0x09002018, 0x50000000 },
- { 0x09002019, 0x4c000000 },
- { 0x0900201a, 0x58000000 },
- { 0x0980201b, 0x50000001 },
- { 0x0900201d, 0x4c000000 },
- { 0x0900201e, 0x58000000 },
- { 0x0900201f, 0x50000000 },
- { 0x09802020, 0x54000007 },
- { 0x09002028, 0x6c000000 },
- { 0x09002029, 0x70000000 },
- { 0x0980202a, 0x04000004 },
- { 0x0900202f, 0x74000000 },
- { 0x09802030, 0x54000008 },
- { 0x09002039, 0x50000000 },
- { 0x0900203a, 0x4c000000 },
- { 0x0980203b, 0x54000003 },
- { 0x0980203f, 0x40000001 },
- { 0x09802041, 0x54000002 },
- { 0x09002044, 0x64000000 },
- { 0x09002045, 0x58000000 },
- { 0x09002046, 0x48000000 },
- { 0x09802047, 0x5400000a },
- { 0x09002052, 0x64000000 },
- { 0x09002053, 0x54000000 },
- { 0x09002054, 0x40000000 },
- { 0x09802055, 0x54000009 },
- { 0x0900205f, 0x74000000 },
- { 0x09802060, 0x04000003 },
- { 0x0980206a, 0x04000005 },
- { 0x09002070, 0x3c000000 },
- { 0x21002071, 0x14000000 },
- { 0x09802074, 0x3c000005 },
- { 0x0980207a, 0x64000002 },
- { 0x0900207d, 0x58000000 },
- { 0x0900207e, 0x48000000 },
- { 0x2100207f, 0x14000000 },
- { 0x09802080, 0x3c000009 },
- { 0x0980208a, 0x64000002 },
- { 0x0900208d, 0x58000000 },
- { 0x0900208e, 0x48000000 },
- { 0x21802090, 0x18000004 },
- { 0x098020a0, 0x5c000015 },
- { 0x1b8020d0, 0x3000000c },
- { 0x1b8020dd, 0x2c000003 },
- { 0x1b0020e1, 0x30000000 },
- { 0x1b8020e2, 0x2c000002 },
- { 0x1b8020e5, 0x30000006 },
- { 0x09802100, 0x68000001 },
- { 0x09002102, 0x24000000 },
- { 0x09802103, 0x68000003 },
- { 0x09002107, 0x24000000 },
- { 0x09802108, 0x68000001 },
- { 0x0900210a, 0x14000000 },
- { 0x0980210b, 0x24000002 },
- { 0x0980210e, 0x14000001 },
- { 0x09802110, 0x24000002 },
- { 0x09002113, 0x14000000 },
- { 0x09002114, 0x68000000 },
- { 0x09002115, 0x24000000 },
- { 0x09802116, 0x68000002 },
- { 0x09802119, 0x24000004 },
- { 0x0980211e, 0x68000005 },
- { 0x09002124, 0x24000000 },
- { 0x09002125, 0x68000000 },
- { 0x13002126, 0x2400e2a3 },
- { 0x09002127, 0x68000000 },
- { 0x09002128, 0x24000000 },
- { 0x09002129, 0x68000000 },
- { 0x2100212a, 0x2400df41 },
- { 0x2100212b, 0x2400dfba },
- { 0x0980212c, 0x24000001 },
- { 0x0900212e, 0x68000000 },
- { 0x0900212f, 0x14000000 },
- { 0x09802130, 0x24000001 },
- { 0x09002132, 0x68000000 },
- { 0x09002133, 0x24000000 },
- { 0x09002134, 0x14000000 },
- { 0x09802135, 0x1c000003 },
- { 0x09002139, 0x14000000 },
- { 0x0980213a, 0x68000001 },
- { 0x0980213c, 0x14000001 },
- { 0x0980213e, 0x24000001 },
- { 0x09802140, 0x64000004 },
- { 0x09002145, 0x24000000 },
- { 0x09802146, 0x14000003 },
- { 0x0900214a, 0x68000000 },
- { 0x0900214b, 0x64000000 },
- { 0x0900214c, 0x68000000 },
- { 0x09802153, 0x3c00000c },
- { 0x09002160, 0x38000010 },
- { 0x09002161, 0x38000010 },
- { 0x09002162, 0x38000010 },
- { 0x09002163, 0x38000010 },
- { 0x09002164, 0x38000010 },
- { 0x09002165, 0x38000010 },
- { 0x09002166, 0x38000010 },
- { 0x09002167, 0x38000010 },
- { 0x09002168, 0x38000010 },
- { 0x09002169, 0x38000010 },
- { 0x0900216a, 0x38000010 },
- { 0x0900216b, 0x38000010 },
- { 0x0900216c, 0x38000010 },
- { 0x0900216d, 0x38000010 },
- { 0x0900216e, 0x38000010 },
- { 0x0900216f, 0x38000010 },
- { 0x09002170, 0x3800fff0 },
- { 0x09002171, 0x3800fff0 },
- { 0x09002172, 0x3800fff0 },
- { 0x09002173, 0x3800fff0 },
- { 0x09002174, 0x3800fff0 },
- { 0x09002175, 0x3800fff0 },
- { 0x09002176, 0x3800fff0 },
- { 0x09002177, 0x3800fff0 },
- { 0x09002178, 0x3800fff0 },
- { 0x09002179, 0x3800fff0 },
- { 0x0900217a, 0x3800fff0 },
- { 0x0900217b, 0x3800fff0 },
- { 0x0900217c, 0x3800fff0 },
- { 0x0900217d, 0x3800fff0 },
- { 0x0900217e, 0x3800fff0 },
- { 0x0900217f, 0x3800fff0 },
- { 0x09802180, 0x38000003 },
- { 0x09802190, 0x64000004 },
- { 0x09802195, 0x68000004 },
- { 0x0980219a, 0x64000001 },
- { 0x0980219c, 0x68000003 },
- { 0x090021a0, 0x64000000 },
- { 0x098021a1, 0x68000001 },
- { 0x090021a3, 0x64000000 },
- { 0x098021a4, 0x68000001 },
- { 0x090021a6, 0x64000000 },
- { 0x098021a7, 0x68000006 },
- { 0x090021ae, 0x64000000 },
- { 0x098021af, 0x6800001e },
- { 0x098021ce, 0x64000001 },
- { 0x098021d0, 0x68000001 },
- { 0x090021d2, 0x64000000 },
- { 0x090021d3, 0x68000000 },
- { 0x090021d4, 0x64000000 },
- { 0x098021d5, 0x6800001e },
- { 0x098021f4, 0x6400010b },
- { 0x09802300, 0x68000007 },
- { 0x09802308, 0x64000003 },
- { 0x0980230c, 0x68000013 },
- { 0x09802320, 0x64000001 },
- { 0x09802322, 0x68000006 },
- { 0x09002329, 0x58000000 },
- { 0x0900232a, 0x48000000 },
- { 0x0980232b, 0x68000050 },
- { 0x0900237c, 0x64000000 },
- { 0x0980237d, 0x6800001d },
- { 0x0980239b, 0x64000018 },
- { 0x090023b4, 0x58000000 },
- { 0x090023b5, 0x48000000 },
- { 0x090023b6, 0x54000000 },
- { 0x098023b7, 0x68000024 },
- { 0x09802400, 0x68000026 },
- { 0x09802440, 0x6800000a },
- { 0x09802460, 0x3c00003b },
- { 0x0980249c, 0x68000019 },
- { 0x090024b6, 0x6800001a },
- { 0x090024b7, 0x6800001a },
- { 0x090024b8, 0x6800001a },
- { 0x090024b9, 0x6800001a },
- { 0x090024ba, 0x6800001a },
- { 0x090024bb, 0x6800001a },
- { 0x090024bc, 0x6800001a },
- { 0x090024bd, 0x6800001a },
- { 0x090024be, 0x6800001a },
- { 0x090024bf, 0x6800001a },
- { 0x090024c0, 0x6800001a },
- { 0x090024c1, 0x6800001a },
- { 0x090024c2, 0x6800001a },
- { 0x090024c3, 0x6800001a },
- { 0x090024c4, 0x6800001a },
- { 0x090024c5, 0x6800001a },
- { 0x090024c6, 0x6800001a },
- { 0x090024c7, 0x6800001a },
- { 0x090024c8, 0x6800001a },
- { 0x090024c9, 0x6800001a },
- { 0x090024ca, 0x6800001a },
- { 0x090024cb, 0x6800001a },
- { 0x090024cc, 0x6800001a },
- { 0x090024cd, 0x6800001a },
- { 0x090024ce, 0x6800001a },
- { 0x090024cf, 0x6800001a },
- { 0x090024d0, 0x6800ffe6 },
- { 0x090024d1, 0x6800ffe6 },
- { 0x090024d2, 0x6800ffe6 },
- { 0x090024d3, 0x6800ffe6 },
- { 0x090024d4, 0x6800ffe6 },
- { 0x090024d5, 0x6800ffe6 },
- { 0x090024d6, 0x6800ffe6 },
- { 0x090024d7, 0x6800ffe6 },
- { 0x090024d8, 0x6800ffe6 },
- { 0x090024d9, 0x6800ffe6 },
- { 0x090024da, 0x6800ffe6 },
- { 0x090024db, 0x6800ffe6 },
- { 0x090024dc, 0x6800ffe6 },
- { 0x090024dd, 0x6800ffe6 },
- { 0x090024de, 0x6800ffe6 },
- { 0x090024df, 0x6800ffe6 },
- { 0x090024e0, 0x6800ffe6 },
- { 0x090024e1, 0x6800ffe6 },
- { 0x090024e2, 0x6800ffe6 },
- { 0x090024e3, 0x6800ffe6 },
- { 0x090024e4, 0x6800ffe6 },
- { 0x090024e5, 0x6800ffe6 },
- { 0x090024e6, 0x6800ffe6 },
- { 0x090024e7, 0x6800ffe6 },
- { 0x090024e8, 0x6800ffe6 },
- { 0x090024e9, 0x6800ffe6 },
- { 0x098024ea, 0x3c000015 },
- { 0x09802500, 0x680000b6 },
- { 0x090025b7, 0x64000000 },
- { 0x098025b8, 0x68000008 },
- { 0x090025c1, 0x64000000 },
- { 0x098025c2, 0x68000035 },
- { 0x098025f8, 0x64000007 },
- { 0x09802600, 0x6800006e },
- { 0x0900266f, 0x64000000 },
- { 0x09802670, 0x6800002c },
- { 0x098026a0, 0x68000011 },
- { 0x09802701, 0x68000003 },
- { 0x09802706, 0x68000003 },
- { 0x0980270c, 0x6800001b },
- { 0x09802729, 0x68000022 },
- { 0x0900274d, 0x68000000 },
- { 0x0980274f, 0x68000003 },
- { 0x09002756, 0x68000000 },
- { 0x09802758, 0x68000006 },
- { 0x09802761, 0x68000006 },
- { 0x09002768, 0x58000000 },
- { 0x09002769, 0x48000000 },
- { 0x0900276a, 0x58000000 },
- { 0x0900276b, 0x48000000 },
- { 0x0900276c, 0x58000000 },
- { 0x0900276d, 0x48000000 },
- { 0x0900276e, 0x58000000 },
- { 0x0900276f, 0x48000000 },
- { 0x09002770, 0x58000000 },
- { 0x09002771, 0x48000000 },
- { 0x09002772, 0x58000000 },
- { 0x09002773, 0x48000000 },
- { 0x09002774, 0x58000000 },
- { 0x09002775, 0x48000000 },
- { 0x09802776, 0x3c00001d },
- { 0x09002794, 0x68000000 },
- { 0x09802798, 0x68000017 },
- { 0x098027b1, 0x6800000d },
- { 0x098027c0, 0x64000004 },
- { 0x090027c5, 0x58000000 },
- { 0x090027c6, 0x48000000 },
- { 0x098027d0, 0x64000015 },
- { 0x090027e6, 0x58000000 },
- { 0x090027e7, 0x48000000 },
- { 0x090027e8, 0x58000000 },
- { 0x090027e9, 0x48000000 },
- { 0x090027ea, 0x58000000 },
- { 0x090027eb, 0x48000000 },
- { 0x098027f0, 0x6400000f },
- { 0x04802800, 0x680000ff },
- { 0x09802900, 0x64000082 },
- { 0x09002983, 0x58000000 },
- { 0x09002984, 0x48000000 },
- { 0x09002985, 0x58000000 },
- { 0x09002986, 0x48000000 },
- { 0x09002987, 0x58000000 },
- { 0x09002988, 0x48000000 },
- { 0x09002989, 0x58000000 },
- { 0x0900298a, 0x48000000 },
- { 0x0900298b, 0x58000000 },
- { 0x0900298c, 0x48000000 },
- { 0x0900298d, 0x58000000 },
- { 0x0900298e, 0x48000000 },
- { 0x0900298f, 0x58000000 },
- { 0x09002990, 0x48000000 },
- { 0x09002991, 0x58000000 },
- { 0x09002992, 0x48000000 },
- { 0x09002993, 0x58000000 },
- { 0x09002994, 0x48000000 },
- { 0x09002995, 0x58000000 },
- { 0x09002996, 0x48000000 },
- { 0x09002997, 0x58000000 },
- { 0x09002998, 0x48000000 },
- { 0x09802999, 0x6400003e },
- { 0x090029d8, 0x58000000 },
- { 0x090029d9, 0x48000000 },
- { 0x090029da, 0x58000000 },
- { 0x090029db, 0x48000000 },
- { 0x098029dc, 0x6400001f },
- { 0x090029fc, 0x58000000 },
- { 0x090029fd, 0x48000000 },
- { 0x098029fe, 0x64000101 },
- { 0x09802b00, 0x68000013 },
- { 0x11002c00, 0x24000030 },
- { 0x11002c01, 0x24000030 },
- { 0x11002c02, 0x24000030 },
- { 0x11002c03, 0x24000030 },
- { 0x11002c04, 0x24000030 },
- { 0x11002c05, 0x24000030 },
- { 0x11002c06, 0x24000030 },
- { 0x11002c07, 0x24000030 },
- { 0x11002c08, 0x24000030 },
- { 0x11002c09, 0x24000030 },
- { 0x11002c0a, 0x24000030 },
- { 0x11002c0b, 0x24000030 },
- { 0x11002c0c, 0x24000030 },
- { 0x11002c0d, 0x24000030 },
- { 0x11002c0e, 0x24000030 },
- { 0x11002c0f, 0x24000030 },
- { 0x11002c10, 0x24000030 },
- { 0x11002c11, 0x24000030 },
- { 0x11002c12, 0x24000030 },
- { 0x11002c13, 0x24000030 },
- { 0x11002c14, 0x24000030 },
- { 0x11002c15, 0x24000030 },
- { 0x11002c16, 0x24000030 },
- { 0x11002c17, 0x24000030 },
- { 0x11002c18, 0x24000030 },
- { 0x11002c19, 0x24000030 },
- { 0x11002c1a, 0x24000030 },
- { 0x11002c1b, 0x24000030 },
- { 0x11002c1c, 0x24000030 },
- { 0x11002c1d, 0x24000030 },
- { 0x11002c1e, 0x24000030 },
- { 0x11002c1f, 0x24000030 },
- { 0x11002c20, 0x24000030 },
- { 0x11002c21, 0x24000030 },
- { 0x11002c22, 0x24000030 },
- { 0x11002c23, 0x24000030 },
- { 0x11002c24, 0x24000030 },
- { 0x11002c25, 0x24000030 },
- { 0x11002c26, 0x24000030 },
- { 0x11002c27, 0x24000030 },
- { 0x11002c28, 0x24000030 },
- { 0x11002c29, 0x24000030 },
- { 0x11002c2a, 0x24000030 },
- { 0x11002c2b, 0x24000030 },
- { 0x11002c2c, 0x24000030 },
- { 0x11002c2d, 0x24000030 },
- { 0x11002c2e, 0x24000030 },
- { 0x11002c30, 0x1400ffd0 },
- { 0x11002c31, 0x1400ffd0 },
- { 0x11002c32, 0x1400ffd0 },
- { 0x11002c33, 0x1400ffd0 },
- { 0x11002c34, 0x1400ffd0 },
- { 0x11002c35, 0x1400ffd0 },
- { 0x11002c36, 0x1400ffd0 },
- { 0x11002c37, 0x1400ffd0 },
- { 0x11002c38, 0x1400ffd0 },
- { 0x11002c39, 0x1400ffd0 },
- { 0x11002c3a, 0x1400ffd0 },
- { 0x11002c3b, 0x1400ffd0 },
- { 0x11002c3c, 0x1400ffd0 },
- { 0x11002c3d, 0x1400ffd0 },
- { 0x11002c3e, 0x1400ffd0 },
- { 0x11002c3f, 0x1400ffd0 },
- { 0x11002c40, 0x1400ffd0 },
- { 0x11002c41, 0x1400ffd0 },
- { 0x11002c42, 0x1400ffd0 },
- { 0x11002c43, 0x1400ffd0 },
- { 0x11002c44, 0x1400ffd0 },
- { 0x11002c45, 0x1400ffd0 },
- { 0x11002c46, 0x1400ffd0 },
- { 0x11002c47, 0x1400ffd0 },
- { 0x11002c48, 0x1400ffd0 },
- { 0x11002c49, 0x1400ffd0 },
- { 0x11002c4a, 0x1400ffd0 },
- { 0x11002c4b, 0x1400ffd0 },
- { 0x11002c4c, 0x1400ffd0 },
- { 0x11002c4d, 0x1400ffd0 },
- { 0x11002c4e, 0x1400ffd0 },
- { 0x11002c4f, 0x1400ffd0 },
- { 0x11002c50, 0x1400ffd0 },
- { 0x11002c51, 0x1400ffd0 },
- { 0x11002c52, 0x1400ffd0 },
- { 0x11002c53, 0x1400ffd0 },
- { 0x11002c54, 0x1400ffd0 },
- { 0x11002c55, 0x1400ffd0 },
- { 0x11002c56, 0x1400ffd0 },
- { 0x11002c57, 0x1400ffd0 },
- { 0x11002c58, 0x1400ffd0 },
- { 0x11002c59, 0x1400ffd0 },
- { 0x11002c5a, 0x1400ffd0 },
- { 0x11002c5b, 0x1400ffd0 },
- { 0x11002c5c, 0x1400ffd0 },
- { 0x11002c5d, 0x1400ffd0 },
- { 0x11002c5e, 0x1400ffd0 },
- { 0x0a002c80, 0x24000001 },
- { 0x0a002c81, 0x1400ffff },
- { 0x0a002c82, 0x24000001 },
- { 0x0a002c83, 0x1400ffff },
- { 0x0a002c84, 0x24000001 },
- { 0x0a002c85, 0x1400ffff },
- { 0x0a002c86, 0x24000001 },
- { 0x0a002c87, 0x1400ffff },
- { 0x0a002c88, 0x24000001 },
- { 0x0a002c89, 0x1400ffff },
- { 0x0a002c8a, 0x24000001 },
- { 0x0a002c8b, 0x1400ffff },
- { 0x0a002c8c, 0x24000001 },
- { 0x0a002c8d, 0x1400ffff },
- { 0x0a002c8e, 0x24000001 },
- { 0x0a002c8f, 0x1400ffff },
- { 0x0a002c90, 0x24000001 },
- { 0x0a002c91, 0x1400ffff },
- { 0x0a002c92, 0x24000001 },
- { 0x0a002c93, 0x1400ffff },
- { 0x0a002c94, 0x24000001 },
- { 0x0a002c95, 0x1400ffff },
- { 0x0a002c96, 0x24000001 },
- { 0x0a002c97, 0x1400ffff },
- { 0x0a002c98, 0x24000001 },
- { 0x0a002c99, 0x1400ffff },
- { 0x0a002c9a, 0x24000001 },
- { 0x0a002c9b, 0x1400ffff },
- { 0x0a002c9c, 0x24000001 },
- { 0x0a002c9d, 0x1400ffff },
- { 0x0a002c9e, 0x24000001 },
- { 0x0a002c9f, 0x1400ffff },
- { 0x0a002ca0, 0x24000001 },
- { 0x0a002ca1, 0x1400ffff },
- { 0x0a002ca2, 0x24000001 },
- { 0x0a002ca3, 0x1400ffff },
- { 0x0a002ca4, 0x24000001 },
- { 0x0a002ca5, 0x1400ffff },
- { 0x0a002ca6, 0x24000001 },
- { 0x0a002ca7, 0x1400ffff },
- { 0x0a002ca8, 0x24000001 },
- { 0x0a002ca9, 0x1400ffff },
- { 0x0a002caa, 0x24000001 },
- { 0x0a002cab, 0x1400ffff },
- { 0x0a002cac, 0x24000001 },
- { 0x0a002cad, 0x1400ffff },
- { 0x0a002cae, 0x24000001 },
- { 0x0a002caf, 0x1400ffff },
- { 0x0a002cb0, 0x24000001 },
- { 0x0a002cb1, 0x1400ffff },
- { 0x0a002cb2, 0x24000001 },
- { 0x0a002cb3, 0x1400ffff },
- { 0x0a002cb4, 0x24000001 },
- { 0x0a002cb5, 0x1400ffff },
- { 0x0a002cb6, 0x24000001 },
- { 0x0a002cb7, 0x1400ffff },
- { 0x0a002cb8, 0x24000001 },
- { 0x0a002cb9, 0x1400ffff },
- { 0x0a002cba, 0x24000001 },
- { 0x0a002cbb, 0x1400ffff },
- { 0x0a002cbc, 0x24000001 },
- { 0x0a002cbd, 0x1400ffff },
- { 0x0a002cbe, 0x24000001 },
- { 0x0a002cbf, 0x1400ffff },
- { 0x0a002cc0, 0x24000001 },
- { 0x0a002cc1, 0x1400ffff },
- { 0x0a002cc2, 0x24000001 },
- { 0x0a002cc3, 0x1400ffff },
- { 0x0a002cc4, 0x24000001 },
- { 0x0a002cc5, 0x1400ffff },
- { 0x0a002cc6, 0x24000001 },
- { 0x0a002cc7, 0x1400ffff },
- { 0x0a002cc8, 0x24000001 },
- { 0x0a002cc9, 0x1400ffff },
- { 0x0a002cca, 0x24000001 },
- { 0x0a002ccb, 0x1400ffff },
- { 0x0a002ccc, 0x24000001 },
- { 0x0a002ccd, 0x1400ffff },
- { 0x0a002cce, 0x24000001 },
- { 0x0a002ccf, 0x1400ffff },
- { 0x0a002cd0, 0x24000001 },
- { 0x0a002cd1, 0x1400ffff },
- { 0x0a002cd2, 0x24000001 },
- { 0x0a002cd3, 0x1400ffff },
- { 0x0a002cd4, 0x24000001 },
- { 0x0a002cd5, 0x1400ffff },
- { 0x0a002cd6, 0x24000001 },
- { 0x0a002cd7, 0x1400ffff },
- { 0x0a002cd8, 0x24000001 },
- { 0x0a002cd9, 0x1400ffff },
- { 0x0a002cda, 0x24000001 },
- { 0x0a002cdb, 0x1400ffff },
- { 0x0a002cdc, 0x24000001 },
- { 0x0a002cdd, 0x1400ffff },
- { 0x0a002cde, 0x24000001 },
- { 0x0a002cdf, 0x1400ffff },
- { 0x0a002ce0, 0x24000001 },
- { 0x0a002ce1, 0x1400ffff },
- { 0x0a002ce2, 0x24000001 },
- { 0x0a002ce3, 0x1400ffff },
- { 0x0a002ce4, 0x14000000 },
- { 0x0a802ce5, 0x68000005 },
- { 0x0a802cf9, 0x54000003 },
- { 0x0a002cfd, 0x3c000000 },
- { 0x0a802cfe, 0x54000001 },
- { 0x10002d00, 0x1400e3a0 },
- { 0x10002d01, 0x1400e3a0 },
- { 0x10002d02, 0x1400e3a0 },
- { 0x10002d03, 0x1400e3a0 },
- { 0x10002d04, 0x1400e3a0 },
- { 0x10002d05, 0x1400e3a0 },
- { 0x10002d06, 0x1400e3a0 },
- { 0x10002d07, 0x1400e3a0 },
- { 0x10002d08, 0x1400e3a0 },
- { 0x10002d09, 0x1400e3a0 },
- { 0x10002d0a, 0x1400e3a0 },
- { 0x10002d0b, 0x1400e3a0 },
- { 0x10002d0c, 0x1400e3a0 },
- { 0x10002d0d, 0x1400e3a0 },
- { 0x10002d0e, 0x1400e3a0 },
- { 0x10002d0f, 0x1400e3a0 },
- { 0x10002d10, 0x1400e3a0 },
- { 0x10002d11, 0x1400e3a0 },
- { 0x10002d12, 0x1400e3a0 },
- { 0x10002d13, 0x1400e3a0 },
- { 0x10002d14, 0x1400e3a0 },
- { 0x10002d15, 0x1400e3a0 },
- { 0x10002d16, 0x1400e3a0 },
- { 0x10002d17, 0x1400e3a0 },
- { 0x10002d18, 0x1400e3a0 },
- { 0x10002d19, 0x1400e3a0 },
- { 0x10002d1a, 0x1400e3a0 },
- { 0x10002d1b, 0x1400e3a0 },
- { 0x10002d1c, 0x1400e3a0 },
- { 0x10002d1d, 0x1400e3a0 },
- { 0x10002d1e, 0x1400e3a0 },
- { 0x10002d1f, 0x1400e3a0 },
- { 0x10002d20, 0x1400e3a0 },
- { 0x10002d21, 0x1400e3a0 },
- { 0x10002d22, 0x1400e3a0 },
- { 0x10002d23, 0x1400e3a0 },
- { 0x10002d24, 0x1400e3a0 },
- { 0x10002d25, 0x1400e3a0 },
- { 0x3a802d30, 0x1c000035 },
- { 0x3a002d6f, 0x18000000 },
- { 0x0f802d80, 0x1c000016 },
- { 0x0f802da0, 0x1c000006 },
- { 0x0f802da8, 0x1c000006 },
- { 0x0f802db0, 0x1c000006 },
- { 0x0f802db8, 0x1c000006 },
- { 0x0f802dc0, 0x1c000006 },
- { 0x0f802dc8, 0x1c000006 },
- { 0x0f802dd0, 0x1c000006 },
- { 0x0f802dd8, 0x1c000006 },
- { 0x09802e00, 0x54000001 },
- { 0x09002e02, 0x50000000 },
- { 0x09002e03, 0x4c000000 },
- { 0x09002e04, 0x50000000 },
- { 0x09002e05, 0x4c000000 },
- { 0x09802e06, 0x54000002 },
- { 0x09002e09, 0x50000000 },
- { 0x09002e0a, 0x4c000000 },
- { 0x09002e0b, 0x54000000 },
- { 0x09002e0c, 0x50000000 },
- { 0x09002e0d, 0x4c000000 },
- { 0x09802e0e, 0x54000008 },
- { 0x09002e17, 0x44000000 },
- { 0x09002e1c, 0x50000000 },
- { 0x09002e1d, 0x4c000000 },
- { 0x16802e80, 0x68000019 },
- { 0x16802e9b, 0x68000058 },
- { 0x16802f00, 0x680000d5 },
- { 0x09802ff0, 0x6800000b },
- { 0x09003000, 0x74000000 },
- { 0x09803001, 0x54000002 },
- { 0x09003004, 0x68000000 },
- { 0x16003005, 0x18000000 },
- { 0x09003006, 0x1c000000 },
- { 0x16003007, 0x38000000 },
- { 0x09003008, 0x58000000 },
- { 0x09003009, 0x48000000 },
- { 0x0900300a, 0x58000000 },
- { 0x0900300b, 0x48000000 },
- { 0x0900300c, 0x58000000 },
- { 0x0900300d, 0x48000000 },
- { 0x0900300e, 0x58000000 },
- { 0x0900300f, 0x48000000 },
- { 0x09003010, 0x58000000 },
- { 0x09003011, 0x48000000 },
- { 0x09803012, 0x68000001 },
- { 0x09003014, 0x58000000 },
- { 0x09003015, 0x48000000 },
- { 0x09003016, 0x58000000 },
- { 0x09003017, 0x48000000 },
- { 0x09003018, 0x58000000 },
- { 0x09003019, 0x48000000 },
- { 0x0900301a, 0x58000000 },
- { 0x0900301b, 0x48000000 },
- { 0x0900301c, 0x44000000 },
- { 0x0900301d, 0x58000000 },
- { 0x0980301e, 0x48000001 },
- { 0x09003020, 0x68000000 },
- { 0x16803021, 0x38000008 },
- { 0x1b80302a, 0x30000005 },
- { 0x09003030, 0x44000000 },
- { 0x09803031, 0x18000004 },
- { 0x09803036, 0x68000001 },
- { 0x16803038, 0x38000002 },
- { 0x1600303b, 0x18000000 },
- { 0x0900303c, 0x1c000000 },
- { 0x0900303d, 0x54000000 },
- { 0x0980303e, 0x68000001 },
- { 0x1a803041, 0x1c000055 },
- { 0x1b803099, 0x30000001 },
- { 0x0980309b, 0x60000001 },
- { 0x1a80309d, 0x18000001 },
- { 0x1a00309f, 0x1c000000 },
- { 0x090030a0, 0x44000000 },
- { 0x1d8030a1, 0x1c000059 },
- { 0x090030fb, 0x54000000 },
- { 0x098030fc, 0x18000002 },
- { 0x1d0030ff, 0x1c000000 },
- { 0x03803105, 0x1c000027 },
- { 0x17803131, 0x1c00005d },
- { 0x09803190, 0x68000001 },
- { 0x09803192, 0x3c000003 },
- { 0x09803196, 0x68000009 },
- { 0x038031a0, 0x1c000017 },
- { 0x098031c0, 0x6800000f },
- { 0x1d8031f0, 0x1c00000f },
- { 0x17803200, 0x6800001e },
- { 0x09803220, 0x3c000009 },
- { 0x0980322a, 0x68000019 },
- { 0x09003250, 0x68000000 },
- { 0x09803251, 0x3c00000e },
- { 0x17803260, 0x6800001f },
- { 0x09803280, 0x3c000009 },
- { 0x0980328a, 0x68000026 },
- { 0x098032b1, 0x3c00000e },
- { 0x098032c0, 0x6800003e },
- { 0x09803300, 0x680000ff },
- { 0x16803400, 0x1c0019b5 },
- { 0x09804dc0, 0x6800003f },
- { 0x16804e00, 0x1c0051bb },
- { 0x3c80a000, 0x1c000014 },
- { 0x3c00a015, 0x18000000 },
- { 0x3c80a016, 0x1c000476 },
- { 0x3c80a490, 0x68000036 },
- { 0x0980a700, 0x60000016 },
- { 0x3080a800, 0x1c000001 },
- { 0x3000a802, 0x28000000 },
- { 0x3080a803, 0x1c000002 },
- { 0x3000a806, 0x30000000 },
- { 0x3080a807, 0x1c000003 },
- { 0x3000a80b, 0x30000000 },
- { 0x3080a80c, 0x1c000016 },
- { 0x3080a823, 0x28000001 },
- { 0x3080a825, 0x30000001 },
- { 0x3000a827, 0x28000000 },
- { 0x3080a828, 0x68000003 },
- { 0x1780ac00, 0x1c002ba3 },
- { 0x0980d800, 0x1000037f },
- { 0x0980db80, 0x1000007f },
- { 0x0980dc00, 0x100003ff },
- { 0x0980e000, 0x0c0018ff },
- { 0x1680f900, 0x1c00012d },
- { 0x1680fa30, 0x1c00003a },
- { 0x1680fa70, 0x1c000069 },
- { 0x2180fb00, 0x14000006 },
- { 0x0180fb13, 0x14000004 },
- { 0x1900fb1d, 0x1c000000 },
- { 0x1900fb1e, 0x30000000 },
- { 0x1980fb1f, 0x1c000009 },
- { 0x1900fb29, 0x64000000 },
- { 0x1980fb2a, 0x1c00000c },
- { 0x1980fb38, 0x1c000004 },
- { 0x1900fb3e, 0x1c000000 },
- { 0x1980fb40, 0x1c000001 },
- { 0x1980fb43, 0x1c000001 },
- { 0x1980fb46, 0x1c00006b },
- { 0x0080fbd3, 0x1c00016a },
- { 0x0900fd3e, 0x58000000 },
- { 0x0900fd3f, 0x48000000 },
- { 0x0080fd50, 0x1c00003f },
- { 0x0080fd92, 0x1c000035 },
- { 0x0080fdf0, 0x1c00000b },
- { 0x0000fdfc, 0x5c000000 },
- { 0x0900fdfd, 0x68000000 },
- { 0x1b80fe00, 0x3000000f },
- { 0x0980fe10, 0x54000006 },
- { 0x0900fe17, 0x58000000 },
- { 0x0900fe18, 0x48000000 },
- { 0x0900fe19, 0x54000000 },
- { 0x1b80fe20, 0x30000003 },
- { 0x0900fe30, 0x54000000 },
- { 0x0980fe31, 0x44000001 },
- { 0x0980fe33, 0x40000001 },
- { 0x0900fe35, 0x58000000 },
- { 0x0900fe36, 0x48000000 },
- { 0x0900fe37, 0x58000000 },
- { 0x0900fe38, 0x48000000 },
- { 0x0900fe39, 0x58000000 },
- { 0x0900fe3a, 0x48000000 },
- { 0x0900fe3b, 0x58000000 },
- { 0x0900fe3c, 0x48000000 },
- { 0x0900fe3d, 0x58000000 },
- { 0x0900fe3e, 0x48000000 },
- { 0x0900fe3f, 0x58000000 },
- { 0x0900fe40, 0x48000000 },
- { 0x0900fe41, 0x58000000 },
- { 0x0900fe42, 0x48000000 },
- { 0x0900fe43, 0x58000000 },
- { 0x0900fe44, 0x48000000 },
- { 0x0980fe45, 0x54000001 },
- { 0x0900fe47, 0x58000000 },
- { 0x0900fe48, 0x48000000 },
- { 0x0980fe49, 0x54000003 },
- { 0x0980fe4d, 0x40000002 },
- { 0x0980fe50, 0x54000002 },
- { 0x0980fe54, 0x54000003 },
- { 0x0900fe58, 0x44000000 },
- { 0x0900fe59, 0x58000000 },
- { 0x0900fe5a, 0x48000000 },
- { 0x0900fe5b, 0x58000000 },
- { 0x0900fe5c, 0x48000000 },
- { 0x0900fe5d, 0x58000000 },
- { 0x0900fe5e, 0x48000000 },
- { 0x0980fe5f, 0x54000002 },
- { 0x0900fe62, 0x64000000 },
- { 0x0900fe63, 0x44000000 },
- { 0x0980fe64, 0x64000002 },
- { 0x0900fe68, 0x54000000 },
- { 0x0900fe69, 0x5c000000 },
- { 0x0980fe6a, 0x54000001 },
- { 0x0080fe70, 0x1c000004 },
- { 0x0080fe76, 0x1c000086 },
- { 0x0900feff, 0x04000000 },
- { 0x0980ff01, 0x54000002 },
- { 0x0900ff04, 0x5c000000 },
- { 0x0980ff05, 0x54000002 },
- { 0x0900ff08, 0x58000000 },
- { 0x0900ff09, 0x48000000 },
- { 0x0900ff0a, 0x54000000 },
- { 0x0900ff0b, 0x64000000 },
- { 0x0900ff0c, 0x54000000 },
- { 0x0900ff0d, 0x44000000 },
- { 0x0980ff0e, 0x54000001 },
- { 0x0980ff10, 0x34000009 },
- { 0x0980ff1a, 0x54000001 },
- { 0x0980ff1c, 0x64000002 },
- { 0x0980ff1f, 0x54000001 },
- { 0x2100ff21, 0x24000020 },
- { 0x2100ff22, 0x24000020 },
- { 0x2100ff23, 0x24000020 },
- { 0x2100ff24, 0x24000020 },
- { 0x2100ff25, 0x24000020 },
- { 0x2100ff26, 0x24000020 },
- { 0x2100ff27, 0x24000020 },
- { 0x2100ff28, 0x24000020 },
- { 0x2100ff29, 0x24000020 },
- { 0x2100ff2a, 0x24000020 },
- { 0x2100ff2b, 0x24000020 },
- { 0x2100ff2c, 0x24000020 },
- { 0x2100ff2d, 0x24000020 },
- { 0x2100ff2e, 0x24000020 },
- { 0x2100ff2f, 0x24000020 },
- { 0x2100ff30, 0x24000020 },
- { 0x2100ff31, 0x24000020 },
- { 0x2100ff32, 0x24000020 },
- { 0x2100ff33, 0x24000020 },
- { 0x2100ff34, 0x24000020 },
- { 0x2100ff35, 0x24000020 },
- { 0x2100ff36, 0x24000020 },
- { 0x2100ff37, 0x24000020 },
- { 0x2100ff38, 0x24000020 },
- { 0x2100ff39, 0x24000020 },
- { 0x2100ff3a, 0x24000020 },
- { 0x0900ff3b, 0x58000000 },
- { 0x0900ff3c, 0x54000000 },
- { 0x0900ff3d, 0x48000000 },
- { 0x0900ff3e, 0x60000000 },
- { 0x0900ff3f, 0x40000000 },
- { 0x0900ff40, 0x60000000 },
- { 0x2100ff41, 0x1400ffe0 },
- { 0x2100ff42, 0x1400ffe0 },
- { 0x2100ff43, 0x1400ffe0 },
- { 0x2100ff44, 0x1400ffe0 },
- { 0x2100ff45, 0x1400ffe0 },
- { 0x2100ff46, 0x1400ffe0 },
- { 0x2100ff47, 0x1400ffe0 },
- { 0x2100ff48, 0x1400ffe0 },
- { 0x2100ff49, 0x1400ffe0 },
- { 0x2100ff4a, 0x1400ffe0 },
- { 0x2100ff4b, 0x1400ffe0 },
- { 0x2100ff4c, 0x1400ffe0 },
- { 0x2100ff4d, 0x1400ffe0 },
- { 0x2100ff4e, 0x1400ffe0 },
- { 0x2100ff4f, 0x1400ffe0 },
- { 0x2100ff50, 0x1400ffe0 },
- { 0x2100ff51, 0x1400ffe0 },
- { 0x2100ff52, 0x1400ffe0 },
- { 0x2100ff53, 0x1400ffe0 },
- { 0x2100ff54, 0x1400ffe0 },
- { 0x2100ff55, 0x1400ffe0 },
- { 0x2100ff56, 0x1400ffe0 },
- { 0x2100ff57, 0x1400ffe0 },
- { 0x2100ff58, 0x1400ffe0 },
- { 0x2100ff59, 0x1400ffe0 },
- { 0x2100ff5a, 0x1400ffe0 },
- { 0x0900ff5b, 0x58000000 },
- { 0x0900ff5c, 0x64000000 },
- { 0x0900ff5d, 0x48000000 },
- { 0x0900ff5e, 0x64000000 },
- { 0x0900ff5f, 0x58000000 },
- { 0x0900ff60, 0x48000000 },
- { 0x0900ff61, 0x54000000 },
- { 0x0900ff62, 0x58000000 },
- { 0x0900ff63, 0x48000000 },
- { 0x0980ff64, 0x54000001 },
- { 0x1d80ff66, 0x1c000009 },
- { 0x0900ff70, 0x18000000 },
- { 0x1d80ff71, 0x1c00002c },
- { 0x0980ff9e, 0x18000001 },
- { 0x1780ffa0, 0x1c00001e },
- { 0x1780ffc2, 0x1c000005 },
- { 0x1780ffca, 0x1c000005 },
- { 0x1780ffd2, 0x1c000005 },
- { 0x1780ffda, 0x1c000002 },
- { 0x0980ffe0, 0x5c000001 },
- { 0x0900ffe2, 0x64000000 },
- { 0x0900ffe3, 0x60000000 },
- { 0x0900ffe4, 0x68000000 },
- { 0x0980ffe5, 0x5c000001 },
- { 0x0900ffe8, 0x68000000 },
- { 0x0980ffe9, 0x64000003 },
- { 0x0980ffed, 0x68000001 },
- { 0x0980fff9, 0x04000002 },
- { 0x0980fffc, 0x68000001 },
- { 0x23810000, 0x1c00000b },
- { 0x2381000d, 0x1c000019 },
- { 0x23810028, 0x1c000012 },
- { 0x2381003c, 0x1c000001 },
- { 0x2381003f, 0x1c00000e },
- { 0x23810050, 0x1c00000d },
- { 0x23810080, 0x1c00007a },
- { 0x09810100, 0x54000001 },
- { 0x09010102, 0x68000000 },
- { 0x09810107, 0x3c00002c },
- { 0x09810137, 0x68000008 },
- { 0x13810140, 0x38000034 },
- { 0x13810175, 0x3c000003 },
- { 0x13810179, 0x68000010 },
- { 0x1301018a, 0x3c000000 },
- { 0x29810300, 0x1c00001e },
- { 0x29810320, 0x3c000003 },
- { 0x12810330, 0x1c000019 },
- { 0x1201034a, 0x38000000 },
- { 0x3b810380, 0x1c00001d },
- { 0x3b01039f, 0x54000000 },
- { 0x2a8103a0, 0x1c000023 },
- { 0x2a8103c8, 0x1c000007 },
- { 0x2a0103d0, 0x68000000 },
- { 0x2a8103d1, 0x38000004 },
- { 0x0d010400, 0x24000028 },
- { 0x0d010401, 0x24000028 },
- { 0x0d010402, 0x24000028 },
- { 0x0d010403, 0x24000028 },
- { 0x0d010404, 0x24000028 },
- { 0x0d010405, 0x24000028 },
- { 0x0d010406, 0x24000028 },
- { 0x0d010407, 0x24000028 },
- { 0x0d010408, 0x24000028 },
- { 0x0d010409, 0x24000028 },
- { 0x0d01040a, 0x24000028 },
- { 0x0d01040b, 0x24000028 },
- { 0x0d01040c, 0x24000028 },
- { 0x0d01040d, 0x24000028 },
- { 0x0d01040e, 0x24000028 },
- { 0x0d01040f, 0x24000028 },
- { 0x0d010410, 0x24000028 },
- { 0x0d010411, 0x24000028 },
- { 0x0d010412, 0x24000028 },
- { 0x0d010413, 0x24000028 },
- { 0x0d010414, 0x24000028 },
- { 0x0d010415, 0x24000028 },
- { 0x0d010416, 0x24000028 },
- { 0x0d010417, 0x24000028 },
- { 0x0d010418, 0x24000028 },
- { 0x0d010419, 0x24000028 },
- { 0x0d01041a, 0x24000028 },
- { 0x0d01041b, 0x24000028 },
- { 0x0d01041c, 0x24000028 },
- { 0x0d01041d, 0x24000028 },
- { 0x0d01041e, 0x24000028 },
- { 0x0d01041f, 0x24000028 },
- { 0x0d010420, 0x24000028 },
- { 0x0d010421, 0x24000028 },
- { 0x0d010422, 0x24000028 },
- { 0x0d010423, 0x24000028 },
- { 0x0d010424, 0x24000028 },
- { 0x0d010425, 0x24000028 },
- { 0x0d010426, 0x24000028 },
- { 0x0d010427, 0x24000028 },
- { 0x0d010428, 0x1400ffd8 },
- { 0x0d010429, 0x1400ffd8 },
- { 0x0d01042a, 0x1400ffd8 },
- { 0x0d01042b, 0x1400ffd8 },
- { 0x0d01042c, 0x1400ffd8 },
- { 0x0d01042d, 0x1400ffd8 },
- { 0x0d01042e, 0x1400ffd8 },
- { 0x0d01042f, 0x1400ffd8 },
- { 0x0d010430, 0x1400ffd8 },
- { 0x0d010431, 0x1400ffd8 },
- { 0x0d010432, 0x1400ffd8 },
- { 0x0d010433, 0x1400ffd8 },
- { 0x0d010434, 0x1400ffd8 },
- { 0x0d010435, 0x1400ffd8 },
- { 0x0d010436, 0x1400ffd8 },
- { 0x0d010437, 0x1400ffd8 },
- { 0x0d010438, 0x1400ffd8 },
- { 0x0d010439, 0x1400ffd8 },
- { 0x0d01043a, 0x1400ffd8 },
- { 0x0d01043b, 0x1400ffd8 },
- { 0x0d01043c, 0x1400ffd8 },
- { 0x0d01043d, 0x1400ffd8 },
- { 0x0d01043e, 0x1400ffd8 },
- { 0x0d01043f, 0x1400ffd8 },
- { 0x0d010440, 0x1400ffd8 },
- { 0x0d010441, 0x1400ffd8 },
- { 0x0d010442, 0x1400ffd8 },
- { 0x0d010443, 0x1400ffd8 },
- { 0x0d010444, 0x1400ffd8 },
- { 0x0d010445, 0x1400ffd8 },
- { 0x0d010446, 0x1400ffd8 },
- { 0x0d010447, 0x1400ffd8 },
- { 0x0d010448, 0x1400ffd8 },
- { 0x0d010449, 0x1400ffd8 },
- { 0x0d01044a, 0x1400ffd8 },
- { 0x0d01044b, 0x1400ffd8 },
- { 0x0d01044c, 0x1400ffd8 },
- { 0x0d01044d, 0x1400ffd8 },
- { 0x0d01044e, 0x1400ffd8 },
- { 0x0d01044f, 0x1400ffd8 },
- { 0x2e810450, 0x1c00004d },
- { 0x2c8104a0, 0x34000009 },
- { 0x0b810800, 0x1c000005 },
- { 0x0b010808, 0x1c000000 },
- { 0x0b81080a, 0x1c00002b },
- { 0x0b810837, 0x1c000001 },
- { 0x0b01083c, 0x1c000000 },
- { 0x0b01083f, 0x1c000000 },
- { 0x1e010a00, 0x1c000000 },
- { 0x1e810a01, 0x30000002 },
- { 0x1e810a05, 0x30000001 },
- { 0x1e810a0c, 0x30000003 },
- { 0x1e810a10, 0x1c000003 },
- { 0x1e810a15, 0x1c000002 },
- { 0x1e810a19, 0x1c00001a },
- { 0x1e810a38, 0x30000002 },
- { 0x1e010a3f, 0x30000000 },
- { 0x1e810a40, 0x3c000007 },
- { 0x1e810a50, 0x54000008 },
- { 0x0981d000, 0x680000f5 },
- { 0x0981d100, 0x68000026 },
- { 0x0981d12a, 0x6800003a },
- { 0x0981d165, 0x28000001 },
- { 0x1b81d167, 0x30000002 },
- { 0x0981d16a, 0x68000002 },
- { 0x0981d16d, 0x28000005 },
- { 0x0981d173, 0x04000007 },
- { 0x1b81d17b, 0x30000007 },
- { 0x0981d183, 0x68000001 },
- { 0x1b81d185, 0x30000006 },
- { 0x0981d18c, 0x6800001d },
- { 0x1b81d1aa, 0x30000003 },
- { 0x0981d1ae, 0x6800002f },
- { 0x1381d200, 0x68000041 },
- { 0x1381d242, 0x30000002 },
- { 0x1301d245, 0x68000000 },
- { 0x0981d300, 0x68000056 },
- { 0x0981d400, 0x24000019 },
- { 0x0981d41a, 0x14000019 },
- { 0x0981d434, 0x24000019 },
- { 0x0981d44e, 0x14000006 },
- { 0x0981d456, 0x14000011 },
- { 0x0981d468, 0x24000019 },
- { 0x0981d482, 0x14000019 },
- { 0x0901d49c, 0x24000000 },
- { 0x0981d49e, 0x24000001 },
- { 0x0901d4a2, 0x24000000 },
- { 0x0981d4a5, 0x24000001 },
- { 0x0981d4a9, 0x24000003 },
- { 0x0981d4ae, 0x24000007 },
- { 0x0981d4b6, 0x14000003 },
- { 0x0901d4bb, 0x14000000 },
- { 0x0981d4bd, 0x14000006 },
- { 0x0981d4c5, 0x1400000a },
- { 0x0981d4d0, 0x24000019 },
- { 0x0981d4ea, 0x14000019 },
- { 0x0981d504, 0x24000001 },
- { 0x0981d507, 0x24000003 },
- { 0x0981d50d, 0x24000007 },
- { 0x0981d516, 0x24000006 },
- { 0x0981d51e, 0x14000019 },
- { 0x0981d538, 0x24000001 },
- { 0x0981d53b, 0x24000003 },
- { 0x0981d540, 0x24000004 },
- { 0x0901d546, 0x24000000 },
- { 0x0981d54a, 0x24000006 },
- { 0x0981d552, 0x14000019 },
- { 0x0981d56c, 0x24000019 },
- { 0x0981d586, 0x14000019 },
- { 0x0981d5a0, 0x24000019 },
- { 0x0981d5ba, 0x14000019 },
- { 0x0981d5d4, 0x24000019 },
- { 0x0981d5ee, 0x14000019 },
- { 0x0981d608, 0x24000019 },
- { 0x0981d622, 0x14000019 },
- { 0x0981d63c, 0x24000019 },
- { 0x0981d656, 0x14000019 },
- { 0x0981d670, 0x24000019 },
- { 0x0981d68a, 0x1400001b },
- { 0x0981d6a8, 0x24000018 },
- { 0x0901d6c1, 0x64000000 },
- { 0x0981d6c2, 0x14000018 },
- { 0x0901d6db, 0x64000000 },
- { 0x0981d6dc, 0x14000005 },
- { 0x0981d6e2, 0x24000018 },
- { 0x0901d6fb, 0x64000000 },
- { 0x0981d6fc, 0x14000018 },
- { 0x0901d715, 0x64000000 },
- { 0x0981d716, 0x14000005 },
- { 0x0981d71c, 0x24000018 },
- { 0x0901d735, 0x64000000 },
- { 0x0981d736, 0x14000018 },
- { 0x0901d74f, 0x64000000 },
- { 0x0981d750, 0x14000005 },
- { 0x0981d756, 0x24000018 },
- { 0x0901d76f, 0x64000000 },
- { 0x0981d770, 0x14000018 },
- { 0x0901d789, 0x64000000 },
- { 0x0981d78a, 0x14000005 },
- { 0x0981d790, 0x24000018 },
- { 0x0901d7a9, 0x64000000 },
- { 0x0981d7aa, 0x14000018 },
- { 0x0901d7c3, 0x64000000 },
- { 0x0981d7c4, 0x14000005 },
- { 0x0981d7ce, 0x34000031 },
- { 0x16820000, 0x1c00a6d6 },
- { 0x1682f800, 0x1c00021d },
- { 0x090e0001, 0x04000000 },
- { 0x098e0020, 0x0400005f },
- { 0x1b8e0100, 0x300000ef },
- { 0x098f0000, 0x0c00fffd },
- { 0x09900000, 0x0c00fffd },
-};
#define CallIdentifier_h
#include <runtime/UString.h>
-#include "FastAllocBase.h"
+#include <wtf/text/CString.h>
+#include <wtf/text/StringHash.h>
namespace JSC {
- struct CallIdentifier : public FastAllocBase {
+ struct CallIdentifier {
+ WTF_MAKE_FAST_ALLOCATED;
+ public:
UString m_name;
UString m_url;
unsigned m_lineNumber;
static unsigned hash(const CallIdentifier& key)
{
unsigned hashCodes[3] = {
- key.m_name.rep()->hash(),
- key.m_url.rep()->hash(),
+ key.m_name.impl()->hash(),
+ key.m_url.impl()->hash(),
key.m_lineNumber
};
- return UString::Rep::computeHash(reinterpret_cast<char*>(hashCodes), sizeof(hashCodes));
+ return StringHasher::hashMemory<sizeof(hashCodes)>(hashCodes);
}
static bool equal(const CallIdentifier& a, const CallIdentifier& b) { return a == b; }
#ifndef NDEBUG
operator const char*() const { return c_str(); }
- const char* c_str() const { return m_name.UTF8String().data(); }
+ const char* c_str() const { return m_name.utf8().data(); }
#endif
};
{
// FIXME: When multi-threading is supported this will be a vector and calls
// into the profiler will need to know which thread it is executing on.
- m_head = ProfileNode::create(CallIdentifier("Thread_1", UString(), 0), 0, 0);
+ m_head = ProfileNode::create(0, CallIdentifier("Thread_1", UString(), 0), 0, 0);
}
Profile::~Profile()
m_head->debugPrintData(0);
}
-typedef pair<UString::Rep*, unsigned> NameCountPair;
+typedef pair<StringImpl*, unsigned> NameCountPair;
static inline bool functionNameCountPairComparator(const NameCountPair& a, const NameCountPair& b)
{
std::sort(sortedFunctions.begin(), sortedFunctions.end(), functionNameCountPairComparator);
for (NameCountPairVector::iterator it = sortedFunctions.begin(); it != sortedFunctions.end(); ++it)
- printf(" %-12d%s\n", (*it).second, UString((*it).first).UTF8String().data());
+ printf(" %-12d%s\n", (*it).second, UString((*it).first).utf8().data());
printf("\nSort by top of stack, same collapsed (when >= 5):\n");
}
static const char* NonJSExecution = "(idle)";
-PassRefPtr<ProfileGenerator> ProfileGenerator::create(const UString& title, ExecState* originatingExec, unsigned uid)
+PassRefPtr<ProfileGenerator> ProfileGenerator::create(ExecState* exec, const UString& title, unsigned uid)
{
- return adoptRef(new ProfileGenerator(title, originatingExec, uid));
+ return adoptRef(new ProfileGenerator(exec, title, uid));
}
-ProfileGenerator::ProfileGenerator(const UString& title, ExecState* originatingExec, unsigned uid)
- : m_originatingGlobalExec(originatingExec ? originatingExec->lexicalGlobalObject()->globalExec() : 0)
- , m_profileGroup(originatingExec ? originatingExec->lexicalGlobalObject()->profileGroup() : 0)
+ProfileGenerator::ProfileGenerator(ExecState* exec, const UString& title, unsigned uid)
+ : m_origin(exec ? exec->lexicalGlobalObject() : 0)
+ , m_profileGroup(exec ? exec->lexicalGlobalObject()->profileGroup() : 0)
{
m_profile = Profile::create(title, uid);
m_currentNode = m_head = m_profile->head();
- if (originatingExec)
- addParentForConsoleStart(originatingExec);
+ if (exec)
+ addParentForConsoleStart(exec);
}
void ProfileGenerator::addParentForConsoleStart(ExecState* exec)
JSValue function;
exec->interpreter()->retrieveLastCaller(exec, lineNumber, sourceID, sourceURL, function);
- m_currentNode = ProfileNode::create(Profiler::createCallIdentifier(exec, function ? function.toThisObject(exec) : 0, sourceURL, lineNumber), m_head.get(), m_head.get());
+ m_currentNode = ProfileNode::create(exec, Profiler::createCallIdentifier(exec, function ? function.toThisObject(exec) : 0, sourceURL, lineNumber), m_head.get(), m_head.get());
m_head->insertNode(m_currentNode.get());
}
return m_profile->title();
}
-void ProfileGenerator::willExecute(const CallIdentifier& callIdentifier)
+void ProfileGenerator::willExecute(ExecState* callerCallFrame, const CallIdentifier& callIdentifier)
{
if (JAVASCRIPTCORE_PROFILE_WILL_EXECUTE_ENABLED()) {
- CString name = callIdentifier.m_name.UTF8String();
- CString url = callIdentifier.m_url.UTF8String();
+ CString name = callIdentifier.m_name.utf8();
+ CString url = callIdentifier.m_url.utf8();
JAVASCRIPTCORE_PROFILE_WILL_EXECUTE(m_profileGroup, const_cast<char*>(name.data()), const_cast<char*>(url.data()), callIdentifier.m_lineNumber);
}
- if (!m_originatingGlobalExec)
+ if (!m_origin)
return;
- ASSERT_ARG(m_currentNode, m_currentNode);
- m_currentNode = m_currentNode->willExecute(callIdentifier);
+ ASSERT(m_currentNode);
+ m_currentNode = m_currentNode->willExecute(callerCallFrame, callIdentifier);
}
-void ProfileGenerator::didExecute(const CallIdentifier& callIdentifier)
+void ProfileGenerator::didExecute(ExecState* callerCallFrame, const CallIdentifier& callIdentifier)
{
if (JAVASCRIPTCORE_PROFILE_DID_EXECUTE_ENABLED()) {
- CString name = callIdentifier.m_name.UTF8String();
- CString url = callIdentifier.m_url.UTF8String();
+ CString name = callIdentifier.m_name.utf8();
+ CString url = callIdentifier.m_url.utf8();
JAVASCRIPTCORE_PROFILE_DID_EXECUTE(m_profileGroup, const_cast<char*>(name.data()), const_cast<char*>(url.data()), callIdentifier.m_lineNumber);
}
- if (!m_originatingGlobalExec)
+ if (!m_origin)
return;
- ASSERT_ARG(m_currentNode, m_currentNode);
+ ASSERT(m_currentNode);
if (m_currentNode->callIdentifier() != callIdentifier) {
- RefPtr<ProfileNode> returningNode = ProfileNode::create(callIdentifier, m_head.get(), m_currentNode.get());
+ RefPtr<ProfileNode> returningNode = ProfileNode::create(callerCallFrame, callIdentifier, m_head.get(), m_currentNode.get());
returningNode->setStartTime(m_currentNode->startTime());
returningNode->didExecute();
m_currentNode->insertNode(returningNode.release());
m_currentNode = m_currentNode->didExecute();
}
+void ProfileGenerator::exceptionUnwind(ExecState* handlerCallFrame, const CallIdentifier&)
+{
+ // If the current node was called by the handler (==) or any
+ // more nested function (>) the we have exited early from it.
+ ASSERT(m_currentNode);
+ while (m_currentNode->callerCallFrame() >= handlerCallFrame) {
+ didExecute(m_currentNode->callerCallFrame(), m_currentNode->callIdentifier());
+ ASSERT(m_currentNode);
+ }
+}
+
void ProfileGenerator::stopProfiling()
{
m_profile->forEach(&ProfileNode::stopProfiling);
removeProfileStart();
removeProfileEnd();
- ASSERT_ARG(m_currentNode, m_currentNode);
+ ASSERT(m_currentNode);
// Set the current node to the parent, because we are in a call that
// will not get didExecute call.
m_currentNode = m_currentNode->parent();
if (double headSelfTime = m_head->selfTime()) {
- RefPtr<ProfileNode> idleNode = ProfileNode::create(CallIdentifier(NonJSExecution, UString(), 0), m_head.get(), m_head.get());
+ RefPtr<ProfileNode> idleNode = ProfileNode::create(0, CallIdentifier(NonJSExecution, UString(), 0), m_head.get(), m_head.get());
idleNode->setTotalTime(headSelfTime);
idleNode->setSelfTime(headSelfTime);
namespace JSC {
class ExecState;
+ class JSGlobalObject;
class Profile;
class ProfileNode;
class UString;
class ProfileGenerator : public RefCounted<ProfileGenerator> {
public:
- static PassRefPtr<ProfileGenerator> create(const UString& title, ExecState* originatingExec, unsigned uid);
+ static PassRefPtr<ProfileGenerator> create(ExecState*, const UString& title, unsigned uid);
// Members
const UString& title() const;
PassRefPtr<Profile> profile() const { return m_profile; }
- ExecState* originatingGlobalExec() const { return m_originatingGlobalExec; }
+ JSGlobalObject* origin() const { return m_origin; }
unsigned profileGroup() const { return m_profileGroup; }
// Collecting
- void willExecute(const CallIdentifier&);
- void didExecute(const CallIdentifier&);
+ void willExecute(ExecState* callerCallFrame, const CallIdentifier&);
+ void didExecute(ExecState* callerCallFrame, const CallIdentifier&);
+
+ void exceptionUnwind(ExecState* handlerCallFrame, const CallIdentifier&);
// Stopping Profiling
void stopProfiling();
- typedef void (ProfileGenerator::*ProfileFunction)(const CallIdentifier& callIdentifier);
+ typedef void (ProfileGenerator::*ProfileFunction)(ExecState* callerOrHandlerCallFrame, const CallIdentifier& callIdentifier);
private:
- ProfileGenerator(const UString& title, ExecState* originatingExec, unsigned uid);
+ ProfileGenerator(ExecState*, const UString& title, unsigned uid);
void addParentForConsoleStart(ExecState*);
void removeProfileStart();
void removeProfileEnd();
RefPtr<Profile> m_profile;
- ExecState* m_originatingGlobalExec;
+ JSGlobalObject* m_origin;
unsigned m_profileGroup;
RefPtr<ProfileNode> m_head;
RefPtr<ProfileNode> m_currentNode;
static double getCount()
{
#if OS(WINDOWS)
- static LARGE_INTEGER frequency = {0};
+ static LARGE_INTEGER frequency;
if (!frequency.QuadPart)
QueryPerformanceFrequency(&frequency);
LARGE_INTEGER counter;
#endif
}
-ProfileNode::ProfileNode(const CallIdentifier& callIdentifier, ProfileNode* headNode, ProfileNode* parentNode)
- : m_callIdentifier(callIdentifier)
+ProfileNode::ProfileNode(ExecState* callerCallFrame, const CallIdentifier& callIdentifier, ProfileNode* headNode, ProfileNode* parentNode)
+ : m_callerCallFrame(callerCallFrame)
+ , m_callIdentifier(callIdentifier)
, m_head(headNode)
, m_parent(parentNode)
, m_nextSibling(0)
startTimer();
}
-ProfileNode::ProfileNode(ProfileNode* headNode, ProfileNode* nodeToCopy)
- : m_callIdentifier(nodeToCopy->callIdentifier())
+ProfileNode::ProfileNode(ExecState* callerCallFrame, ProfileNode* headNode, ProfileNode* nodeToCopy)
+ : m_callerCallFrame(callerCallFrame)
+ , m_callIdentifier(nodeToCopy->callIdentifier())
, m_head(headNode)
, m_parent(nodeToCopy->parent())
, m_nextSibling(0)
{
}
-ProfileNode* ProfileNode::willExecute(const CallIdentifier& callIdentifier)
+ProfileNode* ProfileNode::willExecute(ExecState* callerCallFrame, const CallIdentifier& callIdentifier)
{
for (StackIterator currentChild = m_children.begin(); currentChild != m_children.end(); ++currentChild) {
if ((*currentChild)->callIdentifier() == callIdentifier) {
}
}
- RefPtr<ProfileNode> newChild = ProfileNode::create(callIdentifier, m_head ? m_head : this, this); // If this ProfileNode has no head it is the head.
+ RefPtr<ProfileNode> newChild = ProfileNode::create(callerCallFrame, callIdentifier, m_head ? m_head : this, this); // If this ProfileNode has no head it is the head.
if (m_children.size())
m_children.last()->setNextSibling(newChild.get());
m_children.append(newChild.release());
printf(" ");
printf("Function Name %s %d SelfTime %.3fms/%.3f%% TotalTime %.3fms/%.3f%% VSelf %.3fms VTotal %.3fms Visible %s Next Sibling %s\n",
- functionName().UTF8String().data(),
+ functionName().utf8().data(),
m_numberOfCalls, m_actualSelfTime, selfPercent(), m_actualTotalTime, totalPercent(),
m_visibleSelfTime, m_visibleTotalTime,
(m_visible ? "True" : "False"),
- m_nextSibling ? m_nextSibling->functionName().UTF8String().data() : "");
+ m_nextSibling ? m_nextSibling->functionName().utf8().data() : "");
++indentLevel;
printf(" ");
// Print function names
- const char* name = functionName().UTF8String().data();
+ const char* name = functionName().utf8().data();
double sampleCount = m_actualTotalTime * 1000;
if (indentLevel) {
for (int i = 0; i < indentLevel; ++i)
printf(" ");
- countedFunctions.add(functionName().rep());
+ countedFunctions.add(functionName().impl());
printf("%.0f %s\n", sampleCount ? sampleCount : 1, name);
} else
while (indentLevel--)
printf(" ");
- printf("%.0f %s\n", sampleCount - sumOfChildrensCount, functionName().UTF8String().data());
+ printf("%.0f %s\n", sampleCount - sumOfChildrensCount, functionName().utf8().data());
}
return m_actualTotalTime;
#define ProfileNode_h
#include "CallIdentifier.h"
-#include <wtf/Vector.h>
+#include <wtf/HashCountedSet.h>
#include <wtf/RefCounted.h>
#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
namespace JSC {
+ class ExecState;
class ProfileNode;
typedef Vector<RefPtr<ProfileNode> >::const_iterator StackIterator;
- typedef HashCountedSet<UString::Rep*> FunctionCallHashCount;
+ typedef HashCountedSet<StringImpl*> FunctionCallHashCount;
class ProfileNode : public RefCounted<ProfileNode> {
public:
- static PassRefPtr<ProfileNode> create(const CallIdentifier& callIdentifier, ProfileNode* headNode, ProfileNode* parentNode)
+ static PassRefPtr<ProfileNode> create(ExecState* callerCallFrame, const CallIdentifier& callIdentifier, ProfileNode* headNode, ProfileNode* parentNode)
{
- return adoptRef(new ProfileNode(callIdentifier, headNode, parentNode));
+ return adoptRef(new ProfileNode(callerCallFrame, callIdentifier, headNode, parentNode));
}
- static PassRefPtr<ProfileNode> create(ProfileNode* headNode, ProfileNode* node)
+ static PassRefPtr<ProfileNode> create(ExecState* callerCallFrame, ProfileNode* headNode, ProfileNode* node)
{
- return adoptRef(new ProfileNode(headNode, node));
+ return adoptRef(new ProfileNode(callerCallFrame, headNode, node));
}
bool operator==(ProfileNode* node) { return m_callIdentifier == node->callIdentifier(); }
- ProfileNode* willExecute(const CallIdentifier&);
+ ProfileNode* willExecute(ExecState* callerCallFrame, const CallIdentifier&);
ProfileNode* didExecute();
void stopProfiling();
// CallIdentifier members
+ ExecState* callerCallFrame() const { return m_callerCallFrame; }
const CallIdentifier& callIdentifier() const { return m_callIdentifier; }
const UString& functionName() const { return m_callIdentifier.m_name; }
const UString& url() const { return m_callIdentifier.m_url; }
#endif
private:
- ProfileNode(const CallIdentifier&, ProfileNode* headNode, ProfileNode* parentNode);
- ProfileNode(ProfileNode* headNode, ProfileNode* nodeToCopy);
+ ProfileNode(ExecState* callerCallFrame, const CallIdentifier&, ProfileNode* headNode, ProfileNode* parentNode);
+ ProfileNode(ExecState* callerCallFrame, ProfileNode* headNode, ProfileNode* nodeToCopy);
void startTimer();
void resetChildrensSiblings();
static inline bool functionNameDescendingComparator(const RefPtr<ProfileNode>& a, const RefPtr<ProfileNode>& b) { return a->functionName() > b->functionName(); }
static inline bool functionNameAscendingComparator(const RefPtr<ProfileNode>& a, const RefPtr<ProfileNode>& b) { return a->functionName() < b->functionName(); }
+ ExecState* m_callerCallFrame;
CallIdentifier m_callIdentifier;
ProfileNode* m_head;
ProfileNode* m_parent;
#include "CommonIdentifiers.h"
#include "CallFrame.h"
#include "CodeBlock.h"
+#include "InternalFunction.h"
#include "JSFunction.h"
#include "JSGlobalObject.h"
#include "Nodes.h"
#include "Profile.h"
#include "ProfileGenerator.h"
#include "ProfileNode.h"
+#include "UStringConcatenate.h"
#include <stdio.h>
namespace JSC {
// Check if we currently have a Profile for this global ExecState and title.
// If so return early and don't create a new Profile.
- ExecState* globalExec = exec ? exec->lexicalGlobalObject()->globalExec() : 0;
+ JSGlobalObject* origin = exec ? exec->lexicalGlobalObject() : 0;
for (size_t i = 0; i < m_currentProfiles.size(); ++i) {
ProfileGenerator* profileGenerator = m_currentProfiles[i].get();
- if (profileGenerator->originatingGlobalExec() == globalExec && profileGenerator->title() == title)
+ if (profileGenerator->origin() == origin && profileGenerator->title() == title)
return;
}
s_sharedEnabledProfilerReference = this;
- RefPtr<ProfileGenerator> profileGenerator = ProfileGenerator::create(title, exec, ++ProfilesUID);
+ RefPtr<ProfileGenerator> profileGenerator = ProfileGenerator::create(exec, title, ++ProfilesUID);
m_currentProfiles.append(profileGenerator);
}
PassRefPtr<Profile> Profiler::stopProfiling(ExecState* exec, const UString& title)
{
- ExecState* globalExec = exec ? exec->lexicalGlobalObject()->globalExec() : 0;
+ JSGlobalObject* origin = exec ? exec->lexicalGlobalObject() : 0;
for (ptrdiff_t i = m_currentProfiles.size() - 1; i >= 0; --i) {
ProfileGenerator* profileGenerator = m_currentProfiles[i].get();
- if (profileGenerator->originatingGlobalExec() == globalExec && (title.isNull() || profileGenerator->title() == title)) {
+ if (profileGenerator->origin() == origin && (title.isNull() || profileGenerator->title() == title)) {
profileGenerator->stopProfiling();
RefPtr<Profile> returnProfile = profileGenerator->profile();
return 0;
}
-static inline void dispatchFunctionToProfiles(const Vector<RefPtr<ProfileGenerator> >& profiles, ProfileGenerator::ProfileFunction function, const CallIdentifier& callIdentifier, unsigned currentProfileTargetGroup)
+void Profiler::stopProfiling(JSGlobalObject* origin)
+{
+ for (ptrdiff_t i = m_currentProfiles.size() - 1; i >= 0; --i) {
+ ProfileGenerator* profileGenerator = m_currentProfiles[i].get();
+ if (profileGenerator->origin() == origin) {
+ profileGenerator->stopProfiling();
+ m_currentProfiles.remove(i);
+ if (!m_currentProfiles.size())
+ s_sharedEnabledProfilerReference = 0;
+ }
+ }
+}
+
+static inline void dispatchFunctionToProfiles(ExecState* callerOrHandlerCallFrame, const Vector<RefPtr<ProfileGenerator> >& profiles, ProfileGenerator::ProfileFunction function, const CallIdentifier& callIdentifier, unsigned currentProfileTargetGroup)
{
for (size_t i = 0; i < profiles.size(); ++i) {
- if (profiles[i]->profileGroup() == currentProfileTargetGroup || !profiles[i]->originatingGlobalExec())
- (profiles[i].get()->*function)(callIdentifier);
+ if (profiles[i]->profileGroup() == currentProfileTargetGroup || !profiles[i]->origin())
+ (profiles[i].get()->*function)(callerOrHandlerCallFrame, callIdentifier);
}
}
-void Profiler::willExecute(ExecState* exec, JSValue function)
+void Profiler::willExecute(ExecState* callerCallFrame, JSValue function)
{
ASSERT(!m_currentProfiles.isEmpty());
- dispatchFunctionToProfiles(m_currentProfiles, &ProfileGenerator::willExecute, createCallIdentifier(exec, function, "", 0), exec->lexicalGlobalObject()->profileGroup());
+ dispatchFunctionToProfiles(callerCallFrame, m_currentProfiles, &ProfileGenerator::willExecute, createCallIdentifier(callerCallFrame, function, "", 0), callerCallFrame->lexicalGlobalObject()->profileGroup());
}
-void Profiler::willExecute(ExecState* exec, const UString& sourceURL, int startingLineNumber)
+void Profiler::willExecute(ExecState* callerCallFrame, const UString& sourceURL, int startingLineNumber)
{
ASSERT(!m_currentProfiles.isEmpty());
- CallIdentifier callIdentifier = createCallIdentifier(exec, JSValue(), sourceURL, startingLineNumber);
+ CallIdentifier callIdentifier = createCallIdentifier(callerCallFrame, JSValue(), sourceURL, startingLineNumber);
+
+ dispatchFunctionToProfiles(callerCallFrame, m_currentProfiles, &ProfileGenerator::willExecute, callIdentifier, callerCallFrame->lexicalGlobalObject()->profileGroup());
+}
+
+void Profiler::didExecute(ExecState* callerCallFrame, JSValue function)
+{
+ ASSERT(!m_currentProfiles.isEmpty());
- dispatchFunctionToProfiles(m_currentProfiles, &ProfileGenerator::willExecute, callIdentifier, exec->lexicalGlobalObject()->profileGroup());
+ dispatchFunctionToProfiles(callerCallFrame, m_currentProfiles, &ProfileGenerator::didExecute, createCallIdentifier(callerCallFrame, function, "", 0), callerCallFrame->lexicalGlobalObject()->profileGroup());
}
-void Profiler::didExecute(ExecState* exec, JSValue function)
+void Profiler::didExecute(ExecState* callerCallFrame, const UString& sourceURL, int startingLineNumber)
{
ASSERT(!m_currentProfiles.isEmpty());
- dispatchFunctionToProfiles(m_currentProfiles, &ProfileGenerator::didExecute, createCallIdentifier(exec, function, "", 0), exec->lexicalGlobalObject()->profileGroup());
+ dispatchFunctionToProfiles(callerCallFrame, m_currentProfiles, &ProfileGenerator::didExecute, createCallIdentifier(callerCallFrame, JSValue(), sourceURL, startingLineNumber), callerCallFrame->lexicalGlobalObject()->profileGroup());
}
-void Profiler::didExecute(ExecState* exec, const UString& sourceURL, int startingLineNumber)
+void Profiler::exceptionUnwind(ExecState* handlerCallFrame)
{
ASSERT(!m_currentProfiles.isEmpty());
- dispatchFunctionToProfiles(m_currentProfiles, &ProfileGenerator::didExecute, createCallIdentifier(exec, JSValue(), sourceURL, startingLineNumber), exec->lexicalGlobalObject()->profileGroup());
+ dispatchFunctionToProfiles(handlerCallFrame, m_currentProfiles, &ProfileGenerator::exceptionUnwind, createCallIdentifier(handlerCallFrame, JSValue(), "", 0), handlerCallFrame->lexicalGlobalObject()->profileGroup());
}
CallIdentifier Profiler::createCallIdentifier(ExecState* exec, JSValue functionValue, const UString& defaultSourceURL, int defaultLineNumber)
return CallIdentifier(GlobalCodeExecution, defaultSourceURL, defaultLineNumber);
if (!functionValue.isObject())
return CallIdentifier("(unknown)", defaultSourceURL, defaultLineNumber);
- if (asObject(functionValue)->inherits(&JSFunction::info)) {
+ if (asObject(functionValue)->inherits(&JSFunction::s_info)) {
JSFunction* function = asFunction(functionValue);
if (!function->executable()->isHostFunction())
return createCallIdentifierFromFunctionImp(exec, function);
}
- if (asObject(functionValue)->inherits(&InternalFunction::info))
+ if (asObject(functionValue)->inherits(&JSFunction::s_info))
+ return CallIdentifier(static_cast<JSFunction*>(asObject(functionValue))->name(exec), defaultSourceURL, defaultLineNumber);
+ if (asObject(functionValue)->inherits(&InternalFunction::s_info))
return CallIdentifier(static_cast<InternalFunction*>(asObject(functionValue))->name(exec), defaultSourceURL, defaultLineNumber);
- return CallIdentifier(makeString("(", asObject(functionValue)->className(), " object)"), defaultSourceURL, defaultLineNumber);
+ return CallIdentifier(makeUString("(", asObject(functionValue)->className(), " object)"), defaultSourceURL, defaultLineNumber);
}
CallIdentifier createCallIdentifierFromFunctionImp(ExecState* exec, JSFunction* function)
class ExecState;
class JSGlobalData;
+ class JSGlobalObject;
class JSObject;
class JSValue;
class ProfileGenerator;
class UString;
struct CallIdentifier;
- class Profiler : public FastAllocBase {
+ class Profiler {
+ WTF_MAKE_FAST_ALLOCATED;
public:
static Profiler** enabledProfilerReference()
{
void startProfiling(ExecState*, const UString& title);
PassRefPtr<Profile> stopProfiling(ExecState*, const UString& title);
+ void stopProfiling(JSGlobalObject*);
- void willExecute(ExecState*, JSValue function);
- void willExecute(ExecState*, const UString& sourceURL, int startingLineNumber);
- void didExecute(ExecState*, JSValue function);
- void didExecute(ExecState*, const UString& sourceURL, int startingLineNumber);
+ void willExecute(ExecState* callerCallFrame, JSValue function);
+ void willExecute(ExecState* callerCallFrame, const UString& sourceURL, int startingLineNumber);
+ void didExecute(ExecState* callerCallFrame, JSValue function);
+ void didExecute(ExecState* callerCallFrame, const UString& sourceURL, int startingLineNumber);
+
+ void exceptionUnwind(ExecState* handlerCallFrame);
const Vector<RefPtr<ProfileGenerator> >& currentProfiles() { return m_currentProfiles; };
#import "JSRetainPtr.h"
#import <Foundation/Foundation.h>
-#if PLATFORM(IPHONE_SIMULATOR)
+#if PLATFORM(IOS_SIMULATOR)
#import <Foundation/NSDistributedNotificationCenter.h>
#endif
if ([defaults boolForKey:@"EnableJSProfiling"])
[self startProfiling];
-#if PLATFORM(IPHONE_SIMULATOR)
+#if PLATFORM(IOS_SIMULATOR)
// FIXME: <rdar://problem/6546135>
// The catch-all notifications
[[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(startProfiling) name:@"ProfilerServerStartNotification" object:nil];
NSProcessInfo *processInfo = [NSProcessInfo processInfo];
_serverName = [[NSString alloc] initWithFormat:@"ProfilerServer-%d", [processInfo processIdentifier]];
-#if PLATFORM(IPHONE_SIMULATOR)
+#if PLATFORM(IOS_SIMULATOR)
// FIXME: <rdar://problem/6546135>
[[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(startProfiling) name:[_serverName stringByAppendingString:@"-Start"] object:nil];
[[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(stopProfiling) name:[_serverName stringByAppendingString:@"-Stop"] object:nil];
--- /dev/null
+2011-03-01 Andras Becsi <abecsi@webkit.org>
+
+ Reviewed by Csaba Osztrogonác.
+
+ [Qt] Clean up the project files and move common options to WebKit.pri.
+
+ * api/QtScript.pro: Deduplicate options.
+
+2011-02-24 Andras Becsi <abecsi@webkit.org>
+
+ Reviewed by Laszlo Gombos.
+
+ [Qt] MinGW build fails to link
+ https://bugs.webkit.org/show_bug.cgi?id=55050
+
+ Prepend the libraries of subcomponents instead of appending them
+ to fix the library order according to the dependency of the libraries
+
+ * api/QtScript.pro:
+
+2010-09-29 Caio Marcelo de Oliveira Filho <caio.oliveira@openbossa.org>
+
+ Reviewed by Andreas Kling.
+
+ [Qt] QScriptEngine should have an API for creating Date objects
+ https://bugs.webkit.org/show_bug.cgi?id=41667
+
+ Implement newDate(), isDate() and toDateTime() functions. Use the
+ QDateTime::{to,set}MSecsSinceEpoch() functions to do the
+ calculations.
+
+ * api/qscriptengine.cpp:
+ (QScriptEngine::newDate):
+ * api/qscriptengine.h:
+ * api/qscriptengine_p.cpp:
+ (QScriptEnginePrivate::newDate):
+ * api/qscriptengine_p.h:
+ (QScriptEnginePrivate::isDate):
+
+ * api/qscriptoriginalglobalobject_p.h:
+ (QScriptOriginalGlobalObject::QScriptOriginalGlobalObject): need
+ to keep track of Date Constructor and Prototype.
+ (QScriptOriginalGlobalObject::~QScriptOriginalGlobalObject): ditto.
+ (QScriptOriginalGlobalObject::isDate): use the Date Constructor
+ and Prototype to identify Date values.
+
+ * api/qscriptvalue.cpp:
+ (QScriptValue::isDate):
+ (QScriptValue::toDateTime):
+ * api/qscriptvalue.h:
+ * api/qscriptvalue_p.h:
+ (QScriptValuePrivate::isDate):
+ (QScriptValuePrivate::toDateTime):
+ * tests/qscriptengine/tst_qscriptengine.cpp:
+ (tst_QScriptEngine::newDate):
+
+2010-07-27 Jedrzej Nowacki <jedrzej.nowacki@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ Update the QScriptValue autotests suite.
+
+ QScriptValue generated files were updated, changes are:
+ - More tested values (for example QSE::newObject() and QSE::newArray())
+ - Tested values are recreated before each test and are not reused.
+ The change implies better code coverage and some expected result changes.
+ - A new test to check copy and assign functions.
+ - Tests are using standard QTestLib interface, without any custom macros.
+
+ [Qt] Improve test coverage for the QScriptValue
+ https://bugs.webkit.org/show_bug.cgi?id=42366
+
+ * tests/qscriptvalue/tst_qscriptvalue.cpp:
+ (tst_QScriptValue::tst_QScriptValue):
+ (tst_QScriptValue::~tst_QScriptValue):
+ (tst_QScriptValue::assignAndCopyConstruct_data):
+ (tst_QScriptValue::assignAndCopyConstruct):
+ * tests/qscriptvalue/tst_qscriptvalue.h:
+ * tests/qscriptvalue/tst_qscriptvalue_generated_comparison.cpp:
+ (tst_QScriptValue::equals_data):
+ (tst_QScriptValue::equals):
+ (tst_QScriptValue::strictlyEquals_data):
+ (tst_QScriptValue::strictlyEquals):
+ (tst_QScriptValue::instanceOf_data):
+ (tst_QScriptValue::instanceOf):
+ * tests/qscriptvalue/tst_qscriptvalue_generated_init.cpp:
+ (tst_QScriptValue::initScriptValues):
+ * tests/qscriptvalue/tst_qscriptvalue_generated_istype.cpp:
+ (tst_QScriptValue::isValid_data):
+ (tst_QScriptValue::isValid):
+ (tst_QScriptValue::isBool_data):
+ (tst_QScriptValue::isBool):
+ (tst_QScriptValue::isBoolean_data):
+ (tst_QScriptValue::isBoolean):
+ (tst_QScriptValue::isNumber_data):
+ (tst_QScriptValue::isNumber):
+ (tst_QScriptValue::isFunction_data):
+ (tst_QScriptValue::isFunction):
+ (tst_QScriptValue::isNull_data):
+ (tst_QScriptValue::isNull):
+ (tst_QScriptValue::isString_data):
+ (tst_QScriptValue::isString):
+ (tst_QScriptValue::isUndefined_data):
+ (tst_QScriptValue::isUndefined):
+ (tst_QScriptValue::isObject_data):
+ (tst_QScriptValue::isObject):
+ (tst_QScriptValue::isArray_data):
+ (tst_QScriptValue::isArray):
+ (tst_QScriptValue::isError_data):
+ (tst_QScriptValue::isError):
+ * tests/qscriptvalue/tst_qscriptvalue_generated_totype.cpp:
+ (tst_QScriptValue::toString_data):
+ (tst_QScriptValue::toString):
+ (tst_QScriptValue::toNumber_data):
+ (tst_QScriptValue::toNumber):
+ (tst_QScriptValue::toBool_data):
+ (tst_QScriptValue::toBool):
+ (tst_QScriptValue::toBoolean_data):
+ (tst_QScriptValue::toBoolean):
+ (tst_QScriptValue::toInteger_data):
+ (tst_QScriptValue::toInteger):
+ (tst_QScriptValue::toInt32_data):
+ (tst_QScriptValue::toInt32):
+ (tst_QScriptValue::toUInt32_data):
+ (tst_QScriptValue::toUInt32):
+ (tst_QScriptValue::toUInt16_data):
+ (tst_QScriptValue::toUInt16):
+
+2010-07-27 Caio Marcelo de Oliveira Filho <caio.oliveira@openbossa.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Implement QScriptEngine::newFunction() parts that doesn't depend on QScriptContext
+ https://bugs.webkit.org/show_bug.cgi?id=42174
+
+ Since our function can be called in Javascript both as a function
+ and as a constructor, we couldn't use the existing
+ JSObjectMakeFunctionWithCallback() and JSObjectMakeConstructor().
+
+ Instead, a JSClassRef was created, implementing the needed
+ callbacks (the callAsConstructor is not there yet because its
+ behaviour depends on QScriptContext).
+
+ For the moment, QScriptContext is defined as a void type, since we
+ still don't use it.
+
+ The variant of newFunction() that also takes an external argument
+ was also implemented. The details of implementation were added to
+ the qscriptfunction{.c,_p.h} files.
+
+ This commit also adds tests, some of them from Qt's upstream.
+
+ * api/QtScript.pro:
+ * api/qscriptengine.cpp:
+ (QScriptEngine::newFunction):
+ * api/qscriptengine.h:
+ * api/qscriptengine_p.cpp:
+ (QScriptEnginePrivate::QScriptEnginePrivate):
+ (QScriptEnginePrivate::~QScriptEnginePrivate):
+ (QScriptEnginePrivate::newFunction):
+ * api/qscriptengine_p.h:
+ * api/qscriptfunction.cpp: Added.
+ (qt_NativeFunction_finalize):
+ (qt_NativeFunction_callAsFunction):
+ (qt_NativeFunctionWithArg_finalize):
+ (qt_NativeFunctionWithArg_callAsFunction):
+ * api/qscriptfunction_p.h: Added.
+ (QNativeFunctionData::QNativeFunctionData):
+ (QNativeFunctionWithArgData::QNativeFunctionWithArgData):
+ * api/qscriptoriginalglobalobject_p.h:
+ (QScriptOriginalGlobalObject::QScriptOriginalGlobalObject):
+ (QScriptOriginalGlobalObject::~QScriptOriginalGlobalObject):
+ (QScriptOriginalGlobalObject::functionPrototype):
+ * tests/qscriptengine/tst_qscriptengine.cpp:
+ (myFunction):
+ (myFunctionWithArg):
+ (myFunctionThatReturns):
+ (myFunctionThatReturnsWithoutEngine):
+ (myFunctionThatReturnsWrongEngine):
+ (tst_QScriptEngine::newFunction):
+
+2010-07-23 Jedrzej Nowacki <jedrzej.nowacki@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ QScriptValue::equals benchmark crash fix.
+
+ Patch changes QScriptValue::equals implementation to cover
+ more edge cases.
+
+ Problem exposes an issue in our autotests (all values got
+ bound to an engine too fast - bug 42366).
+
+ [Qt] QScriptValue::equals asserts
+ https://bugs.webkit.org/show_bug.cgi?id=42363
+
+ * api/qscriptvalue_p.h:
+ (QScriptValuePrivate::equals):
+
+2010-07-14 Jedrzej Nowacki <jedrzej.nowacki@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ Introduce QScriptOriginalGlobalObject.
+
+ QtScript exposes more functionality than JSC C API. Sometimes it is
+ necessary to take a shortcut in implementation. Really often we have
+ to use a standard JS function. These function could be changed or
+ even deleted by a script, so a backup of a reference to an object is needed.
+
+ In them same time this is rather a workaround then real fix, so the code
+ should be separated and changed easily in future. It is why we need
+ the new internal class.
+
+ The patch fixes a few crashes.
+
+ [Qt] QScriptEngine should work correctly even after global object changes
+ https://bugs.webkit.org/show_bug.cgi?id=41839
+
+ * api/QtScript.pro:
+ * api/qscriptengine_p.cpp:
+ (QScriptEnginePrivate::QScriptEnginePrivate):
+ (QScriptEnginePrivate::~QScriptEnginePrivate):
+ * api/qscriptengine_p.h:
+ (QScriptEnginePrivate::isArray):
+ (QScriptEnginePrivate::isError):
+ (QScriptEnginePrivate::objectHasOwnProperty):
+ (QScriptEnginePrivate::objectGetOwnPropertyNames):
+ * api/qscriptoriginalglobalobject_p.h: Added.
+ (QScriptOriginalGlobalObject::QScriptOriginalGlobalObject):
+ (QScriptOriginalGlobalObject::initializeMember):
+ (QScriptOriginalGlobalObject::~QScriptOriginalGlobalObject):
+ (QScriptOriginalGlobalObject::objectHasOwnProperty):
+ (QScriptOriginalGlobalObject::objectGetOwnPropertyNames):
+ (QScriptOriginalGlobalObject::isArray):
+ (QScriptOriginalGlobalObject::isError):
+ (QScriptOriginalGlobalObject::isType):
+ * api/qscriptvalue_p.h:
+ (QScriptValuePrivate::isError):
+ (QScriptValuePrivate::hasOwnProperty):
+ * api/qscriptvalueiterator_p.h:
+ (QScriptValueIteratorPrivate::QScriptValueIteratorPrivate):
+ * tests/qscriptvalue/tst_qscriptvalue.cpp:
+ (tst_QScriptValue::globalObjectChanges):
+ * tests/qscriptvalue/tst_qscriptvalue.h:
+
+2010-07-13 Jedrzej Nowacki <jedrzej.nowacki@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ Introduce QScriptValueIterator.
+
+ The QScriptValueIterator class permits to iterate over a QScriptValue's properties.
+
+ [Qt] QtScript should provide an API for enumerating a JS object's properties
+ https://bugs.webkit.org/show_bug.cgi?id=41680
+
+ * api/QtScript.pro:
+ * api/qscriptvalueiterator.cpp: Added.
+ (QScriptValueIterator::QScriptValueIterator):
+ (QScriptValueIterator::~QScriptValueIterator):
+ (QScriptValueIterator::hasNext):
+ (QScriptValueIterator::next):
+ (QScriptValueIterator::hasPrevious):
+ (QScriptValueIterator::previous):
+ (QScriptValueIterator::toFront):
+ (QScriptValueIterator::toBack):
+ (QScriptValueIterator::name):
+ (QScriptValueIterator::scriptName):
+ (QScriptValueIterator::value):
+ (QScriptValueIterator::setValue):
+ (QScriptValueIterator::remove):
+ (QScriptValueIterator::flags):
+ (QScriptValueIterator::operator=):
+ * api/qscriptvalueiterator.h: Added.
+ * api/qscriptvalueiterator_p.h: Added.
+ (QScriptValueIteratorPrivate::QScriptValueIteratorPrivate):
+ (QScriptValueIteratorPrivate::~QScriptValueIteratorPrivate):
+ (QScriptValueIteratorPrivate::hasNext):
+ (QScriptValueIteratorPrivate::next):
+ (QScriptValueIteratorPrivate::hasPrevious):
+ (QScriptValueIteratorPrivate::previous):
+ (QScriptValueIteratorPrivate::name):
+ (QScriptValueIteratorPrivate::scriptName):
+ (QScriptValueIteratorPrivate::value):
+ (QScriptValueIteratorPrivate::setValue):
+ (QScriptValueIteratorPrivate::remove):
+ (QScriptValueIteratorPrivate::toFront):
+ (QScriptValueIteratorPrivate::toBack):
+ (QScriptValueIteratorPrivate::flags):
+ (QScriptValueIteratorPrivate::isValid):
+ (QScriptValueIteratorPrivate::engine):
+ * tests/qscriptvalueiterator/qscriptvalueiterator.pro: Added.
+ * tests/qscriptvalueiterator/tst_qscriptvalueiterator.cpp: Added.
+ (tst_QScriptValueIterator::tst_QScriptValueIterator):
+ (tst_QScriptValueIterator::~tst_QScriptValueIterator):
+ (tst_QScriptValueIterator::iterateForward_data):
+ (tst_QScriptValueIterator::iterateForward):
+ (tst_QScriptValueIterator::iterateBackward_data):
+ (tst_QScriptValueIterator::iterateBackward):
+ (tst_QScriptValueIterator::iterateArray_data):
+ (tst_QScriptValueIterator::iterateArray):
+ (tst_QScriptValueIterator::iterateBackAndForth):
+ (tst_QScriptValueIterator::setValue):
+ (tst_QScriptValueIterator::remove):
+ (tst_QScriptValueIterator::removeMixed):
+ (tst_QScriptValueIterator::removeUndeletable):
+ (tst_QScriptValueIterator::iterateString):
+ (tst_QScriptValueIterator::assignObjectToIterator):
+ * tests/tests.pro:
+
+2010-07-09 Jedrzej Nowacki <jedrzej.nowacki@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ Implementation of the QScriptValue::propertyFlags function.
+
+ The function returns the flags of a property with the given name,
+ using a given mode to resolve the property. This is a simple
+ implementation that is sufficient to test the QScriptValueIterator.
+
+ [Qt] QScriptValue API should have a property flag accessor.
+ https://bugs.webkit.org/show_bug.cgi?id=41769
+
+ * api/qscriptvalue.cpp:
+ (QScriptValue::propertyFlags):
+ * api/qscriptvalue.h:
+ * api/qscriptvalue_p.h:
+ (QScriptValuePrivate::propertyFlags):
+ * tests/qscriptvalue/tst_qscriptvalue.cpp:
+ (tst_QScriptValue::propertyFlag_data):
+ (tst_QScriptValue::propertyFlag):
+ * tests/qscriptvalue/tst_qscriptvalue.h:
+
+2010-07-07 Caio Marcelo de Oliveira Filho <caio.oliveira@openbossa.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ Implementation of QScriptValue::isArray()
+ https://bugs.webkit.org/show_bug.cgi?id=41713
+
+ Since we don't have access to the [[Class]] internal property of
+ builtins (including Array), the solution was to keep the original 'Array'
+ (constructor) and 'Array.prototype' objects and use them to identify
+ if a given object is an Array.
+
+ Also uncomment some tests and add some tests of newArray() that
+ depended on isArray().
+
+ * api/qscriptengine_p.cpp:
+ (QScriptEnginePrivate::QScriptEnginePrivate):
+ (QScriptEnginePrivate::~QScriptEnginePrivate):
+ * api/qscriptengine_p.h:
+ (QScriptEnginePrivate::isArray):
+ * api/qscriptvalue.cpp:
+ (QScriptValue::isArray):
+ * api/qscriptvalue.h:
+ * api/qscriptvalue_p.h:
+ (QScriptValuePrivate::isArray):
+ * tests/qscriptengine/tst_qscriptengine.cpp:
+ (tst_QScriptEngine::newArray):
+
+2010-07-06 Jedrzej Nowacki <jedrzej.nowacki@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ Implementation of QScriptValue properties accessors.
+
+ The patch contains implementation of the QScriptValue::property() and
+ the QScriptValue::setProperty(). It is not full functionality, as these
+ method are too complex for one patch, but it is enough to cover about
+ 95% of use cases.
+
+ Missing functionality:
+ - Few of the PropertyFlags are ignored.
+ - Only a public part of the ResolveFlags can be used (ResolveLocal,
+ ResolvePrototype).
+
+ A lot of new test cases were added.
+
+ [Qt] QScriptValue should have API for accessing object properties
+ https://bugs.webkit.org/show_bug.cgi?id=40903
+
+ * api/qscriptconverter_p.h:
+ (QScriptConverter::toPropertyFlags):
+ * api/qscriptstring_p.h:
+ (QScriptStringPrivate::operator JSStringRef):
+ * api/qscriptvalue.cpp:
+ (QScriptValue::property):
+ (QScriptValue::setProperty):
+ * api/qscriptvalue.h:
+ (QScriptValue::):
+ * api/qscriptvalue_p.h:
+ (QScriptValuePrivate::assignEngine):
+ (QScriptValuePrivate::property):
+ (QScriptValuePrivate::hasOwnProperty):
+ (QScriptValuePrivate::setProperty):
+ (QScriptValuePrivate::deleteProperty):
+ * tests/qscriptvalue/tst_qscriptvalue.cpp:
+ (tst_QScriptValue::getPropertySimple_data):
+ (tst_QScriptValue::getPropertySimple):
+ (tst_QScriptValue::setPropertySimple):
+ (tst_QScriptValue::getPropertyResolveFlag):
+ (tst_QScriptValue::getSetProperty):
+ (tst_QScriptValue::setProperty_data):
+ (tst_QScriptValue::setProperty):
+ * tests/qscriptvalue/tst_qscriptvalue.h:
+
+2010-07-02 Jedrzej Nowacki <jedrzej.nowacki@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ Compilation fix.
+
+ QScriptEnginePrivate::newArray can't be const because it can
+ throw an exception.
+
+ [Qt] QScriptEnginePrivate compilation fix
+ https://bugs.webkit.org/show_bug.cgi?id=41520
+
+ * api/qscriptengine_p.cpp:
+ (QScriptEnginePrivate::newArray):
+ * api/qscriptengine_p.h:
+
+2010-06-28 Jedrzej Nowacki <jedrzej.nowacki@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ Implement exception reporting in the QtScript API.
+
+ The exception should be accessible through the API by the uncaughtException
+ function. Functions; hasUncaughtException, clearExceptions, uncaughtExceptionLineNumber,
+ uncaughtExceptionBacktrace were added to facilitate error checking and debugging.
+
+ [Qt] QtScript API should be exceptions aware.
+ https://bugs.webkit.org/show_bug.cgi?id=41199
+
+ * api/qscriptengine.cpp:
+ (QScriptEngine::hasUncaughtException):
+ (QScriptEngine::uncaughtException):
+ (QScriptEngine::clearExceptions):
+ (QScriptEngine::uncaughtExceptionLineNumber):
+ (QScriptEngine::uncaughtExceptionBacktrace):
+ * api/qscriptengine.h:
+ * api/qscriptengine_p.cpp:
+ (QScriptEnginePrivate::QScriptEnginePrivate):
+ (QScriptEnginePrivate::~QScriptEnginePrivate):
+ (QScriptEnginePrivate::uncaughtException):
+ * api/qscriptengine_p.h:
+ (QScriptEnginePrivate::):
+ (QScriptEnginePrivate::evaluate):
+ (QScriptEnginePrivate::hasUncaughtException):
+ (QScriptEnginePrivate::clearExceptions):
+ (QScriptEnginePrivate::setException):
+ (QScriptEnginePrivate::uncaughtExceptionLineNumber):
+ (QScriptEnginePrivate::uncaughtExceptionBacktrace):
+ * api/qscriptvalue_p.h:
+ (QScriptValuePrivate::toString):
+ (QScriptValuePrivate::toNumber):
+ (QScriptValuePrivate::toObject):
+ (QScriptValuePrivate::equals):
+ (QScriptValuePrivate::instanceOf):
+ (QScriptValuePrivate::call):
+ (QScriptValuePrivate::inherits):
+ * tests/qscriptengine/tst_qscriptengine.cpp:
+ (tst_QScriptEngine::uncaughtException):
+
CONFIG += building-libs
isEmpty(JSC_GENERATED_SOURCES_DIR):JSC_GENERATED_SOURCES_DIR = ../../generated
-CONFIG(debug, debug|release) {
- OBJECTS_DIR = obj/debug
-} else { # Release
- OBJECTS_DIR = obj/release
-}
isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../../..
include($$PWD/../../../WebKit.pri)
include($$PWD/../../JavaScriptCore.pri)
-addJavaScriptCoreLib(../..)
+prependJavaScriptCoreLib(../..)
INCLUDEPATH += $$PWD/../../API
SOURCES += $$PWD/qscriptengine.cpp \
$$PWD/qscriptengine_p.cpp \
$$PWD/qscriptvalue.cpp \
+ $$PWD/qscriptvalueiterator.cpp \
$$PWD/qscriptstring.cpp \
$$PWD/qscriptprogram.cpp \
$$PWD/qscriptsyntaxcheckresult.cpp \
+ $$PWD/qscriptfunction.cpp
HEADERS += $$PWD/qtscriptglobal.h \
$$PWD/qscriptengine.h \
$$PWD/qscriptengine_p.h \
$$PWD/qscriptvalue.h \
$$PWD/qscriptvalue_p.h \
+ $$PWD/qscriptvalueiterator.h \
+ $$PWD/qscriptvalueiterator_p.h \
$$PWD/qscriptconverter_p.h \
$$PWD/qscriptstring.h \
$$PWD/qscriptstring_p.h \
$$PWD/qscriptprogram.h \
$$PWD/qscriptprogram_p.h \
$$PWD/qscriptsyntaxcheckresult.h \
-
+ $$PWD/qscriptoriginalglobalobject_p.h \
+ $$PWD/qscriptfunction_p.h
!static: DEFINES += QT_MAKEDLL
#ifndef qscriptconverter_p_h
#define qscriptconverter_p_h
+#include "qscriptvalue.h"
#include <JavaScriptCore/JavaScript.h>
+#include <QtCore/qglobal.h>
#include <QtCore/qnumeric.h>
#include <QtCore/qstring.h>
#include <QtCore/qvarlengtharray.h>
buf.append(0);
return QString::fromLatin1(buf.constData());
}
+
+ static JSPropertyAttributes toPropertyFlags(const QFlags<QScriptValue::PropertyFlag>& flags)
+ {
+ JSPropertyAttributes attr = 0;
+ if (flags.testFlag(QScriptValue::ReadOnly))
+ attr |= kJSPropertyAttributeReadOnly;
+ if (flags.testFlag(QScriptValue::Undeletable))
+ attr |= kJSPropertyAttributeDontDelete;
+ if (flags.testFlag(QScriptValue::SkipInEnumeration))
+ attr |= kJSPropertyAttributeDontEnum;
+ return attr;
+ }
};
#endif // qscriptconverter_p_h
#include "qscriptprogram_p.h"
#include "qscriptsyntaxcheckresult_p.h"
#include "qscriptvalue_p.h"
+#include <QtCore/qdatetime.h>
+#include <QtCore/qnumeric.h>
/*!
Constructs a QScriptEngine object.
return QScriptValuePrivate::get(d_ptr->evaluate(QScriptProgramPrivate::get(program)));
}
+/*!
+ Returns true if the last script evaluation resulted in an uncaught
+ exception; otherwise returns false.
+
+ The exception state is cleared when evaluate() is called.
+
+ \sa uncaughtException(), uncaughtExceptionLineNumber(),
+ uncaughtExceptionBacktrace()
+*/
+bool QScriptEngine::hasUncaughtException() const
+{
+ return d_ptr->hasUncaughtException();
+}
+
+/*!
+ Returns the current uncaught exception, or an invalid QScriptValue
+ if there is no uncaught exception.
+
+ The exception value is typically an \c{Error} object; in that case,
+ you can call toString() on the return value to obtain an error
+ message.
+
+ \sa hasUncaughtException(), uncaughtExceptionLineNumber(),
+ uncaughtExceptionBacktrace()
+*/
+QScriptValue QScriptEngine::uncaughtException() const
+{
+ return QScriptValuePrivate::get(d_ptr->uncaughtException());
+}
+
+/*!
+ Clears any uncaught exceptions in this engine.
+
+ \sa hasUncaughtException()
+*/
+void QScriptEngine::clearExceptions()
+{
+ d_ptr->clearExceptions();
+}
+
+/*!
+ Returns the line number where the last uncaught exception occurred.
+
+ Line numbers are 1-based, unless a different base was specified as
+ the second argument to evaluate().
+
+ \sa hasUncaughtException(), uncaughtExceptionBacktrace()
+*/
+int QScriptEngine::uncaughtExceptionLineNumber() const
+{
+ return d_ptr->uncaughtExceptionLineNumber();
+}
+
+/*!
+ Returns a human-readable backtrace of the last uncaught exception.
+
+ Each line is of the form \c{<function-name>(<arguments>)@<file-name>:<line-number>}.
+
+ \sa uncaughtException()
+*/
+QStringList QScriptEngine::uncaughtExceptionBacktrace() const
+{
+ return d_ptr->uncaughtExceptionBacktrace();
+}
+
/*!
Runs the garbage collector.
return QScriptStringPrivate::get(d_ptr->toStringHandle(str));
}
+/*!
+ Converts the given \a value to an object, if such a conversion is
+ possible; otherwise returns an invalid QScriptValue. The conversion
+ is performed according to the following table:
+
+ \table
+ \header \o Input Type \o Result
+ \row \o Undefined \o An invalid QScriptValue.
+ \row \o Null \o An invalid QScriptValue.
+ \row \o Boolean \o A new Boolean object whose internal value is set to the value of the boolean.
+ \row \o Number \o A new Number object whose internal value is set to the value of the number.
+ \row \o String \o A new String object whose internal value is set to the value of the string.
+ \row \o Object \o The result is the object itself (no conversion).
+ \endtable
+
+ \sa newObject()
+*/
+QScriptValue QScriptEngine::toObject(const QScriptValue& value)
+{
+ return QScriptValuePrivate::get(QScriptValuePrivate::get(value)->toObject(d_ptr.data()));
+}
+
/*!
Returns a QScriptValue of the primitive type Null.
return QScriptValue(this, QScriptValue::UndefinedValue);
}
+/*!
+ Creates a QScriptValue that wraps a native (C++) function. \a fun
+ must be a C++ function with signature QScriptEngine::FunctionSignature.
+ \a length is the number of arguments that \a fun expects; this becomes
+ the \c{length} property of the created QScriptValue.
+
+ Note that \a length only gives an indication of the number of
+ arguments that the function expects; an actual invocation of a
+ function can include any number of arguments. You can check the
+ \l{QScriptContext::argumentCount()}{argumentCount()} of the
+ QScriptContext associated with the invocation to determine the
+ actual number of arguments passed.
+
+ A \c{prototype} property is automatically created for the resulting
+ function object, to provide for the possibility that the function
+ will be used as a constructor.
+
+ By combining newFunction() and the property flags
+ QScriptValue::PropertyGetter and QScriptValue::PropertySetter, you
+ can create script object properties that behave like normal
+ properties in script code, but are in fact accessed through
+ functions (analogous to how properties work in \l{Qt's Property
+ System}). Example:
+
+ \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 11
+
+ When the property \c{foo} of the script object is subsequently
+ accessed in script code, \c{getSetFoo()} will be invoked to handle
+ the access. In this particular case, we chose to store the "real"
+ value of \c{foo} as a property of the accessor function itself; you
+ are of course free to do whatever you like in this function.
+
+ In the above example, a single native function was used to handle
+ both reads and writes to the property; the argument count is used to
+ determine if we are handling a read or write. You can also use two
+ separate functions; just specify the relevant flag
+ (QScriptValue::PropertyGetter or QScriptValue::PropertySetter) when
+ setting the property, e.g.:
+
+ \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 12
+
+ \sa QScriptValue::call()
+*/
+QScriptValue QScriptEngine::newFunction(QScriptEngine::FunctionSignature fun, int length)
+{
+ return QScriptValuePrivate::get(d_ptr->newFunction(fun, 0, length));
+}
+
+/*!
+ Creates a constructor function from \a fun, with the given \a length.
+ The \c{prototype} property of the resulting function is set to be the
+ given \a prototype. The \c{constructor} property of \a prototype is
+ set to be the resulting function.
+
+ When a function is called as a constructor (e.g. \c{new Foo()}), the
+ `this' object associated with the function call is the new object
+ that the function is expected to initialize; the prototype of this
+ default constructed object will be the function's public
+ \c{prototype} property. If you always want the function to behave as
+ a constructor (e.g. \c{Foo()} should also create a new object), or
+ if you need to create your own object rather than using the default
+ `this' object, you should make sure that the prototype of your
+ object is set correctly; either by setting it manually, or, when
+ wrapping a custom type, by having registered the defaultPrototype()
+ of that type. Example:
+
+ \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 9
+
+ To wrap a custom type and provide a constructor for it, you'd typically
+ do something like this:
+
+ \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 10
+*/
+QScriptValue QScriptEngine::newFunction(QScriptEngine::FunctionSignature fun, const QScriptValue& prototype, int length)
+{
+ return QScriptValuePrivate::get(d_ptr->newFunction(fun, QScriptValuePrivate::get(prototype), length));
+}
+
+/*!
+ \internal
+ \since 4.4
+*/
+QScriptValue QScriptEngine::newFunction(QScriptEngine::FunctionWithArgSignature fun, void* arg)
+{
+ return QScriptValuePrivate::get(d_ptr->newFunction(fun, arg));
+}
+
+/*!
+ Creates a QtScript object of class Object.
+
+ The prototype of the created object will be the Object
+ prototype object.
+
+ \sa newArray(), QScriptValue::setProperty()
+*/
+QScriptValue QScriptEngine::newObject()
+{
+ return QScriptValuePrivate::get(d_ptr->newObject());
+}
+
+/*!
+ Creates a QtScript object of class Array with the given \a length.
+
+ \sa newObject()
+*/
+QScriptValue QScriptEngine::newArray(uint length)
+{
+ return QScriptValuePrivate::get(d_ptr->newArray(length));
+}
+
+/*!
+ Creates a QtScript object of class Date with the given \a value
+ (the number of milliseconds since 01 January 1970, UTC).
+*/
+QScriptValue QScriptEngine::newDate(qsreal value)
+{
+ return QScriptValuePrivate::get(d_ptr->newDate(value));
+}
+
+/*!
+ Creates a QtScript object of class Date from the given \a value.
+
+ \sa QScriptValue::toDateTime()
+*/
+QScriptValue QScriptEngine::newDate(const QDateTime& value)
+{
+ if (value.isValid())
+ return QScriptValuePrivate::get(d_ptr->newDate(qsreal(value.toMSecsSinceEpoch())));
+ return QScriptValuePrivate::get(d_ptr->newDate(qSNaN()));
+}
+
/*!
Returns this engine's Global Object.
{
return QScriptValuePrivate::get(d_ptr->globalObject());
}
+
+/*!
+ \typedef QScriptEngine::FunctionSignature
+ \relates QScriptEngine
+
+ The function signature \c{QScriptValue f(QScriptContext *, QScriptEngine *)}.
+
+ A function with such a signature can be passed to
+ QScriptEngine::newFunction() to wrap the function.
+*/
+
+/*!
+ \typedef QScriptEngine::FunctionWithArgSignature
+ \relates QScriptEngine
+
+ The function signature \c{QScriptValue f(QScriptContext *, QScriptEngine *, void *)}.
+
+ A function with such a signature can be passed to
+ QScriptEngine::newFunction() to wrap the function.
+*/
#include "qscriptprogram.h"
#include "qscriptstring.h"
#include "qscriptsyntaxcheckresult.h"
+#include "qscriptvalue.h"
#include <QtCore/qobject.h>
#include <QtCore/qshareddata.h>
#include <QtCore/qstring.h>
-class QScriptValue;
+class QDateTime;
class QScriptEnginePrivate;
+// FIXME: Remove this once QScriptContext is properly defined.
+typedef void QScriptContext;
+
// Internal typedef
typedef QExplicitlySharedDataPointer<QScriptEnginePrivate> QScriptEnginePtr;
QScriptValue evaluate(const QString& program, const QString& fileName = QString(), int lineNumber = 1);
QScriptValue evaluate(const QScriptProgram& program);
+ bool hasUncaughtException() const;
+ QScriptValue uncaughtException() const;
+ void clearExceptions();
+ int uncaughtExceptionLineNumber() const;
+ QStringList uncaughtExceptionBacktrace() const;
+
void collectGarbage();
void reportAdditionalMemoryCost(int cost);
QScriptString toStringHandle(const QString& str);
+ QScriptValue toObject(const QScriptValue& value);
QScriptValue nullValue();
QScriptValue undefinedValue();
+
+ typedef QScriptValue (*FunctionSignature)(QScriptContext *, QScriptEngine *);
+ typedef QScriptValue (*FunctionWithArgSignature)(QScriptContext *, QScriptEngine *, void *);
+
+ QScriptValue newFunction(FunctionSignature fun, int length = 0);
+ QScriptValue newFunction(FunctionSignature fun, const QScriptValue& prototype, int length = 0);
+ QScriptValue newFunction(FunctionWithArgSignature fun, void* arg);
+
+ QScriptValue newObject();
+ QScriptValue newArray(uint length = 0);
+ QScriptValue newDate(qsreal value);
+ QScriptValue newDate(const QDateTime& value);
QScriptValue globalObject() const;
private:
friend class QScriptEnginePrivate;
#include "qscriptengine_p.h"
+#include "qscriptfunction_p.h"
#include "qscriptprogram_p.h"
#include "qscriptvalue_p.h"
QScriptEnginePrivate::QScriptEnginePrivate(const QScriptEngine* engine)
: q_ptr(const_cast<QScriptEngine*>(engine))
, m_context(JSGlobalContextCreate(0))
+ , m_exception(0)
+ , m_originalGlobalObject(m_context)
+ , m_nativeFunctionClass(JSClassCreate(&qt_NativeFunctionClass))
+ , m_nativeFunctionWithArgClass(JSClassCreate(&qt_NativeFunctionWithArgClass))
{
}
QScriptEnginePrivate::~QScriptEnginePrivate()
{
+ JSClassRelease(m_nativeFunctionClass);
+ JSClassRelease(m_nativeFunctionWithArgClass);
+ if (m_exception)
+ JSValueUnprotect(m_context, m_exception);
JSGlobalContextRelease(m_context);
}
{
if (program->isNull())
return new QScriptValuePrivate;
- return new QScriptValuePrivate(this, evaluate(program->program(), program->file(), program->line()));
+ return new QScriptValuePrivate(this, evaluate(*program, program->file(), program->line()));
+}
+
+QScriptValuePrivate* QScriptEnginePrivate::uncaughtException() const
+{
+ return m_exception ? new QScriptValuePrivate(this, m_exception) : new QScriptValuePrivate();
+}
+
+QScriptValuePrivate* QScriptEnginePrivate::newFunction(QScriptEngine::FunctionSignature fun, QScriptValuePrivate* prototype, int length)
+{
+ // Note that this private data will be deleted in the object finalize function.
+ QNativeFunctionData* data = new QNativeFunctionData(this, fun);
+ JSObjectRef funJS = JSObjectMake(m_context, m_nativeFunctionClass, reinterpret_cast<void*>(data));
+ QScriptValuePrivate* proto = prototype ? prototype : newObject();
+ return newFunction(funJS, proto);
+}
+
+QScriptValuePrivate* QScriptEnginePrivate::newFunction(QScriptEngine::FunctionWithArgSignature fun, void* arg)
+{
+ // Note that this private data will be deleted in the object finalize function.
+ QNativeFunctionWithArgData* data = new QNativeFunctionWithArgData(this, fun, arg);
+ JSObjectRef funJS = JSObjectMake(m_context, m_nativeFunctionWithArgClass, reinterpret_cast<void*>(data));
+ QScriptValuePrivate* proto = newObject();
+ return newFunction(funJS, proto);
+}
+
+QScriptValuePrivate* QScriptEnginePrivate::newFunction(JSObjectRef funJS, QScriptValuePrivate* prototype)
+{
+ JSObjectSetPrototype(m_context, funJS, m_originalGlobalObject.functionPrototype());
+
+ QScriptValuePrivate* result = new QScriptValuePrivate(this, funJS);
+ static JSStringRef protoName = QScriptConverter::toString("prototype");
+ static JSStringRef constructorName = QScriptConverter::toString("constructor");
+ result->setProperty(protoName, prototype, QScriptValue::Undeletable);
+ prototype->setProperty(constructorName, result, QScriptValue::PropertyFlags(QScriptValue::Undeletable | QScriptValue::SkipInEnumeration));
+
+ return result;
+}
+
+QScriptValuePrivate* QScriptEnginePrivate::newObject() const
+{
+ return new QScriptValuePrivate(this, JSObjectMake(m_context, /* jsClass */ 0, /* userData */ 0));
+}
+
+QScriptValuePrivate* QScriptEnginePrivate::newArray(uint length)
+{
+ JSValueRef exception = 0;
+ JSObjectRef array = JSObjectMakeArray(m_context, /* argumentCount */ 0, /* arguments */ 0, &exception);
+
+ if (!exception) {
+ if (length > 0) {
+ JSRetainPtr<JSStringRef> lengthRef(Adopt, JSStringCreateWithUTF8CString("length"));
+ // array is an Array instance, so an exception should not occure here.
+ JSObjectSetProperty(m_context, array, lengthRef.get(), JSValueMakeNumber(m_context, length), kJSPropertyAttributeNone, /* exception */ 0);
+ }
+ } else {
+ setException(exception, NotNullException);
+ return new QScriptValuePrivate();
+ }
+
+ return new QScriptValuePrivate(this, array);
+}
+
+QScriptValuePrivate* QScriptEnginePrivate::newDate(qsreal value)
+{
+ JSValueRef exception = 0;
+ JSValueRef argument = JSValueMakeNumber(m_context, value);
+ JSObjectRef result = JSObjectMakeDate(m_context, /* argumentCount */ 1, &argument, &exception);
+
+ if (exception) {
+ setException(exception, NotNullException);
+ return new QScriptValuePrivate();
+ }
+
+ return new QScriptValuePrivate(this, result);
}
QScriptValuePrivate* QScriptEnginePrivate::globalObject() const
{
- JSObjectRef globalObject = JSContextGetGlobalObject(context());
- return new QScriptValuePrivate(this, globalObject, globalObject);
+ JSObjectRef globalObject = JSContextGetGlobalObject(m_context);
+ return new QScriptValuePrivate(this, globalObject);
}
#include "qscriptconverter_p.h"
#include "qscriptengine.h"
+#include "qscriptoriginalglobalobject_p.h"
#include "qscriptstring_p.h"
#include "qscriptsyntaxcheckresult_p.h"
#include "qscriptvalue.h"
#include <JavaScriptCore/JavaScript.h>
+#include <JavaScriptCore/JSRetainPtr.h>
#include <JSBasePrivate.h>
#include <QtCore/qshareddata.h>
#include <QtCore/qstring.h>
+#include <QtCore/qstringlist.h>
class QScriptEngine;
class QScriptSyntaxCheckResultPrivate;
QScriptEnginePrivate(const QScriptEngine*);
~QScriptEnginePrivate();
+ enum SetExceptionFlag {
+ IgnoreNullException = 0x01,
+ NotNullException = 0x02,
+ };
+
QScriptSyntaxCheckResultPrivate* checkSyntax(const QString& program);
QScriptValuePrivate* evaluate(const QString& program, const QString& fileName, int lineNumber);
QScriptValuePrivate* evaluate(const QScriptProgramPrivate* program);
inline JSValueRef evaluate(JSStringRef program, JSStringRef fileName, int lineNumber);
+ inline bool hasUncaughtException() const;
+ QScriptValuePrivate* uncaughtException() const;
+ inline void clearExceptions();
+ inline void setException(JSValueRef exception, const /* SetExceptionFlags */ unsigned flags = IgnoreNullException);
+ inline int uncaughtExceptionLineNumber() const;
+ inline QStringList uncaughtExceptionBacktrace() const;
+
inline void collectGarbage();
inline void reportAdditionalMemoryCost(int cost);
inline JSValueRef makeJSValue(bool number) const;
inline JSValueRef makeJSValue(QScriptValue::SpecialValue value) const;
+ QScriptValuePrivate* newFunction(QScriptEngine::FunctionSignature fun, QScriptValuePrivate* prototype, int length);
+ QScriptValuePrivate* newFunction(QScriptEngine::FunctionWithArgSignature fun, void* arg);
+ QScriptValuePrivate* newFunction(JSObjectRef funObject, QScriptValuePrivate* prototype);
+
+ QScriptValuePrivate* newObject() const;
+ QScriptValuePrivate* newArray(uint length);
+ QScriptValuePrivate* newDate(qsreal value);
QScriptValuePrivate* globalObject() const;
inline QScriptStringPrivate* toStringHandle(const QString& str) const;
- inline JSGlobalContextRef context() const;
+ inline operator JSGlobalContextRef() const;
+
+ inline bool isDate(JSValueRef value) const;
+ inline bool isArray(JSValueRef value) const;
+ inline bool isError(JSValueRef value) const;
+ inline bool objectHasOwnProperty(JSObjectRef object, JSStringRef property) const;
+ inline QVector<JSStringRef> objectGetOwnPropertyNames(JSObjectRef object) const;
+
private:
QScriptEngine* q_ptr;
JSGlobalContextRef m_context;
+ JSValueRef m_exception;
+
+ QScriptOriginalGlobalObject m_originalGlobalObject;
+
+ JSClassRef m_nativeFunctionClass;
+ JSClassRef m_nativeFunctionWithArgClass;
};
{
JSValueRef exception;
JSValueRef result = JSEvaluateScript(m_context, program, /* Global Object */ 0, fileName, lineNumber, &exception);
- if (!result)
+ if (!result) {
+ setException(exception, NotNullException);
return exception; // returns an exception
+ }
+ clearExceptions();
return result;
}
+bool QScriptEnginePrivate::hasUncaughtException() const
+{
+ return m_exception;
+}
+
+void QScriptEnginePrivate::clearExceptions()
+{
+ if (m_exception)
+ JSValueUnprotect(m_context, m_exception);
+ m_exception = 0;
+}
+
+void QScriptEnginePrivate::setException(JSValueRef exception, const /* SetExceptionFlags */ unsigned flags)
+{
+ if (!((flags & NotNullException) || exception))
+ return;
+ Q_ASSERT(exception);
+
+ if (m_exception)
+ JSValueUnprotect(m_context, m_exception);
+ JSValueProtect(m_context, exception);
+ m_exception = exception;
+}
+
+int QScriptEnginePrivate::uncaughtExceptionLineNumber() const
+{
+ if (!hasUncaughtException() || !JSValueIsObject(m_context, m_exception))
+ return -1;
+
+ JSValueRef exception = 0;
+ JSRetainPtr<JSStringRef> lineNumberPropertyName(Adopt, QScriptConverter::toString("line"));
+ JSValueRef lineNumber = JSObjectGetProperty(m_context, const_cast<JSObjectRef>(m_exception), lineNumberPropertyName.get(), &exception);
+ int result = JSValueToNumber(m_context, lineNumber, &exception);
+ return exception ? -1 : result;
+}
+
+QStringList QScriptEnginePrivate::uncaughtExceptionBacktrace() const
+{
+ if (!hasUncaughtException() || !JSValueIsObject(m_context, m_exception))
+ return QStringList();
+
+ JSValueRef exception = 0;
+ JSRetainPtr<JSStringRef> fileNamePropertyName(Adopt, QScriptConverter::toString("sourceURL"));
+ JSRetainPtr<JSStringRef> lineNumberPropertyName(Adopt, QScriptConverter::toString("line"));
+ JSValueRef jsFileName = JSObjectGetProperty(m_context, const_cast<JSObjectRef>(m_exception), fileNamePropertyName.get(), &exception);
+ JSValueRef jsLineNumber = JSObjectGetProperty(m_context, const_cast<JSObjectRef>(m_exception), lineNumberPropertyName.get(), &exception);
+ JSRetainPtr<JSStringRef> fileName(Adopt, JSValueToStringCopy(m_context, jsFileName, &exception));
+ int lineNumber = JSValueToNumber(m_context, jsLineNumber, &exception);
+ return QStringList(QString::fromLatin1("<anonymous>()@%0:%1")
+ .arg(QScriptConverter::toString(fileName.get()))
+ .arg(QScriptConverter::toString(exception ? -1 : lineNumber)));
+}
+
void QScriptEnginePrivate::collectGarbage()
{
JSGarbageCollect(m_context);
return new QScriptStringPrivate(str);
}
-JSGlobalContextRef QScriptEnginePrivate::context() const
+QScriptEnginePrivate::operator JSGlobalContextRef() const
{
+ Q_ASSERT(this);
return m_context;
}
+bool QScriptEnginePrivate::isDate(JSValueRef value) const
+{
+ return m_originalGlobalObject.isDate(value);
+}
+
+bool QScriptEnginePrivate::isArray(JSValueRef value) const
+{
+ return m_originalGlobalObject.isArray(value);
+}
+
+bool QScriptEnginePrivate::isError(JSValueRef value) const
+{
+ return m_originalGlobalObject.isError(value);
+}
+
+inline bool QScriptEnginePrivate::objectHasOwnProperty(JSObjectRef object, JSStringRef property) const
+{
+ // FIXME We need a JSC C API function for this.
+ return m_originalGlobalObject.objectHasOwnProperty(object, property);
+}
+
+inline QVector<JSStringRef> QScriptEnginePrivate::objectGetOwnPropertyNames(JSObjectRef object) const
+{
+ // FIXME We can't use C API function JSObjectGetPropertyNames as it returns only enumerable properties.
+ return m_originalGlobalObject.objectGetOwnPropertyNames(object);
+}
+
#endif
--- /dev/null
+/*
+ Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+ 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.
+*/
+
+// Contains the necessary helper structures to make possible expose
+// C/C++ functions to JavaScript environment.
+
+#include "config.h"
+
+#include "qscriptfunction_p.h"
+
+static void qt_NativeFunction_finalize(JSObjectRef object)
+{
+ void* priv = JSObjectGetPrivate(object);
+ delete reinterpret_cast<QNativeFunctionData*>(priv);
+}
+
+static JSValueRef qt_NativeFunction_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ QNativeFunctionData* data = reinterpret_cast<QNativeFunctionData*>(JSObjectGetPrivate(object));
+
+ // TODO: build a QScriptContext and use it in the native call.
+ QScriptContext* scriptContext = 0;
+ Q_UNUSED(context);
+ Q_UNUSED(thisObject);
+ Q_UNUSED(argumentCount);
+ Q_UNUSED(arguments);
+ Q_UNUSED(exception);
+
+ QScriptEnginePrivate* engine = data->engine;
+ QScriptValuePrivate* result = QScriptValuePrivate::get(data->fun(scriptContext, QScriptEnginePrivate::get(engine)));
+ if (!result->isValid()) {
+ qWarning("Invalid value returned from native function, returning undefined value instead.");
+ return engine->makeJSValue(QScriptValue::UndefinedValue);
+ }
+
+ // Make sure that the result will be assigned to the correct engine.
+ if (!result->engine()) {
+ Q_ASSERT(result->isValid());
+ result->assignEngine(engine);
+ } else if (result->engine() != engine) {
+ qWarning("Value from different engine returned from native function, returning undefined value instead.");
+ return engine->makeJSValue(QScriptValue::UndefinedValue);
+ }
+
+ return *result;
+}
+
+JSClassDefinition qt_NativeFunctionClass = {
+ 0, // version
+ kJSClassAttributeNoAutomaticPrototype, // attributes
+
+ "", // className
+ 0, // parentClass
+
+ 0, // staticValues
+ 0, // staticFunctions
+
+ 0, // initialize
+ qt_NativeFunction_finalize, // finalize
+ 0, // hasProperty
+ 0, // getProperty
+ 0, // setProperty
+ 0, // deleteProperty
+ 0, // getPropertyNames
+ qt_NativeFunction_callAsFunction, // callAsFunction
+ 0, // callAsConstructor
+ 0, // hasInstance
+ 0 // convertToType
+};
+
+static void qt_NativeFunctionWithArg_finalize(JSObjectRef object)
+{
+ void* priv = JSObjectGetPrivate(object);
+ delete reinterpret_cast<QNativeFunctionWithArgData*>(priv);
+}
+
+static JSValueRef qt_NativeFunctionWithArg_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ QNativeFunctionWithArgData* data = reinterpret_cast<QNativeFunctionWithArgData*>(JSObjectGetPrivate(object));
+
+ // TODO: build a QScriptContext and use it in the native call.
+ QScriptContext* scriptContext = 0;
+ Q_UNUSED(context);
+ Q_UNUSED(thisObject);
+ Q_UNUSED(argumentCount);
+ Q_UNUSED(arguments);
+ Q_UNUSED(exception);
+
+ QScriptEnginePrivate* engine = data->engine;
+ QScriptValuePrivate* result = QScriptValuePrivate::get(data->fun(scriptContext, QScriptEnginePrivate::get(engine), data->arg));
+ if (!result->isValid()) {
+ qWarning("Invalid value returned from native function, returning undefined value instead.");
+ return engine->makeJSValue(QScriptValue::UndefinedValue);
+ }
+
+ // Make sure that the result will be assigned to the correct engine.
+ if (!result->engine()) {
+ Q_ASSERT(result->isValid());
+ result->assignEngine(engine);
+ } else if (result->engine() != engine) {
+ qWarning("Value from different engine returned from native function, returning undefined value instead.");
+ return engine->makeJSValue(QScriptValue::UndefinedValue);
+ }
+
+ return *result;
+}
+
+JSClassDefinition qt_NativeFunctionWithArgClass = {
+ 0, // version
+ kJSClassAttributeNoAutomaticPrototype, // attributes
+
+ "", // className
+ 0, // parentClass
+
+ 0, // staticValues
+ 0, // staticFunctions
+
+ 0, // initialize
+ qt_NativeFunctionWithArg_finalize, // finalize
+ 0, // hasProperty
+ 0, // getProperty
+ 0, // setProperty
+ 0, // deleteProperty
+ 0, // getPropertyNames
+ qt_NativeFunctionWithArg_callAsFunction, // callAsFunction
+ 0, // callAsConstructor
+ 0, // hasInstance
+ 0 // convertToType
+};
--- /dev/null
+/*
+ Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+ 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.
+*/
+
+#ifndef qscriptfunction_p_h
+#define qscriptfunction_p_h
+
+#include "config.h"
+
+#include "qscriptengine.h"
+#include "qscriptvalue_p.h"
+
+extern JSClassDefinition qt_NativeFunctionClass;
+extern JSClassDefinition qt_NativeFunctionWithArgClass;
+
+struct QNativeFunctionData
+{
+ QNativeFunctionData(QScriptEnginePrivate* engine, QScriptEngine::FunctionSignature fun)
+ : engine(engine)
+ , fun(fun)
+ {
+ }
+
+ QScriptEnginePrivate* engine;
+ QScriptEngine::FunctionSignature fun;
+};
+
+struct QNativeFunctionWithArgData
+{
+ QNativeFunctionWithArgData(QScriptEnginePrivate* engine, QScriptEngine::FunctionWithArgSignature fun, void* arg)
+ : engine(engine)
+ , fun(fun)
+ , arg(arg)
+ {
+ }
+
+ QScriptEnginePrivate* engine;
+ QScriptEngine::FunctionWithArgSignature fun;
+ void* arg;
+};
+
+#endif
--- /dev/null
+/*
+ Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+ 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.
+*/
+
+#ifndef qscriptoriginalglobalobject_p_h
+#define qscriptoriginalglobalobject_p_h
+
+#include <JavaScriptCore/JavaScript.h>
+#include <JavaScriptCore/JSRetainPtr.h>
+#include <QtCore/qvector.h>
+
+/*!
+ \internal
+ This class is a workaround for missing JSC C API functionality. This class keeps all important
+ properties of an original (default) global object, so we can use it even if the global object was
+ changed.
+
+ FIXME this class is a container for workarounds :-) it should be replaced by proper JSC C API calls.
+
+ The class have to be created on the QScriptEnginePrivate creation time (before any change got applied to
+ global object).
+*/
+class QScriptOriginalGlobalObject {
+public:
+ inline QScriptOriginalGlobalObject(JSGlobalContextRef context);
+ inline ~QScriptOriginalGlobalObject();
+
+ inline bool objectHasOwnProperty(JSObjectRef object, JSStringRef property) const;
+ inline QVector<JSStringRef> objectGetOwnPropertyNames(JSObjectRef object) const;
+
+ inline bool isDate(JSValueRef value) const;
+ inline bool isArray(JSValueRef value) const;
+ inline bool isError(JSValueRef value) const;
+
+ inline JSValueRef functionPrototype() const;
+private:
+ inline bool isType(JSValueRef value, JSObjectRef constructor, JSValueRef prototype) const;
+ inline void initializeMember(JSObjectRef globalObject, JSStringRef prototypeName, const char* type, JSObjectRef& constructor, JSValueRef& prototype);
+
+ // Copy of the global context reference (the same as in QScriptEnginePrivate).
+ JSGlobalContextRef m_context;
+
+ // Copy of constructors and prototypes used in isType functions.
+ JSObjectRef m_arrayConstructor;
+ JSValueRef m_arrayPrototype;
+ JSObjectRef m_errorConstructor;
+ JSValueRef m_errorPrototype;
+ JSObjectRef m_functionConstructor;
+ JSValueRef m_functionPrototype;
+ JSObjectRef m_dateConstructor;
+ JSValueRef m_datePrototype;
+
+ // Reference to standard JS functions that are not exposed by JSC C API.
+ JSObjectRef m_hasOwnPropertyFunction;
+ JSObjectRef m_getOwnPropertyNamesFunction;
+};
+
+QScriptOriginalGlobalObject::QScriptOriginalGlobalObject(JSGlobalContextRef context)
+ : m_context(JSGlobalContextRetain(context))
+{
+ JSObjectRef globalObject = JSContextGetGlobalObject(m_context);
+ JSValueRef exception = 0;
+ JSRetainPtr<JSStringRef> propertyName;
+
+ propertyName.adopt(JSStringCreateWithUTF8CString("prototype"));
+ initializeMember(globalObject, propertyName.get(), "Array", m_arrayConstructor, m_arrayPrototype);
+ initializeMember(globalObject, propertyName.get(), "Error", m_errorConstructor, m_errorPrototype);
+ initializeMember(globalObject, propertyName.get(), "Function", m_functionConstructor, m_functionPrototype);
+ initializeMember(globalObject, propertyName.get(), "Date", m_dateConstructor, m_datePrototype);
+
+ propertyName.adopt(JSStringCreateWithUTF8CString("hasOwnProperty"));
+ m_hasOwnPropertyFunction = const_cast<JSObjectRef>(JSObjectGetProperty(m_context, globalObject, propertyName.get(), &exception));
+ JSValueProtect(m_context, m_hasOwnPropertyFunction);
+ Q_ASSERT(JSValueIsObject(m_context, m_hasOwnPropertyFunction));
+ Q_ASSERT(JSObjectIsFunction(m_context, m_hasOwnPropertyFunction));
+ Q_ASSERT(!exception);
+
+ propertyName.adopt(JSStringCreateWithUTF8CString("Object"));
+ JSObjectRef objectConstructor
+ = const_cast<JSObjectRef>(JSObjectGetProperty(m_context, globalObject, propertyName.get(), &exception));
+ propertyName.adopt(JSStringCreateWithUTF8CString("getOwnPropertyNames"));
+ m_getOwnPropertyNamesFunction
+ = const_cast<JSObjectRef>(JSObjectGetProperty(m_context, objectConstructor, propertyName.get(), &exception));
+ JSValueProtect(m_context, m_getOwnPropertyNamesFunction);
+ Q_ASSERT(JSValueIsObject(m_context, m_getOwnPropertyNamesFunction));
+ Q_ASSERT(JSObjectIsFunction(m_context, m_getOwnPropertyNamesFunction));
+ Q_ASSERT(!exception);
+}
+
+inline void QScriptOriginalGlobalObject::initializeMember(JSObjectRef globalObject, JSStringRef prototypeName, const char* type, JSObjectRef& constructor, JSValueRef& prototype)
+{
+ JSRetainPtr<JSStringRef> typeName(Adopt, JSStringCreateWithUTF8CString(type));
+ JSValueRef exception = 0;
+
+ // Save references to the Type constructor and prototype.
+ JSValueRef typeConstructor = JSObjectGetProperty(m_context, globalObject, typeName.get(), &exception);
+ Q_ASSERT(JSValueIsObject(m_context, typeConstructor));
+ constructor = JSValueToObject(m_context, typeConstructor, &exception);
+ JSValueProtect(m_context, constructor);
+
+ // Note that this is not the [[Prototype]] internal property (which we could
+ // get via JSObjectGetPrototype), but the Type.prototype, that will be set
+ // as [[Prototype]] of Type instances.
+ prototype = JSObjectGetProperty(m_context, constructor, prototypeName, &exception);
+ Q_ASSERT(JSValueIsObject(m_context, prototype));
+ JSValueProtect(m_context, prototype);
+ Q_ASSERT(!exception);
+}
+
+QScriptOriginalGlobalObject::~QScriptOriginalGlobalObject()
+{
+ JSValueUnprotect(m_context, m_arrayConstructor);
+ JSValueUnprotect(m_context, m_arrayPrototype);
+ JSValueUnprotect(m_context, m_errorConstructor);
+ JSValueUnprotect(m_context, m_errorPrototype);
+ JSValueUnprotect(m_context, m_functionConstructor);
+ JSValueUnprotect(m_context, m_functionPrototype);
+ JSValueUnprotect(m_context, m_dateConstructor);
+ JSValueUnprotect(m_context, m_datePrototype);
+ JSValueUnprotect(m_context, m_hasOwnPropertyFunction);
+ JSValueUnprotect(m_context, m_getOwnPropertyNamesFunction);
+ JSGlobalContextRelease(m_context);
+}
+
+inline bool QScriptOriginalGlobalObject::objectHasOwnProperty(JSObjectRef object, JSStringRef property) const
+{
+ // FIXME This function should be replaced by JSC C API.
+ JSValueRef exception = 0;
+ JSValueRef propertyName[] = { JSValueMakeString(m_context, property) };
+ JSValueRef result = JSObjectCallAsFunction(m_context, m_hasOwnPropertyFunction, object, 1, propertyName, &exception);
+ return exception ? false : JSValueToBoolean(m_context, result);
+}
+
+/*!
+ \internal
+ This method gives ownership of all JSStringRefs.
+*/
+inline QVector<JSStringRef> QScriptOriginalGlobalObject::objectGetOwnPropertyNames(JSObjectRef object) const
+{
+ JSValueRef exception = 0;
+ JSObjectRef propertyNames
+ = const_cast<JSObjectRef>(JSObjectCallAsFunction(m_context,
+ m_getOwnPropertyNamesFunction,
+ /* thisObject */ 0,
+ /* argumentCount */ 1,
+ &object,
+ &exception));
+ Q_ASSERT(JSValueIsObject(m_context, propertyNames));
+ Q_ASSERT(!exception);
+ JSStringRef lengthName = QScriptConverter::toString("length");
+ int count = JSValueToNumber(m_context, JSObjectGetProperty(m_context, propertyNames, lengthName, &exception), &exception);
+
+ Q_ASSERT(!exception);
+ QVector<JSStringRef> names;
+ names.reserve(count);
+ for (int i = 0; i < count; ++i) {
+ JSValueRef tmp = JSObjectGetPropertyAtIndex(m_context, propertyNames, i, &exception);
+ names.append(JSValueToStringCopy(m_context, tmp, &exception));
+ Q_ASSERT(!exception);
+ }
+ return names;
+}
+
+inline bool QScriptOriginalGlobalObject::isDate(JSValueRef value) const
+{
+ return isType(value, m_dateConstructor, m_datePrototype);
+}
+
+inline bool QScriptOriginalGlobalObject::isArray(JSValueRef value) const
+{
+ return isType(value, m_arrayConstructor, m_arrayPrototype);
+}
+
+inline bool QScriptOriginalGlobalObject::isError(JSValueRef value) const
+{
+ return isType(value, m_errorConstructor, m_errorPrototype);
+}
+
+inline JSValueRef QScriptOriginalGlobalObject::functionPrototype() const
+{
+ return m_functionPrototype;
+}
+
+inline bool QScriptOriginalGlobalObject::isType(JSValueRef value, JSObjectRef constructor, JSValueRef prototype) const
+{
+ // JSC API doesn't export the [[Class]] information for the builtins. But we know that a value
+ // is an object of the Type if it was created with the Type constructor or if it is the Type.prototype.
+ JSValueRef exception = 0;
+ bool result = JSValueIsInstanceOfConstructor(m_context, value, constructor, &exception) || JSValueIsStrictEqual(m_context, value, prototype);
+ Q_ASSERT(!exception);
+ return result;
+}
+
+#endif // qscriptoriginalglobalobject_p_h
inline bool operator==(const QScriptProgramPrivate& other) const;
inline bool operator!=(const QScriptProgramPrivate& other) const;
- inline JSStringRef program() const;
+ inline operator JSStringRef() const;
inline JSStringRef file() const;
inline int line() const;
private:
|| !JSStringIsEqual(m_program, other.m_program);
}
-JSStringRef QScriptProgramPrivate::program() const { return m_program; }
+QScriptProgramPrivate::operator JSStringRef() const
+{
+ return m_program;
+}
+
JSStringRef QScriptProgramPrivate::file() const {return m_fileName; }
int QScriptProgramPrivate::line() const { return m_line; }
inline quint64 id() const;
+ inline operator JSStringRef() const;
+
private:
JSStringRef m_string;
};
return reinterpret_cast<quint32>(m_string);
}
+/*!
+ \internal
+ This method should be used for invoking JSC functions.
+ \note This method keeps ownership of an internal JSStringRef.
+*/
+QScriptStringPrivate::operator JSStringRef() const
+{
+ return m_string;
+}
+
#endif // qscriptstring_p_h
QScriptSyntaxCheckResultPrivate::~QScriptSyntaxCheckResultPrivate()
{
if (m_exception)
- JSValueUnprotect(m_engine->context(), m_exception);
+ JSValueUnprotect(*m_engine, m_exception);
}
QString QScriptSyntaxCheckResultPrivate::errorMessage() const
if (!m_exception)
return QString();
- JSStringRef tmp = JSValueToStringCopy(m_engine->context(), m_exception, /* exception */ 0);
+ JSStringRef tmp = JSValueToStringCopy(*m_engine, m_exception, /* exception */ 0);
QString message = QScriptConverter::toString(tmp);
JSStringRelease(tmp);
return message;
return -1;
// m_exception is an instance of the Exception so it has "line" attribute.
JSStringRef lineAttrName = QScriptConverter::toString("line");
- JSValueRef line = JSObjectGetProperty(m_engine->context(),
+ JSValueRef line = JSObjectGetProperty(*m_engine,
m_exception,
lineAttrName,
/* exceptions */0);
JSStringRelease(lineAttrName);
- return JSValueToNumber(m_engine->context(), line, /* exceptions */0);
+ return JSValueToNumber(*m_engine, line, /* exceptions */0);
}
return d_ptr->isError();
}
+/*!
+ Returns true if this QScriptValue is an object of the Array class;
+ otherwise returns false.
+
+ \sa QScriptEngine::newArray()
+*/
+bool QScriptValue::isArray() const
+{
+ return d_ptr->isArray();
+}
+
+/*!
+ Returns true if this QScriptValue is an object of the Date class;
+ otherwise returns false.
+
+ \sa QScriptEngine::newDate()
+*/
+bool QScriptValue::isDate() const
+{
+ return d_ptr->isDate();
+}
+
/*!
Returns true if this QScriptValue is of the Object type; otherwise
returns false.
return d_ptr->toUInt16();
}
+/*!
+ \obsolete
+
+ This function is obsolete; use QScriptEngine::toObject() instead.
+*/
+QScriptValue QScriptValue::toObject() const
+{
+ return QScriptValuePrivate::get(d_ptr->toObject());
+}
+
+/*!
+ Returns a QDateTime representation of this value, in local time.
+ If this QScriptValue is not a date, or the value of the date is
+ NaN (Not-a-Number), an invalid QDateTime is returned.
+
+ \sa isDate()
+*/
+QDateTime QScriptValue::toDateTime() const
+{
+ return d_ptr->toDateTime();
+}
+
/*!
Calls this QScriptValue as a function, using \a thisObject as
the `this' object in the function call, and passing \a args
return 0;
}
+/*!
+ If this QScriptValue is an object, returns the internal prototype
+ (\c{__proto__} property) of this object; otherwise returns an
+ invalid QScriptValue.
+
+ \sa setPrototype(), isObject()
+*/
+QScriptValue QScriptValue::prototype() const
+{
+ return QScriptValuePrivate::get(d_ptr->prototype());
+}
+
+/*!
+ If this QScriptValue is an object, sets the internal prototype
+ (\c{__proto__} property) of this object to be \a prototype;
+ otherwise does nothing.
+
+ The internal prototype should not be confused with the public
+ property with name "prototype"; the public prototype is usually
+ only set on functions that act as constructors.
+
+ \sa prototype(), isObject()
+*/
+void QScriptValue::setPrototype(const QScriptValue& prototype)
+{
+ d_ptr->setPrototype(QScriptValuePrivate::get(prototype));
+}
+
/*!
Assigns the \a other value to this QScriptValue.
*/
bool QScriptValue::equals(const QScriptValue& other) const
{
- return d_ptr == other.d_ptr || d_ptr->equals(QScriptValuePrivate::get(other));
+ return d_ptr->equals(QScriptValuePrivate::get(other));
}
/*!
*/
bool QScriptValue::strictlyEquals(const QScriptValue& other) const
{
- return d_ptr == other.d_ptr || d_ptr->strictlyEquals(QScriptValuePrivate::get(other));
+ return d_ptr->strictlyEquals(QScriptValuePrivate::get(other));
+}
+
+/*!
+ Returns true if this QScriptValue is an instance of
+ \a other; otherwise returns false.
+
+ This QScriptValue is considered to be an instance of \a other if
+ \a other is a function and the value of the \c{prototype}
+ property of \a other is in the prototype chain of this
+ QScriptValue.
+*/
+bool QScriptValue::instanceOf(const QScriptValue& other) const
+{
+ return d_ptr->instanceOf(QScriptValuePrivate::get(other));
+}
+
+/*!
+ Returns the value of this QScriptValue's property with the given \a name,
+ using the given \a mode to resolve the property.
+
+ If no such property exists, an invalid QScriptValue is returned.
+
+ If the property is implemented using a getter function (i.e. has the
+ PropertyGetter flag set), calling property() has side-effects on the
+ script engine, since the getter function will be called (possibly
+ resulting in an uncaught script exception). If an exception
+ occurred, property() returns the value that was thrown (typically
+ an \c{Error} object).
+
+ \sa setProperty(), propertyFlags(), QScriptValueIterator
+*/
+QScriptValue QScriptValue::property(const QString& name, const ResolveFlags& mode) const
+{
+ return QScriptValuePrivate::get(d_ptr->property(name, mode));
+}
+
+/*!
+ \overload
+
+ Returns the value of this QScriptValue's property with the given \a name,
+ using the given \a mode to resolve the property.
+
+ This overload of property() is useful when you need to look up the
+ same property repeatedly, since the lookup can be performed faster
+ when the name is represented as an interned string.
+
+ \sa QScriptEngine::toStringHandle(), setProperty()
+*/
+QScriptValue QScriptValue::property(const QScriptString& name, const ResolveFlags& mode) const
+{
+ return QScriptValuePrivate::get(d_ptr->property(QScriptStringPrivate::get(name).constData(), mode));
+}
+
+/*!
+ \overload
+
+ Returns the property at the given \a arrayIndex, using the given \a
+ mode to resolve the property.
+
+ This function is provided for convenience and performance when
+ working with array objects.
+
+ If this QScriptValue is not an Array object, this function behaves
+ as if property() was called with the string representation of \a
+ arrayIndex.
+*/
+QScriptValue QScriptValue::property(quint32 arrayIndex, const ResolveFlags& mode) const
+{
+ return QScriptValuePrivate::get(d_ptr->property(arrayIndex, mode));
+}
+
+/*!
+ Sets the value of this QScriptValue's property with the given \a name to
+ the given \a value.
+
+ If this QScriptValue is not an object, this function does nothing.
+
+ If this QScriptValue does not already have a property with name \a name,
+ a new property is created; the given \a flags then specify how this
+ property may be accessed by script code.
+
+ If \a value is invalid, the property is removed.
+
+ If the property is implemented using a setter function (i.e. has the
+ PropertySetter flag set), calling setProperty() has side-effects on
+ the script engine, since the setter function will be called with the
+ given \a value as argument (possibly resulting in an uncaught script
+ exception).
+
+ Note that you cannot specify custom getter or setter functions for
+ built-in properties, such as the \c{length} property of Array objects
+ or meta properties of QObject objects.
+
+ \sa property()
+*/
+void QScriptValue::setProperty(const QString& name, const QScriptValue& value, const PropertyFlags& flags)
+{
+ d_ptr->setProperty(name, QScriptValuePrivate::get(value), flags);
+}
+
+/*!
+ \overload
+
+ Sets the property at the given \a arrayIndex to the given \a value.
+
+ This function is provided for convenience and performance when
+ working with array objects.
+
+ If this QScriptValue is not an Array object, this function behaves
+ as if setProperty() was called with the string representation of \a
+ arrayIndex.
+*/
+void QScriptValue::setProperty(quint32 arrayIndex, const QScriptValue& value, const PropertyFlags& flags)
+{
+ d_ptr->setProperty(arrayIndex, QScriptValuePrivate::get(value), flags);
+}
+
+/*!
+ Sets the value of this QScriptValue's property with the given \a
+ name to the given \a value. The given \a flags specify how this
+ property may be accessed by script code.
+
+ This overload of setProperty() is useful when you need to set the
+ same property repeatedly, since the operation can be performed
+ faster when the name is represented as an interned string.
+
+ \sa QScriptEngine::toStringHandle()
+*/
+void QScriptValue::setProperty(const QScriptString& name, const QScriptValue& value, const PropertyFlags& flags)
+{
+ d_ptr->setProperty(QScriptStringPrivate::get(name).constData(), QScriptValuePrivate::get(value), flags);
+}
+
+/*!
+ Returns the flags of the property with the given \a name, using the
+ given \a mode to resolve the property.
+
+ \sa property()
+*/
+QScriptValue::PropertyFlags QScriptValue::propertyFlags(const QString& name, const ResolveFlags& mode) const
+{
+ return d_ptr->propertyFlags(name, mode);
+}
+
+/*!
+ Returns the flags of the property with the given \a name, using the
+ given \a mode to resolve the property.
+
+ \sa property()
+*/
+QScriptValue::PropertyFlags QScriptValue::propertyFlags(const QScriptString& name, const ResolveFlags& mode) const
+{
+ return d_ptr->propertyFlags(QScriptStringPrivate::get(name).constData(), mode);
}
#ifndef qscriptvalue_h
#define qscriptvalue_h
+#include "qscriptstring.h"
#include <QtCore/qlist.h>
#include <QtCore/qshareddata.h>
class QScriptEngine;
class QScriptValuePrivate;
+class QDateTime;
class QScriptValue;
typedef QList<QScriptValue> QScriptValueList;
typedef double qsreal;
class QScriptValue {
-public:
+public:
+ enum ResolveFlag {
+ ResolveLocal = 0x00,
+ ResolvePrototype = 0x01,
+ ResolveScope = 0x02,
+ ResolveFull = ResolvePrototype | ResolveScope
+ };
+ Q_DECLARE_FLAGS(ResolveFlags, ResolveFlag)
+
+ enum PropertyFlag {
+ ReadOnly = 0x00000001,
+ Undeletable = 0x00000002,
+ SkipInEnumeration = 0x00000004,
+ PropertyGetter = 0x00000008,
+ PropertySetter = 0x00000010,
+ QObjectMember = 0x00000020,
+ KeepExistingFlags = 0x00000800,
+ UserRange = 0xff000000 // Users may use these as they see fit.
+ };
+ Q_DECLARE_FLAGS(PropertyFlags, PropertyFlag)
+
enum SpecialValue {
NullValue,
UndefinedValue
~QScriptValue();
QScriptValue& operator=(const QScriptValue& other);
+
+ QScriptValue prototype() const;
+ void setPrototype(const QScriptValue& prototype);
+
bool equals(const QScriptValue& other) const;
bool strictlyEquals(const QScriptValue& other) const;
+ bool instanceOf(const QScriptValue& other) const;
+
+ QScriptValue property(const QString& name, const ResolveFlags& mode = ResolvePrototype) const;
+ QScriptValue property(const QScriptString& name, const ResolveFlags& mode = ResolvePrototype) const;
+ QScriptValue property(quint32 arrayIndex, const ResolveFlags& mode = ResolvePrototype) const;
+
+ void setProperty(const QString& name, const QScriptValue& value, const PropertyFlags& flags = KeepExistingFlags);
+ void setProperty(quint32 arrayIndex, const QScriptValue& value, const PropertyFlags& flags = KeepExistingFlags);
+ void setProperty(const QScriptString& name, const QScriptValue& value, const PropertyFlags& flags = KeepExistingFlags);
+
+ PropertyFlags propertyFlags(const QString& name, const ResolveFlags& mode = ResolvePrototype) const;
+ PropertyFlags propertyFlags(const QScriptString& name, const ResolveFlags& mode = ResolvePrototype) const;
QScriptEngine* engine() const;
bool isUndefined() const;
bool isObject() const;
bool isError() const;
+ bool isArray() const;
+ bool isDate() const;
QString toString() const;
qsreal toNumber() const;
qint32 toInt32() const;
quint32 toUInt32() const;
quint16 toUInt16() const;
+ QScriptValue toObject() const;
+ QDateTime toDateTime() const;
QScriptValue call(const QScriptValue& thisObject = QScriptValue(),
const QScriptValueList& args = QScriptValueList());
-
private:
QScriptValue(void*);
QScriptValue(QScriptValuePrivate*);
#include "qscriptvalue.h"
#include <JavaScriptCore/JavaScript.h>
#include <JavaScriptCore/JSRetainPtr.h>
+#include <JSObjectRefPrivate.h>
+#include <QtCore/qdatetime.h>
#include <QtCore/qmath.h>
#include <QtCore/qnumeric.h>
#include <QtCore/qshareddata.h>
CNumber -> QSVP is created from int, uint, double... and no JSC engine has been bind yet. Current
value is kept in m_number
CBool -> QSVP is created from bool and no JSC engine has been associated yet. Current value is kept
- in m_number
- CSpecial -> QSVP is Undefined or Null, but a JSC engine hasn't been associated yet, current value
- is kept in m_number (cast of QScriptValue::SpecialValue)
+ in m_bool
+ CNull -> QSVP is null, but a JSC engine hasn't been associated yet.
+ CUndefined -> QSVP is undefined, but a JSC engine hasn't been associated yet.
JSValue -> QSVP is associated with engine, but there is no information about real type, the state
have really short live cycle. Normally it is created as a function call result.
JSPrimitive -> QSVP is associated with engine, and it is sure that it isn't a JavaScript object.
Each state keep all necessary information to invoke all methods, if not it should be changed to
a proper state. Changed state shouldn't be reverted.
+
+ The QScriptValuePrivate use the JSC C API directly. The QSVP type is equal to combination of
+ the JSValueRef and the JSObjectRef, and it could be automatically casted to these types by cast
+ operators.
*/
class QScriptValuePrivate : public QSharedData {
inline QScriptValuePrivate(const QScriptEnginePrivate* engine, QScriptValue::SpecialValue value);
inline QScriptValuePrivate(const QScriptEnginePrivate* engine, JSValueRef value);
- inline QScriptValuePrivate(const QScriptEnginePrivate* engine, JSValueRef value, JSObjectRef object);
+ inline QScriptValuePrivate(const QScriptEnginePrivate* engine, JSObjectRef object);
inline bool isValid() const;
inline bool isBool();
inline bool isError();
inline bool isObject();
inline bool isFunction();
+ inline bool isArray();
+ inline bool isDate();
inline QString toString() const;
inline qsreal toNumber() const;
inline quint32 toUInt32() const;
inline quint16 toUInt16() const;
+ inline QScriptValuePrivate* toObject(QScriptEnginePrivate* engine);
+ inline QScriptValuePrivate* toObject();
+ inline QDateTime toDateTime();
+ inline QScriptValuePrivate* prototype();
+ inline void setPrototype(QScriptValuePrivate* prototype);
+
inline bool equals(QScriptValuePrivate* other);
- inline bool strictlyEquals(const QScriptValuePrivate* other) const;
+ inline bool strictlyEquals(QScriptValuePrivate* other);
+ inline bool instanceOf(QScriptValuePrivate* other);
inline bool assignEngine(QScriptEnginePrivate* engine);
+ inline QScriptValuePrivate* property(const QString& name, const QScriptValue::ResolveFlags& mode);
+ inline QScriptValuePrivate* property(const QScriptStringPrivate* name, const QScriptValue::ResolveFlags& mode);
+ inline QScriptValuePrivate* property(quint32 arrayIndex, const QScriptValue::ResolveFlags& mode);
+ inline JSValueRef property(quint32 property, JSValueRef* exception);
+ inline JSValueRef property(JSStringRef property, JSValueRef* exception);
+ inline bool hasOwnProperty(quint32 property);
+ inline bool hasOwnProperty(JSStringRef property);
+ template<typename T>
+ inline QScriptValuePrivate* property(T name, const QScriptValue::ResolveFlags& mode);
+
+ inline void setProperty(const QString& name, QScriptValuePrivate* value, const QScriptValue::PropertyFlags& flags);
+ inline void setProperty(const QScriptStringPrivate* name, QScriptValuePrivate* value, const QScriptValue::PropertyFlags& flags);
+ inline void setProperty(const quint32 indexArray, QScriptValuePrivate* value, const QScriptValue::PropertyFlags& flags);
+ inline void setProperty(quint32 property, JSValueRef value, JSPropertyAttributes flags, JSValueRef* exception);
+ inline void setProperty(JSStringRef property, JSValueRef value, JSPropertyAttributes flags, JSValueRef* exception);
+ inline void deleteProperty(quint32 property, JSValueRef* exception);
+ inline void deleteProperty(JSStringRef property, JSValueRef* exception);
+ template<typename T>
+ inline void setProperty(T name, QScriptValuePrivate* value, const QScriptValue::PropertyFlags& flags);
+
+ QScriptValue::PropertyFlags propertyFlags(const QString& name, const QScriptValue::ResolveFlags& mode);
+ QScriptValue::PropertyFlags propertyFlags(const QScriptStringPrivate* name, const QScriptValue::ResolveFlags& mode);
+ QScriptValue::PropertyFlags propertyFlags(const JSStringRef name, const QScriptValue::ResolveFlags& mode);
+
inline QScriptValuePrivate* call(const QScriptValuePrivate* , const QScriptValueList& args);
- inline JSGlobalContextRef context() const;
- inline JSValueRef value() const;
- inline JSObjectRef object() const;
+ inline operator JSValueRef() const;
+ inline operator JSObjectRef() const;
+
inline QScriptEnginePrivate* engine() const;
private:
CString = 0x1000,
CNumber,
CBool,
- CSpecial,
+ CNull,
+ CUndefined,
JSValue = 0x2000, // JS values are equal or higher then this value.
JSPrimitive,
JSObject
} m_state;
QScriptEnginePtr m_engine;
- QString m_string;
- qsreal m_number;
- JSValueRef m_value;
- JSObjectRef m_object;
+ union Value
+ {
+ bool m_bool;
+ qsreal m_number;
+ JSValueRef m_value;
+ JSObjectRef m_object;
+ QString* m_string;
+
+ Value() : m_number(0) {}
+ Value(bool value) : m_bool(value) {}
+ Value(int number) : m_number(number) {}
+ Value(uint number) : m_number(number) {}
+ Value(qsreal number) : m_number(number) {}
+ Value(JSValueRef value) : m_value(value) {}
+ Value(JSObjectRef object) : m_object(object) {}
+ Value(QString* string) : m_string(string) {}
+ } u;
- inline void setValue(JSValueRef);
-
- inline bool inherits(const char*);
inline State refinedJSValue();
inline bool isJSBased() const;
QScriptValuePrivate::~QScriptValuePrivate()
{
- if (m_value)
- JSValueUnprotect(context(), m_value);
+ if (isJSBased())
+ JSValueUnprotect(*m_engine, u.m_value);
+ else if (isStringBased())
+ delete u.m_string;
}
QScriptValuePrivate::QScriptValuePrivate()
: m_state(Invalid)
- , m_value(0)
{
}
QScriptValuePrivate::QScriptValuePrivate(const QString& string)
: m_state(CString)
- , m_string(string)
- , m_value(0)
+ , u(new QString(string))
{
}
QScriptValuePrivate::QScriptValuePrivate(bool value)
: m_state(CBool)
- , m_number(value)
- , m_value(0)
+ , u(value)
{
}
QScriptValuePrivate::QScriptValuePrivate(int number)
: m_state(CNumber)
- , m_number(number)
- , m_value(0)
+ , u(number)
{
}
QScriptValuePrivate::QScriptValuePrivate(uint number)
: m_state(CNumber)
- , m_number(number)
- , m_value(0)
+ , u(number)
{
}
QScriptValuePrivate::QScriptValuePrivate(qsreal number)
: m_state(CNumber)
- , m_number(number)
- , m_value(0)
+ , u(number)
{
}
QScriptValuePrivate::QScriptValuePrivate(QScriptValue::SpecialValue value)
- : m_state(CSpecial)
- , m_number(value)
- , m_value(0)
+ : m_state(value == QScriptValue::NullValue ? CNull : CUndefined)
{
}
QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, bool value)
: m_state(JSPrimitive)
, m_engine(const_cast<QScriptEnginePrivate*>(engine))
- , m_value(engine->makeJSValue(value))
+ , u(engine->makeJSValue(value))
{
Q_ASSERT(engine);
- JSValueProtect(context(), m_value);
+ JSValueProtect(*m_engine, u.m_value);
}
QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, int value)
: m_state(JSPrimitive)
, m_engine(const_cast<QScriptEnginePrivate*>(engine))
- , m_value(m_engine->makeJSValue(value))
+ , u(m_engine->makeJSValue(value))
{
Q_ASSERT(engine);
- JSValueProtect(context(), m_value);
+ JSValueProtect(*m_engine, u.m_value);
}
QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, uint value)
: m_state(JSPrimitive)
, m_engine(const_cast<QScriptEnginePrivate*>(engine))
- , m_value(m_engine->makeJSValue(value))
+ , u(m_engine->makeJSValue(value))
{
Q_ASSERT(engine);
- JSValueProtect(context(), m_value);
+ JSValueProtect(*m_engine, u.m_value);
}
QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, qsreal value)
: m_state(JSPrimitive)
, m_engine(const_cast<QScriptEnginePrivate*>(engine))
- , m_value(m_engine->makeJSValue(value))
+ , u(m_engine->makeJSValue(value))
{
Q_ASSERT(engine);
- JSValueProtect(context(), m_value);
+ JSValueProtect(*m_engine, u.m_value);
}
QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, const QString& value)
: m_state(JSPrimitive)
, m_engine(const_cast<QScriptEnginePrivate*>(engine))
- , m_value(m_engine->makeJSValue(value))
+ , u(m_engine->makeJSValue(value))
{
Q_ASSERT(engine);
- JSValueProtect(context(), m_value);
+ JSValueProtect(*m_engine, u.m_value);
}
QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, QScriptValue::SpecialValue value)
: m_state(JSPrimitive)
, m_engine(const_cast<QScriptEnginePrivate*>(engine))
- , m_value(m_engine->makeJSValue(value))
+ , u(m_engine->makeJSValue(value))
{
Q_ASSERT(engine);
- JSValueProtect(context(), m_value);
+ JSValueProtect(*m_engine, u.m_value);
}
QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, JSValueRef value)
: m_state(JSValue)
, m_engine(const_cast<QScriptEnginePrivate*>(engine))
- , m_value(value)
+ , u(value)
{
Q_ASSERT(engine);
Q_ASSERT(value);
- JSValueProtect(context(), m_value);
+ JSValueProtect(*m_engine, u.m_value);
}
-QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, JSValueRef value, JSObjectRef object)
+QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, JSObjectRef object)
: m_state(JSObject)
, m_engine(const_cast<QScriptEnginePrivate*>(engine))
- , m_value(value)
- , m_object(object)
+ , u(object)
{
Q_ASSERT(engine);
- Q_ASSERT(value);
Q_ASSERT(object);
- JSValueProtect(context(), m_value);
+ JSValueProtect(*m_engine, object);
}
bool QScriptValuePrivate::isValid() const { return m_state != Invalid; }
return false;
// Fall-through.
case JSPrimitive:
- return JSValueIsBoolean(context(), value());
+ return JSValueIsBoolean(*m_engine, *this);
default:
return false;
}
return false;
// Fall-through.
case JSPrimitive:
- return JSValueIsNumber(context(), value());
+ return JSValueIsNumber(*m_engine, *this);
default:
return false;
}
bool QScriptValuePrivate::isNull()
{
switch (m_state) {
- case CSpecial:
- return m_number == static_cast<int>(QScriptValue::NullValue);
+ case CNull:
+ return true;
case JSValue:
if (refinedJSValue() != JSPrimitive)
return false;
// Fall-through.
case JSPrimitive:
- return JSValueIsNull(context(), value());
+ return JSValueIsNull(*m_engine, *this);
default:
return false;
}
return false;
// Fall-through.
case JSPrimitive:
- return JSValueIsString(context(), value());
+ return JSValueIsString(*m_engine, *this);
default:
return false;
}
bool QScriptValuePrivate::isUndefined()
{
switch (m_state) {
- case CSpecial:
- return m_number == static_cast<int>(QScriptValue::UndefinedValue);
+ case CUndefined:
+ return true;
case JSValue:
if (refinedJSValue() != JSPrimitive)
return false;
// Fall-through.
case JSPrimitive:
- return JSValueIsUndefined(context(), value());
+ return JSValueIsUndefined(*m_engine, *this);
default:
return false;
}
return false;
// Fall-through.
case JSObject:
- return inherits("Error");
+ return m_engine->isError(*this);
default:
return false;
}
return false;
// Fall-through.
case JSObject:
- return JSObjectIsFunction(context(), object());
+ return JSObjectIsFunction(*m_engine, *this);
+ default:
+ return false;
+ }
+}
+
+bool QScriptValuePrivate::isArray()
+{
+ switch (m_state) {
+ case JSValue:
+ if (refinedJSValue() != JSObject)
+ return false;
+ // Fall-through.
+ case JSObject:
+ return m_engine->isArray(*this);
+ default:
+ return false;
+ }
+}
+
+bool QScriptValuePrivate::isDate()
+{
+ switch (m_state) {
+ case JSValue:
+ if (refinedJSValue() != JSObject)
+ return false;
+ // Fall-through.
+ case JSObject:
+ return m_engine->isDate(*this);
default:
return false;
}
case Invalid:
return QString();
case CBool:
- return m_number ? QString::fromLatin1("true") : QString::fromLatin1("false");
+ return u.m_bool ? QString::fromLatin1("true") : QString::fromLatin1("false");
case CString:
- return m_string;
+ return *u.m_string;
case CNumber:
- return QScriptConverter::toString(m_number);
- case CSpecial:
- return m_number == QScriptValue::NullValue ? QString::fromLatin1("null") : QString::fromLatin1("undefined");
+ return QScriptConverter::toString(u.m_number);
+ case CNull:
+ return QString::fromLatin1("null");
+ case CUndefined:
+ return QString::fromLatin1("undefined");
case JSValue:
case JSPrimitive:
case JSObject:
- JSRetainPtr<JSStringRef> ptr(Adopt, JSValueToStringCopy(context(), value(), /* exception */ 0));
+ JSValueRef exception = 0;
+ JSRetainPtr<JSStringRef> ptr(Adopt, JSValueToStringCopy(*m_engine, *this, &exception));
+ m_engine->setException(exception);
return QScriptConverter::toString(ptr.get());
}
case JSValue:
case JSPrimitive:
case JSObject:
- return JSValueToNumber(context(), value(), /* exception */ 0);
+ {
+ JSValueRef exception = 0;
+ qsreal result = JSValueToNumber(*m_engine, *this, &exception);
+ m_engine->setException(exception);
+ return result;
+ }
case CNumber:
- return m_number;
+ return u.m_number;
case CBool:
- return m_number ? 1 : 0;
+ return u.m_bool ? 1 : 0;
+ case CNull:
case Invalid:
return 0;
- case CSpecial:
- return m_number == QScriptValue::NullValue ? 0 : qQNaN();
+ case CUndefined:
+ return qQNaN();
case CString:
bool ok;
- qsreal result = m_string.toDouble(&ok);
+ qsreal result = u.m_string->toDouble(&ok);
if (ok)
return result;
- result = m_string.toInt(&ok, 0); // Try other bases.
+ result = u.m_string->toInt(&ok, 0); // Try other bases.
if (ok)
return result;
- if (m_string == "Infinity" || m_string == "-Infinity")
+ if (*u.m_string == "Infinity" || *u.m_string == "-Infinity")
return qInf();
- return m_string.length() ? qQNaN() : 0;
+ return u.m_string->length() ? qQNaN() : 0;
}
Q_ASSERT_X(false, "toNumber()", "Not all states are included in the previous switch statement.");
switch (m_state) {
case JSValue:
case JSPrimitive:
- return JSValueToBoolean(context(), value());
+ return JSValueToBoolean(*m_engine, *this);
case JSObject:
return true;
case CNumber:
- return !(qIsNaN(m_number) || !m_number);
+ return !(qIsNaN(u.m_number) || !u.m_number);
case CBool:
- return m_number;
+ return u.m_bool;
case Invalid:
- case CSpecial:
+ case CNull:
+ case CUndefined:
return false;
case CString:
- return m_string.length();
+ return u.m_string->length();
}
Q_ASSERT_X(false, "toBool()", "Not all states are included in the previous switch statement.");
return toInt32();
}
+/*!
+ Creates a copy of this value and converts it to an object. If this value is an object
+ then pointer to this value will be returned.
+ \attention it should not happen but if this value is bounded to a different engine that the given, the first
+ one will be used.
+ \internal
+ */
+QScriptValuePrivate* QScriptValuePrivate::toObject(QScriptEnginePrivate* engine)
+{
+ switch (m_state) {
+ case Invalid:
+ case CNull:
+ case CUndefined:
+ return new QScriptValuePrivate;
+ case CString:
+ {
+ // Exception can't occur here.
+ JSObjectRef object = JSValueToObject(*engine, engine->makeJSValue(*u.m_string), /* exception */ 0);
+ Q_ASSERT(object);
+ return new QScriptValuePrivate(engine, object);
+ }
+ case CNumber:
+ {
+ // Exception can't occur here.
+ JSObjectRef object = JSValueToObject(*engine, engine->makeJSValue(u.m_number), /* exception */ 0);
+ Q_ASSERT(object);
+ return new QScriptValuePrivate(engine, object);
+ }
+ case CBool:
+ {
+ // Exception can't occure here.
+ JSObjectRef object = JSValueToObject(*engine, engine->makeJSValue(u.m_bool), /* exception */ 0);
+ Q_ASSERT(object);
+ return new QScriptValuePrivate(engine, object);
+ }
+ case JSValue:
+ if (refinedJSValue() != JSPrimitive)
+ break;
+ // Fall-through.
+ case JSPrimitive:
+ {
+ if (engine != this->engine())
+ qWarning("QScriptEngine::toObject: cannot convert value created in a different engine");
+ JSValueRef exception = 0;
+ JSObjectRef object = JSValueToObject(*m_engine, *this, &exception);
+ if (object)
+ return new QScriptValuePrivate(m_engine.constData(), object);
+ else
+ m_engine->setException(exception, QScriptEnginePrivate::NotNullException);
+
+ }
+ return new QScriptValuePrivate;
+ case JSObject:
+ break;
+ }
+
+ if (engine != this->engine())
+ qWarning("QScriptEngine::toObject: cannot convert value created in a different engine");
+ Q_ASSERT(m_state == JSObject);
+ return this;
+}
+
+/*!
+ This method is created only for QScriptValue::toObject() purpose which is obsolete.
+ \internal
+ */
+QScriptValuePrivate* QScriptValuePrivate::toObject()
+{
+ if (isJSBased())
+ return toObject(m_engine.data());
+
+ // Without an engine there is not much we can do.
+ return new QScriptValuePrivate;
+}
+
+QDateTime QScriptValuePrivate::toDateTime()
+{
+ if (!isDate())
+ return QDateTime();
+
+ JSValueRef exception = 0;
+ qsreal t = JSValueToNumber(*m_engine, *this, &exception);
+
+ if (exception) {
+ m_engine->setException(exception, QScriptEnginePrivate::NotNullException);
+ return QDateTime();
+ }
+
+ QDateTime result;
+ result.setMSecsSinceEpoch(qint64(t));
+ return result;
+}
+
+inline QScriptValuePrivate* QScriptValuePrivate::prototype()
+{
+ if (isObject()) {
+ JSValueRef prototype = JSObjectGetPrototype(*m_engine, *this);
+ if (JSValueIsNull(*m_engine, prototype))
+ return new QScriptValuePrivate(engine(), prototype);
+ // The prototype could be either a null or a JSObject, so it is safe to cast the prototype
+ // to the JSObjectRef here.
+ return new QScriptValuePrivate(engine(), const_cast<JSObjectRef>(prototype));
+ }
+ return new QScriptValuePrivate;
+}
+
+inline void QScriptValuePrivate::setPrototype(QScriptValuePrivate* prototype)
+{
+ if (isObject() && prototype->isValid() && (prototype->isObject() || prototype->isNull())) {
+ if (engine() != prototype->engine()) {
+ qWarning("QScriptValue::setPrototype() failed: cannot set a prototype created in a different engine");
+ return;
+ }
+ // FIXME: This could be replaced by a new, faster API
+ // look at https://bugs.webkit.org/show_bug.cgi?id=40060
+ JSObjectSetPrototype(*m_engine, *this, *prototype);
+ JSValueRef proto = JSObjectGetPrototype(*m_engine, *this);
+ if (!JSValueIsStrictEqual(*m_engine, proto, *prototype))
+ qWarning("QScriptValue::setPrototype() failed: cyclic prototype value");
+ }
+}
bool QScriptValuePrivate::equals(QScriptValuePrivate* other)
{
- if (!isValid() || !other->isValid())
+ if (!isValid())
+ return !other->isValid();
+
+ if (!other->isValid())
return false;
- if ((m_state == other->m_state) && !isJSBased()) {
- if (isNumberBased())
- return m_number == other->m_number;
- return m_string == other->m_string;
+ if (!isJSBased() && !other->isJSBased()) {
+ switch (m_state) {
+ case CNull:
+ case CUndefined:
+ return other->isUndefined() || other->isNull();
+ case CNumber:
+ switch (other->m_state) {
+ case CBool:
+ case CString:
+ return u.m_number == other->toNumber();
+ case CNumber:
+ return u.m_number == other->u.m_number;
+ default:
+ return false;
+ }
+ case CBool:
+ switch (other->m_state) {
+ case CBool:
+ return u.m_bool == other->u.m_bool;
+ case CNumber:
+ return toNumber() == other->u.m_number;
+ case CString:
+ return toNumber() == other->toNumber();
+ default:
+ return false;
+ }
+ case CString:
+ switch (other->m_state) {
+ case CBool:
+ return toNumber() == other->toNumber();
+ case CNumber:
+ return toNumber() == other->u.m_number;
+ case CString:
+ return *u.m_string == *other->u.m_string;
+ default:
+ return false;
+ }
+ default:
+ Q_ASSERT_X(false, "equals()", "Not all states are included in the previous switch statement.");
+ }
}
if (isJSBased() && !other->isJSBased()) {
return false;
}
} else if (!isJSBased() && other->isJSBased()) {
- if (!other->assignEngine(other->engine())) {
+ if (!assignEngine(other->engine())) {
qWarning("equals(): Cannot compare to a value created in a different engine");
return false;
}
}
- return JSValueIsEqual(context(), value(), other->value(), /* exception */ 0);
+ JSValueRef exception = 0;
+ bool result = JSValueIsEqual(*m_engine, *this, *other, &exception);
+ m_engine->setException(exception);
+ return result;
}
-bool QScriptValuePrivate::strictlyEquals(const QScriptValuePrivate* other) const
+bool QScriptValuePrivate::strictlyEquals(QScriptValuePrivate* other)
{
- if (m_state != other->m_state)
- return false;
if (isJSBased()) {
+ // We can't compare these two values without binding to the same engine.
+ if (!other->isJSBased()) {
+ if (other->assignEngine(engine()))
+ return JSValueIsStrictEqual(*m_engine, *this, *other);
+ return false;
+ }
if (other->engine() != engine()) {
qWarning("strictlyEquals(): Cannot compare to a value created in a different engine");
return false;
}
- return JSValueIsStrictEqual(context(), value(), other->value());
+ return JSValueIsStrictEqual(*m_engine, *this, *other);
}
- if (isStringBased())
- return m_string == other->m_string;
- if (isNumberBased())
- return m_number == other->m_number;
+ if (isStringBased()) {
+ if (other->isStringBased())
+ return *u.m_string == *(other->u.m_string);
+ if (other->isJSBased()) {
+ assignEngine(other->engine());
+ return JSValueIsStrictEqual(*m_engine, *this, *other);
+ }
+ }
+ if (isNumberBased()) {
+ if (other->isNumberBased())
+ return u.m_number == other->u.m_number;
+ if (other->isJSBased()) {
+ assignEngine(other->engine());
+ return JSValueIsStrictEqual(*m_engine, *this, *other);
+ }
+ }
+ if (!isValid() && !other->isValid())
+ return true;
+
+ return false;
+}
- return false; // Invalid state.
+inline bool QScriptValuePrivate::instanceOf(QScriptValuePrivate* other)
+{
+ if (!isJSBased() || !other->isObject())
+ return false;
+ JSValueRef exception = 0;
+ bool result = JSValueIsInstanceOfConstructor(*m_engine, *this, *other, &exception);
+ m_engine->setException(exception);
+ return result;
}
/*!
*/
bool QScriptValuePrivate::assignEngine(QScriptEnginePrivate* engine)
{
+ Q_ASSERT(engine);
JSValueRef value;
switch (m_state) {
case CBool:
- value = engine->makeJSValue(static_cast<bool>(m_number));
+ value = engine->makeJSValue(u.m_bool);
break;
case CString:
- value = engine->makeJSValue(m_string);
+ value = engine->makeJSValue(*u.m_string);
+ delete u.m_string;
break;
case CNumber:
- value = engine->makeJSValue(m_number);
+ value = engine->makeJSValue(u.m_number);
break;
- case CSpecial:
- value = engine->makeJSValue(static_cast<QScriptValue::SpecialValue>(m_number));
+ case CNull:
+ value = engine->makeJSValue(QScriptValue::NullValue);
+ break;
+ case CUndefined:
+ value = engine->makeJSValue(QScriptValue::UndefinedValue);
break;
default:
if (!isJSBased())
}
m_engine = engine;
m_state = JSPrimitive;
- setValue(value);
+ u.m_value = value;
+ JSValueProtect(*m_engine, value);
return true;
}
+inline QScriptValuePrivate* QScriptValuePrivate::property(const QString& name, const QScriptValue::ResolveFlags& mode)
+{
+ JSRetainPtr<JSStringRef> propertyName(Adopt, QScriptConverter::toString(name));
+ return property<JSStringRef>(propertyName.get(), mode);
+}
+
+inline QScriptValuePrivate* QScriptValuePrivate::property(const QScriptStringPrivate* name, const QScriptValue::ResolveFlags& mode)
+{
+ return property<JSStringRef>(*name, mode);
+}
+
+inline QScriptValuePrivate* QScriptValuePrivate::property(quint32 arrayIndex, const QScriptValue::ResolveFlags& mode)
+{
+ return property<quint32>(arrayIndex, mode);
+}
+
+/*!
+ \internal
+ This method was created to unify access to the JSObjectGetPropertyAtIndex and the JSObjectGetProperty.
+*/
+inline JSValueRef QScriptValuePrivate::property(quint32 property, JSValueRef* exception)
+{
+ return JSObjectGetPropertyAtIndex(*m_engine, *this, property, exception);
+}
+
+/*!
+ \internal
+ This method was created to unify access to the JSObjectGetPropertyAtIndex and the JSObjectGetProperty.
+*/
+inline JSValueRef QScriptValuePrivate::property(JSStringRef property, JSValueRef* exception)
+{
+ return JSObjectGetProperty(*m_engine, *this, property, exception);
+}
+
+/*!
+ \internal
+ This method was created to unify acccess to hasOwnProperty, same function for an array index
+ and a property name access.
+*/
+inline bool QScriptValuePrivate::hasOwnProperty(quint32 property)
+{
+ Q_ASSERT(isObject());
+ // FIXME it could be faster, but JSC C API doesn't expose needed functionality.
+ JSRetainPtr<JSStringRef> propertyName(Adopt, QScriptConverter::toString(QString::number(property)));
+ return hasOwnProperty(propertyName.get());
+}
+
+/*!
+ \internal
+ This method was created to unify acccess to hasOwnProperty, same function for an array index
+ and a property name access.
+*/
+inline bool QScriptValuePrivate::hasOwnProperty(JSStringRef property)
+{
+ Q_ASSERT(isObject());
+ return m_engine->objectHasOwnProperty(*this, property);
+}
+
+/*!
+ \internal
+ This function gets property of an object.
+ \arg propertyName could be type of quint32 (an array index) or JSStringRef (a property name).
+*/
+template<typename T>
+inline QScriptValuePrivate* QScriptValuePrivate::property(T propertyName, const QScriptValue::ResolveFlags& mode)
+{
+ if (!isObject())
+ return new QScriptValuePrivate();
+
+ if ((mode == QScriptValue::ResolveLocal) && (!hasOwnProperty(propertyName)))
+ return new QScriptValuePrivate();
+
+ JSValueRef exception = 0;
+ JSValueRef value = property(propertyName, &exception);
+
+ if (exception) {
+ m_engine->setException(exception, QScriptEnginePrivate::NotNullException);
+ return new QScriptValuePrivate(engine(), exception);
+ }
+ if (JSValueIsUndefined(*m_engine, value))
+ return new QScriptValuePrivate;
+ return new QScriptValuePrivate(engine(), value);
+}
+
+inline void QScriptValuePrivate::setProperty(const QString& name, QScriptValuePrivate* value, const QScriptValue::PropertyFlags& flags)
+{
+ JSRetainPtr<JSStringRef> propertyName(Adopt, QScriptConverter::toString(name));
+ setProperty<JSStringRef>(propertyName.get(), value, flags);
+}
+
+inline void QScriptValuePrivate::setProperty(quint32 arrayIndex, QScriptValuePrivate* value, const QScriptValue::PropertyFlags& flags)
+{
+ setProperty<quint32>(arrayIndex, value, flags);
+}
+
+inline void QScriptValuePrivate::setProperty(const QScriptStringPrivate* name, QScriptValuePrivate* value, const QScriptValue::PropertyFlags& flags)
+{
+ setProperty<JSStringRef>(*name, value, flags);
+}
+
+/*!
+ \internal
+ This method was created to unify access to the JSObjectSetPropertyAtIndex and the JSObjectSetProperty.
+*/
+inline void QScriptValuePrivate::setProperty(quint32 property, JSValueRef value, JSPropertyAttributes flags, JSValueRef* exception)
+{
+ Q_ASSERT(isObject());
+ if (flags) {
+ // FIXME This could be better, but JSC C API doesn't expose needed functionality. It is
+ // not possible to create / modify a property attribute via an array index.
+ JSRetainPtr<JSStringRef> propertyName(Adopt, QScriptConverter::toString(QString::number(property)));
+ JSObjectSetProperty(*m_engine, *this, propertyName.get(), value, flags, exception);
+ return;
+ }
+ JSObjectSetPropertyAtIndex(*m_engine, *this, property, value, exception);
+}
+
+/*!
+ \internal
+ This method was created to unify access to the JSObjectSetPropertyAtIndex and the JSObjectSetProperty.
+*/
+inline void QScriptValuePrivate::setProperty(JSStringRef property, JSValueRef value, JSPropertyAttributes flags, JSValueRef* exception)
+{
+ Q_ASSERT(isObject());
+ JSObjectSetProperty(*m_engine, *this, property, value, flags, exception);
+}
+
+/*!
+ \internal
+ This method was created to unify access to the JSObjectDeleteProperty and a teoretical JSObjectDeletePropertyAtIndex
+ which doesn't exist now.
+*/
+inline void QScriptValuePrivate::deleteProperty(quint32 property, JSValueRef* exception)
+{
+ // FIXME It could be faster, we need a JSC C API for deleting array index properties.
+ JSRetainPtr<JSStringRef> propertyName(Adopt, QScriptConverter::toString(QString::number(property)));
+ JSObjectDeleteProperty(*m_engine, *this, propertyName.get(), exception);
+}
+
+/*!
+ \internal
+ This method was created to unify access to the JSObjectDeleteProperty and a teoretical JSObjectDeletePropertyAtIndex.
+*/
+inline void QScriptValuePrivate::deleteProperty(JSStringRef property, JSValueRef* exception)
+{
+ Q_ASSERT(isObject());
+ JSObjectDeleteProperty(*m_engine, *this, property, exception);
+}
+
+template<typename T>
+inline void QScriptValuePrivate::setProperty(T name, QScriptValuePrivate* value, const QScriptValue::PropertyFlags& flags)
+{
+ if (!isObject())
+ return;
+
+ if (!value->isJSBased())
+ value->assignEngine(engine());
+
+ JSValueRef exception = 0;
+ if (!value->isValid()) {
+ // Remove the property.
+ deleteProperty(name, &exception);
+ m_engine->setException(exception);
+ return;
+ }
+ if (m_engine != value->m_engine) {
+ qWarning("QScriptValue::setProperty() failed: cannot set value created in a different engine");
+ return;
+ }
+
+ setProperty(name, *value, QScriptConverter::toPropertyFlags(flags), &exception);
+ m_engine->setException(exception);
+}
+
+inline QScriptValue::PropertyFlags QScriptValuePrivate::propertyFlags(const QString& name, const QScriptValue::ResolveFlags& mode)
+{
+ JSRetainPtr<JSStringRef> propertyName(Adopt, QScriptConverter::toString(name));
+ return propertyFlags(propertyName.get(), mode);
+}
+
+inline QScriptValue::PropertyFlags QScriptValuePrivate::propertyFlags(const QScriptStringPrivate* name, const QScriptValue::ResolveFlags& mode)
+{
+ return propertyFlags(*name, mode);
+}
+
+inline QScriptValue::PropertyFlags QScriptValuePrivate::propertyFlags(JSStringRef name, const QScriptValue::ResolveFlags& mode)
+{
+ unsigned flags = 0;
+ if (!isObject())
+ return QScriptValue::PropertyFlags(flags);
+
+ // FIXME It could be faster and nicer, but new JSC C API should be created.
+ static JSStringRef objectName = QScriptConverter::toString("Object");
+ static JSStringRef propertyDescriptorName = QScriptConverter::toString("getOwnPropertyDescriptor");
+
+ // FIXME This is dangerous if global object was modified (bug 41839).
+ JSValueRef exception = 0;
+ JSObjectRef globalObject = JSContextGetGlobalObject(*m_engine);
+ JSValueRef objectConstructor = JSObjectGetProperty(*m_engine, globalObject, objectName, &exception);
+ Q_ASSERT(JSValueIsObject(*m_engine, objectConstructor));
+ JSValueRef propertyDescriptorGetter = JSObjectGetProperty(*m_engine, const_cast<JSObjectRef>(objectConstructor), propertyDescriptorName, &exception);
+ Q_ASSERT(JSValueIsObject(*m_engine, propertyDescriptorGetter));
+
+ JSValueRef arguments[] = { *this, JSValueMakeString(*m_engine, name) };
+ JSObjectRef propertyDescriptor
+ = const_cast<JSObjectRef>(JSObjectCallAsFunction(*m_engine,
+ const_cast<JSObjectRef>(propertyDescriptorGetter),
+ /* thisObject */ 0,
+ /* argumentCount */ 2,
+ arguments,
+ &exception));
+ if (exception) {
+ // Invalid property.
+ return QScriptValue::PropertyFlags(flags);
+ }
+
+ if (!JSValueIsObject(*m_engine, propertyDescriptor)) {
+ // Property isn't owned by this object.
+ JSObjectRef proto;
+ if (mode == QScriptValue::ResolveLocal
+ || ((proto = const_cast<JSObjectRef>(JSObjectGetPrototype(*m_engine, *this))) && JSValueIsNull(*m_engine, proto))) {
+ return QScriptValue::PropertyFlags(flags);
+ }
+ QScriptValuePrivate p(engine(), proto);
+ return p.propertyFlags(name, QScriptValue::ResolvePrototype);
+ }
+
+ static JSStringRef writableName = QScriptConverter::toString("writable");
+ static JSStringRef configurableName = QScriptConverter::toString("configurable");
+ static JSStringRef enumerableName = QScriptConverter::toString("enumerable");
+
+ bool readOnly = !JSValueToBoolean(*m_engine, JSObjectGetProperty(*m_engine, propertyDescriptor, writableName, &exception));
+ if (!exception && readOnly)
+ flags |= QScriptValue::ReadOnly;
+ bool undeletable = !JSValueToBoolean(*m_engine, JSObjectGetProperty(*m_engine, propertyDescriptor, configurableName, &exception));
+ if (!exception && undeletable)
+ flags |= QScriptValue::Undeletable;
+ bool skipInEnum = !JSValueToBoolean(*m_engine, JSObjectGetProperty(*m_engine, propertyDescriptor, enumerableName, &exception));
+ if (!exception && skipInEnum)
+ flags |= QScriptValue::SkipInEnumeration;
+
+ return QScriptValue::PropertyFlags(flags);
+}
+
QScriptValuePrivate* QScriptValuePrivate::call(const QScriptValuePrivate*, const QScriptValueList& args)
{
switch (m_state) {
qWarning("QScriptValue::call() failed: cannot call function with values created in a different engine");
return new QScriptValuePrivate;
}
- argv[j] = value->value();
+ argv[j] = *value;
}
// Make the call
JSValueRef exception = 0;
- JSValueRef result = JSObjectCallAsFunction(context(), object(), /* thisObject */ 0, argc, argv.constData(), &exception);
- if (!result && exception)
+ JSValueRef result = JSObjectCallAsFunction(*m_engine, *this, /* thisObject */ 0, argc, argv.constData(), &exception);
+ if (!result && exception) {
+ m_engine->setException(exception);
return new QScriptValuePrivate(engine(), exception);
+ }
if (result && !exception)
return new QScriptValuePrivate(engine(), result);
}
return m_engine.data();
}
-JSGlobalContextRef QScriptValuePrivate::context() const
-{
- Q_ASSERT(isJSBased());
- return m_engine->context();
-}
-
-JSValueRef QScriptValuePrivate::value() const
+QScriptValuePrivate::operator JSValueRef() const
{
Q_ASSERT(isJSBased());
- return m_value;
+ Q_ASSERT(u.m_value);
+ return u.m_value;
}
-JSObjectRef QScriptValuePrivate::object() const
+QScriptValuePrivate::operator JSObjectRef() const
{
Q_ASSERT(m_state == JSObject);
- return m_object;
-}
-
-void QScriptValuePrivate::setValue(JSValueRef value)
-{
- if (m_value)
- JSValueUnprotect(context(), m_value);
- if (value)
- JSValueProtect(context(), value);
- m_value = value;
-}
-
-/*!
- \internal
- Returns true if QSV is created from constructor with the given \a name, it has to be a
- built-in type.
-*/
-bool QScriptValuePrivate::inherits(const char* name)
-{
- Q_ASSERT(isJSBased());
- JSObjectRef globalObject = JSContextGetGlobalObject(context());
- JSStringRef errorAttrName = QScriptConverter::toString(name);
- JSValueRef error = JSObjectGetProperty(context(), globalObject, errorAttrName, /* exception */ 0);
- JSStringRelease(errorAttrName);
- return JSValueIsInstanceOfConstructor(context(), value(), JSValueToObject(context(), error, /* exception */ 0), /* exception */ 0);
+ Q_ASSERT(u.m_object);
+ return u.m_object;
}
/*!
QScriptValuePrivate::State QScriptValuePrivate::refinedJSValue()
{
Q_ASSERT(m_state == JSValue);
- if (!JSValueIsObject(context(), value())) {
+ if (!JSValueIsObject(*m_engine, *this)) {
m_state = JSPrimitive;
} else {
+ // Difference between JSValueRef and JSObjectRef is only in their type, binarywise it is the same.
+ // As m_value and m_object are stored in the u union, it is enough to change the m_state only.
m_state = JSObject;
- // We are sure that value is an JSObject, so we can const_cast safely without
- // calling JSC C API (JSValueToObject(context(), value(), /* exceptions */ 0)).
- m_object = const_cast<JSObjectRef>(m_value);
}
return m_state;
}
\internal
Returns true if current value of QSV is placed in m_number.
*/
-bool QScriptValuePrivate::isNumberBased() const { return !isJSBased() && !isStringBased() && m_state != Invalid; }
+bool QScriptValuePrivate::isNumberBased() const { return m_state == CNumber || m_state == CBool; }
/*!
\internal
--- /dev/null
+/*
+ Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+ 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 "qscriptvalueiterator.h"
+
+#include "qscriptvalue_p.h"
+#include "qscriptvalueiterator_p.h"
+
+/*!
+ \class QScriptValueIterator
+
+ \brief The QScriptValueIterator class provides a Java-style iterator for QScriptValue.
+
+ \ingroup script
+
+
+ The QScriptValueIterator constructor takes a QScriptValue as
+ argument. After construction, the iterator is located at the very
+ beginning of the sequence of properties. Here's how to iterate over
+ all the properties of a QScriptValue:
+
+ \snippet doc/src/snippets/code/src_script_qscriptvalueiterator.cpp 0
+
+ The next() advances the iterator. The name(), value() and flags()
+ functions return the name, value and flags of the last item that was
+ jumped over.
+
+ If you want to remove properties as you iterate over the
+ QScriptValue, use remove(). If you want to modify the value of a
+ property, use setValue().
+
+ Note that QScriptValueIterator only iterates over the QScriptValue's
+ own properties; i.e. it does not follow the prototype chain. You can
+ use a loop like this to follow the prototype chain:
+
+ \snippet doc/src/snippets/code/src_script_qscriptvalueiterator.cpp 1
+
+ Note that QScriptValueIterator will not automatically skip over
+ properties that have the QScriptValue::SkipInEnumeration flag set;
+ that flag only affects iteration in script code. If you want, you
+ can skip over such properties with code like the following:
+
+ \snippet doc/src/snippets/code/src_script_qscriptvalueiterator.cpp 2
+
+ \sa QScriptValue::property()
+*/
+
+/*!
+ Constructs an iterator for traversing \a object. The iterator is
+ set to be at the front of the sequence of properties (before the
+ first property).
+*/
+QScriptValueIterator::QScriptValueIterator(const QScriptValue& object)
+ : d_ptr(new QScriptValueIteratorPrivate(QScriptValuePrivate::get(object)))
+{}
+
+/*!
+ Destroys the iterator.
+*/
+QScriptValueIterator::~QScriptValueIterator()
+{}
+
+/*!
+ Returns true if there is at least one item ahead of the iterator
+ (i.e. the iterator is \e not at the back of the property sequence);
+ otherwise returns false.
+
+ \sa next(), hasPrevious()
+*/
+bool QScriptValueIterator::hasNext() const
+{
+ return d_ptr->hasNext();
+}
+
+/*!
+ Advances the iterator by one position.
+
+ Calling this function on an iterator located at the back of the
+ container leads to undefined results.
+
+ \sa hasNext(), previous(), name()
+*/
+void QScriptValueIterator::next()
+{
+ d_ptr->next();
+}
+
+/*!
+ Returns true if there is at least one item behind the iterator
+ (i.e. the iterator is \e not at the front of the property sequence);
+ otherwise returns false.
+
+ \sa previous(), hasNext()
+*/
+bool QScriptValueIterator::hasPrevious() const
+{
+ return d_ptr->hasPrevious();
+}
+
+/*!
+ Moves the iterator back by one position.
+
+ Calling this function on an iterator located at the front of the
+ container leads to undefined results.
+
+ \sa hasPrevious(), next(), name()
+*/
+void QScriptValueIterator::previous()
+{
+ d_ptr->previous();
+}
+
+/*!
+ Moves the iterator to the front of the QScriptValue (before the
+ first property).
+
+ \sa toBack(), next()
+*/
+void QScriptValueIterator::toFront()
+{
+ d_ptr->toFront();
+}
+
+/*!
+ Moves the iterator to the back of the QScriptValue (after the
+ last property).
+
+ \sa toFront(), previous()
+*/
+void QScriptValueIterator::toBack()
+{
+ d_ptr->toBack();
+}
+
+/*!
+ Returns the name of the last property that was jumped over using
+ next() or previous().
+
+ \sa value(), flags()
+*/
+QString QScriptValueIterator::name() const
+{
+ return d_ptr->name();
+}
+
+/*!
+ Returns the name of the last property that was jumped over using
+ next() or previous().
+*/
+QScriptString QScriptValueIterator::scriptName() const
+{
+ return QScriptStringPrivate::get(d_ptr->scriptName());
+}
+
+/*!
+ Returns the value of the last property that was jumped over using
+ next() or previous().
+
+ \sa setValue(), name()
+*/
+QScriptValue QScriptValueIterator::value() const
+{
+ return QScriptValuePrivate::get(d_ptr->value());
+}
+
+/*!
+ Sets the \a value of the last property that was jumped over using
+ next() or previous().
+
+ \sa value(), name()
+*/
+void QScriptValueIterator::setValue(const QScriptValue& value)
+{
+ d_ptr->setValue(QScriptValuePrivate::get(value));
+}
+
+/*!
+ Removes the last property that was jumped over using next()
+ or previous().
+
+ \sa setValue()
+*/
+void QScriptValueIterator::remove()
+{
+ d_ptr->remove();
+}
+
+/*!
+ Returns the flags of the last property that was jumped over using
+ next() or previous().
+
+ \sa value()
+*/
+QScriptValue::PropertyFlags QScriptValueIterator::flags() const
+{
+ return d_ptr->flags();
+}
+
+/*!
+ Makes the iterator operate on \a object. The iterator is set to be
+ at the front of the sequence of properties (before the first
+ property).
+*/
+QScriptValueIterator& QScriptValueIterator::operator=(QScriptValue& object)
+{
+ d_ptr = new QScriptValueIteratorPrivate(QScriptValuePrivate::get(object));
+ return *this;
+}
--- /dev/null
+/*
+ Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+ 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.
+*/
+
+#ifndef qscriptvalueiterator_h
+#define qscriptvalueiterator_h
+
+#include "qtscriptglobal.h"
+#include "qscriptstring.h"
+#include <QtCore/qshareddata.h>
+#include "qscriptvalue.h"
+
+class QScriptValue;
+class QScriptValueIteratorPrivate;
+
+
+class Q_JAVASCRIPT_EXPORT QScriptValueIterator {
+public:
+ QScriptValueIterator(const QScriptValue& value);
+ ~QScriptValueIterator();
+
+ bool hasNext() const;
+ void next();
+
+ bool hasPrevious() const;
+ void previous();
+
+ QString name() const;
+ QScriptString scriptName() const;
+
+ QScriptValue value() const;
+ void setValue(const QScriptValue& value);
+
+ void remove();
+ QScriptValue::PropertyFlags flags() const;
+
+ void toFront();
+ void toBack();
+
+ QScriptValueIterator& operator=(QScriptValue& value);
+private:
+ QExplicitlySharedDataPointer<QScriptValueIteratorPrivate> d_ptr;
+
+ Q_DECLARE_PRIVATE(QScriptValueIterator)
+ Q_DISABLE_COPY(QScriptValueIterator)
+};
+
+#endif // qscriptvalueiterator_h
--- /dev/null
+/*
+ Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+ 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.
+*/
+
+#ifndef qscriptvalueiterator_p_h
+#define qscriptvalueiterator_p_h
+
+#include "qscriptvalue_p.h"
+#include <JavaScriptCore/JavaScript.h>
+#include <JavaScriptCore/JSRetainPtr.h>
+#include <QtCore/qshareddata.h>
+#include <QtCore/qvector.h>
+
+class QScriptValueIteratorPrivate: public QSharedData {
+public:
+ inline QScriptValueIteratorPrivate(const QScriptValuePrivate* value);
+ inline ~QScriptValueIteratorPrivate();
+
+ inline bool hasNext();
+ inline void next();
+
+ inline bool hasPrevious();
+ inline void previous();
+
+ inline QString name() const;
+ inline QScriptStringPrivate* scriptName() const;
+
+ inline QScriptValuePrivate* value() const;
+ inline void setValue(const QScriptValuePrivate* value);
+
+ inline void remove();
+
+ inline void toFront();
+ inline void toBack();
+
+ QScriptValue::PropertyFlags flags() const;
+
+ inline bool isValid() const;
+private:
+ inline QScriptEnginePrivate* engine() const;
+
+ QExplicitlySharedDataPointer<QScriptValuePrivate> m_object;
+ QVector<JSStringRef> m_names;
+ QMutableVectorIterator<JSStringRef> m_idx;
+};
+
+inline QScriptValueIteratorPrivate::QScriptValueIteratorPrivate(const QScriptValuePrivate* value)
+ : m_object(const_cast<QScriptValuePrivate*>(value))
+ , m_idx(m_names)
+{
+ if (m_object->isObject()) {
+ m_names = engine()->objectGetOwnPropertyNames(*m_object);
+ m_idx = m_names;
+ } else
+ m_object = 0;
+}
+
+inline QScriptValueIteratorPrivate::~QScriptValueIteratorPrivate()
+{
+ QVector<JSStringRef>::const_iterator i = m_names.constBegin();
+ for (; i != m_names.constEnd(); ++i)
+ JSStringRelease(*i);
+}
+
+inline bool QScriptValueIteratorPrivate::hasNext()
+{
+ return m_idx.hasNext();
+}
+
+inline void QScriptValueIteratorPrivate::next()
+{
+ // FIXME (Qt5) This method should return a value (QTBUG-11226).
+ m_idx.next();
+}
+
+inline bool QScriptValueIteratorPrivate::hasPrevious()
+{
+ return m_idx.hasPrevious();
+}
+
+inline void QScriptValueIteratorPrivate::previous()
+{
+ m_idx.previous();
+}
+
+inline QString QScriptValueIteratorPrivate::name() const
+{
+ if (!isValid())
+ return QString();
+ return QScriptConverter::toString(m_idx.value());
+}
+
+inline QScriptStringPrivate* QScriptValueIteratorPrivate::scriptName() const
+{
+ if (!isValid())
+ return new QScriptStringPrivate();
+ return new QScriptStringPrivate(QScriptConverter::toString(m_idx.value()));
+}
+
+inline QScriptValuePrivate* QScriptValueIteratorPrivate::value() const
+{
+ if (!isValid())
+ return new QScriptValuePrivate();
+ JSValueRef exception = 0;
+ JSValueRef value = m_object->property(m_idx.value(), &exception);
+ engine()->setException(exception);
+ return new QScriptValuePrivate(engine(), value);
+}
+
+inline void QScriptValueIteratorPrivate::setValue(const QScriptValuePrivate* value)
+{
+ if (!isValid())
+ return;
+ JSValueRef exception = 0;
+ m_object->setProperty(m_idx.value(), *value, /* flags */ 0, &exception);
+ engine()->setException(exception);
+}
+
+inline void QScriptValueIteratorPrivate::remove()
+{
+ if (!isValid())
+ return;
+ JSValueRef exception = 0;
+ m_object->deleteProperty(m_idx.value(), &exception);
+ engine()->setException(exception);
+ m_idx.remove();
+}
+
+inline void QScriptValueIteratorPrivate::toFront()
+{
+ m_idx.toFront();
+}
+
+inline void QScriptValueIteratorPrivate::toBack()
+{
+ m_idx.toBack();
+}
+
+QScriptValue::PropertyFlags QScriptValueIteratorPrivate::flags() const
+{
+ if (!isValid())
+ return QScriptValue::PropertyFlags(0);
+ return m_object->propertyFlags(m_idx.value(), QScriptValue::ResolveLocal);
+}
+
+inline bool QScriptValueIteratorPrivate::isValid() const
+{
+ return m_object;
+}
+
+inline QScriptEnginePrivate* QScriptValueIteratorPrivate::engine() const
+{
+ Q_ASSERT(isValid());
+ return m_object->engine();
+}
+
+#endif // qscriptvalueiterator_p_h
--- /dev/null
+QMAKE_RPATHDIR = $$OUTPUT_DIR/lib $$QMAKE_RPATHDIR
+QMAKE_LIBDIR = $$OUTPUT_DIR/lib $$QMAKE_LIBDIR
+mac:!static:contains(QT_CONFIG, qt_framework):!CONFIG(webkit_no_framework) {
+ LIBS += -framework QtScript
+ QMAKE_FRAMEWORKPATH = $$OUTPUT_DIR/lib $$QMAKE_FRAMEWORKPATH
+} else {
+ win32-*|wince* {
+ LIBS += -lQtScript$${QT_MAJOR_VERSION}
+ } else {
+ LIBS += -lQtScript
+ }
+}
+
+CONFIG(release, debug|release) {
+ DEFINES += NDEBUG
+}
+
+INCLUDEPATH += $$PWD/../api
+
--- /dev/null
+TEMPLATE = subdirs
+SUBDIRS = qscriptengine \
+ qscriptvalue \
+
--- /dev/null
+TEMPLATE = app
+TARGET = tst_bench_qscriptengine
+
+SOURCES += tst_qscriptengine.cpp
+
+QT += testlib
+
+include(../benchmarks.pri)
+
+symbian* {
+ TARGET.EPOCHEAPSIZE = 0x20000 0x2000000 // Min 128kB, Max 32MB
+ TARGET.EPOCSTACKSIZE = 0x14000
+}
--- /dev/null
+/*
+ Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+ 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 "qscriptengine.h"
+#include "qscriptvalue.h"
+#include <qtest.h>
+
+class tst_QScriptEngine : public QObject {
+ Q_OBJECT
+
+private slots:
+ void checkSyntax_data();
+ void checkSyntax();
+ void constructor();
+ void evaluateString_data();
+ void evaluateString();
+ void evaluateProgram_data();
+ void evaluateProgram();
+ void newObject();
+ void nullValue();
+ void undefinedValue();
+ void globalObject();
+ void toStringHandle();
+};
+
+void tst_QScriptEngine::checkSyntax_data()
+{
+ evaluateString_data();
+}
+
+void tst_QScriptEngine::checkSyntax()
+{
+ QFETCH(QString, code);
+ QScriptEngine engine;
+ QBENCHMARK {
+ engine.checkSyntax(code);
+ }
+}
+
+void tst_QScriptEngine::constructor()
+{
+ QBENCHMARK {
+ QScriptEngine engine;
+ }
+}
+
+void tst_QScriptEngine::evaluateString_data()
+{
+ QTest::addColumn<QString>("code");
+ QTest::newRow("empty script") << QString::fromLatin1("");
+ QTest::newRow("number literal") << QString::fromLatin1("123");
+ QTest::newRow("string literal") << QString::fromLatin1("'ciao'");
+ QTest::newRow("regexp literal") << QString::fromLatin1("/foo/gim");
+ QTest::newRow("null literal") << QString::fromLatin1("null");
+ QTest::newRow("undefined literal") << QString::fromLatin1("undefined");
+ QTest::newRow("empty object literal") << QString::fromLatin1("{}");
+ QTest::newRow("this") << QString::fromLatin1("this");
+}
+
+void tst_QScriptEngine::evaluateString()
+{
+ QFETCH(QString, code);
+ QScriptEngine engine;
+ QBENCHMARK {
+ engine.evaluate(code);
+ }
+}
+
+void tst_QScriptEngine::evaluateProgram_data()
+{
+ evaluateString_data();
+}
+
+void tst_QScriptEngine::evaluateProgram()
+{
+ QFETCH(QString, code);
+ QScriptEngine engine;
+ QScriptProgram program(code);
+ QBENCHMARK {
+ engine.evaluate(program);
+ }
+}
+
+void tst_QScriptEngine::newObject()
+{
+ QScriptEngine engine;
+ QBENCHMARK {
+ engine.newObject();
+ }
+}
+
+void tst_QScriptEngine::nullValue()
+{
+ QScriptEngine engine;
+ QBENCHMARK {
+ engine.nullValue();
+ }
+}
+
+void tst_QScriptEngine::undefinedValue()
+{
+ QScriptEngine engine;
+ QBENCHMARK {
+ engine.undefinedValue();
+ }
+}
+
+void tst_QScriptEngine::globalObject()
+{
+ QScriptEngine engine;
+ QBENCHMARK {
+ engine.globalObject();
+ }
+}
+
+void tst_QScriptEngine::toStringHandle()
+{
+ QScriptEngine engine;
+ QString str = QString::fromLatin1("foobarbaz");
+ QBENCHMARK {
+ engine.toStringHandle(str);
+ }
+}
+
+QTEST_MAIN(tst_QScriptEngine)
+#include "tst_qscriptengine.moc"
--- /dev/null
+TEMPLATE = app
+TARGET = tst_bench_qscriptvalue
+QT += testlib
+
+isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../../../..
+include(../benchmarks.pri)
+
+SOURCES += tst_qscriptvalue.cpp
+
--- /dev/null
+/*
+ Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+ 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 "qscriptengine.h"
+#include "qscriptstring.h"
+#include "qscriptvalue.h"
+#include <qtest.h>
+
+Q_DECLARE_METATYPE(QScriptValue);
+
+class tst_QScriptValue : public QObject {
+ Q_OBJECT
+
+public:
+ tst_QScriptValue()
+ : m_engine(0)
+ {}
+
+ ~tst_QScriptValue()
+ {
+ if (m_engine)
+ delete m_engine;
+ }
+
+private slots:
+ void values_data();
+
+ void ctorBool();
+ void ctorReal();
+ void ctorNumber();
+ void ctorQString();
+ void ctorCString();
+ void ctorSpecial();
+ void ctorQScriptValue();
+
+ void isValid_data();
+ void isValid();
+ void isBool_data();
+ void isBool();
+ void isNumber_data();
+ void isNumber();
+ void isFunction_data();
+ void isFunction();
+ void isNull_data();
+ void isNull();
+ void isString_data();
+ void isString();
+ void isUndefined_data();
+ void isUndefined();
+ void isObject_data();
+ void isObject();
+ void isError_data();
+ void isError();
+
+ void toString_data();
+ void toString();
+ void toNumber_data();
+ void toNumber();
+ void toBool_data();
+ void toBool();
+ void toInteger_data();
+ void toInteger();
+ void toInt32_data();
+ void toInt32();
+ void toUInt32_data();
+ void toUInt32();
+ void toUInt16_data();
+ void toUInt16();
+ void toObject_data();
+ void toObject();
+
+ void equals_data();
+ void equals();
+ void strictlyEquals_data();
+ void strictlyEquals();
+ void instanceOf_data();
+ void instanceOf();
+
+private:
+ QScriptEngine* m_engine;
+};
+
+void tst_QScriptValue::values_data()
+{
+ if (m_engine)
+ delete m_engine;
+ m_engine = new QScriptEngine;
+
+ QTest::addColumn<QScriptValue>("value");
+
+ QTest::newRow("invalid") << QScriptValue();
+
+ QTest::newRow("cbool") << QScriptValue(true);
+ QTest::newRow("cnumber") << QScriptValue(1234);
+ QTest::newRow("cstring") << QScriptValue("abc");
+ QTest::newRow("cnull") << QScriptValue(QScriptValue::NullValue);
+ QTest::newRow("cundefined") << QScriptValue(QScriptValue::UndefinedValue);
+
+ QTest::newRow("jsbool") << m_engine->evaluate("true");
+ QTest::newRow("jsnumber") << m_engine->evaluate("12345");
+ QTest::newRow("jsstring") << m_engine->evaluate("'go'");
+ QTest::newRow("jsfunction") << m_engine->evaluate("(function {})");
+ QTest::newRow("jsnull") << m_engine->nullValue();
+ QTest::newRow("jsundefined") << m_engine->undefinedValue();
+ QTest::newRow("jsobject") << m_engine->newObject();
+ QTest::newRow("jserror") << m_engine->evaluate("new Error()");
+}
+
+void tst_QScriptValue::ctorBool()
+{
+ QBENCHMARK {
+ QScriptValue(true);
+ }
+}
+
+void tst_QScriptValue::ctorReal()
+{
+ QBENCHMARK {
+ QScriptValue(12.3);
+ }
+}
+
+void tst_QScriptValue::ctorNumber()
+{
+ QBENCHMARK {
+ QScriptValue(123);
+ }
+}
+
+void tst_QScriptValue::ctorQString()
+{
+ QString str = QString::fromLatin1("ciao");
+ QBENCHMARK {
+ QScriptValue(str);
+ }
+}
+
+void tst_QScriptValue::ctorCString()
+{
+ QBENCHMARK {
+ QScriptValue("Pong!");
+ }
+}
+
+void tst_QScriptValue::ctorSpecial()
+{
+ QBENCHMARK {
+ (void)QScriptValue(QScriptValue::NullValue);
+ }
+}
+
+void tst_QScriptValue::ctorQScriptValue()
+{
+ QScriptValue tmp(1234);
+ QBENCHMARK {
+ QScriptValue(tmp);
+ }
+}
+
+void tst_QScriptValue::isValid_data()
+{
+ values_data();
+}
+
+void tst_QScriptValue::isValid()
+{
+ QFETCH(QScriptValue, value);
+ QBENCHMARK {
+ value.isValid();
+ }
+}
+
+void tst_QScriptValue::isBool_data()
+{
+ values_data();
+}
+
+void tst_QScriptValue::isBool()
+{
+ QFETCH(QScriptValue, value);
+ QBENCHMARK {
+ value.isBool();
+ }
+}
+
+void tst_QScriptValue::isNumber_data()
+{
+ values_data();
+}
+
+void tst_QScriptValue::isNumber()
+{
+ QFETCH(QScriptValue, value);
+ QBENCHMARK {
+ value.isNumber();
+ }
+}
+
+void tst_QScriptValue::isFunction_data()
+{
+ values_data();
+}
+
+void tst_QScriptValue::isFunction()
+{
+ QFETCH(QScriptValue, value);
+ QBENCHMARK {
+ value.isFunction();
+ }
+}
+
+void tst_QScriptValue::isNull_data()
+{
+ values_data();
+}
+
+void tst_QScriptValue::isNull()
+{
+ QFETCH(QScriptValue, value);
+ QBENCHMARK {
+ value.isNull();
+ }
+}
+
+void tst_QScriptValue::isString_data()
+{
+ values_data();
+}
+
+void tst_QScriptValue::isString()
+{
+ QFETCH(QScriptValue, value);
+ QBENCHMARK {
+ value.isString();
+ }
+}
+
+void tst_QScriptValue::isUndefined_data()
+{
+ values_data();
+}
+
+void tst_QScriptValue::isUndefined()
+{
+ QFETCH(QScriptValue, value);
+ QBENCHMARK {
+ value.isUndefined();
+ }
+}
+
+void tst_QScriptValue::isObject_data()
+{
+ values_data();
+}
+
+void tst_QScriptValue::isObject()
+{
+ QFETCH(QScriptValue, value);
+ QBENCHMARK {
+ value.isObject();
+ }
+}
+
+void tst_QScriptValue::isError_data()
+{
+ values_data();
+}
+
+void tst_QScriptValue::isError()
+{
+ QFETCH(QScriptValue, value);
+ QBENCHMARK {
+ value.isError();
+ }
+}
+
+void tst_QScriptValue::toString_data()
+{
+ values_data();
+}
+
+void tst_QScriptValue::toString()
+{
+ QFETCH(QScriptValue, value);
+ QBENCHMARK {
+ value.toString();
+ }
+}
+
+void tst_QScriptValue::toNumber_data()
+{
+ values_data();
+}
+
+void tst_QScriptValue::toNumber()
+{
+ QFETCH(QScriptValue, value);
+ QBENCHMARK {
+ value.toNumber();
+ }
+}
+
+void tst_QScriptValue::toBool_data()
+{
+ values_data();
+}
+
+void tst_QScriptValue::toBool()
+{
+ QFETCH(QScriptValue, value);
+ QBENCHMARK {
+ value.toBool();
+ }
+}
+
+void tst_QScriptValue::toInteger_data()
+{
+ values_data();
+}
+
+void tst_QScriptValue::toInteger()
+{
+ QFETCH(QScriptValue, value);
+ QBENCHMARK {
+ value.toInteger();
+ }
+}
+
+void tst_QScriptValue::toInt32_data()
+{
+ values_data();
+}
+
+void tst_QScriptValue::toInt32()
+{
+ QFETCH(QScriptValue, value);
+ QBENCHMARK {
+ value.toInt32();
+ }
+}
+
+void tst_QScriptValue::toUInt32_data()
+{
+ values_data();
+}
+
+void tst_QScriptValue::toUInt32()
+{
+ QFETCH(QScriptValue, value);
+ QBENCHMARK {
+ value.toUInt32();
+ }
+}
+
+void tst_QScriptValue::toUInt16_data()
+{
+ values_data();
+}
+
+void tst_QScriptValue::toUInt16()
+{
+ QFETCH(QScriptValue, value);
+ QBENCHMARK {
+ value.toUInt16();
+ }
+}
+
+void tst_QScriptValue::toObject_data()
+{
+ values_data();
+}
+
+void tst_QScriptValue::toObject()
+{
+ QFETCH(QScriptValue, value);
+ QBENCHMARK {
+ value.toObject();
+ }
+}
+
+void tst_QScriptValue::equals_data()
+{
+ values_data();
+}
+
+void tst_QScriptValue::equals()
+{
+ QFETCH(QScriptValue, value);
+ static QScriptValue previous;
+ QBENCHMARK {
+ value.equals(previous);
+ }
+ previous = value;
+}
+
+void tst_QScriptValue::strictlyEquals_data()
+{
+ values_data();
+}
+
+void tst_QScriptValue::strictlyEquals()
+{
+ QFETCH(QScriptValue, value);
+ static QScriptValue previous;
+ QBENCHMARK {
+ value.strictlyEquals(previous);
+ }
+ previous = value;
+}
+
+void tst_QScriptValue::instanceOf_data()
+{
+ values_data();
+}
+
+void tst_QScriptValue::instanceOf()
+{
+ QFETCH(QScriptValue, value);
+ static QScriptValue object = m_engine->newObject();
+ QBENCHMARK {
+ value.instanceOf(object);
+ }
+}
+
+QTEST_MAIN(tst_QScriptValue)
+#include "tst_qscriptvalue.moc"
#include "qscriptprogram.h"
#include "qscriptsyntaxcheckresult.h"
#include "qscriptvalue.h"
+#include <QtCore/qnumeric.h>
#include <QtTest/qtest.h>
class tst_QScriptEngine : public QObject {
void cleanup() {}
private slots:
+ void newFunction();
+ void newObject();
void globalObject();
void evaluate();
void collectGarbage();
void evaluateProgram();
void checkSyntax_data();
void checkSyntax();
+ void toObject();
+ void toObjectTwoEngines();
+ void newArray();
+ void uncaughtException();
+ void newDate();
};
/* Evaluating a script that throw an unhandled exception should return an invalid value. */
QVERIFY2(engine.evaluate("ping").isValid(), "Script throwing an unhandled exception should return an exception value");
}
+static QScriptValue myFunction(QScriptContext*, QScriptEngine* eng)
+{
+ return eng->nullValue();
+}
+
+static QScriptValue myFunctionWithArg(QScriptContext*, QScriptEngine* eng, void* arg)
+{
+ int* result = reinterpret_cast<int*>(arg);
+ return QScriptValue(eng, *result);
+}
+
+static QScriptValue myFunctionThatReturns(QScriptContext*, QScriptEngine* eng)
+{
+ return QScriptValue(eng, 42);
+}
+
+static QScriptValue myFunctionThatReturnsWithoutEngine(QScriptContext*, QScriptEngine*)
+{
+ return QScriptValue(1024);
+}
+
+static QScriptValue myFunctionThatReturnsWrongEngine(QScriptContext*, QScriptEngine*, void* arg)
+{
+ QScriptEngine* wrongEngine = reinterpret_cast<QScriptEngine*>(arg);
+ return QScriptValue(wrongEngine, 42);
+}
+
+void tst_QScriptEngine::newFunction()
+{
+ QScriptEngine eng;
+ {
+ QScriptValue fun = eng.newFunction(myFunction);
+ QCOMPARE(fun.isValid(), true);
+ QCOMPARE(fun.isFunction(), true);
+ QCOMPARE(fun.isObject(), true);
+ // QCOMPARE(fun.scriptClass(), (QScriptClass*)0);
+ // a prototype property is automatically constructed
+ {
+ QScriptValue prot = fun.property("prototype", QScriptValue::ResolveLocal);
+ QVERIFY(prot.isObject());
+ QVERIFY(prot.property("constructor").strictlyEquals(fun));
+ QEXPECT_FAIL("", "JSCallbackObject::getOwnPropertyDescriptor() doesn't return correct information yet", Continue);
+ QCOMPARE(fun.propertyFlags("prototype"), QScriptValue::Undeletable);
+ QEXPECT_FAIL("", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QCOMPARE(prot.propertyFlags("constructor"), QScriptValue::PropertyFlags(QScriptValue::Undeletable | QScriptValue::SkipInEnumeration));
+ }
+ // prototype should be Function.prototype
+ QCOMPARE(fun.prototype().isValid(), true);
+ QCOMPARE(fun.prototype().isFunction(), true);
+ QCOMPARE(fun.prototype().strictlyEquals(eng.evaluate("Function.prototype")), true);
+
+ QCOMPARE(fun.call().isNull(), true);
+ // QCOMPARE(fun.construct().isObject(), true);
+ }
+ // the overload that takes an extra argument
+ {
+ int expectedResult = 42;
+ QScriptValue fun = eng.newFunction(myFunctionWithArg, reinterpret_cast<void*>(&expectedResult));
+ QVERIFY(fun.isFunction());
+ // QCOMPARE(fun.scriptClass(), (QScriptClass*)0);
+ // a prototype property is automatically constructed
+ {
+ QScriptValue prot = fun.property("prototype", QScriptValue::ResolveLocal);
+ QVERIFY(prot.isObject());
+ QVERIFY(prot.property("constructor").strictlyEquals(fun));
+ QEXPECT_FAIL("", "JSCallbackObject::getOwnPropertyDescriptor() doesn't return correct information yet", Continue);
+ QCOMPARE(fun.propertyFlags("prototype"), QScriptValue::Undeletable);
+ QEXPECT_FAIL("", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QCOMPARE(prot.propertyFlags("constructor"), QScriptValue::PropertyFlags(QScriptValue::Undeletable | QScriptValue::SkipInEnumeration));
+ }
+ // prototype should be Function.prototype
+ QCOMPARE(fun.prototype().isValid(), true);
+ QCOMPARE(fun.prototype().isFunction(), true);
+ QCOMPARE(fun.prototype().strictlyEquals(eng.evaluate("Function.prototype")), true);
+
+ QScriptValue result = fun.call();
+ QCOMPARE(result.isNumber(), true);
+ QCOMPARE(result.toInt32(), expectedResult);
+ }
+ // the overload that takes a prototype
+ {
+ QScriptValue proto = eng.newObject();
+ QScriptValue fun = eng.newFunction(myFunction, proto);
+ QCOMPARE(fun.isValid(), true);
+ QCOMPARE(fun.isFunction(), true);
+ QCOMPARE(fun.isObject(), true);
+ // internal prototype should be Function.prototype
+ QCOMPARE(fun.prototype().isValid(), true);
+ QCOMPARE(fun.prototype().isFunction(), true);
+ QCOMPARE(fun.prototype().strictlyEquals(eng.evaluate("Function.prototype")), true);
+ // public prototype should be the one we passed
+ QCOMPARE(fun.property("prototype").strictlyEquals(proto), true);
+ QEXPECT_FAIL("", "JSCallbackObject::getOwnPropertyDescriptor() doesn't return correct information yet", Continue);
+ QCOMPARE(fun.propertyFlags("prototype"), QScriptValue::Undeletable);
+ QCOMPARE(proto.property("constructor").strictlyEquals(fun), true);
+ QEXPECT_FAIL("", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QCOMPARE(proto.propertyFlags("constructor"), QScriptValue::PropertyFlags(QScriptValue::Undeletable | QScriptValue::SkipInEnumeration));
+
+ QCOMPARE(fun.call().isNull(), true);
+ // QCOMPARE(fun.construct().isObject(), true);
+ }
+ // whether the return value is correct
+ {
+ QScriptValue fun = eng.newFunction(myFunctionThatReturns);
+ QCOMPARE(fun.isValid(), true);
+ QCOMPARE(fun.isFunction(), true);
+ QCOMPARE(fun.isObject(), true);
+
+ QScriptValue result = fun.call();
+ QCOMPARE(result.isNumber(), true);
+ QCOMPARE(result.toInt32(), 42);
+ }
+ // whether the return value is assigned to the correct engine
+ {
+ QScriptValue fun = eng.newFunction(myFunctionThatReturnsWithoutEngine);
+ QCOMPARE(fun.isValid(), true);
+ QCOMPARE(fun.isFunction(), true);
+ QCOMPARE(fun.isObject(), true);
+
+ QScriptValue result = fun.call();
+ QCOMPARE(result.engine(), &eng);
+ QCOMPARE(result.isNumber(), true);
+ QCOMPARE(result.toInt32(), 1024);
+ }
+ // whether the return value is undefined when returning a value with wrong engine
+ {
+ QScriptEngine wrongEngine;
+
+ QScriptValue fun = eng.newFunction(myFunctionThatReturnsWrongEngine, reinterpret_cast<void*>(&wrongEngine));
+ QCOMPARE(fun.isValid(), true);
+ QCOMPARE(fun.isFunction(), true);
+ QCOMPARE(fun.isObject(), true);
+
+ QTest::ignoreMessage(QtWarningMsg, "Value from different engine returned from native function, returning undefined value instead.");
+ QScriptValue result = fun.call();
+ QCOMPARE(result.isValid(), true);
+ QCOMPARE(result.isUndefined(), true);
+ }
+}
+
+void tst_QScriptEngine::newObject()
+{
+ QScriptEngine engine;
+ QScriptValue object = engine.newObject();
+ QVERIFY(object.isObject());
+ QVERIFY(object.engine() == &engine);
+ QVERIFY(!object.isError());
+ QVERIFY(!object.equals(engine.newObject()));
+ QVERIFY(!object.strictlyEquals(engine.newObject()));
+ QCOMPARE(object.toString(), QString::fromAscii("[object Object]"));
+}
+
void tst_QScriptEngine::globalObject()
{
QScriptEngine engine;
QScriptValue self = engine.evaluate("this");
QVERIFY(global.isObject());
QVERIFY(engine.globalObject().equals(engine.evaluate("this")));
- QEXPECT_FAIL("", "strictlyEquals is broken - bug 36600 in bugs.webkit.org", Continue);
QVERIFY(engine.globalObject().strictlyEquals(self));
}
QCOMPARE(result.errorMessage(), errorMessage);
}
+void tst_QScriptEngine::toObject()
+{
+ QScriptEngine eng;
+ QVERIFY(!eng.toObject(eng.undefinedValue()).isValid());
+ QVERIFY(!eng.toObject(eng.nullValue()).isValid());
+ QVERIFY(!eng.toObject(QScriptValue()).isValid());
+
+ QScriptValue falskt(false);
+ {
+ QScriptValue tmp = eng.toObject(falskt);
+ QVERIFY(tmp.isObject());
+ QVERIFY(!falskt.isObject());
+ QVERIFY(!falskt.engine());
+ QCOMPARE(tmp.toNumber(), falskt.toNumber());
+ }
+
+ QScriptValue sant(true);
+ {
+ QScriptValue tmp = eng.toObject(sant);
+ QVERIFY(tmp.isObject());
+ QVERIFY(!sant.isObject());
+ QVERIFY(!sant.engine());
+ QCOMPARE(tmp.toNumber(), sant.toNumber());
+ }
+
+ QScriptValue number(123.0);
+ {
+ QScriptValue tmp = eng.toObject(number);
+ QVERIFY(tmp.isObject());
+ QVERIFY(!number.isObject());
+ QVERIFY(!number.engine());
+ QCOMPARE(tmp.toNumber(), number.toNumber());
+ }
+
+ QScriptValue str = QScriptValue(&eng, QString("ciao"));
+ {
+ QScriptValue tmp = eng.toObject(str);
+ QVERIFY(tmp.isObject());
+ QVERIFY(!str.isObject());
+ QCOMPARE(tmp.toString(), str.toString());
+ }
+
+ QScriptValue object = eng.evaluate("new Object");
+ {
+ QScriptValue tmp = eng.toObject(object);
+ QVERIFY(tmp.isObject());
+ QVERIFY(object.isObject());
+ QVERIFY(tmp.strictlyEquals(object));
+ }
+}
+
+void tst_QScriptEngine::toObjectTwoEngines()
+{
+ QScriptEngine engine1;
+ QScriptEngine engine2;
+
+ {
+ QScriptValue null = engine1.nullValue();
+ QTest::ignoreMessage(QtWarningMsg, "QScriptEngine::toObject: cannot convert value created in a different engine");
+ QVERIFY(!engine2.toObject(null).isValid());
+ QVERIFY(null.isValid());
+ QTest::ignoreMessage(QtWarningMsg, "QScriptEngine::toObject: cannot convert value created in a different engine");
+ QVERIFY(engine2.toObject(null).engine() != &engine2);
+ }
+ {
+ QScriptValue undefined = engine1.undefinedValue();
+ QTest::ignoreMessage(QtWarningMsg, "QScriptEngine::toObject: cannot convert value created in a different engine");
+ QVERIFY(!engine2.toObject(undefined).isValid());
+ QVERIFY(undefined.isValid());
+ QTest::ignoreMessage(QtWarningMsg, "QScriptEngine::toObject: cannot convert value created in a different engine");
+ QVERIFY(engine2.toObject(undefined).engine() != &engine2);
+ }
+ {
+ QScriptValue value = engine1.evaluate("1");
+ QTest::ignoreMessage(QtWarningMsg, "QScriptEngine::toObject: cannot convert value created in a different engine");
+ QVERIFY(engine2.toObject(value).engine() != &engine2);
+ QVERIFY(!value.isObject());
+ }
+ {
+ QScriptValue string = engine1.evaluate("'Qt'");
+ QTest::ignoreMessage(QtWarningMsg, "QScriptEngine::toObject: cannot convert value created in a different engine");
+ QVERIFY(engine2.toObject(string).engine() != &engine2);
+ QVERIFY(!string.isObject());
+ }
+ {
+ QScriptValue object = engine1.evaluate("new Object");
+ QTest::ignoreMessage(QtWarningMsg, "QScriptEngine::toObject: cannot convert value created in a different engine");
+ QVERIFY(engine2.toObject(object).engine() != &engine2);
+ QVERIFY(object.isObject());
+ }
+}
+
+void tst_QScriptEngine::newArray()
+{
+ QScriptEngine eng;
+ QScriptValue array = eng.newArray();
+ QCOMPARE(array.isValid(), true);
+ QCOMPARE(array.isArray(), true);
+ QCOMPARE(array.isObject(), true);
+ QVERIFY(!array.isFunction());
+ // QCOMPARE(array.scriptClass(), (QScriptClass*)0);
+
+ // Prototype should be Array.prototype.
+ QCOMPARE(array.prototype().isValid(), true);
+ QCOMPARE(array.prototype().isArray(), true);
+ QCOMPARE(array.prototype().strictlyEquals(eng.evaluate("Array.prototype")), true);
+
+ QScriptValue arrayWithSize = eng.newArray(42);
+ QCOMPARE(arrayWithSize.isValid(), true);
+ QCOMPARE(arrayWithSize.isArray(), true);
+ QCOMPARE(arrayWithSize.isObject(), true);
+ QCOMPARE(arrayWithSize.property("length").toInt32(), 42);
+
+ // task 218092
+ {
+ QScriptValue ret = eng.evaluate("[].splice(0, 0, 'a')");
+ QVERIFY(ret.isArray());
+ QCOMPARE(ret.property("length").toInt32(), 0);
+ }
+ {
+ QScriptValue ret = eng.evaluate("['a'].splice(0, 1, 'b')");
+ QVERIFY(ret.isArray());
+ QCOMPARE(ret.property("length").toInt32(), 1);
+ }
+ {
+ QScriptValue ret = eng.evaluate("['a', 'b'].splice(0, 1, 'c')");
+ QVERIFY(ret.isArray());
+ QCOMPARE(ret.property("length").toInt32(), 1);
+ }
+ {
+ QScriptValue ret = eng.evaluate("['a', 'b', 'c'].splice(0, 2, 'd')");
+ QVERIFY(ret.isArray());
+ QCOMPARE(ret.property("length").toInt32(), 2);
+ }
+ {
+ QScriptValue ret = eng.evaluate("['a', 'b', 'c'].splice(1, 2, 'd', 'e', 'f')");
+ QVERIFY(ret.isArray());
+ QCOMPARE(ret.property("length").toInt32(), 2);
+ }
+}
+
+void tst_QScriptEngine::uncaughtException()
+{
+ QScriptEngine eng;
+ QScriptValue fun = eng.evaluate("(function foo () { return null; });");
+ QVERIFY(!eng.uncaughtException().isValid());
+ QVERIFY(fun.isFunction());
+ QScriptValue throwFun = eng.evaluate("( function() { throw new Error('Pong'); });");
+ QVERIFY(throwFun.isFunction());
+ {
+ eng.evaluate("a = 10");
+ QVERIFY(!eng.hasUncaughtException());
+ QVERIFY(!eng.uncaughtException().isValid());
+ }
+ {
+ eng.evaluate("1 = 2");
+ QVERIFY(eng.hasUncaughtException());
+ eng.clearExceptions();
+ QVERIFY(!eng.hasUncaughtException());
+ }
+ {
+ // Check if the call or toString functions can remove the last exception.
+ QVERIFY(throwFun.call().isError());
+ QVERIFY(eng.hasUncaughtException());
+ QScriptValue exception = eng.uncaughtException();
+ fun.call();
+ exception.toString();
+ QVERIFY(eng.hasUncaughtException());
+ QVERIFY(eng.uncaughtException().strictlyEquals(exception));
+ }
+ eng.clearExceptions();
+ {
+ // Check if in the call function a new exception can override an existing one.
+ throwFun.call();
+ QVERIFY(eng.hasUncaughtException());
+ QScriptValue exception = eng.uncaughtException();
+ throwFun.call();
+ QVERIFY(eng.hasUncaughtException());
+ QVERIFY(!exception.strictlyEquals(eng.uncaughtException()));
+ }
+ {
+ eng.evaluate("throwFun = (function foo () { throw new Error('bla') });");
+ eng.evaluate("1;\nthrowFun();");
+ QVERIFY(eng.hasUncaughtException());
+ QCOMPARE(eng.uncaughtExceptionLineNumber(), 1);
+ eng.clearExceptions();
+ QVERIFY(!eng.hasUncaughtException());
+ }
+ for (int x = 1; x < 4; ++x) {
+ QScriptValue ret = eng.evaluate("a = 10;\nb = 20;\n0 = 0;\n",
+ QString::fromLatin1("FooScript") + QString::number(x),
+ /* lineNumber */ x);
+ QVERIFY(eng.hasUncaughtException());
+ QCOMPARE(eng.uncaughtExceptionLineNumber(), x + 2);
+ QVERIFY(eng.uncaughtException().strictlyEquals(ret));
+ QVERIFY(eng.hasUncaughtException());
+ QVERIFY(eng.uncaughtException().strictlyEquals(ret));
+ QString backtrace = QString::fromLatin1("<anonymous>()@FooScript") + QString::number(x) + ":" + QString::number(x + 2);
+ QCOMPARE(eng.uncaughtExceptionBacktrace().join(""), backtrace);
+ QVERIFY(fun.call().isNull());
+ QVERIFY(eng.hasUncaughtException());
+ QCOMPARE(eng.uncaughtExceptionLineNumber(), x + 2);
+ QVERIFY(eng.uncaughtException().strictlyEquals(ret));
+ eng.clearExceptions();
+ QVERIFY(!eng.hasUncaughtException());
+ QCOMPARE(eng.uncaughtExceptionLineNumber(), -1);
+ QVERIFY(!eng.uncaughtException().isValid());
+ eng.evaluate("2 = 3");
+ QVERIFY(eng.hasUncaughtException());
+ QScriptValue ret2 = throwFun.call();
+ QVERIFY(ret2.isError());
+ QVERIFY(eng.hasUncaughtException());
+ QVERIFY(eng.uncaughtException().strictlyEquals(ret2));
+ QCOMPARE(eng.uncaughtExceptionLineNumber(), 1);
+ eng.clearExceptions();
+ QVERIFY(!eng.hasUncaughtException());
+ eng.evaluate("1 + 2");
+ QVERIFY(!eng.hasUncaughtException());
+ }
+}
+
+void tst_QScriptEngine::newDate()
+{
+ QScriptEngine eng;
+ {
+ QScriptValue date = eng.newDate(0);
+ QCOMPARE(date.isValid(), true);
+ QCOMPARE(date.isDate(), true);
+ QCOMPARE(date.isObject(), true);
+ QVERIFY(!date.isFunction());
+ // prototype should be Date.prototype
+ QCOMPARE(date.prototype().isValid(), true);
+ QCOMPARE(date.prototype().isDate(), true);
+ QCOMPARE(date.prototype().strictlyEquals(eng.evaluate("Date.prototype")), true);
+ }
+ {
+ QDateTime dt = QDateTime(QDate(1, 2, 3), QTime(4, 5, 6, 7), Qt::LocalTime);
+ QScriptValue date = eng.newDate(dt);
+ QCOMPARE(date.isValid(), true);
+ QCOMPARE(date.isDate(), true);
+ QCOMPARE(date.isObject(), true);
+ // prototype should be Date.prototype
+ QCOMPARE(date.prototype().isValid(), true);
+ QCOMPARE(date.prototype().isDate(), true);
+ QCOMPARE(date.prototype().strictlyEquals(eng.evaluate("Date.prototype")), true);
+
+ QCOMPARE(date.toDateTime(), dt);
+ }
+ {
+ QDateTime dt = QDateTime(QDate(1, 2, 3), QTime(4, 5, 6, 7), Qt::UTC);
+ QScriptValue date = eng.newDate(dt);
+ // toDateTime() result should be in local time
+ QCOMPARE(date.toDateTime(), dt.toLocalTime());
+ }
+ // Date.parse() should return NaN when it fails
+ {
+ QScriptValue ret = eng.evaluate("Date.parse()");
+ QVERIFY(ret.isNumber());
+ QVERIFY(qIsNaN(ret.toNumber()));
+ }
+ // Date.parse() should be able to parse the output of Date().toString()
+ {
+ QScriptValue ret = eng.evaluate("var x = new Date(); var s = x.toString(); s == new Date(Date.parse(s)).toString()");
+ QVERIFY(ret.isBoolean());
+ QCOMPARE(ret.toBoolean(), true);
+ }
+}
QTEST_MAIN(tst_QScriptEngine)
#include "tst_qscriptengine.moc"
SOURCES += \
tst_qscriptvalue.cpp \
- tst_qscriptvalue_generated.cpp
+ tst_qscriptvalue_generated_init.cpp \
+ tst_qscriptvalue_generated_comparison.cpp \
+ tst_qscriptvalue_generated_istype.cpp \
+ tst_qscriptvalue_generated_totype.cpp \
HEADERS += \
tst_qscriptvalue.h
#include <QtCore/qnumeric.h>
tst_QScriptValue::tst_QScriptValue()
- : engine(0)
+ : m_engine(0)
{
}
tst_QScriptValue::~tst_QScriptValue()
{
- delete engine;
+ delete m_engine;
}
-void tst_QScriptValue::dataHelper(InitDataFunction init, DefineDataFunction define)
-{
- QTest::addColumn<QString>("__expression__");
- (this->*init)();
- QHash<QString, QScriptValue>::const_iterator it;
- for (it = m_values.constBegin(); it != m_values.constEnd(); ++it) {
- m_currentExpression = it.key();
- (this->*define)(it.key().toLatin1());
- }
- m_currentExpression = QString();
-}
-
-QTestData& tst_QScriptValue::newRow(const char* tag)
-{
- return QTest::newRow(tag) << m_currentExpression;
-}
-
-void tst_QScriptValue::testHelper(TestFunction fun)
-{
- QFETCH(QString, __expression__);
- QScriptValue value = m_values.value(__expression__);
- (this->*fun)(__expression__.toLatin1(), value);
-}
-
-
void tst_QScriptValue::ctor()
{
QScriptEngine eng;
QVERIFY(QScriptValue(0, QString("ciao")).isString());
}
+void tst_QScriptValue::getPropertySimple_data()
+{
+ QTest::addColumn<QString>("code");
+ QTest::addColumn<QString>("propertyName");
+ QTest::addColumn<QString>("desc");
+ QTest::addColumn<bool>("isArrayIndex");
+
+ QTest::newRow("new Array()")
+ << QString::fromAscii("new Array()")
+ << QString::fromAscii("length")
+ << QString::fromAscii("0")
+ << false;
+ QTest::newRow("new Object().length")
+ << QString::fromAscii("new Object()")
+ << QString::fromAscii("length")
+ << QString::fromAscii("") // Undefined is an invalid property.
+ << false;
+ QTest::newRow("new Object().toString")
+ << QString::fromAscii("new Object()")
+ << QString::fromAscii("toString")
+ << QString::fromAscii("function toString() {\n [native code]\n}")
+ << false;
+ QTest::newRow("[1,2,3,4]")
+ << QString::fromAscii("[1,2,3,'s',4]")
+ << QString::fromAscii("2")
+ << QString::fromAscii("3")
+ << true;
+ QTest::newRow("[1,3,'a','b']")
+ << QString::fromAscii("[1,3,'a','b']")
+ << QString::fromAscii("3")
+ << QString::fromAscii("b")
+ << true;
+ QTest::newRow("[4,5]")
+ << QString::fromAscii("[4,5]")
+ << QString::fromAscii("123")
+ << QString::fromAscii("") // Undefined is an invalid property.
+ << true;
+ QTest::newRow("[1,3,4]")
+ << QString::fromAscii("[1,3,4]")
+ << QString::fromAscii("abc")
+ << QString::fromAscii("") // Undefined is an invalid property.
+ << true;
+}
+
+void tst_QScriptValue::getPropertySimple()
+{
+ QFETCH(QString, code);
+ QFETCH(QString, propertyName);
+ QFETCH(QString, desc);
+
+ QScriptEngine engine;
+ QScriptValue object = engine.evaluate(code);
+ QVERIFY(object.isValid());
+ {
+ QScriptValue property = object.property(propertyName);
+ QCOMPARE(property.toString(), desc);
+ }
+ {
+ QScriptString name = engine.toStringHandle(propertyName);
+ QScriptValue property = object.property(name);
+ QCOMPARE(property.toString(), desc);
+ }
+ {
+ bool ok;
+ quint32 idx = engine.toStringHandle(propertyName).toArrayIndex(&ok);
+ if (ok) {
+ QScriptValue property = object.property(idx);
+ QCOMPARE(property.toString(), desc);
+ }
+ }
+}
+
+void tst_QScriptValue::setPropertySimple()
+{
+ QScriptEngine engine;
+ {
+ QScriptValue invalid;
+ QScriptValue property(1234);
+
+ invalid.setProperty("aaa", property);
+ invalid.setProperty(13, property);
+ invalid.setProperty(engine.toStringHandle("aaa"), property);
+
+ QVERIFY(!invalid.property("aaa").isValid());
+ QVERIFY(!invalid.property(13).isValid());
+ QVERIFY(!invalid.property(engine.toStringHandle("aaa")).isValid());
+ }
+ {
+ QScriptValue object = engine.newObject();
+ QScriptValue property;
+
+ object.setProperty(13, property);
+ object.setProperty("aaa", property);
+ object.setProperty(engine.toStringHandle("aaa"), property);
+
+ QVERIFY(!object.property(13).isValid());
+ QVERIFY(!object.property("aaa").isValid());
+ QVERIFY(!object.property(engine.toStringHandle("aaa")).isValid());
+ }
+ {
+ // Check if setting an invalid property works as deleteProperty.
+ QScriptValue object = engine.evaluate("o = {13: 0, 'aaa': 3, 'bbb': 1}");
+ QScriptValue property;
+
+ QVERIFY(object.property(13).isValid());
+ QVERIFY(object.property("aaa").isValid());
+ QVERIFY(object.property(engine.toStringHandle("aaa")).isValid());
+
+ object.setProperty(13, property);
+ object.setProperty("aaa", property);
+ object.setProperty(engine.toStringHandle("bbb"), property);
+
+ QVERIFY(!object.property(13).isValid());
+ QVERIFY(!object.property("aaa").isValid());
+ QVERIFY(!object.property(engine.toStringHandle("aaa")).isValid());
+ }
+ {
+ QScriptValue object = engine.evaluate("new Object");
+ QVERIFY(object.isObject());
+ QScriptValue property = object.property("foo");
+ QVERIFY(!property.isValid());
+ property = QScriptValue(2);
+ object.setProperty("foo", property);
+ QVERIFY(object.property("foo").isNumber());
+ QVERIFY(object.property("foo").toNumber() == 2);
+ }
+ {
+ QScriptValue o1 = engine.evaluate("o1 = new Object; o1");
+ QScriptValue o2 = engine.evaluate("o2 = new Object; o2");
+ QVERIFY(engine.evaluate("o1.__proto__ = o2; o1.__proto__ === o2").toBool());
+ QVERIFY(engine.evaluate("o2.foo = 22; o1.foo == 22").toBool());
+ QVERIFY(o1.property("foo").toString() == "22");
+ o2.setProperty("foo", QScriptValue(&engine, 456.0));
+ QVERIFY(engine.evaluate("o1.foo == 456").toBool());
+ QVERIFY(o1.property("foo").isNumber());
+ }
+}
+
+void tst_QScriptValue::getPropertyResolveFlag()
+{
+ QScriptEngine engine;
+ QScriptValue object1 = engine.evaluate("o1 = new Object();");
+ QScriptValue object2 = engine.evaluate("o2 = new Object(); o1.__proto__ = o2; o2");
+ QScriptValue number(&engine, 456.0);
+ QVERIFY(object1.isObject());
+ QVERIFY(object2.isObject());
+ QVERIFY(number.isNumber());
+
+ object2.setProperty("propertyInPrototype", number);
+ QVERIFY(object2.property("propertyInPrototype").isNumber());
+ // default is ResolvePrototype
+ QCOMPARE(object1.property("propertyInPrototype").strictlyEquals(number), true);
+ QCOMPARE(object1.property("propertyInPrototype", QScriptValue::ResolvePrototype)
+ .strictlyEquals(number), true);
+ QCOMPARE(object1.property("propertyInPrototype", QScriptValue::ResolveLocal).isValid(), false);
+}
+
+void tst_QScriptValue::getSetProperty()
+{
+ QScriptEngine eng;
+
+ QScriptValue object = eng.newObject();
+
+ QScriptValue str = QScriptValue(&eng, "bar");
+ object.setProperty("foo", str);
+ QCOMPARE(object.property("foo").toString(), str.toString());
+
+ QScriptValue num = QScriptValue(&eng, 123.0);
+ object.setProperty("baz", num);
+ QCOMPARE(object.property("baz").toNumber(), num.toNumber());
+
+ QScriptValue strstr = QScriptValue("bar");
+ QCOMPARE(strstr.engine(), (QScriptEngine *)0);
+ object.setProperty("foo", strstr);
+ QCOMPARE(object.property("foo").toString(), strstr.toString());
+ QCOMPARE(strstr.engine(), &eng); // the value has been bound to the engine
+
+ QScriptValue numnum = QScriptValue(123.0);
+ object.setProperty("baz", numnum);
+ QCOMPARE(object.property("baz").toNumber(), numnum.toNumber());
+
+ QScriptValue inv;
+ inv.setProperty("foo", num);
+ QCOMPARE(inv.property("foo").isValid(), false);
+
+ QScriptValue array = eng.newArray();
+ array.setProperty(0, num);
+ QCOMPARE(array.property(0).toNumber(), num.toNumber());
+ QCOMPARE(array.property("0").toNumber(), num.toNumber());
+ QCOMPARE(array.property("length").toUInt32(), quint32(1));
+ array.setProperty(1, str);
+ QCOMPARE(array.property(1).toString(), str.toString());
+ QCOMPARE(array.property("1").toString(), str.toString());
+ QCOMPARE(array.property("length").toUInt32(), quint32(2));
+ array.setProperty("length", QScriptValue(&eng, 1));
+ QCOMPARE(array.property("length").toUInt32(), quint32(1));
+ QCOMPARE(array.property(1).isValid(), false);
+
+ // task 162051 -- detecting whether the property is an array index or not
+ QVERIFY(eng.evaluate("a = []; a['00'] = 123; a['00']").strictlyEquals(QScriptValue(&eng, 123)));
+ QVERIFY(eng.evaluate("a.length").strictlyEquals(QScriptValue(&eng, 0)));
+ QVERIFY(eng.evaluate("a.hasOwnProperty('00')").strictlyEquals(QScriptValue(&eng, true)));
+ QVERIFY(eng.evaluate("a.hasOwnProperty('0')").strictlyEquals(QScriptValue(&eng, false)));
+ QVERIFY(eng.evaluate("a[0]").isUndefined());
+ QVERIFY(eng.evaluate("a[0.5] = 456; a[0.5]").strictlyEquals(QScriptValue(&eng, 456)));
+ QVERIFY(eng.evaluate("a.length").strictlyEquals(QScriptValue(&eng, 0)));
+ QVERIFY(eng.evaluate("a.hasOwnProperty('0.5')").strictlyEquals(QScriptValue(&eng, true)));
+ QVERIFY(eng.evaluate("a[0]").isUndefined());
+ QVERIFY(eng.evaluate("a[0] = 789; a[0]").strictlyEquals(QScriptValue(&eng, 789)));
+ QVERIFY(eng.evaluate("a.length").strictlyEquals(QScriptValue(&eng, 1)));
+
+ // task 183072 -- 0x800000000 is not an array index
+ eng.evaluate("a = []; a[0x800000000] = 123");
+ QVERIFY(eng.evaluate("a.length").strictlyEquals(QScriptValue(&eng, 0)));
+ QVERIFY(eng.evaluate("a[0]").isUndefined());
+ QVERIFY(eng.evaluate("a[0x800000000]").strictlyEquals(QScriptValue(&eng, 123)));
+
+ QScriptEngine otherEngine;
+ QScriptValue otherNum = QScriptValue(&otherEngine, 123);
+ QTest::ignoreMessage(QtWarningMsg, "QScriptValue::setProperty() failed: cannot set value created in a different engine");
+ object.setProperty("oof", otherNum);
+ QCOMPARE(object.property("oof").isValid(), false);
+
+ // test ResolveMode
+ QScriptValue object2 = eng.newObject();
+ object.setPrototype(object2);
+ QScriptValue num2 = QScriptValue(&eng, 456.0);
+ object2.setProperty("propertyInPrototype", num2);
+ // default is ResolvePrototype
+ QCOMPARE(object.property("propertyInPrototype")
+ .strictlyEquals(num2), true);
+ QCOMPARE(object.property("propertyInPrototype", QScriptValue::ResolvePrototype)
+ .strictlyEquals(num2), true);
+ QCOMPARE(object.property("propertyInPrototype", QScriptValue::ResolveLocal)
+ .isValid(), false);
+ QEXPECT_FAIL("", "QScriptValue::ResolveScope is not implemented", Continue);
+ QCOMPARE(object.property("propertyInPrototype", QScriptValue::ResolveScope)
+ .strictlyEquals(num2), false);
+ QCOMPARE(object.property("propertyInPrototype", QScriptValue::ResolveFull)
+ .strictlyEquals(num2), true);
+
+ // test property removal (setProperty(QScriptValue()))
+ QScriptValue object3 = eng.newObject();
+ object3.setProperty("foo", num);
+ QCOMPARE(object3.property("foo").strictlyEquals(num), true);
+ object3.setProperty("bar", str);
+ QCOMPARE(object3.property("bar").strictlyEquals(str), true);
+ object3.setProperty("foo", QScriptValue());
+ QCOMPARE(object3.property("foo").isValid(), false);
+ QCOMPARE(object3.property("bar").strictlyEquals(str), true);
+ object3.setProperty("foo", num);
+ QCOMPARE(object3.property("foo").strictlyEquals(num), true);
+ QCOMPARE(object3.property("bar").strictlyEquals(str), true);
+ object3.setProperty("bar", QScriptValue());
+ QCOMPARE(object3.property("bar").isValid(), false);
+ QCOMPARE(object3.property("foo").strictlyEquals(num), true);
+ object3.setProperty("foo", QScriptValue());
+ object3.setProperty("foo", QScriptValue());
+
+ eng.globalObject().setProperty("object3", object3);
+ QCOMPARE(eng.evaluate("object3.hasOwnProperty('foo')")
+ .strictlyEquals(QScriptValue(&eng, false)), true);
+ object3.setProperty("foo", num);
+ QCOMPARE(eng.evaluate("object3.hasOwnProperty('foo')")
+ .strictlyEquals(QScriptValue(&eng, true)), true);
+ eng.globalObject().setProperty("object3", QScriptValue());
+ QCOMPARE(eng.evaluate("this.hasOwnProperty('object3')")
+ .strictlyEquals(QScriptValue(&eng, false)), true);
+
+ eng.globalObject().setProperty("object", object);
+
+ // ReadOnly
+ object.setProperty("readOnlyProperty", num, QScriptValue::ReadOnly);
+ // QCOMPARE(object.propertyFlags("readOnlyProperty"), QScriptValue::ReadOnly);
+ QCOMPARE(object.property("readOnlyProperty").strictlyEquals(num), true);
+ eng.evaluate("object.readOnlyProperty = !object.readOnlyProperty");
+ QCOMPARE(object.property("readOnlyProperty").strictlyEquals(num), true);
+ // Should still be part of enumeration.
+ {
+ QScriptValue ret = eng.evaluate(
+ "found = false;"
+ "for (var p in object) {"
+ " if (p == 'readOnlyProperty') {"
+ " found = true; break;"
+ " }"
+ "} found");
+ QCOMPARE(ret.strictlyEquals(QScriptValue(&eng, true)), true);
+ }
+ // should still be deletable
+ {
+ QScriptValue ret = eng.evaluate("delete object.readOnlyProperty");
+ QCOMPARE(ret.strictlyEquals(QScriptValue(&eng, true)), true);
+ QCOMPARE(object.property("readOnlyProperty").isValid(), false);
+ }
+
+ // Undeletable
+ object.setProperty("undeletableProperty", num, QScriptValue::Undeletable);
+ // QCOMPARE(object.propertyFlags("undeletableProperty"), QScriptValue::Undeletable);
+ QCOMPARE(object.property("undeletableProperty").strictlyEquals(num), true);
+ {
+ QScriptValue ret = eng.evaluate("delete object.undeletableProperty");
+ QCOMPARE(ret.strictlyEquals(QScriptValue(&eng, true)), false);
+ QCOMPARE(object.property("undeletableProperty").strictlyEquals(num), true);
+ }
+ // should still be writable
+ eng.evaluate("object.undeletableProperty = object.undeletableProperty + 1");
+ QCOMPARE(object.property("undeletableProperty").toNumber(), num.toNumber() + 1);
+ // should still be part of enumeration
+ {
+ QScriptValue ret = eng.evaluate(
+ "found = false;"
+ "for (var p in object) {"
+ " if (p == 'undeletableProperty') {"
+ " found = true; break;"
+ " }"
+ "} found");
+ QCOMPARE(ret.strictlyEquals(QScriptValue(&eng, true)), true);
+ }
+ // should still be deletable from C++
+ object.setProperty("undeletableProperty", QScriptValue());
+ QEXPECT_FAIL("", "With JSC-based back-end, undeletable properties can't be deleted from C++", Continue);
+ QVERIFY(!object.property("undeletableProperty").isValid());
+ // QEXPECT_FAIL("", "With JSC-based back-end, undeletable properties can't be deleted from C++", Continue);
+ // QCOMPARE(object.propertyFlags("undeletableProperty"), 0);
+
+ // SkipInEnumeration
+ object.setProperty("dontEnumProperty", num, QScriptValue::SkipInEnumeration);
+ // QCOMPARE(object.propertyFlags("dontEnumProperty"), QScriptValue::SkipInEnumeration);
+ QCOMPARE(object.property("dontEnumProperty").strictlyEquals(num), true);
+ // should not be part of enumeration
+ {
+ QScriptValue ret = eng.evaluate(
+ "found = false;"
+ "for (var p in object) {"
+ " if (p == 'dontEnumProperty') {"
+ " found = true; break;"
+ " }"
+ "} found");
+ QCOMPARE(ret.strictlyEquals(QScriptValue(&eng, false)), true);
+ }
+ // should still be writable
+ eng.evaluate("object.dontEnumProperty = object.dontEnumProperty + 1");
+ QCOMPARE(object.property("dontEnumProperty").toNumber(), num.toNumber() + 1);
+ // should still be deletable
+ {
+ QScriptValue ret = eng.evaluate("delete object.dontEnumProperty");
+ QCOMPARE(ret.strictlyEquals(QScriptValue(&eng, true)), true);
+ QCOMPARE(object.property("dontEnumProperty").isValid(), false);
+ }
+
+ // change flags
+ object.setProperty("flagProperty", str);
+ // QCOMPARE(object.propertyFlags("flagProperty"), static_cast<QScriptValue::PropertyFlags>(0));
+
+ object.setProperty("flagProperty", str, QScriptValue::ReadOnly);
+ // QCOMPARE(object.propertyFlags("flagProperty"), QScriptValue::ReadOnly);
+
+ // object.setProperty("flagProperty", str, object.propertyFlags("flagProperty") | QScriptValue::SkipInEnumeration);
+ // QCOMPARE(object.propertyFlags("flagProperty"), QScriptValue::ReadOnly | QScriptValue::SkipInEnumeration);
+
+ object.setProperty("flagProperty", str, QScriptValue::KeepExistingFlags);
+ // QCOMPARE(object.propertyFlags("flagProperty"), QScriptValue::ReadOnly | QScriptValue::SkipInEnumeration);
+
+ object.setProperty("flagProperty", str, QScriptValue::UserRange);
+ // QCOMPARE(object.propertyFlags("flagProperty"), QScriptValue::UserRange);
+
+ // flags of property in the prototype
+ {
+ QScriptValue object2 = eng.newObject();
+ object2.setPrototype(object);
+ // QCOMPARE(object2.propertyFlags("flagProperty", QScriptValue::ResolveLocal), 0);
+ // QCOMPARE(object2.propertyFlags("flagProperty"), QScriptValue::UserRange);
+ }
+
+ // using interned strings
+ QScriptString foo = eng.toStringHandle("foo");
+
+ object.setProperty(foo, QScriptValue());
+ QVERIFY(!object.property(foo).isValid());
+
+ object.setProperty(foo, num);
+ QVERIFY(object.property(foo).strictlyEquals(num));
+ QVERIFY(object.property("foo").strictlyEquals(num));
+ // QVERIFY(object.propertyFlags(foo) == 0);
+}
+
void tst_QScriptValue::toStringSimple_data()
{
QTest::addColumn<QString>("code");
QVERIFY(incr.call().isValid()); // Exception.
}
+void tst_QScriptValue::getSetPrototype()
+{
+ QScriptEngine engine;
+ QScriptValue object = engine.evaluate("new Object()");
+ QScriptValue object2 = engine.evaluate("new Object()");
+ object2.setPrototype(object);
+ QCOMPARE(object2.prototype().strictlyEquals(object), true);
+
+ QScriptValue inv;
+ inv.setPrototype(object);
+ QCOMPARE(inv.prototype().isValid(), false);
+
+ QScriptEngine otherEngine;
+ QScriptValue object3 = otherEngine.evaluate("new Object()");
+ QTest::ignoreMessage(QtWarningMsg, "QScriptValue::setPrototype() failed: cannot set a prototype created in a different engine");
+ object2.setPrototype(object3);
+ QCOMPARE(object2.prototype().strictlyEquals(object), true);
+
+ // cyclic prototypes
+ {
+ QScriptValue ret = engine.evaluate("o = { }; p = { }; o.__proto__ = p; p.__proto__ = o");
+ QCOMPARE(ret.isError(), true);
+ QCOMPARE(ret.toString(), QLatin1String("Error: cyclic __proto__ value"));
+ }
+ {
+ QScriptValue ret = engine.evaluate("p.__proto__ = { }");
+ QCOMPARE(ret.isError(), false);
+ }
+
+ QScriptValue old = object.prototype();
+ QTest::ignoreMessage(QtWarningMsg, "QScriptValue::setPrototype() failed: cyclic prototype value");
+ object.setPrototype(object);
+ QCOMPARE(object.prototype().strictlyEquals(old), true);
+
+ object2.setPrototype(object);
+ QTest::ignoreMessage(QtWarningMsg, "QScriptValue::setPrototype() failed: cyclic prototype value");
+ object.setPrototype(object2);
+ QCOMPARE(object.prototype().strictlyEquals(old), true);
+}
+
+void tst_QScriptValue::toObjectSimple()
+{
+ QScriptEngine eng;
+
+ QScriptValue undefined = eng.undefinedValue();
+ QCOMPARE(undefined.toObject().isValid(), false);
+ QScriptValue null = eng.nullValue();
+ QCOMPARE(null.toObject().isValid(), false);
+ QCOMPARE(QScriptValue().toObject().isValid(), false);
+
+ QScriptValue falskt = QScriptValue(&eng, false);
+ {
+ QScriptValue tmp = falskt.toObject();
+ QCOMPARE(tmp.isObject(), true);
+ QCOMPARE(falskt.isObject(), false);
+ QCOMPARE(tmp.toNumber(), falskt.toNumber());
+ }
+
+ QScriptValue sant = QScriptValue(&eng, true);
+ {
+ QScriptValue tmp = sant.toObject();
+ QCOMPARE(tmp.isObject(), true);
+ QCOMPARE(sant.isObject(), false);
+ QCOMPARE(tmp.toNumber(), sant.toNumber());
+ }
+
+ QScriptValue number = QScriptValue(&eng, 123.0);
+ {
+ QScriptValue tmp = number.toObject();
+ QCOMPARE(tmp.isObject(), true);
+ QCOMPARE(number.isObject(), false);
+ QCOMPARE(tmp.toNumber(), number.toNumber());
+ }
+
+ QScriptValue str = QScriptValue(&eng, QString("ciao"));
+ {
+ QScriptValue tmp = str.toObject();
+ QCOMPARE(tmp.isObject(), true);
+ QCOMPARE(str.isObject(), false);
+ QCOMPARE(tmp.toString(), str.toString());
+ }
+
+
+ QScriptValue object = eng.evaluate("new Object");
+ {
+ QScriptValue tmp = object.toObject();
+ QVERIFY(tmp.strictlyEquals(object));
+ QCOMPARE(tmp.isObject(), true);
+ }
+
+
+ // V2 constructors: in this case, you have to use QScriptEngine::toObject()
+ {
+ QScriptValue undefined = QScriptValue(QScriptValue::UndefinedValue);
+ QVERIFY(!undefined.toObject().isValid());
+ QVERIFY(!eng.toObject(undefined).isValid());
+ QVERIFY(!undefined.engine());
+
+ QScriptValue null = QScriptValue(QScriptValue::NullValue);
+ QVERIFY(!null.toObject().isValid());
+ QVERIFY(!eng.toObject(null).isValid());
+ QVERIFY(!null.engine());
+
+ QScriptValue falskt = QScriptValue(false);
+ QVERIFY(!falskt.toObject().isValid());
+ QCOMPARE(falskt.isObject(), false);
+ QVERIFY(!falskt.engine());
+ {
+ QScriptValue tmp = eng.toObject(falskt);
+ QVERIFY(tmp.isObject());
+ QVERIFY(tmp.toBool());
+ QVERIFY(!falskt.isObject());
+ }
+
+ QScriptValue sant = QScriptValue(true);
+ QVERIFY(!sant.toObject().isValid());
+ QCOMPARE(sant.isObject(), false);
+ QVERIFY(!sant.engine());
+ {
+ QScriptValue tmp = eng.toObject(sant);
+ QVERIFY(tmp.isObject());
+ QVERIFY(tmp.toBool());
+ QVERIFY(!sant.isObject());
+ }
+
+ QScriptValue number = QScriptValue(123.0);
+ QVERIFY(!number.toObject().isValid());
+ QVERIFY(!number.engine());
+ QCOMPARE(number.isObject(), false);
+ {
+ QScriptValue tmp = eng.toObject(number);
+ QVERIFY(tmp.isObject());
+ QCOMPARE(tmp.toInt32(), number.toInt32());
+ QVERIFY(!number.isObject());
+ }
+
+ QScriptValue str = QScriptValue(QString::fromLatin1("ciao"));
+ QVERIFY(!str.toObject().isValid());
+ QVERIFY(!str.engine());
+ QCOMPARE(str.isObject(), false);
+ {
+ QScriptValue tmp = eng.toObject(str);
+ QVERIFY(tmp.isObject());
+ QCOMPARE(tmp.toString(), QString::fromLatin1("ciao"));
+ QVERIFY(!str.isObject());
+ }
+ }
+}
+
+void tst_QScriptValue::setProperty_data()
+{
+ QTest::addColumn<QScriptValue>("property");
+ QTest::addColumn<int>("flag");
+
+ QTest::newRow("int + keepExistingFlags") << QScriptValue(123456) << static_cast<int>(QScriptValue::KeepExistingFlags);
+ QTest::newRow("int + undeletable") << QScriptValue(123456) << static_cast<int>(QScriptValue::Undeletable);
+ QTest::newRow("int + readOnly") << QScriptValue(123456) << static_cast<int>(QScriptValue::ReadOnly);
+ QTest::newRow("int + readOnly|undeletable") << QScriptValue(123456) << static_cast<int>(QScriptValue::ReadOnly | QScriptValue::Undeletable);
+ QTest::newRow("int + skipInEnumeration") << QScriptValue(123456) << static_cast<int>(QScriptValue::SkipInEnumeration);
+ QTest::newRow("int + skipInEnumeration|readOnly") << QScriptValue(123456) << static_cast<int>(QScriptValue::SkipInEnumeration | QScriptValue::ReadOnly);
+ QTest::newRow("int + skipInEnumeration|undeletable") << QScriptValue(123456) << static_cast<int>(QScriptValue::SkipInEnumeration | QScriptValue::Undeletable);
+ QTest::newRow("int + skipInEnumeration|readOnly|undeletable") << QScriptValue(123456) << static_cast<int>(QScriptValue::SkipInEnumeration | QScriptValue::ReadOnly | QScriptValue::Undeletable);
+}
+
+void tst_QScriptValue::setProperty()
+{
+ QFETCH(QScriptValue, property);
+ QFETCH(int, flag);
+ QScriptValue::PropertyFlags flags = static_cast<QScriptValue::PropertyFlag>(flag);
+
+ QScriptEngine engine;
+ QScriptValue object = engine.evaluate("o = new Object; o");
+ QScriptValue proto = engine.evaluate("p = new Object; o.__proto__ = p; p");
+ engine.evaluate("o.defined1 = 1");
+ engine.evaluate("o.defined2 = 1");
+ engine.evaluate("o[5] = 1");
+ engine.evaluate("p.overloaded1 = 1");
+ engine.evaluate("o.overloaded1 = 2");
+ engine.evaluate("p[6] = 1");
+ engine.evaluate("o[6] = 2");
+ engine.evaluate("p.overloaded2 = 1");
+ engine.evaluate("o.overloaded2 = 2");
+ engine.evaluate("p.overloaded3 = 1");
+ engine.evaluate("o.overloaded3 = 2");
+ engine.evaluate("p[7] = 1");
+ engine.evaluate("o[7] = 2");
+ engine.evaluate("p.overloaded4 = 1");
+ engine.evaluate("o.overloaded4 = 2");
+
+ // tries to set undefined property directly on object.
+ object.setProperty(QString::fromAscii("undefined1"), property, flags);
+ QVERIFY(engine.evaluate("o.undefined1").strictlyEquals(property));
+ object.setProperty(engine.toStringHandle("undefined2"), property, flags);
+ QVERIFY(object.property("undefined2").strictlyEquals(property));
+ object.setProperty(4, property, flags);
+ QVERIFY(object.property(4).strictlyEquals(property));
+
+ // tries to set defined property directly on object
+ object.setProperty("defined1", property, flags);
+ QVERIFY(engine.evaluate("o.defined1").strictlyEquals(property));
+ object.setProperty(engine.toStringHandle("defined2"), property, flags);
+ QVERIFY(object.property("defined2").strictlyEquals(property));
+ object.setProperty(5, property, flags);
+ QVERIFY(object.property(5).strictlyEquals(property));
+
+ // tries to set overloaded property directly on object
+ object.setProperty("overloaded1", property, flags);
+ QVERIFY(engine.evaluate("o.overloaded1").strictlyEquals(property));
+ object.setProperty(engine.toStringHandle("overloaded2"), property, flags);
+ QVERIFY(object.property("overloaded2").strictlyEquals(property));
+ object.setProperty(6, property, flags);
+ QVERIFY(object.property(6).strictlyEquals(property));
+
+ // tries to set overloaded property directly on prototype
+ proto.setProperty("overloaded3", property, flags);
+ QVERIFY(!engine.evaluate("o.overloaded3").strictlyEquals(property));
+ proto.setProperty(engine.toStringHandle("overloaded4"), property, flags);
+ QVERIFY(!object.property("overloaded4").strictlyEquals(property));
+ proto.setProperty(7, property, flags);
+ QVERIFY(!object.property(7).strictlyEquals(property));
+
+ // tries to set undefined property directly on prototype
+ proto.setProperty("undefined3", property, flags);
+ QVERIFY(engine.evaluate("o.undefined3").strictlyEquals(property));
+ proto.setProperty(engine.toStringHandle("undefined4"), property, flags);
+ QVERIFY(object.property("undefined4").strictlyEquals(property));
+ proto.setProperty(8, property, flags);
+ QVERIFY(object.property(8).strictlyEquals(property));
+
+ bool readOnly = flags & QScriptValue::ReadOnly;
+ bool skipInEnumeration = flags & QScriptValue::SkipInEnumeration;
+ bool undeletable = flags & QScriptValue::Undeletable;
+
+ QVERIFY(readOnly == engine.evaluate("!Object.getOwnPropertyDescriptor(o, '4').writable").toBool());
+ QEXPECT_FAIL("int + readOnly", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QVERIFY(readOnly == engine.evaluate("!Object.getOwnPropertyDescriptor(o, '5').writable").toBool());
+ QEXPECT_FAIL("int + readOnly", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QVERIFY(readOnly == engine.evaluate("!Object.getOwnPropertyDescriptor(o, '6').writable").toBool());
+ QEXPECT_FAIL("int + readOnly", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QVERIFY(readOnly == engine.evaluate("!Object.getOwnPropertyDescriptor(p, '7').writable").toBool());
+ QVERIFY(readOnly == engine.evaluate("!Object.getOwnPropertyDescriptor(p, '8').writable").toBool());
+ QVERIFY(readOnly == engine.evaluate("!Object.getOwnPropertyDescriptor(o, 'undefined1').writable").toBool());
+ QVERIFY(readOnly == engine.evaluate("!Object.getOwnPropertyDescriptor(o, 'undefined2').writable").toBool());
+ QVERIFY(readOnly == engine.evaluate("!Object.getOwnPropertyDescriptor(p, 'undefined3').writable").toBool());
+ QVERIFY(readOnly == engine.evaluate("!Object.getOwnPropertyDescriptor(p, 'undefined4').writable").toBool());
+ QEXPECT_FAIL("int + readOnly", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QVERIFY(readOnly == engine.evaluate("!Object.getOwnPropertyDescriptor(o, 'defined1').writable").toBool());
+ QEXPECT_FAIL("int + readOnly", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QVERIFY(readOnly == engine.evaluate("!Object.getOwnPropertyDescriptor(o, 'defined2').writable").toBool());
+ QVERIFY(engine.evaluate("!Object.getOwnPropertyDescriptor(p, 'undefined1').writable").toBool());
+ QVERIFY(engine.evaluate("!Object.getOwnPropertyDescriptor(p, 'undefined1').writable").toBool());
+ QEXPECT_FAIL("int + readOnly", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QVERIFY(readOnly == engine.evaluate("!Object.getOwnPropertyDescriptor(p, 'overloaded3').writable").toBool());
+ QEXPECT_FAIL("int + readOnly", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QVERIFY(readOnly == engine.evaluate("!Object.getOwnPropertyDescriptor(p, 'overloaded4').writable").toBool());
+ QEXPECT_FAIL("int + readOnly", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QVERIFY(readOnly == engine.evaluate("!Object.getOwnPropertyDescriptor(o, 'overloaded1').writable").toBool());
+ QEXPECT_FAIL("int + readOnly", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QVERIFY(readOnly == engine.evaluate("!Object.getOwnPropertyDescriptor(o, 'overloaded2').writable").toBool());
+ QVERIFY(!engine.evaluate("!Object.getOwnPropertyDescriptor(o, 'overloaded3').writable").toBool());
+ QVERIFY(!engine.evaluate("!Object.getOwnPropertyDescriptor(o, 'overloaded4').writable").toBool());
+
+ QVERIFY(undeletable == engine.evaluate("!Object.getOwnPropertyDescriptor(o, '4').configurable").toBool());
+ QEXPECT_FAIL("int + undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QVERIFY(undeletable == engine.evaluate("!Object.getOwnPropertyDescriptor(o, '5').configurable").toBool());
+ QEXPECT_FAIL("int + undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QVERIFY(undeletable == engine.evaluate("!Object.getOwnPropertyDescriptor(o, '6').configurable").toBool());
+ QEXPECT_FAIL("int + undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QVERIFY(undeletable == engine.evaluate("!Object.getOwnPropertyDescriptor(p, '7').configurable").toBool());
+ QVERIFY(undeletable == engine.evaluate("!Object.getOwnPropertyDescriptor(p, '8').configurable").toBool());
+ QVERIFY(undeletable == engine.evaluate("!Object.getOwnPropertyDescriptor(o, 'undefined1').configurable").toBool());
+ QVERIFY(undeletable == engine.evaluate("!Object.getOwnPropertyDescriptor(o, 'undefined2').configurable").toBool());
+ QVERIFY(undeletable == engine.evaluate("!Object.getOwnPropertyDescriptor(p, 'undefined3').configurable").toBool());
+ QVERIFY(undeletable == engine.evaluate("!Object.getOwnPropertyDescriptor(p, 'undefined4').configurable").toBool());
+ QEXPECT_FAIL("int + undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QVERIFY(undeletable == engine.evaluate("!Object.getOwnPropertyDescriptor(o, 'defined1').configurable").toBool());
+ QEXPECT_FAIL("int + undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QVERIFY(undeletable == engine.evaluate("!Object.getOwnPropertyDescriptor(o, 'defined2').configurable").toBool());
+ QEXPECT_FAIL("int + undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QVERIFY(undeletable == engine.evaluate("!Object.getOwnPropertyDescriptor(o, 'overloaded1').configurable").toBool());
+ QEXPECT_FAIL("int + undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QVERIFY(undeletable == engine.evaluate("!Object.getOwnPropertyDescriptor(o, 'overloaded2').configurable").toBool());
+ QVERIFY(engine.evaluate("Object.getOwnPropertyDescriptor(p, 'overloaded1').configurable").toBool());
+ QVERIFY(engine.evaluate("Object.getOwnPropertyDescriptor(p, 'overloaded2').configurable").toBool());
+ QVERIFY(engine.evaluate("Object.getOwnPropertyDescriptor(o, 'overloaded3').configurable").toBool());
+ QVERIFY(engine.evaluate("Object.getOwnPropertyDescriptor(o, 'overloaded4').configurable").toBool());
+ QEXPECT_FAIL("int + undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QVERIFY(undeletable == engine.evaluate("!Object.getOwnPropertyDescriptor(p, 'overloaded3').configurable").toBool());
+ QEXPECT_FAIL("int + undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QVERIFY(undeletable == engine.evaluate("!Object.getOwnPropertyDescriptor(p, 'overloaded4').configurable").toBool());
+
+ QVERIFY(skipInEnumeration != engine.evaluate("Object.getOwnPropertyDescriptor(o, '4').enumerable").toBool());
+ QEXPECT_FAIL("int + skipInEnumeration", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QVERIFY(skipInEnumeration != engine.evaluate("Object.getOwnPropertyDescriptor(o, '5').enumerable").toBool());
+ QEXPECT_FAIL("int + skipInEnumeration", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QVERIFY(skipInEnumeration != engine.evaluate("Object.getOwnPropertyDescriptor(o, '6').enumerable").toBool());
+ QEXPECT_FAIL("int + skipInEnumeration", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QVERIFY(skipInEnumeration != engine.evaluate("Object.getOwnPropertyDescriptor(p, '7').enumerable").toBool());
+ QVERIFY(skipInEnumeration != engine.evaluate("Object.getOwnPropertyDescriptor(p, '8').enumerable").toBool());
+ QVERIFY(skipInEnumeration != engine.evaluate("Object.getOwnPropertyDescriptor(o, 'undefined1').enumerable").toBool());
+ QVERIFY(skipInEnumeration != engine.evaluate("Object.getOwnPropertyDescriptor(o, 'undefined2').enumerable").toBool());
+ QVERIFY(skipInEnumeration != engine.evaluate("Object.getOwnPropertyDescriptor(p, 'undefined3').enumerable").toBool());
+ QVERIFY(skipInEnumeration != engine.evaluate("Object.getOwnPropertyDescriptor(p, 'undefined4').enumerable").toBool());
+ QEXPECT_FAIL("int + skipInEnumeration", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QVERIFY(skipInEnumeration != engine.evaluate("Object.getOwnPropertyDescriptor(o, 'overloaded1').enumerable").toBool());
+ QEXPECT_FAIL("int + skipInEnumeration", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QVERIFY(skipInEnumeration != engine.evaluate("Object.getOwnPropertyDescriptor(o, 'overloaded2').enumerable").toBool());
+ QVERIFY(engine.evaluate("p.propertyIsEnumerable('overloaded1')").toBool());
+ QVERIFY(engine.evaluate("p.propertyIsEnumerable('overloaded2')").toBool());
+ QVERIFY(engine.evaluate("o.propertyIsEnumerable('overloaded3')").toBool());
+ QVERIFY(engine.evaluate("o.propertyIsEnumerable('overloaded4')").toBool());
+ QEXPECT_FAIL("int + skipInEnumeration", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QVERIFY(skipInEnumeration != engine.evaluate("p.propertyIsEnumerable('overloaded3')").toBool());
+ QEXPECT_FAIL("int + skipInEnumeration", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QVERIFY(skipInEnumeration != engine.evaluate("p.propertyIsEnumerable('overloaded4')").toBool());
+ QEXPECT_FAIL("int + skipInEnumeration", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QVERIFY(skipInEnumeration != engine.evaluate("o.propertyIsEnumerable('defined1')").toBool());
+ QEXPECT_FAIL("int + skipInEnumeration", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QEXPECT_FAIL("int + skipInEnumeration|readOnly|undeletable", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue);
+ QVERIFY(skipInEnumeration != engine.evaluate("o.propertyIsEnumerable('defined2')").toBool());
+}
+
+void tst_QScriptValue::propertyFlag_data()
+{
+ QTest::addColumn<QString>("name");
+ QTest::addColumn<int>("flag");
+
+ QTest::newRow("?Cr@jzi!%$") << "?Cr@jzi!%$" << static_cast<int>(0);
+ QTest::newRow("ReadOnly") << "ReadOnly" << static_cast<int>(QScriptValue::ReadOnly);
+ QTest::newRow("Undeletable") << "Undeletable" << static_cast<int>(QScriptValue::Undeletable);
+ QTest::newRow("SkipInEnumeration") << "SkipInEnumeration" << static_cast<int>(QScriptValue::SkipInEnumeration);
+ QTest::newRow("ReadOnly | Undeletable") << "ReadOnly_Undeletable" << static_cast<int>(QScriptValue::ReadOnly | QScriptValue::Undeletable);
+ QTest::newRow("ReadOnly | SkipInEnumeration") << "ReadOnly_SkipInEnumeration" << static_cast<int>(QScriptValue::ReadOnly | QScriptValue::SkipInEnumeration);
+ QTest::newRow("Undeletable | SkipInEnumeration") << "Undeletable_SkipInEnumeration" << static_cast<int>(QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ QTest::newRow("ReadOnly | Undeletable | SkipInEnumeration") << "ReadOnly_Undeletable_SkipInEnumeration" << static_cast<int>(QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+}
+
+void tst_QScriptValue::propertyFlag()
+{
+ QScriptEngine engine;
+ QFETCH(QString, name);
+ QFETCH(int, flag);
+ const QScriptString nameHandle = engine.toStringHandle(name);
+ const QString protoName = "proto" + name;
+ const QScriptString protoNameHandle = engine.toStringHandle(protoName);
+
+ QScriptValue proto = engine.newObject();
+ QScriptValue object = engine.newObject();
+ object.setPrototype(proto);
+
+ proto.setProperty(protoName, QScriptValue(124816), QScriptValue::PropertyFlag(flag));
+ object.setProperty(name, QScriptValue(124816), QScriptValue::PropertyFlag(flag));
+
+ // Check using QString name
+ QCOMPARE(object.propertyFlags(name), QScriptValue::PropertyFlag(flag));
+ QCOMPARE(object.propertyFlags(protoName, QScriptValue::ResolvePrototype), QScriptValue::PropertyFlag(flag));
+ QVERIFY(!object.propertyFlags(protoName, QScriptValue::ResolveLocal));
+
+ // Check using QScriptString name
+ QCOMPARE(object.propertyFlags(nameHandle), QScriptValue::PropertyFlag(flag));
+ QCOMPARE(object.propertyFlags(protoNameHandle, QScriptValue::ResolvePrototype), QScriptValue::PropertyFlag(flag));
+ QVERIFY(!object.propertyFlags(protoNameHandle, QScriptValue::ResolveLocal));
+}
+
+void tst_QScriptValue::globalObjectChanges()
+{
+ // API functionality shouldn't depend on Global Object.
+ QScriptEngine engine;
+ QScriptValue array = engine.newArray();
+ QScriptValue error = engine.evaluate("new Error");
+ QScriptValue object = engine.newObject();
+
+ object.setProperty("foo", 512);
+
+ // Remove properties form global object.
+ engine.evaluate("delete Object; delete Error; delete Array;");
+
+ QVERIFY(array.isArray());
+ QVERIFY(error.isError());
+ QVERIFY(object.isObject());
+
+ QVERIFY(object.property("foo").isValid());
+ QVERIFY(object.property("foo", QScriptValue::ResolveLocal).isValid());
+ object.setProperty("foo", QScriptValue());
+ QVERIFY(!object.property("foo").isValid());
+ QVERIFY(!object.property("foo", QScriptValue::ResolveLocal).isValid());
+}
+
+void tst_QScriptValue::assignAndCopyConstruct_data()
+{
+ QTest::addColumn<QScriptValue>("value");
+ if (m_engine)
+ delete m_engine;
+ m_engine = new QScriptEngine;
+ // Copy & assign code is the same for all types, so it is enough to check only a few value.
+ for (unsigned i = 0; i < 10; ++i) {
+ QPair<QString, QScriptValue> testcase = initScriptValues(i);
+ QTest::newRow(testcase.first.toAscii().constData()) << testcase.second;
+ }
+}
+
+void tst_QScriptValue::assignAndCopyConstruct()
+{
+ QFETCH(QScriptValue, value);
+ QScriptValue copy(value);
+ QEXPECT_FAIL("QScriptValue(QScriptValue::NullValue)", "FIXME: WebKit bug 43038", Abort);
+ QEXPECT_FAIL("QScriptValue(QScriptValue::UndefinedValue)", "FIXME: WebKit bug 43038", Abort);
+ QCOMPARE(copy.strictlyEquals(value), !value.isNumber() || !qIsNaN(value.toNumber()));
+ QCOMPARE(copy.engine(), value.engine());
+
+ QScriptValue assigned = copy;
+ QCOMPARE(assigned.strictlyEquals(value), !copy.isNumber() || !qIsNaN(copy.toNumber()));
+ QCOMPARE(assigned.engine(), assigned.engine());
+
+ QScriptValue other(!value.toBool());
+ assigned = other;
+ QVERIFY(!assigned.strictlyEquals(copy));
+ QVERIFY(assigned.strictlyEquals(other));
+ QCOMPARE(assigned.engine(), other.engine());
+}
QTEST_MAIN(tst_QScriptValue)
#include <QtCore/qnumeric.h>
#include <QtTest/qtest.h>
+#define DEFINE_TEST_VALUE(expr) m_values.insert(QString::fromLatin1(#expr), expr)
+
Q_DECLARE_METATYPE(QScriptValue*);
Q_DECLARE_METATYPE(QScriptValue);
+typedef QPair<QString, QScriptValue> QPairQStringAndQScriptValue;
+Q_DECLARE_METATYPE(QPairQStringAndQScriptValue);
class tst_QScriptValue : public QObject {
Q_OBJECT
void dataSharing();
void constructors_data();
void constructors();
+ void getSetPrototype();
void call();
void ctor();
+ void toObjectSimple();
+ void getPropertySimple_data();
+ void getPropertySimple();
+ void setPropertySimple();
+ void setProperty_data();
+ void setProperty();
+ void getSetProperty();
+ void getPropertyResolveFlag();
+ void propertyFlag_data();
+ void propertyFlag();
+ void globalObjectChanges();
+ void assignAndCopyConstruct_data();
+ void assignAndCopyConstruct();
// Generated test functions.
+ void isArray_data();
+ void isArray();
+
void isBool_data();
void isBool();
void isBoolean_data();
void isBoolean();
+ void isError_data();
+ void isError();
+
void isNumber_data();
void isNumber();
void toUInt16_data();
void toUInt16();
-private:
- typedef void (tst_QScriptValue::*InitDataFunction)();
- typedef void (tst_QScriptValue::*DefineDataFunction)(const char*);
- void dataHelper(InitDataFunction init, DefineDataFunction define);
- QTestData& newRow(const char* tag);
-
- typedef void (tst_QScriptValue::*TestFunction)(const char*, const QScriptValue&);
- void testHelper(TestFunction fun);
-
- // Generated functions
-
- void initScriptValues();
-
- void isBool_initData();
- void isBool_makeData(const char* expr);
- void isBool_test(const char* expr, const QScriptValue& value);
-
- void isBoolean_initData();
- void isBoolean_makeData(const char* expr);
- void isBoolean_test(const char* expr, const QScriptValue& value);
-
- void isNumber_initData();
- void isNumber_makeData(const char* expr);
- void isNumber_test(const char* expr, const QScriptValue&);
-
- void isFunction_initData();
- void isFunction_makeData(const char* expr);
- void isFunction_test(const char* expr, const QScriptValue& value);
-
- void isNull_initData();
- void isNull_makeData(const char* expr);
- void isNull_test(const char* expr, const QScriptValue& value);
-
- void isObject_initData();
- void isObject_makeData(const char* expr);
- void isObject_test(const char* expr, const QScriptValue& value);
+ void equals_data();
+ void equals();
- void isString_initData();
- void isString_makeData(const char* expr);
- void isString_test(const char* expr, const QScriptValue& value);
+ void strictlyEquals_data();
+ void strictlyEquals();
- void isUndefined_initData();
- void isUndefined_makeData(const char* expr);
- void isUndefined_test(const char* expr, const QScriptValue& value);
-
- void isValid_initData();
- void isValid_makeData(const char* expr);
- void isValid_test(const char* expr, const QScriptValue& value);
-
- void toString_initData();
- void toString_makeData(const char*);
- void toString_test(const char*, const QScriptValue&);
-
- void toNumber_initData();
- void toNumber_makeData(const char*);
- void toNumber_test(const char*, const QScriptValue&);
-
- void toBool_initData();
- void toBool_makeData(const char*);
- void toBool_test(const char*, const QScriptValue&);
-
- void toBoolean_initData();
- void toBoolean_makeData(const char*);
- void toBoolean_test(const char*, const QScriptValue&);
-
- void toInteger_initData();
- void toInteger_makeData(const char*);
- void toInteger_test(const char*, const QScriptValue&);
-
- void toInt32_initData();
- void toInt32_makeData(const char*);
- void toInt32_test(const char*, const QScriptValue&);
-
- void toUInt32_initData();
- void toUInt32_makeData(const char*);
- void toUInt32_test(const char*, const QScriptValue&);
-
- void toUInt16_initData();
- void toUInt16_makeData(const char*);
- void toUInt16_test(const char*, const QScriptValue&);
+ void instanceOf_data();
+ void instanceOf();
private:
- QScriptEngine* engine;
- QHash<QString, QScriptValue> m_values;
- QString m_currentExpression;
-};
-
-#define DEFINE_TEST_FUNCTION(name) \
-void tst_QScriptValue::name##_data() { dataHelper(&tst_QScriptValue::name##_initData, &tst_QScriptValue::name##_makeData); } \
-void tst_QScriptValue::name() { testHelper(&tst_QScriptValue::name##_test); }
-
+ // Generated function
+ QPair<QString, QScriptValue> initScriptValues(uint idx);
+ QScriptEngine* m_engine;
+};
#endif // tst_qscriptvalue_h
+++ /dev/null
-/*
- Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
-
- 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 "tst_qscriptvalue.h"
-
-#define DEFINE_TEST_VALUE(expr) m_values.insert(QString::fromLatin1(#expr), expr)
-
-void tst_QScriptValue::initScriptValues()
-{
- m_values.clear();
- if (engine)
- delete engine;
- engine = new QScriptEngine;
- DEFINE_TEST_VALUE(QScriptValue());
- DEFINE_TEST_VALUE(QScriptValue(QScriptValue::UndefinedValue));
- DEFINE_TEST_VALUE(QScriptValue(QScriptValue::NullValue));
- DEFINE_TEST_VALUE(QScriptValue(true));
- DEFINE_TEST_VALUE(QScriptValue(false));
- DEFINE_TEST_VALUE(QScriptValue(int(122)));
- DEFINE_TEST_VALUE(QScriptValue(uint(124)));
- DEFINE_TEST_VALUE(QScriptValue(0));
- DEFINE_TEST_VALUE(QScriptValue(0.0));
- DEFINE_TEST_VALUE(QScriptValue(123.0));
- DEFINE_TEST_VALUE(QScriptValue(6.37e-8));
- DEFINE_TEST_VALUE(QScriptValue(-6.37e-8));
- DEFINE_TEST_VALUE(QScriptValue(0x43211234));
- DEFINE_TEST_VALUE(QScriptValue(0x10000));
- DEFINE_TEST_VALUE(QScriptValue(0x10001));
- DEFINE_TEST_VALUE(QScriptValue(qSNaN()));
- DEFINE_TEST_VALUE(QScriptValue(qQNaN()));
- DEFINE_TEST_VALUE(QScriptValue(qInf()));
- DEFINE_TEST_VALUE(QScriptValue(-qInf()));
- DEFINE_TEST_VALUE(QScriptValue("NaN"));
- DEFINE_TEST_VALUE(QScriptValue("Infinity"));
- DEFINE_TEST_VALUE(QScriptValue("-Infinity"));
- DEFINE_TEST_VALUE(QScriptValue("ciao"));
- DEFINE_TEST_VALUE(QScriptValue(QString::fromLatin1("ciao")));
- DEFINE_TEST_VALUE(QScriptValue(QString("")));
- DEFINE_TEST_VALUE(QScriptValue(QString()));
- DEFINE_TEST_VALUE(QScriptValue(QString("0")));
- DEFINE_TEST_VALUE(QScriptValue(QString("123")));
- DEFINE_TEST_VALUE(QScriptValue(QString("12.4")));
- DEFINE_TEST_VALUE(QScriptValue(0, QScriptValue::UndefinedValue));
- DEFINE_TEST_VALUE(QScriptValue(0, QScriptValue::NullValue));
- DEFINE_TEST_VALUE(QScriptValue(0, true));
- DEFINE_TEST_VALUE(QScriptValue(0, false));
- DEFINE_TEST_VALUE(QScriptValue(0, int(122)));
- DEFINE_TEST_VALUE(QScriptValue(0, uint(124)));
- DEFINE_TEST_VALUE(QScriptValue(0, 0));
- DEFINE_TEST_VALUE(QScriptValue(0, 0.0));
- DEFINE_TEST_VALUE(QScriptValue(0, 123.0));
- DEFINE_TEST_VALUE(QScriptValue(0, 6.37e-8));
- DEFINE_TEST_VALUE(QScriptValue(0, -6.37e-8));
- DEFINE_TEST_VALUE(QScriptValue(0, 0x43211234));
- DEFINE_TEST_VALUE(QScriptValue(0, 0x10000));
- DEFINE_TEST_VALUE(QScriptValue(0, 0x10001));
- DEFINE_TEST_VALUE(QScriptValue(0, qSNaN()));
- DEFINE_TEST_VALUE(QScriptValue(0, qQNaN()));
- DEFINE_TEST_VALUE(QScriptValue(0, qInf()));
- DEFINE_TEST_VALUE(QScriptValue(0, -qInf()));
- DEFINE_TEST_VALUE(QScriptValue(0, "NaN"));
- DEFINE_TEST_VALUE(QScriptValue(0, "Infinity"));
- DEFINE_TEST_VALUE(QScriptValue(0, "-Infinity"));
- DEFINE_TEST_VALUE(QScriptValue(0, "ciao"));
- DEFINE_TEST_VALUE(QScriptValue(0, QString::fromLatin1("ciao")));
- DEFINE_TEST_VALUE(QScriptValue(0, QString("")));
- DEFINE_TEST_VALUE(QScriptValue(0, QString()));
- DEFINE_TEST_VALUE(QScriptValue(0, QString("0")));
- DEFINE_TEST_VALUE(QScriptValue(0, QString("123")));
- DEFINE_TEST_VALUE(QScriptValue(0, QString("12.3")));
- DEFINE_TEST_VALUE(QScriptValue(engine, QScriptValue::UndefinedValue));
- DEFINE_TEST_VALUE(QScriptValue(engine, QScriptValue::NullValue));
- DEFINE_TEST_VALUE(QScriptValue(engine, true));
- DEFINE_TEST_VALUE(QScriptValue(engine, false));
- DEFINE_TEST_VALUE(QScriptValue(engine, int(122)));
- DEFINE_TEST_VALUE(QScriptValue(engine, uint(124)));
- DEFINE_TEST_VALUE(QScriptValue(engine, 0));
- DEFINE_TEST_VALUE(QScriptValue(engine, 0.0));
- DEFINE_TEST_VALUE(QScriptValue(engine, 123.0));
- DEFINE_TEST_VALUE(QScriptValue(engine, 6.37e-8));
- DEFINE_TEST_VALUE(QScriptValue(engine, -6.37e-8));
- DEFINE_TEST_VALUE(QScriptValue(engine, 0x43211234));
- DEFINE_TEST_VALUE(QScriptValue(engine, 0x10000));
- DEFINE_TEST_VALUE(QScriptValue(engine, 0x10001));
- DEFINE_TEST_VALUE(QScriptValue(engine, qSNaN()));
- DEFINE_TEST_VALUE(QScriptValue(engine, qQNaN()));
- DEFINE_TEST_VALUE(QScriptValue(engine, qInf()));
- DEFINE_TEST_VALUE(QScriptValue(engine, -qInf()));
- DEFINE_TEST_VALUE(QScriptValue(engine, "NaN"));
- DEFINE_TEST_VALUE(QScriptValue(engine, "Infinity"));
- DEFINE_TEST_VALUE(QScriptValue(engine, "-Infinity"));
- DEFINE_TEST_VALUE(QScriptValue(engine, "ciao"));
- DEFINE_TEST_VALUE(QScriptValue(engine, QString::fromLatin1("ciao")));
- DEFINE_TEST_VALUE(QScriptValue(engine, QString("")));
- DEFINE_TEST_VALUE(QScriptValue(engine, QString()));
- DEFINE_TEST_VALUE(QScriptValue(engine, QString("0")));
- DEFINE_TEST_VALUE(QScriptValue(engine, QString("123")));
- DEFINE_TEST_VALUE(QScriptValue(engine, QString("1.23")));
- DEFINE_TEST_VALUE(engine->evaluate("[]"));
- DEFINE_TEST_VALUE(engine->evaluate("{}"));
- DEFINE_TEST_VALUE(engine->evaluate("Object.prototype"));
- DEFINE_TEST_VALUE(engine->evaluate("Date.prototype"));
- DEFINE_TEST_VALUE(engine->evaluate("Array.prototype"));
- DEFINE_TEST_VALUE(engine->evaluate("Function.prototype"));
- DEFINE_TEST_VALUE(engine->evaluate("Error.prototype"));
- DEFINE_TEST_VALUE(engine->evaluate("Object"));
- DEFINE_TEST_VALUE(engine->evaluate("Array"));
- DEFINE_TEST_VALUE(engine->evaluate("Number"));
- DEFINE_TEST_VALUE(engine->evaluate("Function"));
- DEFINE_TEST_VALUE(engine->evaluate("(function() { return 1; })"));
- DEFINE_TEST_VALUE(engine->evaluate("(function() { return 'ciao'; })"));
- DEFINE_TEST_VALUE(engine->evaluate("(function() { throw new Error('foo'); })"));
- DEFINE_TEST_VALUE(engine->evaluate("/foo/"));
- DEFINE_TEST_VALUE(engine->evaluate("new Object()"));
- DEFINE_TEST_VALUE(engine->evaluate("new Array()"));
- DEFINE_TEST_VALUE(engine->evaluate("new Error()"));
- DEFINE_TEST_VALUE(engine->evaluate("a = new Object(); a.foo = 22; a.foo"));
- DEFINE_TEST_VALUE(engine->evaluate("Undefined"));
- DEFINE_TEST_VALUE(engine->evaluate("Null"));
- DEFINE_TEST_VALUE(engine->evaluate("True"));
- DEFINE_TEST_VALUE(engine->evaluate("False"));
- DEFINE_TEST_VALUE(engine->evaluate("undefined"));
- DEFINE_TEST_VALUE(engine->evaluate("null"));
- DEFINE_TEST_VALUE(engine->evaluate("true"));
- DEFINE_TEST_VALUE(engine->evaluate("false"));
- DEFINE_TEST_VALUE(engine->evaluate("122"));
- DEFINE_TEST_VALUE(engine->evaluate("124"));
- DEFINE_TEST_VALUE(engine->evaluate("0"));
- DEFINE_TEST_VALUE(engine->evaluate("0.0"));
- DEFINE_TEST_VALUE(engine->evaluate("123.0"));
- DEFINE_TEST_VALUE(engine->evaluate("6.37e-8"));
- DEFINE_TEST_VALUE(engine->evaluate("-6.37e-8"));
- DEFINE_TEST_VALUE(engine->evaluate("0x43211234"));
- DEFINE_TEST_VALUE(engine->evaluate("0x10000"));
- DEFINE_TEST_VALUE(engine->evaluate("0x10001"));
- DEFINE_TEST_VALUE(engine->evaluate("NaN"));
- DEFINE_TEST_VALUE(engine->evaluate("Infinity"));
- DEFINE_TEST_VALUE(engine->evaluate("-Infinity"));
- DEFINE_TEST_VALUE(engine->evaluate("'ciao'"));
- DEFINE_TEST_VALUE(engine->evaluate("''"));
- DEFINE_TEST_VALUE(engine->evaluate("'0'"));
- DEFINE_TEST_VALUE(engine->evaluate("'123'"));
- DEFINE_TEST_VALUE(engine->evaluate("'12.4'"));
- DEFINE_TEST_VALUE(engine->nullValue());
- DEFINE_TEST_VALUE(engine->undefinedValue());
-}
-
-
-void tst_QScriptValue::isValid_initData()
-{
- QTest::addColumn<bool>("expected");
- initScriptValues();
-}
-
-void tst_QScriptValue::isValid_makeData(const char* expr)
-{
- static QSet<QString> isValid;
- if (isValid.isEmpty()) {
- isValid << "QScriptValue(QScriptValue::UndefinedValue)"
- << "QScriptValue(QScriptValue::NullValue)"
- << "QScriptValue(true)"
- << "QScriptValue(false)"
- << "QScriptValue(int(122))"
- << "QScriptValue(uint(124))"
- << "QScriptValue(0)"
- << "QScriptValue(0.0)"
- << "QScriptValue(123.0)"
- << "QScriptValue(6.37e-8)"
- << "QScriptValue(-6.37e-8)"
- << "QScriptValue(0x43211234)"
- << "QScriptValue(0x10000)"
- << "QScriptValue(0x10001)"
- << "QScriptValue(qSNaN())"
- << "QScriptValue(qQNaN())"
- << "QScriptValue(qInf())"
- << "QScriptValue(-qInf())"
- << "QScriptValue(\"NaN\")"
- << "QScriptValue(\"Infinity\")"
- << "QScriptValue(\"-Infinity\")"
- << "QScriptValue(\"ciao\")"
- << "QScriptValue(QString::fromLatin1(\"ciao\"))"
- << "QScriptValue(QString(\"\"))"
- << "QScriptValue(QString())"
- << "QScriptValue(QString(\"0\"))"
- << "QScriptValue(QString(\"123\"))"
- << "QScriptValue(QString(\"12.4\"))"
- << "QScriptValue(0, QScriptValue::UndefinedValue)"
- << "QScriptValue(0, QScriptValue::NullValue)"
- << "QScriptValue(0, true)"
- << "QScriptValue(0, false)"
- << "QScriptValue(0, int(122))"
- << "QScriptValue(0, uint(124))"
- << "QScriptValue(0, 0)"
- << "QScriptValue(0, 0.0)"
- << "QScriptValue(0, 123.0)"
- << "QScriptValue(0, 6.37e-8)"
- << "QScriptValue(0, -6.37e-8)"
- << "QScriptValue(0, 0x43211234)"
- << "QScriptValue(0, 0x10000)"
- << "QScriptValue(0, 0x10001)"
- << "QScriptValue(0, qSNaN())"
- << "QScriptValue(0, qQNaN())"
- << "QScriptValue(0, qInf())"
- << "QScriptValue(0, -qInf())"
- << "QScriptValue(0, \"NaN\")"
- << "QScriptValue(0, \"Infinity\")"
- << "QScriptValue(0, \"-Infinity\")"
- << "QScriptValue(0, \"ciao\")"
- << "QScriptValue(0, QString::fromLatin1(\"ciao\"))"
- << "QScriptValue(0, QString(\"\"))"
- << "QScriptValue(0, QString())"
- << "QScriptValue(0, QString(\"0\"))"
- << "QScriptValue(0, QString(\"123\"))"
- << "QScriptValue(0, QString(\"12.3\"))"
- << "QScriptValue(engine, QScriptValue::UndefinedValue)"
- << "QScriptValue(engine, QScriptValue::NullValue)"
- << "QScriptValue(engine, true)"
- << "QScriptValue(engine, false)"
- << "QScriptValue(engine, int(122))"
- << "QScriptValue(engine, uint(124))"
- << "QScriptValue(engine, 0)"
- << "QScriptValue(engine, 0.0)"
- << "QScriptValue(engine, 123.0)"
- << "QScriptValue(engine, 6.37e-8)"
- << "QScriptValue(engine, -6.37e-8)"
- << "QScriptValue(engine, 0x43211234)"
- << "QScriptValue(engine, 0x10000)"
- << "QScriptValue(engine, 0x10001)"
- << "QScriptValue(engine, qSNaN())"
- << "QScriptValue(engine, qQNaN())"
- << "QScriptValue(engine, qInf())"
- << "QScriptValue(engine, -qInf())"
- << "QScriptValue(engine, \"NaN\")"
- << "QScriptValue(engine, \"Infinity\")"
- << "QScriptValue(engine, \"-Infinity\")"
- << "QScriptValue(engine, \"ciao\")"
- << "QScriptValue(engine, QString::fromLatin1(\"ciao\"))"
- << "QScriptValue(engine, QString(\"\"))"
- << "QScriptValue(engine, QString())"
- << "QScriptValue(engine, QString(\"0\"))"
- << "QScriptValue(engine, QString(\"123\"))"
- << "QScriptValue(engine, QString(\"1.23\"))"
- << "engine->evaluate(\"[]\")"
- << "engine->evaluate(\"{}\")"
- << "engine->evaluate(\"Object.prototype\")"
- << "engine->evaluate(\"Date.prototype\")"
- << "engine->evaluate(\"Array.prototype\")"
- << "engine->evaluate(\"Function.prototype\")"
- << "engine->evaluate(\"Error.prototype\")"
- << "engine->evaluate(\"Object\")"
- << "engine->evaluate(\"Array\")"
- << "engine->evaluate(\"Number\")"
- << "engine->evaluate(\"Function\")"
- << "engine->evaluate(\"(function() { return 1; })\")"
- << "engine->evaluate(\"(function() { return 'ciao'; })\")"
- << "engine->evaluate(\"(function() { throw new Error('foo'); })\")"
- << "engine->evaluate(\"/foo/\")"
- << "engine->evaluate(\"new Object()\")"
- << "engine->evaluate(\"new Array()\")"
- << "engine->evaluate(\"new Error()\")"
- << "engine->evaluate(\"a = new Object(); a.foo = 22; a.foo\")"
- << "engine->evaluate(\"Undefined\")"
- << "engine->evaluate(\"Null\")"
- << "engine->evaluate(\"True\")"
- << "engine->evaluate(\"False\")"
- << "engine->evaluate(\"undefined\")"
- << "engine->evaluate(\"null\")"
- << "engine->evaluate(\"true\")"
- << "engine->evaluate(\"false\")"
- << "engine->evaluate(\"122\")"
- << "engine->evaluate(\"124\")"
- << "engine->evaluate(\"0\")"
- << "engine->evaluate(\"0.0\")"
- << "engine->evaluate(\"123.0\")"
- << "engine->evaluate(\"6.37e-8\")"
- << "engine->evaluate(\"-6.37e-8\")"
- << "engine->evaluate(\"0x43211234\")"
- << "engine->evaluate(\"0x10000\")"
- << "engine->evaluate(\"0x10001\")"
- << "engine->evaluate(\"NaN\")"
- << "engine->evaluate(\"Infinity\")"
- << "engine->evaluate(\"-Infinity\")"
- << "engine->evaluate(\"'ciao'\")"
- << "engine->evaluate(\"''\")"
- << "engine->evaluate(\"'0'\")"
- << "engine->evaluate(\"'123'\")"
- << "engine->evaluate(\"'12.4'\")"
- << "engine->nullValue()"
- << "engine->undefinedValue()";
- }
- newRow(expr) << isValid.contains(expr);
-}
-
-void tst_QScriptValue::isValid_test(const char*, const QScriptValue& value)
-{
- QFETCH(bool, expected);
- QCOMPARE(value.isValid(), expected);
- QCOMPARE(value.isValid(), expected);
-}
-
-DEFINE_TEST_FUNCTION(isValid)
-
-
-void tst_QScriptValue::isBool_initData()
-{
- QTest::addColumn<bool>("expected");
- initScriptValues();
-}
-
-void tst_QScriptValue::isBool_makeData(const char* expr)
-{
- static QSet<QString> isBool;
- if (isBool.isEmpty()) {
- isBool << "QScriptValue(true)"
- << "QScriptValue(false)"
- << "QScriptValue(0, true)"
- << "QScriptValue(0, false)"
- << "QScriptValue(engine, true)"
- << "QScriptValue(engine, false)"
- << "engine->evaluate(\"true\")"
- << "engine->evaluate(\"false\")";
- }
- newRow(expr) << isBool.contains(expr);
-}
-
-void tst_QScriptValue::isBool_test(const char*, const QScriptValue& value)
-{
- QFETCH(bool, expected);
- QCOMPARE(value.isBool(), expected);
- QCOMPARE(value.isBool(), expected);
-}
-
-DEFINE_TEST_FUNCTION(isBool)
-
-
-void tst_QScriptValue::isBoolean_initData()
-{
- QTest::addColumn<bool>("expected");
- initScriptValues();
-}
-
-void tst_QScriptValue::isBoolean_makeData(const char* expr)
-{
- static QSet<QString> isBoolean;
- if (isBoolean.isEmpty()) {
- isBoolean << "QScriptValue(true)"
- << "QScriptValue(false)"
- << "QScriptValue(0, true)"
- << "QScriptValue(0, false)"
- << "QScriptValue(engine, true)"
- << "QScriptValue(engine, false)"
- << "engine->evaluate(\"true\")"
- << "engine->evaluate(\"false\")";
- }
- newRow(expr) << isBoolean.contains(expr);
-}
-
-void tst_QScriptValue::isBoolean_test(const char*, const QScriptValue& value)
-{
- QFETCH(bool, expected);
- QCOMPARE(value.isBoolean(), expected);
- QCOMPARE(value.isBoolean(), expected);
-}
-
-DEFINE_TEST_FUNCTION(isBoolean)
-
-
-void tst_QScriptValue::isNumber_initData()
-{
- QTest::addColumn<bool>("expected");
- initScriptValues();
-}
-
-void tst_QScriptValue::isNumber_makeData(const char* expr)
-{
- static QSet<QString> isNumber;
- if (isNumber.isEmpty()) {
- isNumber << "QScriptValue(int(122))"
- << "QScriptValue(uint(124))"
- << "QScriptValue(0)"
- << "QScriptValue(0.0)"
- << "QScriptValue(123.0)"
- << "QScriptValue(6.37e-8)"
- << "QScriptValue(-6.37e-8)"
- << "QScriptValue(0x43211234)"
- << "QScriptValue(0x10000)"
- << "QScriptValue(0x10001)"
- << "QScriptValue(qSNaN())"
- << "QScriptValue(qQNaN())"
- << "QScriptValue(qInf())"
- << "QScriptValue(-qInf())"
- << "QScriptValue(0, int(122))"
- << "QScriptValue(0, uint(124))"
- << "QScriptValue(0, 0)"
- << "QScriptValue(0, 0.0)"
- << "QScriptValue(0, 123.0)"
- << "QScriptValue(0, 6.37e-8)"
- << "QScriptValue(0, -6.37e-8)"
- << "QScriptValue(0, 0x43211234)"
- << "QScriptValue(0, 0x10000)"
- << "QScriptValue(0, 0x10001)"
- << "QScriptValue(0, qSNaN())"
- << "QScriptValue(0, qQNaN())"
- << "QScriptValue(0, qInf())"
- << "QScriptValue(0, -qInf())"
- << "QScriptValue(engine, int(122))"
- << "QScriptValue(engine, uint(124))"
- << "QScriptValue(engine, 0)"
- << "QScriptValue(engine, 0.0)"
- << "QScriptValue(engine, 123.0)"
- << "QScriptValue(engine, 6.37e-8)"
- << "QScriptValue(engine, -6.37e-8)"
- << "QScriptValue(engine, 0x43211234)"
- << "QScriptValue(engine, 0x10000)"
- << "QScriptValue(engine, 0x10001)"
- << "QScriptValue(engine, qSNaN())"
- << "QScriptValue(engine, qQNaN())"
- << "QScriptValue(engine, qInf())"
- << "QScriptValue(engine, -qInf())"
- << "engine->evaluate(\"a = new Object(); a.foo = 22; a.foo\")"
- << "engine->evaluate(\"122\")"
- << "engine->evaluate(\"124\")"
- << "engine->evaluate(\"0\")"
- << "engine->evaluate(\"0.0\")"
- << "engine->evaluate(\"123.0\")"
- << "engine->evaluate(\"6.37e-8\")"
- << "engine->evaluate(\"-6.37e-8\")"
- << "engine->evaluate(\"0x43211234\")"
- << "engine->evaluate(\"0x10000\")"
- << "engine->evaluate(\"0x10001\")"
- << "engine->evaluate(\"NaN\")"
- << "engine->evaluate(\"Infinity\")"
- << "engine->evaluate(\"-Infinity\")";
- }
- newRow(expr) << isNumber.contains(expr);
-}
-
-void tst_QScriptValue::isNumber_test(const char*, const QScriptValue& value)
-{
- QFETCH(bool, expected);
- QCOMPARE(value.isNumber(), expected);
- QCOMPARE(value.isNumber(), expected);
-}
-
-DEFINE_TEST_FUNCTION(isNumber)
-
-
-void tst_QScriptValue::isFunction_initData()
-{
- QTest::addColumn<bool>("expected");
- initScriptValues();
-}
-
-void tst_QScriptValue::isFunction_makeData(const char* expr)
-{
- static QSet<QString> isFunction;
- if (isFunction.isEmpty()) {
- isFunction << "engine->evaluate(\"Function.prototype\")"
- << "engine->evaluate(\"Object\")"
- << "engine->evaluate(\"Array\")"
- << "engine->evaluate(\"Number\")"
- << "engine->evaluate(\"Function\")"
- << "engine->evaluate(\"(function() { return 1; })\")"
- << "engine->evaluate(\"(function() { return 'ciao'; })\")"
- << "engine->evaluate(\"(function() { throw new Error('foo'); })\")"
- << "engine->evaluate(\"/foo/\")";
- }
- newRow(expr) << isFunction.contains(expr);
-}
-
-void tst_QScriptValue::isFunction_test(const char*, const QScriptValue& value)
-{
- QFETCH(bool, expected);
- QCOMPARE(value.isFunction(), expected);
- QCOMPARE(value.isFunction(), expected);
-}
-
-DEFINE_TEST_FUNCTION(isFunction)
-
-
-void tst_QScriptValue::isNull_initData()
-{
- QTest::addColumn<bool>("expected");
- initScriptValues();
-}
-
-void tst_QScriptValue::isNull_makeData(const char* expr)
-{
- static QSet<QString> isNull;
- if (isNull.isEmpty()) {
- isNull << "QScriptValue(QScriptValue::NullValue)"
- << "QScriptValue(0, QScriptValue::NullValue)"
- << "QScriptValue(engine, QScriptValue::NullValue)"
- << "engine->evaluate(\"null\")"
- << "engine->nullValue()";
- }
- newRow(expr) << isNull.contains(expr);
-}
-
-void tst_QScriptValue::isNull_test(const char*, const QScriptValue& value)
-{
- QFETCH(bool, expected);
- QCOMPARE(value.isNull(), expected);
- QCOMPARE(value.isNull(), expected);
-}
-
-DEFINE_TEST_FUNCTION(isNull)
-
-
-void tst_QScriptValue::isString_initData()
-{
- QTest::addColumn<bool>("expected");
- initScriptValues();
-}
-
-void tst_QScriptValue::isString_makeData(const char* expr)
-{
- static QSet<QString> isString;
- if (isString.isEmpty()) {
- isString << "QScriptValue(\"NaN\")"
- << "QScriptValue(\"Infinity\")"
- << "QScriptValue(\"-Infinity\")"
- << "QScriptValue(\"ciao\")"
- << "QScriptValue(QString::fromLatin1(\"ciao\"))"
- << "QScriptValue(QString(\"\"))"
- << "QScriptValue(QString())"
- << "QScriptValue(QString(\"0\"))"
- << "QScriptValue(QString(\"123\"))"
- << "QScriptValue(QString(\"12.4\"))"
- << "QScriptValue(0, \"NaN\")"
- << "QScriptValue(0, \"Infinity\")"
- << "QScriptValue(0, \"-Infinity\")"
- << "QScriptValue(0, \"ciao\")"
- << "QScriptValue(0, QString::fromLatin1(\"ciao\"))"
- << "QScriptValue(0, QString(\"\"))"
- << "QScriptValue(0, QString())"
- << "QScriptValue(0, QString(\"0\"))"
- << "QScriptValue(0, QString(\"123\"))"
- << "QScriptValue(0, QString(\"12.3\"))"
- << "QScriptValue(engine, \"NaN\")"
- << "QScriptValue(engine, \"Infinity\")"
- << "QScriptValue(engine, \"-Infinity\")"
- << "QScriptValue(engine, \"ciao\")"
- << "QScriptValue(engine, QString::fromLatin1(\"ciao\"))"
- << "QScriptValue(engine, QString(\"\"))"
- << "QScriptValue(engine, QString())"
- << "QScriptValue(engine, QString(\"0\"))"
- << "QScriptValue(engine, QString(\"123\"))"
- << "QScriptValue(engine, QString(\"1.23\"))"
- << "engine->evaluate(\"'ciao'\")"
- << "engine->evaluate(\"''\")"
- << "engine->evaluate(\"'0'\")"
- << "engine->evaluate(\"'123'\")"
- << "engine->evaluate(\"'12.4'\")";
- }
- newRow(expr) << isString.contains(expr);
-}
-
-void tst_QScriptValue::isString_test(const char*, const QScriptValue& value)
-{
- QFETCH(bool, expected);
- QCOMPARE(value.isString(), expected);
- QCOMPARE(value.isString(), expected);
-}
-
-DEFINE_TEST_FUNCTION(isString)
-
-
-void tst_QScriptValue::isUndefined_initData()
-{
- QTest::addColumn<bool>("expected");
- initScriptValues();
-}
-
-void tst_QScriptValue::isUndefined_makeData(const char* expr)
-{
- static QSet<QString> isUndefined;
- if (isUndefined.isEmpty()) {
- isUndefined << "QScriptValue(QScriptValue::UndefinedValue)"
- << "QScriptValue(0, QScriptValue::UndefinedValue)"
- << "QScriptValue(engine, QScriptValue::UndefinedValue)"
- << "engine->evaluate(\"{}\")"
- << "engine->evaluate(\"undefined\")"
- << "engine->undefinedValue()";
- }
- newRow(expr) << isUndefined.contains(expr);
-}
-
-void tst_QScriptValue::isUndefined_test(const char*, const QScriptValue& value)
-{
- QFETCH(bool, expected);
- QCOMPARE(value.isUndefined(), expected);
- QCOMPARE(value.isUndefined(), expected);
-}
-
-DEFINE_TEST_FUNCTION(isUndefined)
-
-
-
-
-
-void tst_QScriptValue::isObject_initData()
-{
- QTest::addColumn<bool>("expected");
- initScriptValues();
-}
-
-void tst_QScriptValue::isObject_makeData(const char* expr)
-{
- static QSet<QString> isObject;
- if (isObject.isEmpty()) {
- isObject << "engine->evaluate(\"[]\")"
- << "engine->evaluate(\"Object.prototype\")"
- << "engine->evaluate(\"Date.prototype\")"
- << "engine->evaluate(\"Array.prototype\")"
- << "engine->evaluate(\"Function.prototype\")"
- << "engine->evaluate(\"Error.prototype\")"
- << "engine->evaluate(\"Object\")"
- << "engine->evaluate(\"Array\")"
- << "engine->evaluate(\"Number\")"
- << "engine->evaluate(\"Function\")"
- << "engine->evaluate(\"(function() { return 1; })\")"
- << "engine->evaluate(\"(function() { return 'ciao'; })\")"
- << "engine->evaluate(\"(function() { throw new Error('foo'); })\")"
- << "engine->evaluate(\"/foo/\")"
- << "engine->evaluate(\"new Object()\")"
- << "engine->evaluate(\"new Array()\")"
- << "engine->evaluate(\"new Error()\")"
- << "engine->evaluate(\"Undefined\")"
- << "engine->evaluate(\"Null\")"
- << "engine->evaluate(\"True\")"
- << "engine->evaluate(\"False\")";
- }
- newRow(expr) << isObject.contains(expr);
-}
-
-void tst_QScriptValue::isObject_test(const char*, const QScriptValue& value)
-{
- QFETCH(bool, expected);
- QCOMPARE(value.isObject(), expected);
- QCOMPARE(value.isObject(), expected);
-}
-
-DEFINE_TEST_FUNCTION(isObject)
-
-
-void tst_QScriptValue::toString_initData()
-{
- QTest::addColumn<QString>("expected");
- initScriptValues();
-}
-
-void tst_QScriptValue::toString_makeData(const char* expr)
-{
- static QHash<QString, QString> toString;
- if (toString.isEmpty()) {
- toString.insert("QScriptValue()", "");
- toString.insert("QScriptValue(QScriptValue::UndefinedValue)", "undefined");
- toString.insert("QScriptValue(QScriptValue::NullValue)", "null");
- toString.insert("QScriptValue(true)", "true");
- toString.insert("QScriptValue(false)", "false");
- toString.insert("QScriptValue(int(122))", "122");
- toString.insert("QScriptValue(uint(124))", "124");
- toString.insert("QScriptValue(0)", "0");
- toString.insert("QScriptValue(0.0)", "0");
- toString.insert("QScriptValue(123.0)", "123");
- toString.insert("QScriptValue(6.37e-8)", "6.37e-8");
- toString.insert("QScriptValue(-6.37e-8)", "-6.37e-8");
- toString.insert("QScriptValue(0x43211234)", "1126240820");
- toString.insert("QScriptValue(0x10000)", "65536");
- toString.insert("QScriptValue(0x10001)", "65537");
- toString.insert("QScriptValue(qSNaN())", "NaN");
- toString.insert("QScriptValue(qQNaN())", "NaN");
- toString.insert("QScriptValue(qInf())", "Infinity");
- toString.insert("QScriptValue(-qInf())", "-Infinity");
- toString.insert("QScriptValue(\"NaN\")", "NaN");
- toString.insert("QScriptValue(\"Infinity\")", "Infinity");
- toString.insert("QScriptValue(\"-Infinity\")", "-Infinity");
- toString.insert("QScriptValue(\"ciao\")", "ciao");
- toString.insert("QScriptValue(QString::fromLatin1(\"ciao\"))", "ciao");
- toString.insert("QScriptValue(QString(\"\"))", "");
- toString.insert("QScriptValue(QString())", "");
- toString.insert("QScriptValue(QString(\"0\"))", "0");
- toString.insert("QScriptValue(QString(\"123\"))", "123");
- toString.insert("QScriptValue(QString(\"12.4\"))", "12.4");
- toString.insert("QScriptValue(0, QScriptValue::UndefinedValue)", "undefined");
- toString.insert("QScriptValue(0, QScriptValue::NullValue)", "null");
- toString.insert("QScriptValue(0, true)", "true");
- toString.insert("QScriptValue(0, false)", "false");
- toString.insert("QScriptValue(0, int(122))", "122");
- toString.insert("QScriptValue(0, uint(124))", "124");
- toString.insert("QScriptValue(0, 0)", "0");
- toString.insert("QScriptValue(0, 0.0)", "0");
- toString.insert("QScriptValue(0, 123.0)", "123");
- toString.insert("QScriptValue(0, 6.37e-8)", "6.37e-8");
- toString.insert("QScriptValue(0, -6.37e-8)", "-6.37e-8");
- toString.insert("QScriptValue(0, 0x43211234)", "1126240820");
- toString.insert("QScriptValue(0, 0x10000)", "65536");
- toString.insert("QScriptValue(0, 0x10001)", "65537");
- toString.insert("QScriptValue(0, qSNaN())", "NaN");
- toString.insert("QScriptValue(0, qQNaN())", "NaN");
- toString.insert("QScriptValue(0, qInf())", "Infinity");
- toString.insert("QScriptValue(0, -qInf())", "-Infinity");
- toString.insert("QScriptValue(0, \"NaN\")", "NaN");
- toString.insert("QScriptValue(0, \"Infinity\")", "Infinity");
- toString.insert("QScriptValue(0, \"-Infinity\")", "-Infinity");
- toString.insert("QScriptValue(0, \"ciao\")", "ciao");
- toString.insert("QScriptValue(0, QString::fromLatin1(\"ciao\"))", "ciao");
- toString.insert("QScriptValue(0, QString(\"\"))", "");
- toString.insert("QScriptValue(0, QString())", "");
- toString.insert("QScriptValue(0, QString(\"0\"))", "0");
- toString.insert("QScriptValue(0, QString(\"123\"))", "123");
- toString.insert("QScriptValue(0, QString(\"12.3\"))", "12.3");
- toString.insert("QScriptValue(engine, QScriptValue::UndefinedValue)", "undefined");
- toString.insert("QScriptValue(engine, QScriptValue::NullValue)", "null");
- toString.insert("QScriptValue(engine, true)", "true");
- toString.insert("QScriptValue(engine, false)", "false");
- toString.insert("QScriptValue(engine, int(122))", "122");
- toString.insert("QScriptValue(engine, uint(124))", "124");
- toString.insert("QScriptValue(engine, 0)", "0");
- toString.insert("QScriptValue(engine, 0.0)", "0");
- toString.insert("QScriptValue(engine, 123.0)", "123");
- toString.insert("QScriptValue(engine, 6.37e-8)", "6.37e-8");
- toString.insert("QScriptValue(engine, -6.37e-8)", "-6.37e-8");
- toString.insert("QScriptValue(engine, 0x43211234)", "1126240820");
- toString.insert("QScriptValue(engine, 0x10000)", "65536");
- toString.insert("QScriptValue(engine, 0x10001)", "65537");
- toString.insert("QScriptValue(engine, qSNaN())", "NaN");
- toString.insert("QScriptValue(engine, qQNaN())", "NaN");
- toString.insert("QScriptValue(engine, qInf())", "Infinity");
- toString.insert("QScriptValue(engine, -qInf())", "-Infinity");
- toString.insert("QScriptValue(engine, \"NaN\")", "NaN");
- toString.insert("QScriptValue(engine, \"Infinity\")", "Infinity");
- toString.insert("QScriptValue(engine, \"-Infinity\")", "-Infinity");
- toString.insert("QScriptValue(engine, \"ciao\")", "ciao");
- toString.insert("QScriptValue(engine, QString::fromLatin1(\"ciao\"))", "ciao");
- toString.insert("QScriptValue(engine, QString(\"\"))", "");
- toString.insert("QScriptValue(engine, QString())", "");
- toString.insert("QScriptValue(engine, QString(\"0\"))", "0");
- toString.insert("QScriptValue(engine, QString(\"123\"))", "123");
- toString.insert("QScriptValue(engine, QString(\"1.23\"))", "1.23");
- toString.insert("engine->evaluate(\"[]\")", "");
- toString.insert("engine->evaluate(\"{}\")", "undefined");
- toString.insert("engine->evaluate(\"Object.prototype\")", "[object Object]");
- toString.insert("engine->evaluate(\"Date.prototype\")", "Invalid Date");
- toString.insert("engine->evaluate(\"Array.prototype\")", "");
- toString.insert("engine->evaluate(\"Function.prototype\")", "function () {\n [native code]\n}");
- toString.insert("engine->evaluate(\"Error.prototype\")", "Error: Unknown error");
- toString.insert("engine->evaluate(\"Object\")", "function Object() {\n [native code]\n}");
- toString.insert("engine->evaluate(\"Array\")", "function Array() {\n [native code]\n}");
- toString.insert("engine->evaluate(\"Number\")", "function Number() {\n [native code]\n}");
- toString.insert("engine->evaluate(\"Function\")", "function Function() {\n [native code]\n}");
- toString.insert("engine->evaluate(\"(function() { return 1; })\")", "function () { return 1; }");
- toString.insert("engine->evaluate(\"(function() { return 'ciao'; })\")", "function () { return 'ciao'; }");
- toString.insert("engine->evaluate(\"(function() { throw new Error('foo'); })\")", "function () { throw new Error('foo'); }");
- toString.insert("engine->evaluate(\"/foo/\")", "/foo/");
- toString.insert("engine->evaluate(\"new Object()\")", "[object Object]");
- toString.insert("engine->evaluate(\"new Array()\")", "");
- toString.insert("engine->evaluate(\"new Error()\")", "Error: Unknown error");
- toString.insert("engine->evaluate(\"a = new Object(); a.foo = 22; a.foo\")", "22");
- toString.insert("engine->evaluate(\"Undefined\")", "ReferenceError: Can't find variable: Undefined");
- toString.insert("engine->evaluate(\"Null\")", "ReferenceError: Can't find variable: Null");
- toString.insert("engine->evaluate(\"True\")", "ReferenceError: Can't find variable: True");
- toString.insert("engine->evaluate(\"False\")", "ReferenceError: Can't find variable: False");
- toString.insert("engine->evaluate(\"undefined\")", "undefined");
- toString.insert("engine->evaluate(\"null\")", "null");
- toString.insert("engine->evaluate(\"true\")", "true");
- toString.insert("engine->evaluate(\"false\")", "false");
- toString.insert("engine->evaluate(\"122\")", "122");
- toString.insert("engine->evaluate(\"124\")", "124");
- toString.insert("engine->evaluate(\"0\")", "0");
- toString.insert("engine->evaluate(\"0.0\")", "0");
- toString.insert("engine->evaluate(\"123.0\")", "123");
- toString.insert("engine->evaluate(\"6.37e-8\")", "6.37e-8");
- toString.insert("engine->evaluate(\"-6.37e-8\")", "-6.37e-8");
- toString.insert("engine->evaluate(\"0x43211234\")", "1126240820");
- toString.insert("engine->evaluate(\"0x10000\")", "65536");
- toString.insert("engine->evaluate(\"0x10001\")", "65537");
- toString.insert("engine->evaluate(\"NaN\")", "NaN");
- toString.insert("engine->evaluate(\"Infinity\")", "Infinity");
- toString.insert("engine->evaluate(\"-Infinity\")", "-Infinity");
- toString.insert("engine->evaluate(\"'ciao'\")", "ciao");
- toString.insert("engine->evaluate(\"''\")", "");
- toString.insert("engine->evaluate(\"'0'\")", "0");
- toString.insert("engine->evaluate(\"'123'\")", "123");
- toString.insert("engine->evaluate(\"'12.4'\")", "12.4");
- toString.insert("engine->nullValue()", "null");
- toString.insert("engine->undefinedValue()", "undefined");
- }
- newRow(expr) << toString.value(expr);
-}
-
-void tst_QScriptValue::toString_test(const char*, const QScriptValue& value)
-{
- QFETCH(QString, expected);
- QCOMPARE(value.toString(), expected);
- QCOMPARE(value.toString(), expected);
-}
-
-DEFINE_TEST_FUNCTION(toString)
-
-
-void tst_QScriptValue::toNumber_initData()
-{
- QTest::addColumn<qsreal>("expected");
- initScriptValues();
-}
-
-void tst_QScriptValue::toNumber_makeData(const char* expr)
-{
- static QHash<QString, qsreal> toNumber;
- if (toNumber.isEmpty()) {
- toNumber.insert("QScriptValue()", 0);
- toNumber.insert("QScriptValue(QScriptValue::UndefinedValue)", qQNaN());
- toNumber.insert("QScriptValue(QScriptValue::NullValue)", 0);
- toNumber.insert("QScriptValue(true)", 1);
- toNumber.insert("QScriptValue(false)", 0);
- toNumber.insert("QScriptValue(int(122))", 122);
- toNumber.insert("QScriptValue(uint(124))", 124);
- toNumber.insert("QScriptValue(0)", 0);
- toNumber.insert("QScriptValue(0.0)", 0);
- toNumber.insert("QScriptValue(123.0)", 123);
- toNumber.insert("QScriptValue(6.37e-8)", 6.369999999999999e-08);
- toNumber.insert("QScriptValue(-6.37e-8)", -6.369999999999999e-08);
- toNumber.insert("QScriptValue(0x43211234)", 1126240820);
- toNumber.insert("QScriptValue(0x10000)", 65536);
- toNumber.insert("QScriptValue(0x10001)", 65537);
- toNumber.insert("QScriptValue(qSNaN())", qQNaN());
- toNumber.insert("QScriptValue(qQNaN())", qQNaN());
- toNumber.insert("QScriptValue(qInf())", qInf());
- toNumber.insert("QScriptValue(-qInf())", qInf());
- toNumber.insert("QScriptValue(\"NaN\")", qQNaN());
- toNumber.insert("QScriptValue(\"Infinity\")", qInf());
- toNumber.insert("QScriptValue(\"-Infinity\")", qInf());
- toNumber.insert("QScriptValue(\"ciao\")", qQNaN());
- toNumber.insert("QScriptValue(QString::fromLatin1(\"ciao\"))", qQNaN());
- toNumber.insert("QScriptValue(QString(\"\"))", 0);
- toNumber.insert("QScriptValue(QString())", 0);
- toNumber.insert("QScriptValue(QString(\"0\"))", 0);
- toNumber.insert("QScriptValue(QString(\"123\"))", 123);
- toNumber.insert("QScriptValue(QString(\"12.4\"))", 12.4);
- toNumber.insert("QScriptValue(0, QScriptValue::UndefinedValue)", qQNaN());
- toNumber.insert("QScriptValue(0, QScriptValue::NullValue)", 0);
- toNumber.insert("QScriptValue(0, true)", 1);
- toNumber.insert("QScriptValue(0, false)", 0);
- toNumber.insert("QScriptValue(0, int(122))", 122);
- toNumber.insert("QScriptValue(0, uint(124))", 124);
- toNumber.insert("QScriptValue(0, 0)", 0);
- toNumber.insert("QScriptValue(0, 0.0)", 0);
- toNumber.insert("QScriptValue(0, 123.0)", 123);
- toNumber.insert("QScriptValue(0, 6.37e-8)", 6.369999999999999e-08);
- toNumber.insert("QScriptValue(0, -6.37e-8)", -6.369999999999999e-08);
- toNumber.insert("QScriptValue(0, 0x43211234)", 1126240820);
- toNumber.insert("QScriptValue(0, 0x10000)", 65536);
- toNumber.insert("QScriptValue(0, 0x10001)", 65537);
- toNumber.insert("QScriptValue(0, qSNaN())", qQNaN());
- toNumber.insert("QScriptValue(0, qQNaN())", qQNaN());
- toNumber.insert("QScriptValue(0, qInf())", qInf());
- toNumber.insert("QScriptValue(0, -qInf())", qInf());
- toNumber.insert("QScriptValue(0, \"NaN\")", qQNaN());
- toNumber.insert("QScriptValue(0, \"Infinity\")", qInf());
- toNumber.insert("QScriptValue(0, \"-Infinity\")", qInf());
- toNumber.insert("QScriptValue(0, \"ciao\")", qQNaN());
- toNumber.insert("QScriptValue(0, QString::fromLatin1(\"ciao\"))", qQNaN());
- toNumber.insert("QScriptValue(0, QString(\"\"))", 0);
- toNumber.insert("QScriptValue(0, QString())", 0);
- toNumber.insert("QScriptValue(0, QString(\"0\"))", 0);
- toNumber.insert("QScriptValue(0, QString(\"123\"))", 123);
- toNumber.insert("QScriptValue(0, QString(\"12.3\"))", 12.3);
- toNumber.insert("QScriptValue(engine, QScriptValue::UndefinedValue)", qQNaN());
- toNumber.insert("QScriptValue(engine, QScriptValue::NullValue)", 0);
- toNumber.insert("QScriptValue(engine, true)", 1);
- toNumber.insert("QScriptValue(engine, false)", 0);
- toNumber.insert("QScriptValue(engine, int(122))", 122);
- toNumber.insert("QScriptValue(engine, uint(124))", 124);
- toNumber.insert("QScriptValue(engine, 0)", 0);
- toNumber.insert("QScriptValue(engine, 0.0)", 0);
- toNumber.insert("QScriptValue(engine, 123.0)", 123);
- toNumber.insert("QScriptValue(engine, 6.37e-8)", 6.369999999999999e-08);
- toNumber.insert("QScriptValue(engine, -6.37e-8)", -6.369999999999999e-08);
- toNumber.insert("QScriptValue(engine, 0x43211234)", 1126240820);
- toNumber.insert("QScriptValue(engine, 0x10000)", 65536);
- toNumber.insert("QScriptValue(engine, 0x10001)", 65537);
- toNumber.insert("QScriptValue(engine, qSNaN())", qQNaN());
- toNumber.insert("QScriptValue(engine, qQNaN())", qQNaN());
- toNumber.insert("QScriptValue(engine, qInf())", qInf());
- toNumber.insert("QScriptValue(engine, -qInf())", qInf());
- toNumber.insert("QScriptValue(engine, \"NaN\")", qQNaN());
- toNumber.insert("QScriptValue(engine, \"Infinity\")", qInf());
- toNumber.insert("QScriptValue(engine, \"-Infinity\")", qInf());
- toNumber.insert("QScriptValue(engine, \"ciao\")", qQNaN());
- toNumber.insert("QScriptValue(engine, QString::fromLatin1(\"ciao\"))", qQNaN());
- toNumber.insert("QScriptValue(engine, QString(\"\"))", 0);
- toNumber.insert("QScriptValue(engine, QString())", 0);
- toNumber.insert("QScriptValue(engine, QString(\"0\"))", 0);
- toNumber.insert("QScriptValue(engine, QString(\"123\"))", 123);
- toNumber.insert("QScriptValue(engine, QString(\"1.23\"))", 1.23);
- toNumber.insert("engine->evaluate(\"[]\")", 0);
- toNumber.insert("engine->evaluate(\"{}\")", qQNaN());
- toNumber.insert("engine->evaluate(\"Object.prototype\")", qQNaN());
- toNumber.insert("engine->evaluate(\"Date.prototype\")", qQNaN());
- toNumber.insert("engine->evaluate(\"Array.prototype\")", 0);
- toNumber.insert("engine->evaluate(\"Function.prototype\")", qQNaN());
- toNumber.insert("engine->evaluate(\"Error.prototype\")", qQNaN());
- toNumber.insert("engine->evaluate(\"Object\")", qQNaN());
- toNumber.insert("engine->evaluate(\"Array\")", qQNaN());
- toNumber.insert("engine->evaluate(\"Number\")", qQNaN());
- toNumber.insert("engine->evaluate(\"Function\")", qQNaN());
- toNumber.insert("engine->evaluate(\"(function() { return 1; })\")", qQNaN());
- toNumber.insert("engine->evaluate(\"(function() { return 'ciao'; })\")", qQNaN());
- toNumber.insert("engine->evaluate(\"(function() { throw new Error('foo'); })\")", qQNaN());
- toNumber.insert("engine->evaluate(\"/foo/\")", qQNaN());
- toNumber.insert("engine->evaluate(\"new Object()\")", qQNaN());
- toNumber.insert("engine->evaluate(\"new Array()\")", 0);
- toNumber.insert("engine->evaluate(\"new Error()\")", qQNaN());
- toNumber.insert("engine->evaluate(\"a = new Object(); a.foo = 22; a.foo\")", 22);
- toNumber.insert("engine->evaluate(\"Undefined\")", qQNaN());
- toNumber.insert("engine->evaluate(\"Null\")", qQNaN());
- toNumber.insert("engine->evaluate(\"True\")", qQNaN());
- toNumber.insert("engine->evaluate(\"False\")", qQNaN());
- toNumber.insert("engine->evaluate(\"undefined\")", qQNaN());
- toNumber.insert("engine->evaluate(\"null\")", 0);
- toNumber.insert("engine->evaluate(\"true\")", 1);
- toNumber.insert("engine->evaluate(\"false\")", 0);
- toNumber.insert("engine->evaluate(\"122\")", 122);
- toNumber.insert("engine->evaluate(\"124\")", 124);
- toNumber.insert("engine->evaluate(\"0\")", 0);
- toNumber.insert("engine->evaluate(\"0.0\")", 0);
- toNumber.insert("engine->evaluate(\"123.0\")", 123);
- toNumber.insert("engine->evaluate(\"6.37e-8\")", 6.369999999999999e-08);
- toNumber.insert("engine->evaluate(\"-6.37e-8\")", -6.369999999999999e-08);
- toNumber.insert("engine->evaluate(\"0x43211234\")", 1126240820);
- toNumber.insert("engine->evaluate(\"0x10000\")", 65536);
- toNumber.insert("engine->evaluate(\"0x10001\")", 65537);
- toNumber.insert("engine->evaluate(\"NaN\")", qQNaN());
- toNumber.insert("engine->evaluate(\"Infinity\")", qInf());
- toNumber.insert("engine->evaluate(\"-Infinity\")", qInf());
- toNumber.insert("engine->evaluate(\"'ciao'\")", qQNaN());
- toNumber.insert("engine->evaluate(\"''\")", 0);
- toNumber.insert("engine->evaluate(\"'0'\")", 0);
- toNumber.insert("engine->evaluate(\"'123'\")", 123);
- toNumber.insert("engine->evaluate(\"'12.4'\")", 12.4);
- toNumber.insert("engine->nullValue()", 0);
- toNumber.insert("engine->undefinedValue()", qQNaN());
- }
- newRow(expr) << toNumber.value(expr);
-}
-
-void tst_QScriptValue::toNumber_test(const char*, const QScriptValue& value)
-{
- QFETCH(qsreal, expected);
- if (qIsNaN(expected)) {
- QVERIFY(qIsNaN(value.toNumber()));
- return;
- }
- if (qIsInf(expected)) {
- QVERIFY(qIsInf(value.toNumber()));
- QVERIFY(qIsInf(value.toNumber()));
- return;
- }
- QCOMPARE(value.toNumber(), expected);
- QCOMPARE(value.toNumber(), expected);
-}
-
-DEFINE_TEST_FUNCTION(toNumber)
-
-
-void tst_QScriptValue::toBool_initData()
-{
- QTest::addColumn<bool>("expected");
- initScriptValues();
-}
-
-void tst_QScriptValue::toBool_makeData(const char* expr)
-{
- static QHash<QString, bool> toBool;
- if (toBool.isEmpty()) {
- toBool.insert("QScriptValue()", false);
- toBool.insert("QScriptValue(QScriptValue::UndefinedValue)", false);
- toBool.insert("QScriptValue(QScriptValue::NullValue)", false);
- toBool.insert("QScriptValue(true)", true);
- toBool.insert("QScriptValue(false)", false);
- toBool.insert("QScriptValue(int(122))", true);
- toBool.insert("QScriptValue(uint(124))", true);
- toBool.insert("QScriptValue(0)", false);
- toBool.insert("QScriptValue(0.0)", false);
- toBool.insert("QScriptValue(123.0)", true);
- toBool.insert("QScriptValue(6.37e-8)", true);
- toBool.insert("QScriptValue(-6.37e-8)", true);
- toBool.insert("QScriptValue(0x43211234)", true);
- toBool.insert("QScriptValue(0x10000)", true);
- toBool.insert("QScriptValue(0x10001)", true);
- toBool.insert("QScriptValue(qSNaN())", false);
- toBool.insert("QScriptValue(qQNaN())", false);
- toBool.insert("QScriptValue(qInf())", true);
- toBool.insert("QScriptValue(-qInf())", true);
- toBool.insert("QScriptValue(\"NaN\")", true);
- toBool.insert("QScriptValue(\"Infinity\")", true);
- toBool.insert("QScriptValue(\"-Infinity\")", true);
- toBool.insert("QScriptValue(\"ciao\")", true);
- toBool.insert("QScriptValue(QString::fromLatin1(\"ciao\"))", true);
- toBool.insert("QScriptValue(QString(\"\"))", false);
- toBool.insert("QScriptValue(QString())", false);
- toBool.insert("QScriptValue(QString(\"0\"))", true);
- toBool.insert("QScriptValue(QString(\"123\"))", true);
- toBool.insert("QScriptValue(QString(\"12.4\"))", true);
- toBool.insert("QScriptValue(0, QScriptValue::UndefinedValue)", false);
- toBool.insert("QScriptValue(0, QScriptValue::NullValue)", false);
- toBool.insert("QScriptValue(0, true)", true);
- toBool.insert("QScriptValue(0, false)", false);
- toBool.insert("QScriptValue(0, int(122))", true);
- toBool.insert("QScriptValue(0, uint(124))", true);
- toBool.insert("QScriptValue(0, 0)", false);
- toBool.insert("QScriptValue(0, 0.0)", false);
- toBool.insert("QScriptValue(0, 123.0)", true);
- toBool.insert("QScriptValue(0, 6.37e-8)", true);
- toBool.insert("QScriptValue(0, -6.37e-8)", true);
- toBool.insert("QScriptValue(0, 0x43211234)", true);
- toBool.insert("QScriptValue(0, 0x10000)", true);
- toBool.insert("QScriptValue(0, 0x10001)", true);
- toBool.insert("QScriptValue(0, qSNaN())", false);
- toBool.insert("QScriptValue(0, qQNaN())", false);
- toBool.insert("QScriptValue(0, qInf())", true);
- toBool.insert("QScriptValue(0, -qInf())", true);
- toBool.insert("QScriptValue(0, \"NaN\")", true);
- toBool.insert("QScriptValue(0, \"Infinity\")", true);
- toBool.insert("QScriptValue(0, \"-Infinity\")", true);
- toBool.insert("QScriptValue(0, \"ciao\")", true);
- toBool.insert("QScriptValue(0, QString::fromLatin1(\"ciao\"))", true);
- toBool.insert("QScriptValue(0, QString(\"\"))", false);
- toBool.insert("QScriptValue(0, QString())", false);
- toBool.insert("QScriptValue(0, QString(\"0\"))", true);
- toBool.insert("QScriptValue(0, QString(\"123\"))", true);
- toBool.insert("QScriptValue(0, QString(\"12.3\"))", true);
- toBool.insert("QScriptValue(engine, QScriptValue::UndefinedValue)", false);
- toBool.insert("QScriptValue(engine, QScriptValue::NullValue)", false);
- toBool.insert("QScriptValue(engine, true)", true);
- toBool.insert("QScriptValue(engine, false)", false);
- toBool.insert("QScriptValue(engine, int(122))", true);
- toBool.insert("QScriptValue(engine, uint(124))", true);
- toBool.insert("QScriptValue(engine, 0)", false);
- toBool.insert("QScriptValue(engine, 0.0)", false);
- toBool.insert("QScriptValue(engine, 123.0)", true);
- toBool.insert("QScriptValue(engine, 6.37e-8)", true);
- toBool.insert("QScriptValue(engine, -6.37e-8)", true);
- toBool.insert("QScriptValue(engine, 0x43211234)", true);
- toBool.insert("QScriptValue(engine, 0x10000)", true);
- toBool.insert("QScriptValue(engine, 0x10001)", true);
- toBool.insert("QScriptValue(engine, qSNaN())", false);
- toBool.insert("QScriptValue(engine, qQNaN())", false);
- toBool.insert("QScriptValue(engine, qInf())", true);
- toBool.insert("QScriptValue(engine, -qInf())", true);
- toBool.insert("QScriptValue(engine, \"NaN\")", true);
- toBool.insert("QScriptValue(engine, \"Infinity\")", true);
- toBool.insert("QScriptValue(engine, \"-Infinity\")", true);
- toBool.insert("QScriptValue(engine, \"ciao\")", true);
- toBool.insert("QScriptValue(engine, QString::fromLatin1(\"ciao\"))", true);
- toBool.insert("QScriptValue(engine, QString(\"\"))", false);
- toBool.insert("QScriptValue(engine, QString())", false);
- toBool.insert("QScriptValue(engine, QString(\"0\"))", true);
- toBool.insert("QScriptValue(engine, QString(\"123\"))", true);
- toBool.insert("QScriptValue(engine, QString(\"1.23\"))", true);
- toBool.insert("engine->evaluate(\"[]\")", true);
- toBool.insert("engine->evaluate(\"{}\")", false);
- toBool.insert("engine->evaluate(\"Object.prototype\")", true);
- toBool.insert("engine->evaluate(\"Date.prototype\")", true);
- toBool.insert("engine->evaluate(\"Array.prototype\")", true);
- toBool.insert("engine->evaluate(\"Function.prototype\")", true);
- toBool.insert("engine->evaluate(\"Error.prototype\")", true);
- toBool.insert("engine->evaluate(\"Object\")", true);
- toBool.insert("engine->evaluate(\"Array\")", true);
- toBool.insert("engine->evaluate(\"Number\")", true);
- toBool.insert("engine->evaluate(\"Function\")", true);
- toBool.insert("engine->evaluate(\"(function() { return 1; })\")", true);
- toBool.insert("engine->evaluate(\"(function() { return 'ciao'; })\")", true);
- toBool.insert("engine->evaluate(\"(function() { throw new Error('foo'); })\")", true);
- toBool.insert("engine->evaluate(\"/foo/\")", true);
- toBool.insert("engine->evaluate(\"new Object()\")", true);
- toBool.insert("engine->evaluate(\"new Array()\")", true);
- toBool.insert("engine->evaluate(\"new Error()\")", true);
- toBool.insert("engine->evaluate(\"a = new Object(); a.foo = 22; a.foo\")", true);
- toBool.insert("engine->evaluate(\"Undefined\")", true);
- toBool.insert("engine->evaluate(\"Null\")", true);
- toBool.insert("engine->evaluate(\"True\")", true);
- toBool.insert("engine->evaluate(\"False\")", true);
- toBool.insert("engine->evaluate(\"undefined\")", false);
- toBool.insert("engine->evaluate(\"null\")", false);
- toBool.insert("engine->evaluate(\"true\")", true);
- toBool.insert("engine->evaluate(\"false\")", false);
- toBool.insert("engine->evaluate(\"122\")", true);
- toBool.insert("engine->evaluate(\"124\")", true);
- toBool.insert("engine->evaluate(\"0\")", false);
- toBool.insert("engine->evaluate(\"0.0\")", false);
- toBool.insert("engine->evaluate(\"123.0\")", true);
- toBool.insert("engine->evaluate(\"6.37e-8\")", true);
- toBool.insert("engine->evaluate(\"-6.37e-8\")", true);
- toBool.insert("engine->evaluate(\"0x43211234\")", true);
- toBool.insert("engine->evaluate(\"0x10000\")", true);
- toBool.insert("engine->evaluate(\"0x10001\")", true);
- toBool.insert("engine->evaluate(\"NaN\")", false);
- toBool.insert("engine->evaluate(\"Infinity\")", true);
- toBool.insert("engine->evaluate(\"-Infinity\")", true);
- toBool.insert("engine->evaluate(\"'ciao'\")", true);
- toBool.insert("engine->evaluate(\"''\")", false);
- toBool.insert("engine->evaluate(\"'0'\")", true);
- toBool.insert("engine->evaluate(\"'123'\")", true);
- toBool.insert("engine->evaluate(\"'12.4'\")", true);
- toBool.insert("engine->nullValue()", false);
- toBool.insert("engine->undefinedValue()", false);
- }
- newRow(expr) << toBool.value(expr);
-}
-
-void tst_QScriptValue::toBool_test(const char*, const QScriptValue& value)
-{
- QFETCH(bool, expected);
- QCOMPARE(value.toBool(), expected);
- QCOMPARE(value.toBool(), expected);
-}
-
-DEFINE_TEST_FUNCTION(toBool)
-
-
-void tst_QScriptValue::toBoolean_initData()
-{
- QTest::addColumn<bool>("expected");
- initScriptValues();
-}
-
-void tst_QScriptValue::toBoolean_makeData(const char* expr)
-{
- static QHash<QString, bool> toBoolean;
- if (toBoolean.isEmpty()) {
- toBoolean.insert("QScriptValue()", false);
- toBoolean.insert("QScriptValue(QScriptValue::UndefinedValue)", false);
- toBoolean.insert("QScriptValue(QScriptValue::NullValue)", false);
- toBoolean.insert("QScriptValue(true)", true);
- toBoolean.insert("QScriptValue(false)", false);
- toBoolean.insert("QScriptValue(int(122))", true);
- toBoolean.insert("QScriptValue(uint(124))", true);
- toBoolean.insert("QScriptValue(0)", false);
- toBoolean.insert("QScriptValue(0.0)", false);
- toBoolean.insert("QScriptValue(123.0)", true);
- toBoolean.insert("QScriptValue(6.37e-8)", true);
- toBoolean.insert("QScriptValue(-6.37e-8)", true);
- toBoolean.insert("QScriptValue(0x43211234)", true);
- toBoolean.insert("QScriptValue(0x10000)", true);
- toBoolean.insert("QScriptValue(0x10001)", true);
- toBoolean.insert("QScriptValue(qSNaN())", false);
- toBoolean.insert("QScriptValue(qQNaN())", false);
- toBoolean.insert("QScriptValue(qInf())", true);
- toBoolean.insert("QScriptValue(-qInf())", true);
- toBoolean.insert("QScriptValue(\"NaN\")", true);
- toBoolean.insert("QScriptValue(\"Infinity\")", true);
- toBoolean.insert("QScriptValue(\"-Infinity\")", true);
- toBoolean.insert("QScriptValue(\"ciao\")", true);
- toBoolean.insert("QScriptValue(QString::fromLatin1(\"ciao\"))", true);
- toBoolean.insert("QScriptValue(QString(\"\"))", false);
- toBoolean.insert("QScriptValue(QString())", false);
- toBoolean.insert("QScriptValue(QString(\"0\"))", true);
- toBoolean.insert("QScriptValue(QString(\"123\"))", true);
- toBoolean.insert("QScriptValue(QString(\"12.4\"))", true);
- toBoolean.insert("QScriptValue(0, QScriptValue::UndefinedValue)", false);
- toBoolean.insert("QScriptValue(0, QScriptValue::NullValue)", false);
- toBoolean.insert("QScriptValue(0, true)", true);
- toBoolean.insert("QScriptValue(0, false)", false);
- toBoolean.insert("QScriptValue(0, int(122))", true);
- toBoolean.insert("QScriptValue(0, uint(124))", true);
- toBoolean.insert("QScriptValue(0, 0)", false);
- toBoolean.insert("QScriptValue(0, 0.0)", false);
- toBoolean.insert("QScriptValue(0, 123.0)", true);
- toBoolean.insert("QScriptValue(0, 6.37e-8)", true);
- toBoolean.insert("QScriptValue(0, -6.37e-8)", true);
- toBoolean.insert("QScriptValue(0, 0x43211234)", true);
- toBoolean.insert("QScriptValue(0, 0x10000)", true);
- toBoolean.insert("QScriptValue(0, 0x10001)", true);
- toBoolean.insert("QScriptValue(0, qSNaN())", false);
- toBoolean.insert("QScriptValue(0, qQNaN())", false);
- toBoolean.insert("QScriptValue(0, qInf())", true);
- toBoolean.insert("QScriptValue(0, -qInf())", true);
- toBoolean.insert("QScriptValue(0, \"NaN\")", true);
- toBoolean.insert("QScriptValue(0, \"Infinity\")", true);
- toBoolean.insert("QScriptValue(0, \"-Infinity\")", true);
- toBoolean.insert("QScriptValue(0, \"ciao\")", true);
- toBoolean.insert("QScriptValue(0, QString::fromLatin1(\"ciao\"))", true);
- toBoolean.insert("QScriptValue(0, QString(\"\"))", false);
- toBoolean.insert("QScriptValue(0, QString())", false);
- toBoolean.insert("QScriptValue(0, QString(\"0\"))", true);
- toBoolean.insert("QScriptValue(0, QString(\"123\"))", true);
- toBoolean.insert("QScriptValue(0, QString(\"12.3\"))", true);
- toBoolean.insert("QScriptValue(engine, QScriptValue::UndefinedValue)", false);
- toBoolean.insert("QScriptValue(engine, QScriptValue::NullValue)", false);
- toBoolean.insert("QScriptValue(engine, true)", true);
- toBoolean.insert("QScriptValue(engine, false)", false);
- toBoolean.insert("QScriptValue(engine, int(122))", true);
- toBoolean.insert("QScriptValue(engine, uint(124))", true);
- toBoolean.insert("QScriptValue(engine, 0)", false);
- toBoolean.insert("QScriptValue(engine, 0.0)", false);
- toBoolean.insert("QScriptValue(engine, 123.0)", true);
- toBoolean.insert("QScriptValue(engine, 6.37e-8)", true);
- toBoolean.insert("QScriptValue(engine, -6.37e-8)", true);
- toBoolean.insert("QScriptValue(engine, 0x43211234)", true);
- toBoolean.insert("QScriptValue(engine, 0x10000)", true);
- toBoolean.insert("QScriptValue(engine, 0x10001)", true);
- toBoolean.insert("QScriptValue(engine, qSNaN())", false);
- toBoolean.insert("QScriptValue(engine, qQNaN())", false);
- toBoolean.insert("QScriptValue(engine, qInf())", true);
- toBoolean.insert("QScriptValue(engine, -qInf())", true);
- toBoolean.insert("QScriptValue(engine, \"NaN\")", true);
- toBoolean.insert("QScriptValue(engine, \"Infinity\")", true);
- toBoolean.insert("QScriptValue(engine, \"-Infinity\")", true);
- toBoolean.insert("QScriptValue(engine, \"ciao\")", true);
- toBoolean.insert("QScriptValue(engine, QString::fromLatin1(\"ciao\"))", true);
- toBoolean.insert("QScriptValue(engine, QString(\"\"))", false);
- toBoolean.insert("QScriptValue(engine, QString())", false);
- toBoolean.insert("QScriptValue(engine, QString(\"0\"))", true);
- toBoolean.insert("QScriptValue(engine, QString(\"123\"))", true);
- toBoolean.insert("QScriptValue(engine, QString(\"1.23\"))", true);
- toBoolean.insert("engine->evaluate(\"[]\")", true);
- toBoolean.insert("engine->evaluate(\"{}\")", false);
- toBoolean.insert("engine->evaluate(\"Object.prototype\")", true);
- toBoolean.insert("engine->evaluate(\"Date.prototype\")", true);
- toBoolean.insert("engine->evaluate(\"Array.prototype\")", true);
- toBoolean.insert("engine->evaluate(\"Function.prototype\")", true);
- toBoolean.insert("engine->evaluate(\"Error.prototype\")", true);
- toBoolean.insert("engine->evaluate(\"Object\")", true);
- toBoolean.insert("engine->evaluate(\"Array\")", true);
- toBoolean.insert("engine->evaluate(\"Number\")", true);
- toBoolean.insert("engine->evaluate(\"Function\")", true);
- toBoolean.insert("engine->evaluate(\"(function() { return 1; })\")", true);
- toBoolean.insert("engine->evaluate(\"(function() { return 'ciao'; })\")", true);
- toBoolean.insert("engine->evaluate(\"(function() { throw new Error('foo'); })\")", true);
- toBoolean.insert("engine->evaluate(\"/foo/\")", true);
- toBoolean.insert("engine->evaluate(\"new Object()\")", true);
- toBoolean.insert("engine->evaluate(\"new Array()\")", true);
- toBoolean.insert("engine->evaluate(\"new Error()\")", true);
- toBoolean.insert("engine->evaluate(\"a = new Object(); a.foo = 22; a.foo\")", true);
- toBoolean.insert("engine->evaluate(\"Undefined\")", true);
- toBoolean.insert("engine->evaluate(\"Null\")", true);
- toBoolean.insert("engine->evaluate(\"True\")", true);
- toBoolean.insert("engine->evaluate(\"False\")", true);
- toBoolean.insert("engine->evaluate(\"undefined\")", false);
- toBoolean.insert("engine->evaluate(\"null\")", false);
- toBoolean.insert("engine->evaluate(\"true\")", true);
- toBoolean.insert("engine->evaluate(\"false\")", false);
- toBoolean.insert("engine->evaluate(\"122\")", true);
- toBoolean.insert("engine->evaluate(\"124\")", true);
- toBoolean.insert("engine->evaluate(\"0\")", false);
- toBoolean.insert("engine->evaluate(\"0.0\")", false);
- toBoolean.insert("engine->evaluate(\"123.0\")", true);
- toBoolean.insert("engine->evaluate(\"6.37e-8\")", true);
- toBoolean.insert("engine->evaluate(\"-6.37e-8\")", true);
- toBoolean.insert("engine->evaluate(\"0x43211234\")", true);
- toBoolean.insert("engine->evaluate(\"0x10000\")", true);
- toBoolean.insert("engine->evaluate(\"0x10001\")", true);
- toBoolean.insert("engine->evaluate(\"NaN\")", false);
- toBoolean.insert("engine->evaluate(\"Infinity\")", true);
- toBoolean.insert("engine->evaluate(\"-Infinity\")", true);
- toBoolean.insert("engine->evaluate(\"'ciao'\")", true);
- toBoolean.insert("engine->evaluate(\"''\")", false);
- toBoolean.insert("engine->evaluate(\"'0'\")", true);
- toBoolean.insert("engine->evaluate(\"'123'\")", true);
- toBoolean.insert("engine->evaluate(\"'12.4'\")", true);
- toBoolean.insert("engine->nullValue()", false);
- toBoolean.insert("engine->undefinedValue()", false);
- }
- newRow(expr) << toBoolean.value(expr);
-}
-
-void tst_QScriptValue::toBoolean_test(const char*, const QScriptValue& value)
-{
- QFETCH(bool, expected);
- QCOMPARE(value.toBoolean(), expected);
- QCOMPARE(value.toBoolean(), expected);
-}
-
-DEFINE_TEST_FUNCTION(toBoolean)
-
-
-void tst_QScriptValue::toInteger_initData()
-{
- QTest::addColumn<qsreal>("expected");
- initScriptValues();
-}
-
-void tst_QScriptValue::toInteger_makeData(const char* expr)
-{
- static QHash<QString, qsreal> toInteger;
- if (toInteger.isEmpty()) {
- toInteger.insert("QScriptValue()", 0);
- toInteger.insert("QScriptValue(QScriptValue::UndefinedValue)", 0);
- toInteger.insert("QScriptValue(QScriptValue::NullValue)", 0);
- toInteger.insert("QScriptValue(true)", 1);
- toInteger.insert("QScriptValue(false)", 0);
- toInteger.insert("QScriptValue(int(122))", 122);
- toInteger.insert("QScriptValue(uint(124))", 124);
- toInteger.insert("QScriptValue(0)", 0);
- toInteger.insert("QScriptValue(0.0)", 0);
- toInteger.insert("QScriptValue(123.0)", 123);
- toInteger.insert("QScriptValue(6.37e-8)", 0);
- toInteger.insert("QScriptValue(-6.37e-8)", 0);
- toInteger.insert("QScriptValue(0x43211234)", 1126240820);
- toInteger.insert("QScriptValue(0x10000)", 65536);
- toInteger.insert("QScriptValue(0x10001)", 65537);
- toInteger.insert("QScriptValue(qSNaN())", 0);
- toInteger.insert("QScriptValue(qQNaN())", 0);
- toInteger.insert("QScriptValue(qInf())", qInf());
- toInteger.insert("QScriptValue(-qInf())", qInf());
- toInteger.insert("QScriptValue(\"NaN\")", 0);
- toInteger.insert("QScriptValue(\"Infinity\")", qInf());
- toInteger.insert("QScriptValue(\"-Infinity\")", qInf());
- toInteger.insert("QScriptValue(\"ciao\")", 0);
- toInteger.insert("QScriptValue(QString::fromLatin1(\"ciao\"))", 0);
- toInteger.insert("QScriptValue(QString(\"\"))", 0);
- toInteger.insert("QScriptValue(QString())", 0);
- toInteger.insert("QScriptValue(QString(\"0\"))", 0);
- toInteger.insert("QScriptValue(QString(\"123\"))", 123);
- toInteger.insert("QScriptValue(QString(\"12.4\"))", 12);
- toInteger.insert("QScriptValue(0, QScriptValue::UndefinedValue)", 0);
- toInteger.insert("QScriptValue(0, QScriptValue::NullValue)", 0);
- toInteger.insert("QScriptValue(0, true)", 1);
- toInteger.insert("QScriptValue(0, false)", 0);
- toInteger.insert("QScriptValue(0, int(122))", 122);
- toInteger.insert("QScriptValue(0, uint(124))", 124);
- toInteger.insert("QScriptValue(0, 0)", 0);
- toInteger.insert("QScriptValue(0, 0.0)", 0);
- toInteger.insert("QScriptValue(0, 123.0)", 123);
- toInteger.insert("QScriptValue(0, 6.37e-8)", 0);
- toInteger.insert("QScriptValue(0, -6.37e-8)", 0);
- toInteger.insert("QScriptValue(0, 0x43211234)", 1126240820);
- toInteger.insert("QScriptValue(0, 0x10000)", 65536);
- toInteger.insert("QScriptValue(0, 0x10001)", 65537);
- toInteger.insert("QScriptValue(0, qSNaN())", 0);
- toInteger.insert("QScriptValue(0, qQNaN())", 0);
- toInteger.insert("QScriptValue(0, qInf())", qInf());
- toInteger.insert("QScriptValue(0, -qInf())", qInf());
- toInteger.insert("QScriptValue(0, \"NaN\")", 0);
- toInteger.insert("QScriptValue(0, \"Infinity\")", qInf());
- toInteger.insert("QScriptValue(0, \"-Infinity\")", qInf());
- toInteger.insert("QScriptValue(0, \"ciao\")", 0);
- toInteger.insert("QScriptValue(0, QString::fromLatin1(\"ciao\"))", 0);
- toInteger.insert("QScriptValue(0, QString(\"\"))", 0);
- toInteger.insert("QScriptValue(0, QString())", 0);
- toInteger.insert("QScriptValue(0, QString(\"0\"))", 0);
- toInteger.insert("QScriptValue(0, QString(\"123\"))", 123);
- toInteger.insert("QScriptValue(0, QString(\"12.3\"))", 12);
- toInteger.insert("QScriptValue(engine, QScriptValue::UndefinedValue)", 0);
- toInteger.insert("QScriptValue(engine, QScriptValue::NullValue)", 0);
- toInteger.insert("QScriptValue(engine, true)", 1);
- toInteger.insert("QScriptValue(engine, false)", 0);
- toInteger.insert("QScriptValue(engine, int(122))", 122);
- toInteger.insert("QScriptValue(engine, uint(124))", 124);
- toInteger.insert("QScriptValue(engine, 0)", 0);
- toInteger.insert("QScriptValue(engine, 0.0)", 0);
- toInteger.insert("QScriptValue(engine, 123.0)", 123);
- toInteger.insert("QScriptValue(engine, 6.37e-8)", 0);
- toInteger.insert("QScriptValue(engine, -6.37e-8)", 0);
- toInteger.insert("QScriptValue(engine, 0x43211234)", 1126240820);
- toInteger.insert("QScriptValue(engine, 0x10000)", 65536);
- toInteger.insert("QScriptValue(engine, 0x10001)", 65537);
- toInteger.insert("QScriptValue(engine, qSNaN())", 0);
- toInteger.insert("QScriptValue(engine, qQNaN())", 0);
- toInteger.insert("QScriptValue(engine, qInf())", qInf());
- toInteger.insert("QScriptValue(engine, -qInf())", qInf());
- toInteger.insert("QScriptValue(engine, \"NaN\")", 0);
- toInteger.insert("QScriptValue(engine, \"Infinity\")", qInf());
- toInteger.insert("QScriptValue(engine, \"-Infinity\")", qInf());
- toInteger.insert("QScriptValue(engine, \"ciao\")", 0);
- toInteger.insert("QScriptValue(engine, QString::fromLatin1(\"ciao\"))", 0);
- toInteger.insert("QScriptValue(engine, QString(\"\"))", 0);
- toInteger.insert("QScriptValue(engine, QString())", 0);
- toInteger.insert("QScriptValue(engine, QString(\"0\"))", 0);
- toInteger.insert("QScriptValue(engine, QString(\"123\"))", 123);
- toInteger.insert("QScriptValue(engine, QString(\"1.23\"))", 1);
- toInteger.insert("engine->evaluate(\"[]\")", 0);
- toInteger.insert("engine->evaluate(\"{}\")", 0);
- toInteger.insert("engine->evaluate(\"Object.prototype\")", 0);
- toInteger.insert("engine->evaluate(\"Date.prototype\")", 0);
- toInteger.insert("engine->evaluate(\"Array.prototype\")", 0);
- toInteger.insert("engine->evaluate(\"Function.prototype\")", 0);
- toInteger.insert("engine->evaluate(\"Error.prototype\")", 0);
- toInteger.insert("engine->evaluate(\"Object\")", 0);
- toInteger.insert("engine->evaluate(\"Array\")", 0);
- toInteger.insert("engine->evaluate(\"Number\")", 0);
- toInteger.insert("engine->evaluate(\"Function\")", 0);
- toInteger.insert("engine->evaluate(\"(function() { return 1; })\")", 0);
- toInteger.insert("engine->evaluate(\"(function() { return 'ciao'; })\")", 0);
- toInteger.insert("engine->evaluate(\"(function() { throw new Error('foo'); })\")", 0);
- toInteger.insert("engine->evaluate(\"/foo/\")", 0);
- toInteger.insert("engine->evaluate(\"new Object()\")", 0);
- toInteger.insert("engine->evaluate(\"new Array()\")", 0);
- toInteger.insert("engine->evaluate(\"new Error()\")", 0);
- toInteger.insert("engine->evaluate(\"a = new Object(); a.foo = 22; a.foo\")", 22);
- toInteger.insert("engine->evaluate(\"Undefined\")", 0);
- toInteger.insert("engine->evaluate(\"Null\")", 0);
- toInteger.insert("engine->evaluate(\"True\")", 0);
- toInteger.insert("engine->evaluate(\"False\")", 0);
- toInteger.insert("engine->evaluate(\"undefined\")", 0);
- toInteger.insert("engine->evaluate(\"null\")", 0);
- toInteger.insert("engine->evaluate(\"true\")", 1);
- toInteger.insert("engine->evaluate(\"false\")", 0);
- toInteger.insert("engine->evaluate(\"122\")", 122);
- toInteger.insert("engine->evaluate(\"124\")", 124);
- toInteger.insert("engine->evaluate(\"0\")", 0);
- toInteger.insert("engine->evaluate(\"0.0\")", 0);
- toInteger.insert("engine->evaluate(\"123.0\")", 123);
- toInteger.insert("engine->evaluate(\"6.37e-8\")", 0);
- toInteger.insert("engine->evaluate(\"-6.37e-8\")", 0);
- toInteger.insert("engine->evaluate(\"0x43211234\")", 1126240820);
- toInteger.insert("engine->evaluate(\"0x10000\")", 65536);
- toInteger.insert("engine->evaluate(\"0x10001\")", 65537);
- toInteger.insert("engine->evaluate(\"NaN\")", 0);
- toInteger.insert("engine->evaluate(\"Infinity\")", qInf());
- toInteger.insert("engine->evaluate(\"-Infinity\")", qInf());
- toInteger.insert("engine->evaluate(\"'ciao'\")", 0);
- toInteger.insert("engine->evaluate(\"''\")", 0);
- toInteger.insert("engine->evaluate(\"'0'\")", 0);
- toInteger.insert("engine->evaluate(\"'123'\")", 123);
- toInteger.insert("engine->evaluate(\"'12.4'\")", 12);
- toInteger.insert("engine->nullValue()", 0);
- toInteger.insert("engine->undefinedValue()", 0);
- }
- newRow(expr) << toInteger.value(expr);
-}
-
-void tst_QScriptValue::toInteger_test(const char*, const QScriptValue& value)
-{
- QFETCH(qsreal, expected);
- if (qIsInf(expected)) {
- QVERIFY(qIsInf(value.toInteger()));
- QVERIFY(qIsInf(value.toInteger()));
- return;
- }
- QCOMPARE(value.toInteger(), expected);
- QCOMPARE(value.toInteger(), expected);
-}
-
-DEFINE_TEST_FUNCTION(toInteger)
-
-
-void tst_QScriptValue::toInt32_initData()
-{
- QTest::addColumn<qint32>("expected");
- initScriptValues();
-}
-
-void tst_QScriptValue::toInt32_makeData(const char* expr)
-{
- static QHash<QString, qint32> toInt32;
- if (toInt32.isEmpty()) {
- toInt32.insert("QScriptValue()", 0);
- toInt32.insert("QScriptValue(QScriptValue::UndefinedValue)", 0);
- toInt32.insert("QScriptValue(QScriptValue::NullValue)", 0);
- toInt32.insert("QScriptValue(true)", 1);
- toInt32.insert("QScriptValue(false)", 0);
- toInt32.insert("QScriptValue(int(122))", 122);
- toInt32.insert("QScriptValue(uint(124))", 124);
- toInt32.insert("QScriptValue(0)", 0);
- toInt32.insert("QScriptValue(0.0)", 0);
- toInt32.insert("QScriptValue(123.0)", 123);
- toInt32.insert("QScriptValue(6.37e-8)", 0);
- toInt32.insert("QScriptValue(-6.37e-8)", 0);
- toInt32.insert("QScriptValue(0x43211234)", 1126240820);
- toInt32.insert("QScriptValue(0x10000)", 65536);
- toInt32.insert("QScriptValue(0x10001)", 65537);
- toInt32.insert("QScriptValue(qSNaN())", 0);
- toInt32.insert("QScriptValue(qQNaN())", 0);
- toInt32.insert("QScriptValue(qInf())", 0);
- toInt32.insert("QScriptValue(-qInf())", 0);
- toInt32.insert("QScriptValue(\"NaN\")", 0);
- toInt32.insert("QScriptValue(\"Infinity\")", 0);
- toInt32.insert("QScriptValue(\"-Infinity\")", 0);
- toInt32.insert("QScriptValue(\"ciao\")", 0);
- toInt32.insert("QScriptValue(QString::fromLatin1(\"ciao\"))", 0);
- toInt32.insert("QScriptValue(QString(\"\"))", 0);
- toInt32.insert("QScriptValue(QString())", 0);
- toInt32.insert("QScriptValue(QString(\"0\"))", 0);
- toInt32.insert("QScriptValue(QString(\"123\"))", 123);
- toInt32.insert("QScriptValue(QString(\"12.4\"))", 12);
- toInt32.insert("QScriptValue(0, QScriptValue::UndefinedValue)", 0);
- toInt32.insert("QScriptValue(0, QScriptValue::NullValue)", 0);
- toInt32.insert("QScriptValue(0, true)", 1);
- toInt32.insert("QScriptValue(0, false)", 0);
- toInt32.insert("QScriptValue(0, int(122))", 122);
- toInt32.insert("QScriptValue(0, uint(124))", 124);
- toInt32.insert("QScriptValue(0, 0)", 0);
- toInt32.insert("QScriptValue(0, 0.0)", 0);
- toInt32.insert("QScriptValue(0, 123.0)", 123);
- toInt32.insert("QScriptValue(0, 6.37e-8)", 0);
- toInt32.insert("QScriptValue(0, -6.37e-8)", 0);
- toInt32.insert("QScriptValue(0, 0x43211234)", 1126240820);
- toInt32.insert("QScriptValue(0, 0x10000)", 65536);
- toInt32.insert("QScriptValue(0, 0x10001)", 65537);
- toInt32.insert("QScriptValue(0, qSNaN())", 0);
- toInt32.insert("QScriptValue(0, qQNaN())", 0);
- toInt32.insert("QScriptValue(0, qInf())", 0);
- toInt32.insert("QScriptValue(0, -qInf())", 0);
- toInt32.insert("QScriptValue(0, \"NaN\")", 0);
- toInt32.insert("QScriptValue(0, \"Infinity\")", 0);
- toInt32.insert("QScriptValue(0, \"-Infinity\")", 0);
- toInt32.insert("QScriptValue(0, \"ciao\")", 0);
- toInt32.insert("QScriptValue(0, QString::fromLatin1(\"ciao\"))", 0);
- toInt32.insert("QScriptValue(0, QString(\"\"))", 0);
- toInt32.insert("QScriptValue(0, QString())", 0);
- toInt32.insert("QScriptValue(0, QString(\"0\"))", 0);
- toInt32.insert("QScriptValue(0, QString(\"123\"))", 123);
- toInt32.insert("QScriptValue(0, QString(\"12.3\"))", 12);
- toInt32.insert("QScriptValue(engine, QScriptValue::UndefinedValue)", 0);
- toInt32.insert("QScriptValue(engine, QScriptValue::NullValue)", 0);
- toInt32.insert("QScriptValue(engine, true)", 1);
- toInt32.insert("QScriptValue(engine, false)", 0);
- toInt32.insert("QScriptValue(engine, int(122))", 122);
- toInt32.insert("QScriptValue(engine, uint(124))", 124);
- toInt32.insert("QScriptValue(engine, 0)", 0);
- toInt32.insert("QScriptValue(engine, 0.0)", 0);
- toInt32.insert("QScriptValue(engine, 123.0)", 123);
- toInt32.insert("QScriptValue(engine, 6.37e-8)", 0);
- toInt32.insert("QScriptValue(engine, -6.37e-8)", 0);
- toInt32.insert("QScriptValue(engine, 0x43211234)", 1126240820);
- toInt32.insert("QScriptValue(engine, 0x10000)", 65536);
- toInt32.insert("QScriptValue(engine, 0x10001)", 65537);
- toInt32.insert("QScriptValue(engine, qSNaN())", 0);
- toInt32.insert("QScriptValue(engine, qQNaN())", 0);
- toInt32.insert("QScriptValue(engine, qInf())", 0);
- toInt32.insert("QScriptValue(engine, -qInf())", 0);
- toInt32.insert("QScriptValue(engine, \"NaN\")", 0);
- toInt32.insert("QScriptValue(engine, \"Infinity\")", 0);
- toInt32.insert("QScriptValue(engine, \"-Infinity\")", 0);
- toInt32.insert("QScriptValue(engine, \"ciao\")", 0);
- toInt32.insert("QScriptValue(engine, QString::fromLatin1(\"ciao\"))", 0);
- toInt32.insert("QScriptValue(engine, QString(\"\"))", 0);
- toInt32.insert("QScriptValue(engine, QString())", 0);
- toInt32.insert("QScriptValue(engine, QString(\"0\"))", 0);
- toInt32.insert("QScriptValue(engine, QString(\"123\"))", 123);
- toInt32.insert("QScriptValue(engine, QString(\"1.23\"))", 1);
- toInt32.insert("engine->evaluate(\"[]\")", 0);
- toInt32.insert("engine->evaluate(\"{}\")", 0);
- toInt32.insert("engine->evaluate(\"Object.prototype\")", 0);
- toInt32.insert("engine->evaluate(\"Date.prototype\")", 0);
- toInt32.insert("engine->evaluate(\"Array.prototype\")", 0);
- toInt32.insert("engine->evaluate(\"Function.prototype\")", 0);
- toInt32.insert("engine->evaluate(\"Error.prototype\")", 0);
- toInt32.insert("engine->evaluate(\"Object\")", 0);
- toInt32.insert("engine->evaluate(\"Array\")", 0);
- toInt32.insert("engine->evaluate(\"Number\")", 0);
- toInt32.insert("engine->evaluate(\"Function\")", 0);
- toInt32.insert("engine->evaluate(\"(function() { return 1; })\")", 0);
- toInt32.insert("engine->evaluate(\"(function() { return 'ciao'; })\")", 0);
- toInt32.insert("engine->evaluate(\"(function() { throw new Error('foo'); })\")", 0);
- toInt32.insert("engine->evaluate(\"/foo/\")", 0);
- toInt32.insert("engine->evaluate(\"new Object()\")", 0);
- toInt32.insert("engine->evaluate(\"new Array()\")", 0);
- toInt32.insert("engine->evaluate(\"new Error()\")", 0);
- toInt32.insert("engine->evaluate(\"a = new Object(); a.foo = 22; a.foo\")", 22);
- toInt32.insert("engine->evaluate(\"Undefined\")", 0);
- toInt32.insert("engine->evaluate(\"Null\")", 0);
- toInt32.insert("engine->evaluate(\"True\")", 0);
- toInt32.insert("engine->evaluate(\"False\")", 0);
- toInt32.insert("engine->evaluate(\"undefined\")", 0);
- toInt32.insert("engine->evaluate(\"null\")", 0);
- toInt32.insert("engine->evaluate(\"true\")", 1);
- toInt32.insert("engine->evaluate(\"false\")", 0);
- toInt32.insert("engine->evaluate(\"122\")", 122);
- toInt32.insert("engine->evaluate(\"124\")", 124);
- toInt32.insert("engine->evaluate(\"0\")", 0);
- toInt32.insert("engine->evaluate(\"0.0\")", 0);
- toInt32.insert("engine->evaluate(\"123.0\")", 123);
- toInt32.insert("engine->evaluate(\"6.37e-8\")", 0);
- toInt32.insert("engine->evaluate(\"-6.37e-8\")", 0);
- toInt32.insert("engine->evaluate(\"0x43211234\")", 1126240820);
- toInt32.insert("engine->evaluate(\"0x10000\")", 65536);
- toInt32.insert("engine->evaluate(\"0x10001\")", 65537);
- toInt32.insert("engine->evaluate(\"NaN\")", 0);
- toInt32.insert("engine->evaluate(\"Infinity\")", 0);
- toInt32.insert("engine->evaluate(\"-Infinity\")", 0);
- toInt32.insert("engine->evaluate(\"'ciao'\")", 0);
- toInt32.insert("engine->evaluate(\"''\")", 0);
- toInt32.insert("engine->evaluate(\"'0'\")", 0);
- toInt32.insert("engine->evaluate(\"'123'\")", 123);
- toInt32.insert("engine->evaluate(\"'12.4'\")", 12);
- toInt32.insert("engine->nullValue()", 0);
- toInt32.insert("engine->undefinedValue()", 0);
- }
- newRow(expr) << toInt32.value(expr);
-}
-
-void tst_QScriptValue::toInt32_test(const char*, const QScriptValue& value)
-{
- QFETCH(qint32, expected);
- QCOMPARE(value.toInt32(), expected);
- QCOMPARE(value.toInt32(), expected);
-}
-
-DEFINE_TEST_FUNCTION(toInt32)
-
-
-void tst_QScriptValue::toUInt32_initData()
-{
- QTest::addColumn<quint32>("expected");
- initScriptValues();
-}
-
-void tst_QScriptValue::toUInt32_makeData(const char* expr)
-{
- static QHash<QString, quint32> toUInt32;
- if (toUInt32.isEmpty()) {
- toUInt32.insert("QScriptValue()", 0);
- toUInt32.insert("QScriptValue(QScriptValue::UndefinedValue)", 0);
- toUInt32.insert("QScriptValue(QScriptValue::NullValue)", 0);
- toUInt32.insert("QScriptValue(true)", 1);
- toUInt32.insert("QScriptValue(false)", 0);
- toUInt32.insert("QScriptValue(int(122))", 122);
- toUInt32.insert("QScriptValue(uint(124))", 124);
- toUInt32.insert("QScriptValue(0)", 0);
- toUInt32.insert("QScriptValue(0.0)", 0);
- toUInt32.insert("QScriptValue(123.0)", 123);
- toUInt32.insert("QScriptValue(6.37e-8)", 0);
- toUInt32.insert("QScriptValue(-6.37e-8)", 0);
- toUInt32.insert("QScriptValue(0x43211234)", 1126240820);
- toUInt32.insert("QScriptValue(0x10000)", 65536);
- toUInt32.insert("QScriptValue(0x10001)", 65537);
- toUInt32.insert("QScriptValue(qSNaN())", 0);
- toUInt32.insert("QScriptValue(qQNaN())", 0);
- toUInt32.insert("QScriptValue(qInf())", 0);
- toUInt32.insert("QScriptValue(-qInf())", 0);
- toUInt32.insert("QScriptValue(\"NaN\")", 0);
- toUInt32.insert("QScriptValue(\"Infinity\")", 0);
- toUInt32.insert("QScriptValue(\"-Infinity\")", 0);
- toUInt32.insert("QScriptValue(\"ciao\")", 0);
- toUInt32.insert("QScriptValue(QString::fromLatin1(\"ciao\"))", 0);
- toUInt32.insert("QScriptValue(QString(\"\"))", 0);
- toUInt32.insert("QScriptValue(QString())", 0);
- toUInt32.insert("QScriptValue(QString(\"0\"))", 0);
- toUInt32.insert("QScriptValue(QString(\"123\"))", 123);
- toUInt32.insert("QScriptValue(QString(\"12.4\"))", 12);
- toUInt32.insert("QScriptValue(0, QScriptValue::UndefinedValue)", 0);
- toUInt32.insert("QScriptValue(0, QScriptValue::NullValue)", 0);
- toUInt32.insert("QScriptValue(0, true)", 1);
- toUInt32.insert("QScriptValue(0, false)", 0);
- toUInt32.insert("QScriptValue(0, int(122))", 122);
- toUInt32.insert("QScriptValue(0, uint(124))", 124);
- toUInt32.insert("QScriptValue(0, 0)", 0);
- toUInt32.insert("QScriptValue(0, 0.0)", 0);
- toUInt32.insert("QScriptValue(0, 123.0)", 123);
- toUInt32.insert("QScriptValue(0, 6.37e-8)", 0);
- toUInt32.insert("QScriptValue(0, -6.37e-8)", 0);
- toUInt32.insert("QScriptValue(0, 0x43211234)", 1126240820);
- toUInt32.insert("QScriptValue(0, 0x10000)", 65536);
- toUInt32.insert("QScriptValue(0, 0x10001)", 65537);
- toUInt32.insert("QScriptValue(0, qSNaN())", 0);
- toUInt32.insert("QScriptValue(0, qQNaN())", 0);
- toUInt32.insert("QScriptValue(0, qInf())", 0);
- toUInt32.insert("QScriptValue(0, -qInf())", 0);
- toUInt32.insert("QScriptValue(0, \"NaN\")", 0);
- toUInt32.insert("QScriptValue(0, \"Infinity\")", 0);
- toUInt32.insert("QScriptValue(0, \"-Infinity\")", 0);
- toUInt32.insert("QScriptValue(0, \"ciao\")", 0);
- toUInt32.insert("QScriptValue(0, QString::fromLatin1(\"ciao\"))", 0);
- toUInt32.insert("QScriptValue(0, QString(\"\"))", 0);
- toUInt32.insert("QScriptValue(0, QString())", 0);
- toUInt32.insert("QScriptValue(0, QString(\"0\"))", 0);
- toUInt32.insert("QScriptValue(0, QString(\"123\"))", 123);
- toUInt32.insert("QScriptValue(0, QString(\"12.3\"))", 12);
- toUInt32.insert("QScriptValue(engine, QScriptValue::UndefinedValue)", 0);
- toUInt32.insert("QScriptValue(engine, QScriptValue::NullValue)", 0);
- toUInt32.insert("QScriptValue(engine, true)", 1);
- toUInt32.insert("QScriptValue(engine, false)", 0);
- toUInt32.insert("QScriptValue(engine, int(122))", 122);
- toUInt32.insert("QScriptValue(engine, uint(124))", 124);
- toUInt32.insert("QScriptValue(engine, 0)", 0);
- toUInt32.insert("QScriptValue(engine, 0.0)", 0);
- toUInt32.insert("QScriptValue(engine, 123.0)", 123);
- toUInt32.insert("QScriptValue(engine, 6.37e-8)", 0);
- toUInt32.insert("QScriptValue(engine, -6.37e-8)", 0);
- toUInt32.insert("QScriptValue(engine, 0x43211234)", 1126240820);
- toUInt32.insert("QScriptValue(engine, 0x10000)", 65536);
- toUInt32.insert("QScriptValue(engine, 0x10001)", 65537);
- toUInt32.insert("QScriptValue(engine, qSNaN())", 0);
- toUInt32.insert("QScriptValue(engine, qQNaN())", 0);
- toUInt32.insert("QScriptValue(engine, qInf())", 0);
- toUInt32.insert("QScriptValue(engine, -qInf())", 0);
- toUInt32.insert("QScriptValue(engine, \"NaN\")", 0);
- toUInt32.insert("QScriptValue(engine, \"Infinity\")", 0);
- toUInt32.insert("QScriptValue(engine, \"-Infinity\")", 0);
- toUInt32.insert("QScriptValue(engine, \"ciao\")", 0);
- toUInt32.insert("QScriptValue(engine, QString::fromLatin1(\"ciao\"))", 0);
- toUInt32.insert("QScriptValue(engine, QString(\"\"))", 0);
- toUInt32.insert("QScriptValue(engine, QString())", 0);
- toUInt32.insert("QScriptValue(engine, QString(\"0\"))", 0);
- toUInt32.insert("QScriptValue(engine, QString(\"123\"))", 123);
- toUInt32.insert("QScriptValue(engine, QString(\"1.23\"))", 1);
- toUInt32.insert("engine->evaluate(\"[]\")", 0);
- toUInt32.insert("engine->evaluate(\"{}\")", 0);
- toUInt32.insert("engine->evaluate(\"Object.prototype\")", 0);
- toUInt32.insert("engine->evaluate(\"Date.prototype\")", 0);
- toUInt32.insert("engine->evaluate(\"Array.prototype\")", 0);
- toUInt32.insert("engine->evaluate(\"Function.prototype\")", 0);
- toUInt32.insert("engine->evaluate(\"Error.prototype\")", 0);
- toUInt32.insert("engine->evaluate(\"Object\")", 0);
- toUInt32.insert("engine->evaluate(\"Array\")", 0);
- toUInt32.insert("engine->evaluate(\"Number\")", 0);
- toUInt32.insert("engine->evaluate(\"Function\")", 0);
- toUInt32.insert("engine->evaluate(\"(function() { return 1; })\")", 0);
- toUInt32.insert("engine->evaluate(\"(function() { return 'ciao'; })\")", 0);
- toUInt32.insert("engine->evaluate(\"(function() { throw new Error('foo'); })\")", 0);
- toUInt32.insert("engine->evaluate(\"/foo/\")", 0);
- toUInt32.insert("engine->evaluate(\"new Object()\")", 0);
- toUInt32.insert("engine->evaluate(\"new Array()\")", 0);
- toUInt32.insert("engine->evaluate(\"new Error()\")", 0);
- toUInt32.insert("engine->evaluate(\"a = new Object(); a.foo = 22; a.foo\")", 22);
- toUInt32.insert("engine->evaluate(\"Undefined\")", 0);
- toUInt32.insert("engine->evaluate(\"Null\")", 0);
- toUInt32.insert("engine->evaluate(\"True\")", 0);
- toUInt32.insert("engine->evaluate(\"False\")", 0);
- toUInt32.insert("engine->evaluate(\"undefined\")", 0);
- toUInt32.insert("engine->evaluate(\"null\")", 0);
- toUInt32.insert("engine->evaluate(\"true\")", 1);
- toUInt32.insert("engine->evaluate(\"false\")", 0);
- toUInt32.insert("engine->evaluate(\"122\")", 122);
- toUInt32.insert("engine->evaluate(\"124\")", 124);
- toUInt32.insert("engine->evaluate(\"0\")", 0);
- toUInt32.insert("engine->evaluate(\"0.0\")", 0);
- toUInt32.insert("engine->evaluate(\"123.0\")", 123);
- toUInt32.insert("engine->evaluate(\"6.37e-8\")", 0);
- toUInt32.insert("engine->evaluate(\"-6.37e-8\")", 0);
- toUInt32.insert("engine->evaluate(\"0x43211234\")", 1126240820);
- toUInt32.insert("engine->evaluate(\"0x10000\")", 65536);
- toUInt32.insert("engine->evaluate(\"0x10001\")", 65537);
- toUInt32.insert("engine->evaluate(\"NaN\")", 0);
- toUInt32.insert("engine->evaluate(\"Infinity\")", 0);
- toUInt32.insert("engine->evaluate(\"-Infinity\")", 0);
- toUInt32.insert("engine->evaluate(\"'ciao'\")", 0);
- toUInt32.insert("engine->evaluate(\"''\")", 0);
- toUInt32.insert("engine->evaluate(\"'0'\")", 0);
- toUInt32.insert("engine->evaluate(\"'123'\")", 123);
- toUInt32.insert("engine->evaluate(\"'12.4'\")", 12);
- toUInt32.insert("engine->nullValue()", 0);
- toUInt32.insert("engine->undefinedValue()", 0);
- }
- newRow(expr) << toUInt32.value(expr);
-}
-
-void tst_QScriptValue::toUInt32_test(const char*, const QScriptValue& value)
-{
- QFETCH(quint32, expected);
- QCOMPARE(value.toUInt32(), expected);
- QCOMPARE(value.toUInt32(), expected);
-}
-
-DEFINE_TEST_FUNCTION(toUInt32)
-
-
-void tst_QScriptValue::toUInt16_initData()
-{
- QTest::addColumn<quint16>("expected");
- initScriptValues();
-}
-
-void tst_QScriptValue::toUInt16_makeData(const char* expr)
-{
- static QHash<QString, quint16> toUInt16;
- if (toUInt16.isEmpty()) {
- toUInt16.insert("QScriptValue()", 0);
- toUInt16.insert("QScriptValue(QScriptValue::UndefinedValue)", 0);
- toUInt16.insert("QScriptValue(QScriptValue::NullValue)", 0);
- toUInt16.insert("QScriptValue(true)", 1);
- toUInt16.insert("QScriptValue(false)", 0);
- toUInt16.insert("QScriptValue(int(122))", 122);
- toUInt16.insert("QScriptValue(uint(124))", 124);
- toUInt16.insert("QScriptValue(0)", 0);
- toUInt16.insert("QScriptValue(0.0)", 0);
- toUInt16.insert("QScriptValue(123.0)", 123);
- toUInt16.insert("QScriptValue(6.37e-8)", 0);
- toUInt16.insert("QScriptValue(-6.37e-8)", 0);
- toUInt16.insert("QScriptValue(0x43211234)", 4660);
- toUInt16.insert("QScriptValue(0x10000)", 0);
- toUInt16.insert("QScriptValue(0x10001)", 1);
- toUInt16.insert("QScriptValue(qSNaN())", 0);
- toUInt16.insert("QScriptValue(qQNaN())", 0);
- toUInt16.insert("QScriptValue(qInf())", 0);
- toUInt16.insert("QScriptValue(-qInf())", 0);
- toUInt16.insert("QScriptValue(\"NaN\")", 0);
- toUInt16.insert("QScriptValue(\"Infinity\")", 0);
- toUInt16.insert("QScriptValue(\"-Infinity\")", 0);
- toUInt16.insert("QScriptValue(\"ciao\")", 0);
- toUInt16.insert("QScriptValue(QString::fromLatin1(\"ciao\"))", 0);
- toUInt16.insert("QScriptValue(QString(\"\"))", 0);
- toUInt16.insert("QScriptValue(QString())", 0);
- toUInt16.insert("QScriptValue(QString(\"0\"))", 0);
- toUInt16.insert("QScriptValue(QString(\"123\"))", 123);
- toUInt16.insert("QScriptValue(QString(\"12.4\"))", 12);
- toUInt16.insert("QScriptValue(0, QScriptValue::UndefinedValue)", 0);
- toUInt16.insert("QScriptValue(0, QScriptValue::NullValue)", 0);
- toUInt16.insert("QScriptValue(0, true)", 1);
- toUInt16.insert("QScriptValue(0, false)", 0);
- toUInt16.insert("QScriptValue(0, int(122))", 122);
- toUInt16.insert("QScriptValue(0, uint(124))", 124);
- toUInt16.insert("QScriptValue(0, 0)", 0);
- toUInt16.insert("QScriptValue(0, 0.0)", 0);
- toUInt16.insert("QScriptValue(0, 123.0)", 123);
- toUInt16.insert("QScriptValue(0, 6.37e-8)", 0);
- toUInt16.insert("QScriptValue(0, -6.37e-8)", 0);
- toUInt16.insert("QScriptValue(0, 0x43211234)", 4660);
- toUInt16.insert("QScriptValue(0, 0x10000)", 0);
- toUInt16.insert("QScriptValue(0, 0x10001)", 1);
- toUInt16.insert("QScriptValue(0, qSNaN())", 0);
- toUInt16.insert("QScriptValue(0, qQNaN())", 0);
- toUInt16.insert("QScriptValue(0, qInf())", 0);
- toUInt16.insert("QScriptValue(0, -qInf())", 0);
- toUInt16.insert("QScriptValue(0, \"NaN\")", 0);
- toUInt16.insert("QScriptValue(0, \"Infinity\")", 0);
- toUInt16.insert("QScriptValue(0, \"-Infinity\")", 0);
- toUInt16.insert("QScriptValue(0, \"ciao\")", 0);
- toUInt16.insert("QScriptValue(0, QString::fromLatin1(\"ciao\"))", 0);
- toUInt16.insert("QScriptValue(0, QString(\"\"))", 0);
- toUInt16.insert("QScriptValue(0, QString())", 0);
- toUInt16.insert("QScriptValue(0, QString(\"0\"))", 0);
- toUInt16.insert("QScriptValue(0, QString(\"123\"))", 123);
- toUInt16.insert("QScriptValue(0, QString(\"12.3\"))", 12);
- toUInt16.insert("QScriptValue(engine, QScriptValue::UndefinedValue)", 0);
- toUInt16.insert("QScriptValue(engine, QScriptValue::NullValue)", 0);
- toUInt16.insert("QScriptValue(engine, true)", 1);
- toUInt16.insert("QScriptValue(engine, false)", 0);
- toUInt16.insert("QScriptValue(engine, int(122))", 122);
- toUInt16.insert("QScriptValue(engine, uint(124))", 124);
- toUInt16.insert("QScriptValue(engine, 0)", 0);
- toUInt16.insert("QScriptValue(engine, 0.0)", 0);
- toUInt16.insert("QScriptValue(engine, 123.0)", 123);
- toUInt16.insert("QScriptValue(engine, 6.37e-8)", 0);
- toUInt16.insert("QScriptValue(engine, -6.37e-8)", 0);
- toUInt16.insert("QScriptValue(engine, 0x43211234)", 4660);
- toUInt16.insert("QScriptValue(engine, 0x10000)", 0);
- toUInt16.insert("QScriptValue(engine, 0x10001)", 1);
- toUInt16.insert("QScriptValue(engine, qSNaN())", 0);
- toUInt16.insert("QScriptValue(engine, qQNaN())", 0);
- toUInt16.insert("QScriptValue(engine, qInf())", 0);
- toUInt16.insert("QScriptValue(engine, -qInf())", 0);
- toUInt16.insert("QScriptValue(engine, \"NaN\")", 0);
- toUInt16.insert("QScriptValue(engine, \"Infinity\")", 0);
- toUInt16.insert("QScriptValue(engine, \"-Infinity\")", 0);
- toUInt16.insert("QScriptValue(engine, \"ciao\")", 0);
- toUInt16.insert("QScriptValue(engine, QString::fromLatin1(\"ciao\"))", 0);
- toUInt16.insert("QScriptValue(engine, QString(\"\"))", 0);
- toUInt16.insert("QScriptValue(engine, QString())", 0);
- toUInt16.insert("QScriptValue(engine, QString(\"0\"))", 0);
- toUInt16.insert("QScriptValue(engine, QString(\"123\"))", 123);
- toUInt16.insert("QScriptValue(engine, QString(\"1.23\"))", 1);
- toUInt16.insert("engine->evaluate(\"[]\")", 0);
- toUInt16.insert("engine->evaluate(\"{}\")", 0);
- toUInt16.insert("engine->evaluate(\"Object.prototype\")", 0);
- toUInt16.insert("engine->evaluate(\"Date.prototype\")", 0);
- toUInt16.insert("engine->evaluate(\"Array.prototype\")", 0);
- toUInt16.insert("engine->evaluate(\"Function.prototype\")", 0);
- toUInt16.insert("engine->evaluate(\"Error.prototype\")", 0);
- toUInt16.insert("engine->evaluate(\"Object\")", 0);
- toUInt16.insert("engine->evaluate(\"Array\")", 0);
- toUInt16.insert("engine->evaluate(\"Number\")", 0);
- toUInt16.insert("engine->evaluate(\"Function\")", 0);
- toUInt16.insert("engine->evaluate(\"(function() { return 1; })\")", 0);
- toUInt16.insert("engine->evaluate(\"(function() { return 'ciao'; })\")", 0);
- toUInt16.insert("engine->evaluate(\"(function() { throw new Error('foo'); })\")", 0);
- toUInt16.insert("engine->evaluate(\"/foo/\")", 0);
- toUInt16.insert("engine->evaluate(\"new Object()\")", 0);
- toUInt16.insert("engine->evaluate(\"new Array()\")", 0);
- toUInt16.insert("engine->evaluate(\"new Error()\")", 0);
- toUInt16.insert("engine->evaluate(\"a = new Object(); a.foo = 22; a.foo\")", 22);
- toUInt16.insert("engine->evaluate(\"Undefined\")", 0);
- toUInt16.insert("engine->evaluate(\"Null\")", 0);
- toUInt16.insert("engine->evaluate(\"True\")", 0);
- toUInt16.insert("engine->evaluate(\"False\")", 0);
- toUInt16.insert("engine->evaluate(\"undefined\")", 0);
- toUInt16.insert("engine->evaluate(\"null\")", 0);
- toUInt16.insert("engine->evaluate(\"true\")", 1);
- toUInt16.insert("engine->evaluate(\"false\")", 0);
- toUInt16.insert("engine->evaluate(\"122\")", 122);
- toUInt16.insert("engine->evaluate(\"124\")", 124);
- toUInt16.insert("engine->evaluate(\"0\")", 0);
- toUInt16.insert("engine->evaluate(\"0.0\")", 0);
- toUInt16.insert("engine->evaluate(\"123.0\")", 123);
- toUInt16.insert("engine->evaluate(\"6.37e-8\")", 0);
- toUInt16.insert("engine->evaluate(\"-6.37e-8\")", 0);
- toUInt16.insert("engine->evaluate(\"0x43211234\")", 4660);
- toUInt16.insert("engine->evaluate(\"0x10000\")", 0);
- toUInt16.insert("engine->evaluate(\"0x10001\")", 1);
- toUInt16.insert("engine->evaluate(\"NaN\")", 0);
- toUInt16.insert("engine->evaluate(\"Infinity\")", 0);
- toUInt16.insert("engine->evaluate(\"-Infinity\")", 0);
- toUInt16.insert("engine->evaluate(\"'ciao'\")", 0);
- toUInt16.insert("engine->evaluate(\"''\")", 0);
- toUInt16.insert("engine->evaluate(\"'0'\")", 0);
- toUInt16.insert("engine->evaluate(\"'123'\")", 123);
- toUInt16.insert("engine->evaluate(\"'12.4'\")", 12);
- toUInt16.insert("engine->nullValue()", 0);
- toUInt16.insert("engine->undefinedValue()", 0);
- }
- newRow(expr) << toUInt16.value(expr);
-}
-
-void tst_QScriptValue::toUInt16_test(const char*, const QScriptValue& value)
-{
- QFETCH(quint16, expected);
- QCOMPARE(value.toUInt16(), expected);
- QCOMPARE(value.toUInt16(), expected);
-}
-
-DEFINE_TEST_FUNCTION(toUInt16)
--- /dev/null
+/*
+ Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+ 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.
+*/
+
+/****************************************************************************
+*************** This file has been generated. DO NOT MODIFY! ****************
+****************************************************************************/
+
+#include "tst_qscriptvalue.h"
+
+static const QString equals_array[] = {
+ "QScriptValue() <=> QScriptValue()",
+ "QScriptValue(QScriptValue::UndefinedValue) <=> QScriptValue(QScriptValue::UndefinedValue)",
+ "QScriptValue(QScriptValue::UndefinedValue) <=> QScriptValue(QScriptValue::NullValue)",
+ "QScriptValue(QScriptValue::UndefinedValue) <=> QScriptValue(0, QScriptValue::UndefinedValue)",
+ "QScriptValue(QScriptValue::UndefinedValue) <=> QScriptValue(0, QScriptValue::NullValue)",
+ "QScriptValue(QScriptValue::UndefinedValue) <=> QScriptValue(engine, QScriptValue::UndefinedValue)",
+ "QScriptValue(QScriptValue::UndefinedValue) <=> QScriptValue(engine, QScriptValue::NullValue)",
+ "QScriptValue(QScriptValue::UndefinedValue) <=> engine->evaluate(\"{}\")",
+ "QScriptValue(QScriptValue::UndefinedValue) <=> engine->evaluate(\"undefined\")",
+ "QScriptValue(QScriptValue::UndefinedValue) <=> engine->evaluate(\"null\")",
+ "QScriptValue(QScriptValue::UndefinedValue) <=> engine->nullValue()",
+ "QScriptValue(QScriptValue::UndefinedValue) <=> engine->undefinedValue()",
+ "QScriptValue(QScriptValue::NullValue) <=> QScriptValue(QScriptValue::UndefinedValue)",
+ "QScriptValue(QScriptValue::NullValue) <=> QScriptValue(QScriptValue::NullValue)",
+ "QScriptValue(QScriptValue::NullValue) <=> QScriptValue(0, QScriptValue::UndefinedValue)",
+ "QScriptValue(QScriptValue::NullValue) <=> QScriptValue(0, QScriptValue::NullValue)",
+ "QScriptValue(QScriptValue::NullValue) <=> QScriptValue(engine, QScriptValue::UndefinedValue)",
+ "QScriptValue(QScriptValue::NullValue) <=> QScriptValue(engine, QScriptValue::NullValue)",
+ "QScriptValue(QScriptValue::NullValue) <=> engine->evaluate(\"{}\")",
+ "QScriptValue(QScriptValue::NullValue) <=> engine->evaluate(\"undefined\")",
+ "QScriptValue(QScriptValue::NullValue) <=> engine->evaluate(\"null\")",
+ "QScriptValue(QScriptValue::NullValue) <=> engine->nullValue()",
+ "QScriptValue(QScriptValue::NullValue) <=> engine->undefinedValue()",
+ "QScriptValue(true) <=> QScriptValue(true)",
+ "QScriptValue(true) <=> QScriptValue(0, true)",
+ "QScriptValue(true) <=> QScriptValue(engine, true)",
+ "QScriptValue(true) <=> engine->evaluate(\"true\")",
+ "QScriptValue(false) <=> QScriptValue(false)",
+ "QScriptValue(false) <=> QScriptValue(0)",
+ "QScriptValue(false) <=> QScriptValue(0.0)",
+ "QScriptValue(false) <=> QScriptValue(QString(\"\"))",
+ "QScriptValue(false) <=> QScriptValue(QString())",
+ "QScriptValue(false) <=> QScriptValue(QString(\"0\"))",
+ "QScriptValue(false) <=> QScriptValue(0, false)",
+ "QScriptValue(false) <=> QScriptValue(0, 0)",
+ "QScriptValue(false) <=> QScriptValue(0, 0.0)",
+ "QScriptValue(false) <=> QScriptValue(0, QString(\"\"))",
+ "QScriptValue(false) <=> QScriptValue(0, QString())",
+ "QScriptValue(false) <=> QScriptValue(0, QString(\"0\"))",
+ "QScriptValue(false) <=> QScriptValue(engine, false)",
+ "QScriptValue(false) <=> QScriptValue(engine, 0)",
+ "QScriptValue(false) <=> QScriptValue(engine, 0.0)",
+ "QScriptValue(false) <=> QScriptValue(engine, QString(\"\"))",
+ "QScriptValue(false) <=> QScriptValue(engine, QString())",
+ "QScriptValue(false) <=> QScriptValue(engine, QString(\"0\"))",
+ "QScriptValue(false) <=> engine->evaluate(\"[]\")",
+ "QScriptValue(false) <=> engine->evaluate(\"Array.prototype\")",
+ "QScriptValue(false) <=> engine->evaluate(\"new Array()\")",
+ "QScriptValue(false) <=> engine->evaluate(\"false\")",
+ "QScriptValue(false) <=> engine->evaluate(\"0\")",
+ "QScriptValue(false) <=> engine->evaluate(\"0.0\")",
+ "QScriptValue(false) <=> engine->evaluate(\"''\")",
+ "QScriptValue(false) <=> engine->evaluate(\"'0'\")",
+ "QScriptValue(false) <=> engine->newArray()",
+ "QScriptValue(int(122)) <=> QScriptValue(int(122))",
+ "QScriptValue(int(122)) <=> QScriptValue(0, int(122))",
+ "QScriptValue(int(122)) <=> QScriptValue(engine, int(122))",
+ "QScriptValue(int(122)) <=> engine->evaluate(\"122\")",
+ "QScriptValue(uint(124)) <=> QScriptValue(uint(124))",
+ "QScriptValue(uint(124)) <=> QScriptValue(0, uint(124))",
+ "QScriptValue(uint(124)) <=> QScriptValue(engine, uint(124))",
+ "QScriptValue(uint(124)) <=> engine->evaluate(\"124\")",
+ "QScriptValue(0) <=> QScriptValue(false)",
+ "QScriptValue(0) <=> QScriptValue(0)",
+ "QScriptValue(0) <=> QScriptValue(0.0)",
+ "QScriptValue(0) <=> QScriptValue(QString(\"\"))",
+ "QScriptValue(0) <=> QScriptValue(QString())",
+ "QScriptValue(0) <=> QScriptValue(QString(\"0\"))",
+ "QScriptValue(0) <=> QScriptValue(0, false)",
+ "QScriptValue(0) <=> QScriptValue(0, 0)",
+ "QScriptValue(0) <=> QScriptValue(0, 0.0)",
+ "QScriptValue(0) <=> QScriptValue(0, QString(\"\"))",
+ "QScriptValue(0) <=> QScriptValue(0, QString())",
+ "QScriptValue(0) <=> QScriptValue(0, QString(\"0\"))",
+ "QScriptValue(0) <=> QScriptValue(engine, false)",
+ "QScriptValue(0) <=> QScriptValue(engine, 0)",
+ "QScriptValue(0) <=> QScriptValue(engine, 0.0)",
+ "QScriptValue(0) <=> QScriptValue(engine, QString(\"\"))",
+ "QScriptValue(0) <=> QScriptValue(engine, QString())",
+ "QScriptValue(0) <=> QScriptValue(engine, QString(\"0\"))",
+ "QScriptValue(0) <=> engine->evaluate(\"[]\")",
+ "QScriptValue(0) <=> engine->evaluate(\"Array.prototype\")",
+ "QScriptValue(0) <=> engine->evaluate(\"new Array()\")",
+ "QScriptValue(0) <=> engine->evaluate(\"false\")",
+ "QScriptValue(0) <=> engine->evaluate(\"0\")",
+ "QScriptValue(0) <=> engine->evaluate(\"0.0\")",
+ "QScriptValue(0) <=> engine->evaluate(\"''\")",
+ "QScriptValue(0) <=> engine->evaluate(\"'0'\")",
+ "QScriptValue(0) <=> engine->newArray()",
+ "QScriptValue(0.0) <=> QScriptValue(false)",
+ "QScriptValue(0.0) <=> QScriptValue(0)",
+ "QScriptValue(0.0) <=> QScriptValue(0.0)",
+ "QScriptValue(0.0) <=> QScriptValue(QString(\"\"))",
+ "QScriptValue(0.0) <=> QScriptValue(QString())",
+ "QScriptValue(0.0) <=> QScriptValue(QString(\"0\"))",
+ "QScriptValue(0.0) <=> QScriptValue(0, false)",
+ "QScriptValue(0.0) <=> QScriptValue(0, 0)",
+ "QScriptValue(0.0) <=> QScriptValue(0, 0.0)",
+ "QScriptValue(0.0) <=> QScriptValue(0, QString(\"\"))",
+ "QScriptValue(0.0) <=> QScriptValue(0, QString())",
+ "QScriptValue(0.0) <=> QScriptValue(0, QString(\"0\"))",
+ "QScriptValue(0.0) <=> QScriptValue(engine, false)",
+ "QScriptValue(0.0) <=> QScriptValue(engine, 0)",
+ "QScriptValue(0.0) <=> QScriptValue(engine, 0.0)",
+ "QScriptValue(0.0) <=> QScriptValue(engine, QString(\"\"))",
+ "QScriptValue(0.0) <=> QScriptValue(engine, QString())",
+ "QScriptValue(0.0) <=> QScriptValue(engine, QString(\"0\"))",
+ "QScriptValue(0.0) <=> engine->evaluate(\"[]\")",
+ "QScriptValue(0.0) <=> engine->evaluate(\"Array.prototype\")",
+ "QScriptValue(0.0) <=> engine->evaluate(\"new Array()\")",
+ "QScriptValue(0.0) <=> engine->evaluate(\"false\")",
+ "QScriptValue(0.0) <=> engine->evaluate(\"0\")",
+ "QScriptValue(0.0) <=> engine->evaluate(\"0.0\")",
+ "QScriptValue(0.0) <=> engine->evaluate(\"''\")",
+ "QScriptValue(0.0) <=> engine->evaluate(\"'0'\")",
+ "QScriptValue(0.0) <=> engine->newArray()",
+ "QScriptValue(123.0) <=> QScriptValue(123.0)",
+ "QScriptValue(123.0) <=> QScriptValue(QString(\"123\"))",
+ "QScriptValue(123.0) <=> QScriptValue(0, 123.0)",
+ "QScriptValue(123.0) <=> QScriptValue(0, QString(\"123\"))",
+ "QScriptValue(123.0) <=> QScriptValue(engine, 123.0)",
+ "QScriptValue(123.0) <=> QScriptValue(engine, QString(\"123\"))",
+ "QScriptValue(123.0) <=> engine->evaluate(\"123.0\")",
+ "QScriptValue(123.0) <=> engine->evaluate(\"'123'\")",
+ "QScriptValue(6.37e-8) <=> QScriptValue(6.37e-8)",
+ "QScriptValue(6.37e-8) <=> QScriptValue(0, 6.37e-8)",
+ "QScriptValue(6.37e-8) <=> QScriptValue(engine, 6.37e-8)",
+ "QScriptValue(6.37e-8) <=> engine->evaluate(\"6.37e-8\")",
+ "QScriptValue(-6.37e-8) <=> QScriptValue(-6.37e-8)",
+ "QScriptValue(-6.37e-8) <=> QScriptValue(0, -6.37e-8)",
+ "QScriptValue(-6.37e-8) <=> QScriptValue(engine, -6.37e-8)",
+ "QScriptValue(-6.37e-8) <=> engine->evaluate(\"-6.37e-8\")",
+ "QScriptValue(0x43211234) <=> QScriptValue(0x43211234)",
+ "QScriptValue(0x43211234) <=> QScriptValue(0, 0x43211234)",
+ "QScriptValue(0x43211234) <=> QScriptValue(engine, 0x43211234)",
+ "QScriptValue(0x43211234) <=> engine->evaluate(\"0x43211234\")",
+ "QScriptValue(0x10000) <=> QScriptValue(0x10000)",
+ "QScriptValue(0x10000) <=> QScriptValue(0, 0x10000)",
+ "QScriptValue(0x10000) <=> QScriptValue(engine, 0x10000)",
+ "QScriptValue(0x10000) <=> engine->evaluate(\"0x10000\")",
+ "QScriptValue(0x10001) <=> QScriptValue(0x10001)",
+ "QScriptValue(0x10001) <=> QScriptValue(0, 0x10001)",
+ "QScriptValue(0x10001) <=> QScriptValue(engine, 0x10001)",
+ "QScriptValue(0x10001) <=> engine->evaluate(\"0x10001\")",
+ "QScriptValue(qInf()) <=> QScriptValue(qInf())",
+ "QScriptValue(qInf()) <=> QScriptValue(\"Infinity\")",
+ "QScriptValue(qInf()) <=> QScriptValue(0, qInf())",
+ "QScriptValue(qInf()) <=> QScriptValue(0, \"Infinity\")",
+ "QScriptValue(qInf()) <=> QScriptValue(engine, qInf())",
+ "QScriptValue(qInf()) <=> QScriptValue(engine, \"Infinity\")",
+ "QScriptValue(qInf()) <=> engine->evaluate(\"Infinity\")",
+ "QScriptValue(-qInf()) <=> QScriptValue(-qInf())",
+ "QScriptValue(-qInf()) <=> QScriptValue(\"-Infinity\")",
+ "QScriptValue(-qInf()) <=> QScriptValue(0, -qInf())",
+ "QScriptValue(-qInf()) <=> QScriptValue(0, \"-Infinity\")",
+ "QScriptValue(-qInf()) <=> QScriptValue(engine, -qInf())",
+ "QScriptValue(-qInf()) <=> QScriptValue(engine, \"-Infinity\")",
+ "QScriptValue(-qInf()) <=> engine->evaluate(\"-Infinity\")",
+ "QScriptValue(\"NaN\") <=> QScriptValue(\"NaN\")",
+ "QScriptValue(\"NaN\") <=> QScriptValue(0, \"NaN\")",
+ "QScriptValue(\"NaN\") <=> QScriptValue(engine, \"NaN\")",
+ "QScriptValue(\"Infinity\") <=> QScriptValue(qInf())",
+ "QScriptValue(\"Infinity\") <=> QScriptValue(\"Infinity\")",
+ "QScriptValue(\"Infinity\") <=> QScriptValue(0, qInf())",
+ "QScriptValue(\"Infinity\") <=> QScriptValue(0, \"Infinity\")",
+ "QScriptValue(\"Infinity\") <=> QScriptValue(engine, qInf())",
+ "QScriptValue(\"Infinity\") <=> QScriptValue(engine, \"Infinity\")",
+ "QScriptValue(\"Infinity\") <=> engine->evaluate(\"Infinity\")",
+ "QScriptValue(\"-Infinity\") <=> QScriptValue(-qInf())",
+ "QScriptValue(\"-Infinity\") <=> QScriptValue(\"-Infinity\")",
+ "QScriptValue(\"-Infinity\") <=> QScriptValue(0, -qInf())",
+ "QScriptValue(\"-Infinity\") <=> QScriptValue(0, \"-Infinity\")",
+ "QScriptValue(\"-Infinity\") <=> QScriptValue(engine, -qInf())",
+ "QScriptValue(\"-Infinity\") <=> QScriptValue(engine, \"-Infinity\")",
+ "QScriptValue(\"-Infinity\") <=> engine->evaluate(\"-Infinity\")",
+ "QScriptValue(\"ciao\") <=> QScriptValue(\"ciao\")",
+ "QScriptValue(\"ciao\") <=> QScriptValue(QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(\"ciao\") <=> QScriptValue(0, \"ciao\")",
+ "QScriptValue(\"ciao\") <=> QScriptValue(0, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(\"ciao\") <=> QScriptValue(engine, \"ciao\")",
+ "QScriptValue(\"ciao\") <=> QScriptValue(engine, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(\"ciao\") <=> engine->evaluate(\"'ciao'\")",
+ "QScriptValue(QString::fromLatin1(\"ciao\")) <=> QScriptValue(\"ciao\")",
+ "QScriptValue(QString::fromLatin1(\"ciao\")) <=> QScriptValue(QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(QString::fromLatin1(\"ciao\")) <=> QScriptValue(0, \"ciao\")",
+ "QScriptValue(QString::fromLatin1(\"ciao\")) <=> QScriptValue(0, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(QString::fromLatin1(\"ciao\")) <=> QScriptValue(engine, \"ciao\")",
+ "QScriptValue(QString::fromLatin1(\"ciao\")) <=> QScriptValue(engine, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(QString::fromLatin1(\"ciao\")) <=> engine->evaluate(\"'ciao'\")",
+ "QScriptValue(QString(\"\")) <=> QScriptValue(false)",
+ "QScriptValue(QString(\"\")) <=> QScriptValue(0)",
+ "QScriptValue(QString(\"\")) <=> QScriptValue(0.0)",
+ "QScriptValue(QString(\"\")) <=> QScriptValue(QString(\"\"))",
+ "QScriptValue(QString(\"\")) <=> QScriptValue(QString())",
+ "QScriptValue(QString(\"\")) <=> QScriptValue(0, false)",
+ "QScriptValue(QString(\"\")) <=> QScriptValue(0, 0)",
+ "QScriptValue(QString(\"\")) <=> QScriptValue(0, 0.0)",
+ "QScriptValue(QString(\"\")) <=> QScriptValue(0, QString(\"\"))",
+ "QScriptValue(QString(\"\")) <=> QScriptValue(0, QString())",
+ "QScriptValue(QString(\"\")) <=> QScriptValue(engine, false)",
+ "QScriptValue(QString(\"\")) <=> QScriptValue(engine, 0)",
+ "QScriptValue(QString(\"\")) <=> QScriptValue(engine, 0.0)",
+ "QScriptValue(QString(\"\")) <=> QScriptValue(engine, QString(\"\"))",
+ "QScriptValue(QString(\"\")) <=> QScriptValue(engine, QString())",
+ "QScriptValue(QString(\"\")) <=> engine->evaluate(\"[]\")",
+ "QScriptValue(QString(\"\")) <=> engine->evaluate(\"Array.prototype\")",
+ "QScriptValue(QString(\"\")) <=> engine->evaluate(\"new Array()\")",
+ "QScriptValue(QString(\"\")) <=> engine->evaluate(\"false\")",
+ "QScriptValue(QString(\"\")) <=> engine->evaluate(\"0\")",
+ "QScriptValue(QString(\"\")) <=> engine->evaluate(\"0.0\")",
+ "QScriptValue(QString(\"\")) <=> engine->evaluate(\"''\")",
+ "QScriptValue(QString(\"\")) <=> engine->newArray()",
+ "QScriptValue(QString()) <=> QScriptValue(false)",
+ "QScriptValue(QString()) <=> QScriptValue(0)",
+ "QScriptValue(QString()) <=> QScriptValue(0.0)",
+ "QScriptValue(QString()) <=> QScriptValue(QString(\"\"))",
+ "QScriptValue(QString()) <=> QScriptValue(QString())",
+ "QScriptValue(QString()) <=> QScriptValue(0, false)",
+ "QScriptValue(QString()) <=> QScriptValue(0, 0)",
+ "QScriptValue(QString()) <=> QScriptValue(0, 0.0)",
+ "QScriptValue(QString()) <=> QScriptValue(0, QString(\"\"))",
+ "QScriptValue(QString()) <=> QScriptValue(0, QString())",
+ "QScriptValue(QString()) <=> QScriptValue(engine, false)",
+ "QScriptValue(QString()) <=> QScriptValue(engine, 0)",
+ "QScriptValue(QString()) <=> QScriptValue(engine, 0.0)",
+ "QScriptValue(QString()) <=> QScriptValue(engine, QString(\"\"))",
+ "QScriptValue(QString()) <=> QScriptValue(engine, QString())",
+ "QScriptValue(QString()) <=> engine->evaluate(\"[]\")",
+ "QScriptValue(QString()) <=> engine->evaluate(\"Array.prototype\")",
+ "QScriptValue(QString()) <=> engine->evaluate(\"new Array()\")",
+ "QScriptValue(QString()) <=> engine->evaluate(\"false\")",
+ "QScriptValue(QString()) <=> engine->evaluate(\"0\")",
+ "QScriptValue(QString()) <=> engine->evaluate(\"0.0\")",
+ "QScriptValue(QString()) <=> engine->evaluate(\"''\")",
+ "QScriptValue(QString()) <=> engine->newArray()",
+ "QScriptValue(QString(\"0\")) <=> QScriptValue(false)",
+ "QScriptValue(QString(\"0\")) <=> QScriptValue(0)",
+ "QScriptValue(QString(\"0\")) <=> QScriptValue(0.0)",
+ "QScriptValue(QString(\"0\")) <=> QScriptValue(QString(\"0\"))",
+ "QScriptValue(QString(\"0\")) <=> QScriptValue(0, false)",
+ "QScriptValue(QString(\"0\")) <=> QScriptValue(0, 0)",
+ "QScriptValue(QString(\"0\")) <=> QScriptValue(0, 0.0)",
+ "QScriptValue(QString(\"0\")) <=> QScriptValue(0, QString(\"0\"))",
+ "QScriptValue(QString(\"0\")) <=> QScriptValue(engine, false)",
+ "QScriptValue(QString(\"0\")) <=> QScriptValue(engine, 0)",
+ "QScriptValue(QString(\"0\")) <=> QScriptValue(engine, 0.0)",
+ "QScriptValue(QString(\"0\")) <=> QScriptValue(engine, QString(\"0\"))",
+ "QScriptValue(QString(\"0\")) <=> engine->evaluate(\"false\")",
+ "QScriptValue(QString(\"0\")) <=> engine->evaluate(\"0\")",
+ "QScriptValue(QString(\"0\")) <=> engine->evaluate(\"0.0\")",
+ "QScriptValue(QString(\"0\")) <=> engine->evaluate(\"'0'\")",
+ "QScriptValue(QString(\"123\")) <=> QScriptValue(123.0)",
+ "QScriptValue(QString(\"123\")) <=> QScriptValue(QString(\"123\"))",
+ "QScriptValue(QString(\"123\")) <=> QScriptValue(0, 123.0)",
+ "QScriptValue(QString(\"123\")) <=> QScriptValue(0, QString(\"123\"))",
+ "QScriptValue(QString(\"123\")) <=> QScriptValue(engine, 123.0)",
+ "QScriptValue(QString(\"123\")) <=> QScriptValue(engine, QString(\"123\"))",
+ "QScriptValue(QString(\"123\")) <=> engine->evaluate(\"123.0\")",
+ "QScriptValue(QString(\"123\")) <=> engine->evaluate(\"'123'\")",
+ "QScriptValue(QString(\"12.4\")) <=> QScriptValue(QString(\"12.4\"))",
+ "QScriptValue(QString(\"12.4\")) <=> engine->evaluate(\"'12.4'\")",
+ "QScriptValue(0, QScriptValue::UndefinedValue) <=> QScriptValue(QScriptValue::UndefinedValue)",
+ "QScriptValue(0, QScriptValue::UndefinedValue) <=> QScriptValue(QScriptValue::NullValue)",
+ "QScriptValue(0, QScriptValue::UndefinedValue) <=> QScriptValue(0, QScriptValue::UndefinedValue)",
+ "QScriptValue(0, QScriptValue::UndefinedValue) <=> QScriptValue(0, QScriptValue::NullValue)",
+ "QScriptValue(0, QScriptValue::UndefinedValue) <=> QScriptValue(engine, QScriptValue::UndefinedValue)",
+ "QScriptValue(0, QScriptValue::UndefinedValue) <=> QScriptValue(engine, QScriptValue::NullValue)",
+ "QScriptValue(0, QScriptValue::UndefinedValue) <=> engine->evaluate(\"{}\")",
+ "QScriptValue(0, QScriptValue::UndefinedValue) <=> engine->evaluate(\"undefined\")",
+ "QScriptValue(0, QScriptValue::UndefinedValue) <=> engine->evaluate(\"null\")",
+ "QScriptValue(0, QScriptValue::UndefinedValue) <=> engine->nullValue()",
+ "QScriptValue(0, QScriptValue::UndefinedValue) <=> engine->undefinedValue()",
+ "QScriptValue(0, QScriptValue::NullValue) <=> QScriptValue(QScriptValue::UndefinedValue)",
+ "QScriptValue(0, QScriptValue::NullValue) <=> QScriptValue(QScriptValue::NullValue)",
+ "QScriptValue(0, QScriptValue::NullValue) <=> QScriptValue(0, QScriptValue::UndefinedValue)",
+ "QScriptValue(0, QScriptValue::NullValue) <=> QScriptValue(0, QScriptValue::NullValue)",
+ "QScriptValue(0, QScriptValue::NullValue) <=> QScriptValue(engine, QScriptValue::UndefinedValue)",
+ "QScriptValue(0, QScriptValue::NullValue) <=> QScriptValue(engine, QScriptValue::NullValue)",
+ "QScriptValue(0, QScriptValue::NullValue) <=> engine->evaluate(\"{}\")",
+ "QScriptValue(0, QScriptValue::NullValue) <=> engine->evaluate(\"undefined\")",
+ "QScriptValue(0, QScriptValue::NullValue) <=> engine->evaluate(\"null\")",
+ "QScriptValue(0, QScriptValue::NullValue) <=> engine->nullValue()",
+ "QScriptValue(0, QScriptValue::NullValue) <=> engine->undefinedValue()",
+ "QScriptValue(0, true) <=> QScriptValue(true)",
+ "QScriptValue(0, true) <=> QScriptValue(0, true)",
+ "QScriptValue(0, true) <=> QScriptValue(engine, true)",
+ "QScriptValue(0, true) <=> engine->evaluate(\"true\")",
+ "QScriptValue(0, false) <=> QScriptValue(false)",
+ "QScriptValue(0, false) <=> QScriptValue(0)",
+ "QScriptValue(0, false) <=> QScriptValue(0.0)",
+ "QScriptValue(0, false) <=> QScriptValue(QString(\"\"))",
+ "QScriptValue(0, false) <=> QScriptValue(QString())",
+ "QScriptValue(0, false) <=> QScriptValue(QString(\"0\"))",
+ "QScriptValue(0, false) <=> QScriptValue(0, false)",
+ "QScriptValue(0, false) <=> QScriptValue(0, 0)",
+ "QScriptValue(0, false) <=> QScriptValue(0, 0.0)",
+ "QScriptValue(0, false) <=> QScriptValue(0, QString(\"\"))",
+ "QScriptValue(0, false) <=> QScriptValue(0, QString())",
+ "QScriptValue(0, false) <=> QScriptValue(0, QString(\"0\"))",
+ "QScriptValue(0, false) <=> QScriptValue(engine, false)",
+ "QScriptValue(0, false) <=> QScriptValue(engine, 0)",
+ "QScriptValue(0, false) <=> QScriptValue(engine, 0.0)",
+ "QScriptValue(0, false) <=> QScriptValue(engine, QString(\"\"))",
+ "QScriptValue(0, false) <=> QScriptValue(engine, QString())",
+ "QScriptValue(0, false) <=> QScriptValue(engine, QString(\"0\"))",
+ "QScriptValue(0, false) <=> engine->evaluate(\"[]\")",
+ "QScriptValue(0, false) <=> engine->evaluate(\"Array.prototype\")",
+ "QScriptValue(0, false) <=> engine->evaluate(\"new Array()\")",
+ "QScriptValue(0, false) <=> engine->evaluate(\"false\")",
+ "QScriptValue(0, false) <=> engine->evaluate(\"0\")",
+ "QScriptValue(0, false) <=> engine->evaluate(\"0.0\")",
+ "QScriptValue(0, false) <=> engine->evaluate(\"''\")",
+ "QScriptValue(0, false) <=> engine->evaluate(\"'0'\")",
+ "QScriptValue(0, false) <=> engine->newArray()",
+ "QScriptValue(0, int(122)) <=> QScriptValue(int(122))",
+ "QScriptValue(0, int(122)) <=> QScriptValue(0, int(122))",
+ "QScriptValue(0, int(122)) <=> QScriptValue(engine, int(122))",
+ "QScriptValue(0, int(122)) <=> engine->evaluate(\"122\")",
+ "QScriptValue(0, uint(124)) <=> QScriptValue(uint(124))",
+ "QScriptValue(0, uint(124)) <=> QScriptValue(0, uint(124))",
+ "QScriptValue(0, uint(124)) <=> QScriptValue(engine, uint(124))",
+ "QScriptValue(0, uint(124)) <=> engine->evaluate(\"124\")",
+ "QScriptValue(0, 0) <=> QScriptValue(false)",
+ "QScriptValue(0, 0) <=> QScriptValue(0)",
+ "QScriptValue(0, 0) <=> QScriptValue(0.0)",
+ "QScriptValue(0, 0) <=> QScriptValue(QString(\"\"))",
+ "QScriptValue(0, 0) <=> QScriptValue(QString())",
+ "QScriptValue(0, 0) <=> QScriptValue(QString(\"0\"))",
+ "QScriptValue(0, 0) <=> QScriptValue(0, false)",
+ "QScriptValue(0, 0) <=> QScriptValue(0, 0)",
+ "QScriptValue(0, 0) <=> QScriptValue(0, 0.0)",
+ "QScriptValue(0, 0) <=> QScriptValue(0, QString(\"\"))",
+ "QScriptValue(0, 0) <=> QScriptValue(0, QString())",
+ "QScriptValue(0, 0) <=> QScriptValue(0, QString(\"0\"))",
+ "QScriptValue(0, 0) <=> QScriptValue(engine, false)",
+ "QScriptValue(0, 0) <=> QScriptValue(engine, 0)",
+ "QScriptValue(0, 0) <=> QScriptValue(engine, 0.0)",
+ "QScriptValue(0, 0) <=> QScriptValue(engine, QString(\"\"))",
+ "QScriptValue(0, 0) <=> QScriptValue(engine, QString())",
+ "QScriptValue(0, 0) <=> QScriptValue(engine, QString(\"0\"))",
+ "QScriptValue(0, 0) <=> engine->evaluate(\"[]\")",
+ "QScriptValue(0, 0) <=> engine->evaluate(\"Array.prototype\")",
+ "QScriptValue(0, 0) <=> engine->evaluate(\"new Array()\")",
+ "QScriptValue(0, 0) <=> engine->evaluate(\"false\")",
+ "QScriptValue(0, 0) <=> engine->evaluate(\"0\")",
+ "QScriptValue(0, 0) <=> engine->evaluate(\"0.0\")",
+ "QScriptValue(0, 0) <=> engine->evaluate(\"''\")",
+ "QScriptValue(0, 0) <=> engine->evaluate(\"'0'\")",
+ "QScriptValue(0, 0) <=> engine->newArray()",
+ "QScriptValue(0, 0.0) <=> QScriptValue(false)",
+ "QScriptValue(0, 0.0) <=> QScriptValue(0)",
+ "QScriptValue(0, 0.0) <=> QScriptValue(0.0)",
+ "QScriptValue(0, 0.0) <=> QScriptValue(QString(\"\"))",
+ "QScriptValue(0, 0.0) <=> QScriptValue(QString())",
+ "QScriptValue(0, 0.0) <=> QScriptValue(QString(\"0\"))",
+ "QScriptValue(0, 0.0) <=> QScriptValue(0, false)",
+ "QScriptValue(0, 0.0) <=> QScriptValue(0, 0)",
+ "QScriptValue(0, 0.0) <=> QScriptValue(0, 0.0)",
+ "QScriptValue(0, 0.0) <=> QScriptValue(0, QString(\"\"))",
+ "QScriptValue(0, 0.0) <=> QScriptValue(0, QString())",
+ "QScriptValue(0, 0.0) <=> QScriptValue(0, QString(\"0\"))",
+ "QScriptValue(0, 0.0) <=> QScriptValue(engine, false)",
+ "QScriptValue(0, 0.0) <=> QScriptValue(engine, 0)",
+ "QScriptValue(0, 0.0) <=> QScriptValue(engine, 0.0)",
+ "QScriptValue(0, 0.0) <=> QScriptValue(engine, QString(\"\"))",
+ "QScriptValue(0, 0.0) <=> QScriptValue(engine, QString())",
+ "QScriptValue(0, 0.0) <=> QScriptValue(engine, QString(\"0\"))",
+ "QScriptValue(0, 0.0) <=> engine->evaluate(\"[]\")",
+ "QScriptValue(0, 0.0) <=> engine->evaluate(\"Array.prototype\")",
+ "QScriptValue(0, 0.0) <=> engine->evaluate(\"new Array()\")",
+ "QScriptValue(0, 0.0) <=> engine->evaluate(\"false\")",
+ "QScriptValue(0, 0.0) <=> engine->evaluate(\"0\")",
+ "QScriptValue(0, 0.0) <=> engine->evaluate(\"0.0\")",
+ "QScriptValue(0, 0.0) <=> engine->evaluate(\"''\")",
+ "QScriptValue(0, 0.0) <=> engine->evaluate(\"'0'\")",
+ "QScriptValue(0, 0.0) <=> engine->newArray()",
+ "QScriptValue(0, 123.0) <=> QScriptValue(123.0)",
+ "QScriptValue(0, 123.0) <=> QScriptValue(QString(\"123\"))",
+ "QScriptValue(0, 123.0) <=> QScriptValue(0, 123.0)",
+ "QScriptValue(0, 123.0) <=> QScriptValue(0, QString(\"123\"))",
+ "QScriptValue(0, 123.0) <=> QScriptValue(engine, 123.0)",
+ "QScriptValue(0, 123.0) <=> QScriptValue(engine, QString(\"123\"))",
+ "QScriptValue(0, 123.0) <=> engine->evaluate(\"123.0\")",
+ "QScriptValue(0, 123.0) <=> engine->evaluate(\"'123'\")",
+ "QScriptValue(0, 6.37e-8) <=> QScriptValue(6.37e-8)",
+ "QScriptValue(0, 6.37e-8) <=> QScriptValue(0, 6.37e-8)",
+ "QScriptValue(0, 6.37e-8) <=> QScriptValue(engine, 6.37e-8)",
+ "QScriptValue(0, 6.37e-8) <=> engine->evaluate(\"6.37e-8\")",
+ "QScriptValue(0, -6.37e-8) <=> QScriptValue(-6.37e-8)",
+ "QScriptValue(0, -6.37e-8) <=> QScriptValue(0, -6.37e-8)",
+ "QScriptValue(0, -6.37e-8) <=> QScriptValue(engine, -6.37e-8)",
+ "QScriptValue(0, -6.37e-8) <=> engine->evaluate(\"-6.37e-8\")",
+ "QScriptValue(0, 0x43211234) <=> QScriptValue(0x43211234)",
+ "QScriptValue(0, 0x43211234) <=> QScriptValue(0, 0x43211234)",
+ "QScriptValue(0, 0x43211234) <=> QScriptValue(engine, 0x43211234)",
+ "QScriptValue(0, 0x43211234) <=> engine->evaluate(\"0x43211234\")",
+ "QScriptValue(0, 0x10000) <=> QScriptValue(0x10000)",
+ "QScriptValue(0, 0x10000) <=> QScriptValue(0, 0x10000)",
+ "QScriptValue(0, 0x10000) <=> QScriptValue(engine, 0x10000)",
+ "QScriptValue(0, 0x10000) <=> engine->evaluate(\"0x10000\")",
+ "QScriptValue(0, 0x10001) <=> QScriptValue(0x10001)",
+ "QScriptValue(0, 0x10001) <=> QScriptValue(0, 0x10001)",
+ "QScriptValue(0, 0x10001) <=> QScriptValue(engine, 0x10001)",
+ "QScriptValue(0, 0x10001) <=> engine->evaluate(\"0x10001\")",
+ "QScriptValue(0, qInf()) <=> QScriptValue(qInf())",
+ "QScriptValue(0, qInf()) <=> QScriptValue(\"Infinity\")",
+ "QScriptValue(0, qInf()) <=> QScriptValue(0, qInf())",
+ "QScriptValue(0, qInf()) <=> QScriptValue(0, \"Infinity\")",
+ "QScriptValue(0, qInf()) <=> QScriptValue(engine, qInf())",
+ "QScriptValue(0, qInf()) <=> QScriptValue(engine, \"Infinity\")",
+ "QScriptValue(0, qInf()) <=> engine->evaluate(\"Infinity\")",
+ "QScriptValue(0, -qInf()) <=> QScriptValue(-qInf())",
+ "QScriptValue(0, -qInf()) <=> QScriptValue(\"-Infinity\")",
+ "QScriptValue(0, -qInf()) <=> QScriptValue(0, -qInf())",
+ "QScriptValue(0, -qInf()) <=> QScriptValue(0, \"-Infinity\")",
+ "QScriptValue(0, -qInf()) <=> QScriptValue(engine, -qInf())",
+ "QScriptValue(0, -qInf()) <=> QScriptValue(engine, \"-Infinity\")",
+ "QScriptValue(0, -qInf()) <=> engine->evaluate(\"-Infinity\")",
+ "QScriptValue(0, \"NaN\") <=> QScriptValue(\"NaN\")",
+ "QScriptValue(0, \"NaN\") <=> QScriptValue(0, \"NaN\")",
+ "QScriptValue(0, \"NaN\") <=> QScriptValue(engine, \"NaN\")",
+ "QScriptValue(0, \"Infinity\") <=> QScriptValue(qInf())",
+ "QScriptValue(0, \"Infinity\") <=> QScriptValue(\"Infinity\")",
+ "QScriptValue(0, \"Infinity\") <=> QScriptValue(0, qInf())",
+ "QScriptValue(0, \"Infinity\") <=> QScriptValue(0, \"Infinity\")",
+ "QScriptValue(0, \"Infinity\") <=> QScriptValue(engine, qInf())",
+ "QScriptValue(0, \"Infinity\") <=> QScriptValue(engine, \"Infinity\")",
+ "QScriptValue(0, \"Infinity\") <=> engine->evaluate(\"Infinity\")",
+ "QScriptValue(0, \"-Infinity\") <=> QScriptValue(-qInf())",
+ "QScriptValue(0, \"-Infinity\") <=> QScriptValue(\"-Infinity\")",
+ "QScriptValue(0, \"-Infinity\") <=> QScriptValue(0, -qInf())",
+ "QScriptValue(0, \"-Infinity\") <=> QScriptValue(0, \"-Infinity\")",
+ "QScriptValue(0, \"-Infinity\") <=> QScriptValue(engine, -qInf())",
+ "QScriptValue(0, \"-Infinity\") <=> QScriptValue(engine, \"-Infinity\")",
+ "QScriptValue(0, \"-Infinity\") <=> engine->evaluate(\"-Infinity\")",
+ "QScriptValue(0, \"ciao\") <=> QScriptValue(\"ciao\")",
+ "QScriptValue(0, \"ciao\") <=> QScriptValue(QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(0, \"ciao\") <=> QScriptValue(0, \"ciao\")",
+ "QScriptValue(0, \"ciao\") <=> QScriptValue(0, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(0, \"ciao\") <=> QScriptValue(engine, \"ciao\")",
+ "QScriptValue(0, \"ciao\") <=> QScriptValue(engine, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(0, \"ciao\") <=> engine->evaluate(\"'ciao'\")",
+ "QScriptValue(0, QString::fromLatin1(\"ciao\")) <=> QScriptValue(\"ciao\")",
+ "QScriptValue(0, QString::fromLatin1(\"ciao\")) <=> QScriptValue(QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(0, QString::fromLatin1(\"ciao\")) <=> QScriptValue(0, \"ciao\")",
+ "QScriptValue(0, QString::fromLatin1(\"ciao\")) <=> QScriptValue(0, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(0, QString::fromLatin1(\"ciao\")) <=> QScriptValue(engine, \"ciao\")",
+ "QScriptValue(0, QString::fromLatin1(\"ciao\")) <=> QScriptValue(engine, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(0, QString::fromLatin1(\"ciao\")) <=> engine->evaluate(\"'ciao'\")",
+ "QScriptValue(0, QString(\"\")) <=> QScriptValue(false)",
+ "QScriptValue(0, QString(\"\")) <=> QScriptValue(0)",
+ "QScriptValue(0, QString(\"\")) <=> QScriptValue(0.0)",
+ "QScriptValue(0, QString(\"\")) <=> QScriptValue(QString(\"\"))",
+ "QScriptValue(0, QString(\"\")) <=> QScriptValue(QString())",
+ "QScriptValue(0, QString(\"\")) <=> QScriptValue(0, false)",
+ "QScriptValue(0, QString(\"\")) <=> QScriptValue(0, 0)",
+ "QScriptValue(0, QString(\"\")) <=> QScriptValue(0, 0.0)",
+ "QScriptValue(0, QString(\"\")) <=> QScriptValue(0, QString(\"\"))",
+ "QScriptValue(0, QString(\"\")) <=> QScriptValue(0, QString())",
+ "QScriptValue(0, QString(\"\")) <=> QScriptValue(engine, false)",
+ "QScriptValue(0, QString(\"\")) <=> QScriptValue(engine, 0)",
+ "QScriptValue(0, QString(\"\")) <=> QScriptValue(engine, 0.0)",
+ "QScriptValue(0, QString(\"\")) <=> QScriptValue(engine, QString(\"\"))",
+ "QScriptValue(0, QString(\"\")) <=> QScriptValue(engine, QString())",
+ "QScriptValue(0, QString(\"\")) <=> engine->evaluate(\"[]\")",
+ "QScriptValue(0, QString(\"\")) <=> engine->evaluate(\"Array.prototype\")",
+ "QScriptValue(0, QString(\"\")) <=> engine->evaluate(\"new Array()\")",
+ "QScriptValue(0, QString(\"\")) <=> engine->evaluate(\"false\")",
+ "QScriptValue(0, QString(\"\")) <=> engine->evaluate(\"0\")",
+ "QScriptValue(0, QString(\"\")) <=> engine->evaluate(\"0.0\")",
+ "QScriptValue(0, QString(\"\")) <=> engine->evaluate(\"''\")",
+ "QScriptValue(0, QString(\"\")) <=> engine->newArray()",
+ "QScriptValue(0, QString()) <=> QScriptValue(false)",
+ "QScriptValue(0, QString()) <=> QScriptValue(0)",
+ "QScriptValue(0, QString()) <=> QScriptValue(0.0)",
+ "QScriptValue(0, QString()) <=> QScriptValue(QString(\"\"))",
+ "QScriptValue(0, QString()) <=> QScriptValue(QString())",
+ "QScriptValue(0, QString()) <=> QScriptValue(0, false)",
+ "QScriptValue(0, QString()) <=> QScriptValue(0, 0)",
+ "QScriptValue(0, QString()) <=> QScriptValue(0, 0.0)",
+ "QScriptValue(0, QString()) <=> QScriptValue(0, QString(\"\"))",
+ "QScriptValue(0, QString()) <=> QScriptValue(0, QString())",
+ "QScriptValue(0, QString()) <=> QScriptValue(engine, false)",
+ "QScriptValue(0, QString()) <=> QScriptValue(engine, 0)",
+ "QScriptValue(0, QString()) <=> QScriptValue(engine, 0.0)",
+ "QScriptValue(0, QString()) <=> QScriptValue(engine, QString(\"\"))",
+ "QScriptValue(0, QString()) <=> QScriptValue(engine, QString())",
+ "QScriptValue(0, QString()) <=> engine->evaluate(\"[]\")",
+ "QScriptValue(0, QString()) <=> engine->evaluate(\"Array.prototype\")",
+ "QScriptValue(0, QString()) <=> engine->evaluate(\"new Array()\")",
+ "QScriptValue(0, QString()) <=> engine->evaluate(\"false\")",
+ "QScriptValue(0, QString()) <=> engine->evaluate(\"0\")",
+ "QScriptValue(0, QString()) <=> engine->evaluate(\"0.0\")",
+ "QScriptValue(0, QString()) <=> engine->evaluate(\"''\")",
+ "QScriptValue(0, QString()) <=> engine->newArray()",
+ "QScriptValue(0, QString(\"0\")) <=> QScriptValue(false)",
+ "QScriptValue(0, QString(\"0\")) <=> QScriptValue(0)",
+ "QScriptValue(0, QString(\"0\")) <=> QScriptValue(0.0)",
+ "QScriptValue(0, QString(\"0\")) <=> QScriptValue(QString(\"0\"))",
+ "QScriptValue(0, QString(\"0\")) <=> QScriptValue(0, false)",
+ "QScriptValue(0, QString(\"0\")) <=> QScriptValue(0, 0)",
+ "QScriptValue(0, QString(\"0\")) <=> QScriptValue(0, 0.0)",
+ "QScriptValue(0, QString(\"0\")) <=> QScriptValue(0, QString(\"0\"))",
+ "QScriptValue(0, QString(\"0\")) <=> QScriptValue(engine, false)",
+ "QScriptValue(0, QString(\"0\")) <=> QScriptValue(engine, 0)",
+ "QScriptValue(0, QString(\"0\")) <=> QScriptValue(engine, 0.0)",
+ "QScriptValue(0, QString(\"0\")) <=> QScriptValue(engine, QString(\"0\"))",
+ "QScriptValue(0, QString(\"0\")) <=> engine->evaluate(\"false\")",
+ "QScriptValue(0, QString(\"0\")) <=> engine->evaluate(\"0\")",
+ "QScriptValue(0, QString(\"0\")) <=> engine->evaluate(\"0.0\")",
+ "QScriptValue(0, QString(\"0\")) <=> engine->evaluate(\"'0'\")",
+ "QScriptValue(0, QString(\"123\")) <=> QScriptValue(123.0)",
+ "QScriptValue(0, QString(\"123\")) <=> QScriptValue(QString(\"123\"))",
+ "QScriptValue(0, QString(\"123\")) <=> QScriptValue(0, 123.0)",
+ "QScriptValue(0, QString(\"123\")) <=> QScriptValue(0, QString(\"123\"))",
+ "QScriptValue(0, QString(\"123\")) <=> QScriptValue(engine, 123.0)",
+ "QScriptValue(0, QString(\"123\")) <=> QScriptValue(engine, QString(\"123\"))",
+ "QScriptValue(0, QString(\"123\")) <=> engine->evaluate(\"123.0\")",
+ "QScriptValue(0, QString(\"123\")) <=> engine->evaluate(\"'123'\")",
+ "QScriptValue(0, QString(\"12.3\")) <=> QScriptValue(0, QString(\"12.3\"))",
+ "QScriptValue(engine, QScriptValue::UndefinedValue) <=> QScriptValue(QScriptValue::UndefinedValue)",
+ "QScriptValue(engine, QScriptValue::UndefinedValue) <=> QScriptValue(QScriptValue::NullValue)",
+ "QScriptValue(engine, QScriptValue::UndefinedValue) <=> QScriptValue(0, QScriptValue::UndefinedValue)",
+ "QScriptValue(engine, QScriptValue::UndefinedValue) <=> QScriptValue(0, QScriptValue::NullValue)",
+ "QScriptValue(engine, QScriptValue::UndefinedValue) <=> QScriptValue(engine, QScriptValue::UndefinedValue)",
+ "QScriptValue(engine, QScriptValue::UndefinedValue) <=> QScriptValue(engine, QScriptValue::NullValue)",
+ "QScriptValue(engine, QScriptValue::UndefinedValue) <=> engine->evaluate(\"{}\")",
+ "QScriptValue(engine, QScriptValue::UndefinedValue) <=> engine->evaluate(\"undefined\")",
+ "QScriptValue(engine, QScriptValue::UndefinedValue) <=> engine->evaluate(\"null\")",
+ "QScriptValue(engine, QScriptValue::UndefinedValue) <=> engine->nullValue()",
+ "QScriptValue(engine, QScriptValue::UndefinedValue) <=> engine->undefinedValue()",
+ "QScriptValue(engine, QScriptValue::NullValue) <=> QScriptValue(QScriptValue::UndefinedValue)",
+ "QScriptValue(engine, QScriptValue::NullValue) <=> QScriptValue(QScriptValue::NullValue)",
+ "QScriptValue(engine, QScriptValue::NullValue) <=> QScriptValue(0, QScriptValue::UndefinedValue)",
+ "QScriptValue(engine, QScriptValue::NullValue) <=> QScriptValue(0, QScriptValue::NullValue)",
+ "QScriptValue(engine, QScriptValue::NullValue) <=> QScriptValue(engine, QScriptValue::UndefinedValue)",
+ "QScriptValue(engine, QScriptValue::NullValue) <=> QScriptValue(engine, QScriptValue::NullValue)",
+ "QScriptValue(engine, QScriptValue::NullValue) <=> engine->evaluate(\"{}\")",
+ "QScriptValue(engine, QScriptValue::NullValue) <=> engine->evaluate(\"undefined\")",
+ "QScriptValue(engine, QScriptValue::NullValue) <=> engine->evaluate(\"null\")",
+ "QScriptValue(engine, QScriptValue::NullValue) <=> engine->nullValue()",
+ "QScriptValue(engine, QScriptValue::NullValue) <=> engine->undefinedValue()",
+ "QScriptValue(engine, true) <=> QScriptValue(true)",
+ "QScriptValue(engine, true) <=> QScriptValue(0, true)",
+ "QScriptValue(engine, true) <=> QScriptValue(engine, true)",
+ "QScriptValue(engine, true) <=> engine->evaluate(\"true\")",
+ "QScriptValue(engine, false) <=> QScriptValue(false)",
+ "QScriptValue(engine, false) <=> QScriptValue(0)",
+ "QScriptValue(engine, false) <=> QScriptValue(0.0)",
+ "QScriptValue(engine, false) <=> QScriptValue(QString(\"\"))",
+ "QScriptValue(engine, false) <=> QScriptValue(QString())",
+ "QScriptValue(engine, false) <=> QScriptValue(QString(\"0\"))",
+ "QScriptValue(engine, false) <=> QScriptValue(0, false)",
+ "QScriptValue(engine, false) <=> QScriptValue(0, 0)",
+ "QScriptValue(engine, false) <=> QScriptValue(0, 0.0)",
+ "QScriptValue(engine, false) <=> QScriptValue(0, QString(\"\"))",
+ "QScriptValue(engine, false) <=> QScriptValue(0, QString())",
+ "QScriptValue(engine, false) <=> QScriptValue(0, QString(\"0\"))",
+ "QScriptValue(engine, false) <=> QScriptValue(engine, false)",
+ "QScriptValue(engine, false) <=> QScriptValue(engine, 0)",
+ "QScriptValue(engine, false) <=> QScriptValue(engine, 0.0)",
+ "QScriptValue(engine, false) <=> QScriptValue(engine, QString(\"\"))",
+ "QScriptValue(engine, false) <=> QScriptValue(engine, QString())",
+ "QScriptValue(engine, false) <=> QScriptValue(engine, QString(\"0\"))",
+ "QScriptValue(engine, false) <=> engine->evaluate(\"[]\")",
+ "QScriptValue(engine, false) <=> engine->evaluate(\"Array.prototype\")",
+ "QScriptValue(engine, false) <=> engine->evaluate(\"new Array()\")",
+ "QScriptValue(engine, false) <=> engine->evaluate(\"false\")",
+ "QScriptValue(engine, false) <=> engine->evaluate(\"0\")",
+ "QScriptValue(engine, false) <=> engine->evaluate(\"0.0\")",
+ "QScriptValue(engine, false) <=> engine->evaluate(\"''\")",
+ "QScriptValue(engine, false) <=> engine->evaluate(\"'0'\")",
+ "QScriptValue(engine, false) <=> engine->newArray()",
+ "QScriptValue(engine, int(122)) <=> QScriptValue(int(122))",
+ "QScriptValue(engine, int(122)) <=> QScriptValue(0, int(122))",
+ "QScriptValue(engine, int(122)) <=> QScriptValue(engine, int(122))",
+ "QScriptValue(engine, int(122)) <=> engine->evaluate(\"122\")",
+ "QScriptValue(engine, uint(124)) <=> QScriptValue(uint(124))",
+ "QScriptValue(engine, uint(124)) <=> QScriptValue(0, uint(124))",
+ "QScriptValue(engine, uint(124)) <=> QScriptValue(engine, uint(124))",
+ "QScriptValue(engine, uint(124)) <=> engine->evaluate(\"124\")",
+ "QScriptValue(engine, 0) <=> QScriptValue(false)",
+ "QScriptValue(engine, 0) <=> QScriptValue(0)",
+ "QScriptValue(engine, 0) <=> QScriptValue(0.0)",
+ "QScriptValue(engine, 0) <=> QScriptValue(QString(\"\"))",
+ "QScriptValue(engine, 0) <=> QScriptValue(QString())",
+ "QScriptValue(engine, 0) <=> QScriptValue(QString(\"0\"))",
+ "QScriptValue(engine, 0) <=> QScriptValue(0, false)",
+ "QScriptValue(engine, 0) <=> QScriptValue(0, 0)",
+ "QScriptValue(engine, 0) <=> QScriptValue(0, 0.0)",
+ "QScriptValue(engine, 0) <=> QScriptValue(0, QString(\"\"))",
+ "QScriptValue(engine, 0) <=> QScriptValue(0, QString())",
+ "QScriptValue(engine, 0) <=> QScriptValue(0, QString(\"0\"))",
+ "QScriptValue(engine, 0) <=> QScriptValue(engine, false)",
+ "QScriptValue(engine, 0) <=> QScriptValue(engine, 0)",
+ "QScriptValue(engine, 0) <=> QScriptValue(engine, 0.0)",
+ "QScriptValue(engine, 0) <=> QScriptValue(engine, QString(\"\"))",
+ "QScriptValue(engine, 0) <=> QScriptValue(engine, QString())",
+ "QScriptValue(engine, 0) <=> QScriptValue(engine, QString(\"0\"))",
+ "QScriptValue(engine, 0) <=> engine->evaluate(\"[]\")",
+ "QScriptValue(engine, 0) <=> engine->evaluate(\"Array.prototype\")",
+ "QScriptValue(engine, 0) <=> engine->evaluate(\"new Array()\")",
+ "QScriptValue(engine, 0) <=> engine->evaluate(\"false\")",
+ "QScriptValue(engine, 0) <=> engine->evaluate(\"0\")",
+ "QScriptValue(engine, 0) <=> engine->evaluate(\"0.0\")",
+ "QScriptValue(engine, 0) <=> engine->evaluate(\"''\")",
+ "QScriptValue(engine, 0) <=> engine->evaluate(\"'0'\")",
+ "QScriptValue(engine, 0) <=> engine->newArray()",
+ "QScriptValue(engine, 0.0) <=> QScriptValue(false)",
+ "QScriptValue(engine, 0.0) <=> QScriptValue(0)",
+ "QScriptValue(engine, 0.0) <=> QScriptValue(0.0)",
+ "QScriptValue(engine, 0.0) <=> QScriptValue(QString(\"\"))",
+ "QScriptValue(engine, 0.0) <=> QScriptValue(QString())",
+ "QScriptValue(engine, 0.0) <=> QScriptValue(QString(\"0\"))",
+ "QScriptValue(engine, 0.0) <=> QScriptValue(0, false)",
+ "QScriptValue(engine, 0.0) <=> QScriptValue(0, 0)",
+ "QScriptValue(engine, 0.0) <=> QScriptValue(0, 0.0)",
+ "QScriptValue(engine, 0.0) <=> QScriptValue(0, QString(\"\"))",
+ "QScriptValue(engine, 0.0) <=> QScriptValue(0, QString())",
+ "QScriptValue(engine, 0.0) <=> QScriptValue(0, QString(\"0\"))",
+ "QScriptValue(engine, 0.0) <=> QScriptValue(engine, false)",
+ "QScriptValue(engine, 0.0) <=> QScriptValue(engine, 0)",
+ "QScriptValue(engine, 0.0) <=> QScriptValue(engine, 0.0)",
+ "QScriptValue(engine, 0.0) <=> QScriptValue(engine, QString(\"\"))",
+ "QScriptValue(engine, 0.0) <=> QScriptValue(engine, QString())",
+ "QScriptValue(engine, 0.0) <=> QScriptValue(engine, QString(\"0\"))",
+ "QScriptValue(engine, 0.0) <=> engine->evaluate(\"[]\")",
+ "QScriptValue(engine, 0.0) <=> engine->evaluate(\"Array.prototype\")",
+ "QScriptValue(engine, 0.0) <=> engine->evaluate(\"new Array()\")",
+ "QScriptValue(engine, 0.0) <=> engine->evaluate(\"false\")",
+ "QScriptValue(engine, 0.0) <=> engine->evaluate(\"0\")",
+ "QScriptValue(engine, 0.0) <=> engine->evaluate(\"0.0\")",
+ "QScriptValue(engine, 0.0) <=> engine->evaluate(\"''\")",
+ "QScriptValue(engine, 0.0) <=> engine->evaluate(\"'0'\")",
+ "QScriptValue(engine, 0.0) <=> engine->newArray()",
+ "QScriptValue(engine, 123.0) <=> QScriptValue(123.0)",
+ "QScriptValue(engine, 123.0) <=> QScriptValue(QString(\"123\"))",
+ "QScriptValue(engine, 123.0) <=> QScriptValue(0, 123.0)",
+ "QScriptValue(engine, 123.0) <=> QScriptValue(0, QString(\"123\"))",
+ "QScriptValue(engine, 123.0) <=> QScriptValue(engine, 123.0)",
+ "QScriptValue(engine, 123.0) <=> QScriptValue(engine, QString(\"123\"))",
+ "QScriptValue(engine, 123.0) <=> engine->evaluate(\"123.0\")",
+ "QScriptValue(engine, 123.0) <=> engine->evaluate(\"'123'\")",
+ "QScriptValue(engine, 6.37e-8) <=> QScriptValue(6.37e-8)",
+ "QScriptValue(engine, 6.37e-8) <=> QScriptValue(0, 6.37e-8)",
+ "QScriptValue(engine, 6.37e-8) <=> QScriptValue(engine, 6.37e-8)",
+ "QScriptValue(engine, 6.37e-8) <=> engine->evaluate(\"6.37e-8\")",
+ "QScriptValue(engine, -6.37e-8) <=> QScriptValue(-6.37e-8)",
+ "QScriptValue(engine, -6.37e-8) <=> QScriptValue(0, -6.37e-8)",
+ "QScriptValue(engine, -6.37e-8) <=> QScriptValue(engine, -6.37e-8)",
+ "QScriptValue(engine, -6.37e-8) <=> engine->evaluate(\"-6.37e-8\")",
+ "QScriptValue(engine, 0x43211234) <=> QScriptValue(0x43211234)",
+ "QScriptValue(engine, 0x43211234) <=> QScriptValue(0, 0x43211234)",
+ "QScriptValue(engine, 0x43211234) <=> QScriptValue(engine, 0x43211234)",
+ "QScriptValue(engine, 0x43211234) <=> engine->evaluate(\"0x43211234\")",
+ "QScriptValue(engine, 0x10000) <=> QScriptValue(0x10000)",
+ "QScriptValue(engine, 0x10000) <=> QScriptValue(0, 0x10000)",
+ "QScriptValue(engine, 0x10000) <=> QScriptValue(engine, 0x10000)",
+ "QScriptValue(engine, 0x10000) <=> engine->evaluate(\"0x10000\")",
+ "QScriptValue(engine, 0x10001) <=> QScriptValue(0x10001)",
+ "QScriptValue(engine, 0x10001) <=> QScriptValue(0, 0x10001)",
+ "QScriptValue(engine, 0x10001) <=> QScriptValue(engine, 0x10001)",
+ "QScriptValue(engine, 0x10001) <=> engine->evaluate(\"0x10001\")",
+ "QScriptValue(engine, qInf()) <=> QScriptValue(qInf())",
+ "QScriptValue(engine, qInf()) <=> QScriptValue(\"Infinity\")",
+ "QScriptValue(engine, qInf()) <=> QScriptValue(0, qInf())",
+ "QScriptValue(engine, qInf()) <=> QScriptValue(0, \"Infinity\")",
+ "QScriptValue(engine, qInf()) <=> QScriptValue(engine, qInf())",
+ "QScriptValue(engine, qInf()) <=> QScriptValue(engine, \"Infinity\")",
+ "QScriptValue(engine, qInf()) <=> engine->evaluate(\"Infinity\")",
+ "QScriptValue(engine, -qInf()) <=> QScriptValue(-qInf())",
+ "QScriptValue(engine, -qInf()) <=> QScriptValue(\"-Infinity\")",
+ "QScriptValue(engine, -qInf()) <=> QScriptValue(0, -qInf())",
+ "QScriptValue(engine, -qInf()) <=> QScriptValue(0, \"-Infinity\")",
+ "QScriptValue(engine, -qInf()) <=> QScriptValue(engine, -qInf())",
+ "QScriptValue(engine, -qInf()) <=> QScriptValue(engine, \"-Infinity\")",
+ "QScriptValue(engine, -qInf()) <=> engine->evaluate(\"-Infinity\")",
+ "QScriptValue(engine, \"NaN\") <=> QScriptValue(\"NaN\")",
+ "QScriptValue(engine, \"NaN\") <=> QScriptValue(0, \"NaN\")",
+ "QScriptValue(engine, \"NaN\") <=> QScriptValue(engine, \"NaN\")",
+ "QScriptValue(engine, \"Infinity\") <=> QScriptValue(qInf())",
+ "QScriptValue(engine, \"Infinity\") <=> QScriptValue(\"Infinity\")",
+ "QScriptValue(engine, \"Infinity\") <=> QScriptValue(0, qInf())",
+ "QScriptValue(engine, \"Infinity\") <=> QScriptValue(0, \"Infinity\")",
+ "QScriptValue(engine, \"Infinity\") <=> QScriptValue(engine, qInf())",
+ "QScriptValue(engine, \"Infinity\") <=> QScriptValue(engine, \"Infinity\")",
+ "QScriptValue(engine, \"Infinity\") <=> engine->evaluate(\"Infinity\")",
+ "QScriptValue(engine, \"-Infinity\") <=> QScriptValue(-qInf())",
+ "QScriptValue(engine, \"-Infinity\") <=> QScriptValue(\"-Infinity\")",
+ "QScriptValue(engine, \"-Infinity\") <=> QScriptValue(0, -qInf())",
+ "QScriptValue(engine, \"-Infinity\") <=> QScriptValue(0, \"-Infinity\")",
+ "QScriptValue(engine, \"-Infinity\") <=> QScriptValue(engine, -qInf())",
+ "QScriptValue(engine, \"-Infinity\") <=> QScriptValue(engine, \"-Infinity\")",
+ "QScriptValue(engine, \"-Infinity\") <=> engine->evaluate(\"-Infinity\")",
+ "QScriptValue(engine, \"ciao\") <=> QScriptValue(\"ciao\")",
+ "QScriptValue(engine, \"ciao\") <=> QScriptValue(QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(engine, \"ciao\") <=> QScriptValue(0, \"ciao\")",
+ "QScriptValue(engine, \"ciao\") <=> QScriptValue(0, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(engine, \"ciao\") <=> QScriptValue(engine, \"ciao\")",
+ "QScriptValue(engine, \"ciao\") <=> QScriptValue(engine, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(engine, \"ciao\") <=> engine->evaluate(\"'ciao'\")",
+ "QScriptValue(engine, QString::fromLatin1(\"ciao\")) <=> QScriptValue(\"ciao\")",
+ "QScriptValue(engine, QString::fromLatin1(\"ciao\")) <=> QScriptValue(QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(engine, QString::fromLatin1(\"ciao\")) <=> QScriptValue(0, \"ciao\")",
+ "QScriptValue(engine, QString::fromLatin1(\"ciao\")) <=> QScriptValue(0, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(engine, QString::fromLatin1(\"ciao\")) <=> QScriptValue(engine, \"ciao\")",
+ "QScriptValue(engine, QString::fromLatin1(\"ciao\")) <=> QScriptValue(engine, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(engine, QString::fromLatin1(\"ciao\")) <=> engine->evaluate(\"'ciao'\")",
+ "QScriptValue(engine, QString(\"\")) <=> QScriptValue(false)",
+ "QScriptValue(engine, QString(\"\")) <=> QScriptValue(0)",
+ "QScriptValue(engine, QString(\"\")) <=> QScriptValue(0.0)",
+ "QScriptValue(engine, QString(\"\")) <=> QScriptValue(QString(\"\"))",
+ "QScriptValue(engine, QString(\"\")) <=> QScriptValue(QString())",
+ "QScriptValue(engine, QString(\"\")) <=> QScriptValue(0, false)",
+ "QScriptValue(engine, QString(\"\")) <=> QScriptValue(0, 0)",
+ "QScriptValue(engine, QString(\"\")) <=> QScriptValue(0, 0.0)",
+ "QScriptValue(engine, QString(\"\")) <=> QScriptValue(0, QString(\"\"))",
+ "QScriptValue(engine, QString(\"\")) <=> QScriptValue(0, QString())",
+ "QScriptValue(engine, QString(\"\")) <=> QScriptValue(engine, false)",
+ "QScriptValue(engine, QString(\"\")) <=> QScriptValue(engine, 0)",
+ "QScriptValue(engine, QString(\"\")) <=> QScriptValue(engine, 0.0)",
+ "QScriptValue(engine, QString(\"\")) <=> QScriptValue(engine, QString(\"\"))",
+ "QScriptValue(engine, QString(\"\")) <=> QScriptValue(engine, QString())",
+ "QScriptValue(engine, QString(\"\")) <=> engine->evaluate(\"[]\")",
+ "QScriptValue(engine, QString(\"\")) <=> engine->evaluate(\"Array.prototype\")",
+ "QScriptValue(engine, QString(\"\")) <=> engine->evaluate(\"new Array()\")",
+ "QScriptValue(engine, QString(\"\")) <=> engine->evaluate(\"false\")",
+ "QScriptValue(engine, QString(\"\")) <=> engine->evaluate(\"0\")",
+ "QScriptValue(engine, QString(\"\")) <=> engine->evaluate(\"0.0\")",
+ "QScriptValue(engine, QString(\"\")) <=> engine->evaluate(\"''\")",
+ "QScriptValue(engine, QString(\"\")) <=> engine->newArray()",
+ "QScriptValue(engine, QString()) <=> QScriptValue(false)",
+ "QScriptValue(engine, QString()) <=> QScriptValue(0)",
+ "QScriptValue(engine, QString()) <=> QScriptValue(0.0)",
+ "QScriptValue(engine, QString()) <=> QScriptValue(QString(\"\"))",
+ "QScriptValue(engine, QString()) <=> QScriptValue(QString())",
+ "QScriptValue(engine, QString()) <=> QScriptValue(0, false)",
+ "QScriptValue(engine, QString()) <=> QScriptValue(0, 0)",
+ "QScriptValue(engine, QString()) <=> QScriptValue(0, 0.0)",
+ "QScriptValue(engine, QString()) <=> QScriptValue(0, QString(\"\"))",
+ "QScriptValue(engine, QString()) <=> QScriptValue(0, QString())",
+ "QScriptValue(engine, QString()) <=> QScriptValue(engine, false)",
+ "QScriptValue(engine, QString()) <=> QScriptValue(engine, 0)",
+ "QScriptValue(engine, QString()) <=> QScriptValue(engine, 0.0)",
+ "QScriptValue(engine, QString()) <=> QScriptValue(engine, QString(\"\"))",
+ "QScriptValue(engine, QString()) <=> QScriptValue(engine, QString())",
+ "QScriptValue(engine, QString()) <=> engine->evaluate(\"[]\")",
+ "QScriptValue(engine, QString()) <=> engine->evaluate(\"Array.prototype\")",
+ "QScriptValue(engine, QString()) <=> engine->evaluate(\"new Array()\")",
+ "QScriptValue(engine, QString()) <=> engine->evaluate(\"false\")",
+ "QScriptValue(engine, QString()) <=> engine->evaluate(\"0\")",
+ "QScriptValue(engine, QString()) <=> engine->evaluate(\"0.0\")",
+ "QScriptValue(engine, QString()) <=> engine->evaluate(\"''\")",
+ "QScriptValue(engine, QString()) <=> engine->newArray()",
+ "QScriptValue(engine, QString(\"0\")) <=> QScriptValue(false)",
+ "QScriptValue(engine, QString(\"0\")) <=> QScriptValue(0)",
+ "QScriptValue(engine, QString(\"0\")) <=> QScriptValue(0.0)",
+ "QScriptValue(engine, QString(\"0\")) <=> QScriptValue(QString(\"0\"))",
+ "QScriptValue(engine, QString(\"0\")) <=> QScriptValue(0, false)",
+ "QScriptValue(engine, QString(\"0\")) <=> QScriptValue(0, 0)",
+ "QScriptValue(engine, QString(\"0\")) <=> QScriptValue(0, 0.0)",
+ "QScriptValue(engine, QString(\"0\")) <=> QScriptValue(0, QString(\"0\"))",
+ "QScriptValue(engine, QString(\"0\")) <=> QScriptValue(engine, false)",
+ "QScriptValue(engine, QString(\"0\")) <=> QScriptValue(engine, 0)",
+ "QScriptValue(engine, QString(\"0\")) <=> QScriptValue(engine, 0.0)",
+ "QScriptValue(engine, QString(\"0\")) <=> QScriptValue(engine, QString(\"0\"))",
+ "QScriptValue(engine, QString(\"0\")) <=> engine->evaluate(\"false\")",
+ "QScriptValue(engine, QString(\"0\")) <=> engine->evaluate(\"0\")",
+ "QScriptValue(engine, QString(\"0\")) <=> engine->evaluate(\"0.0\")",
+ "QScriptValue(engine, QString(\"0\")) <=> engine->evaluate(\"'0'\")",
+ "QScriptValue(engine, QString(\"123\")) <=> QScriptValue(123.0)",
+ "QScriptValue(engine, QString(\"123\")) <=> QScriptValue(QString(\"123\"))",
+ "QScriptValue(engine, QString(\"123\")) <=> QScriptValue(0, 123.0)",
+ "QScriptValue(engine, QString(\"123\")) <=> QScriptValue(0, QString(\"123\"))",
+ "QScriptValue(engine, QString(\"123\")) <=> QScriptValue(engine, 123.0)",
+ "QScriptValue(engine, QString(\"123\")) <=> QScriptValue(engine, QString(\"123\"))",
+ "QScriptValue(engine, QString(\"123\")) <=> engine->evaluate(\"123.0\")",
+ "QScriptValue(engine, QString(\"123\")) <=> engine->evaluate(\"'123'\")",
+ "QScriptValue(engine, QString(\"1.23\")) <=> QScriptValue(engine, QString(\"1.23\"))",
+ "engine->evaluate(\"[]\") <=> QScriptValue(false)",
+ "engine->evaluate(\"[]\") <=> QScriptValue(0)",
+ "engine->evaluate(\"[]\") <=> QScriptValue(0.0)",
+ "engine->evaluate(\"[]\") <=> QScriptValue(QString(\"\"))",
+ "engine->evaluate(\"[]\") <=> QScriptValue(QString())",
+ "engine->evaluate(\"[]\") <=> QScriptValue(0, false)",
+ "engine->evaluate(\"[]\") <=> QScriptValue(0, 0)",
+ "engine->evaluate(\"[]\") <=> QScriptValue(0, 0.0)",
+ "engine->evaluate(\"[]\") <=> QScriptValue(0, QString(\"\"))",
+ "engine->evaluate(\"[]\") <=> QScriptValue(0, QString())",
+ "engine->evaluate(\"[]\") <=> QScriptValue(engine, false)",
+ "engine->evaluate(\"[]\") <=> QScriptValue(engine, 0)",
+ "engine->evaluate(\"[]\") <=> QScriptValue(engine, 0.0)",
+ "engine->evaluate(\"[]\") <=> QScriptValue(engine, QString(\"\"))",
+ "engine->evaluate(\"[]\") <=> QScriptValue(engine, QString())",
+ "engine->evaluate(\"[]\") <=> engine->evaluate(\"false\")",
+ "engine->evaluate(\"[]\") <=> engine->evaluate(\"0\")",
+ "engine->evaluate(\"[]\") <=> engine->evaluate(\"0.0\")",
+ "engine->evaluate(\"[]\") <=> engine->evaluate(\"''\")",
+ "engine->evaluate(\"{}\") <=> QScriptValue(QScriptValue::UndefinedValue)",
+ "engine->evaluate(\"{}\") <=> QScriptValue(QScriptValue::NullValue)",
+ "engine->evaluate(\"{}\") <=> QScriptValue(0, QScriptValue::UndefinedValue)",
+ "engine->evaluate(\"{}\") <=> QScriptValue(0, QScriptValue::NullValue)",
+ "engine->evaluate(\"{}\") <=> QScriptValue(engine, QScriptValue::UndefinedValue)",
+ "engine->evaluate(\"{}\") <=> QScriptValue(engine, QScriptValue::NullValue)",
+ "engine->evaluate(\"{}\") <=> engine->evaluate(\"{}\")",
+ "engine->evaluate(\"{}\") <=> engine->evaluate(\"undefined\")",
+ "engine->evaluate(\"{}\") <=> engine->evaluate(\"null\")",
+ "engine->evaluate(\"{}\") <=> engine->nullValue()",
+ "engine->evaluate(\"{}\") <=> engine->undefinedValue()",
+ "engine->evaluate(\"Object.prototype\") <=> engine->evaluate(\"Object.prototype\")",
+ "engine->evaluate(\"Date.prototype\") <=> engine->evaluate(\"Date.prototype\")",
+ "engine->evaluate(\"Array.prototype\") <=> QScriptValue(false)",
+ "engine->evaluate(\"Array.prototype\") <=> QScriptValue(0)",
+ "engine->evaluate(\"Array.prototype\") <=> QScriptValue(0.0)",
+ "engine->evaluate(\"Array.prototype\") <=> QScriptValue(QString(\"\"))",
+ "engine->evaluate(\"Array.prototype\") <=> QScriptValue(QString())",
+ "engine->evaluate(\"Array.prototype\") <=> QScriptValue(0, false)",
+ "engine->evaluate(\"Array.prototype\") <=> QScriptValue(0, 0)",
+ "engine->evaluate(\"Array.prototype\") <=> QScriptValue(0, 0.0)",
+ "engine->evaluate(\"Array.prototype\") <=> QScriptValue(0, QString(\"\"))",
+ "engine->evaluate(\"Array.prototype\") <=> QScriptValue(0, QString())",
+ "engine->evaluate(\"Array.prototype\") <=> QScriptValue(engine, false)",
+ "engine->evaluate(\"Array.prototype\") <=> QScriptValue(engine, 0)",
+ "engine->evaluate(\"Array.prototype\") <=> QScriptValue(engine, 0.0)",
+ "engine->evaluate(\"Array.prototype\") <=> QScriptValue(engine, QString(\"\"))",
+ "engine->evaluate(\"Array.prototype\") <=> QScriptValue(engine, QString())",
+ "engine->evaluate(\"Array.prototype\") <=> engine->evaluate(\"Array.prototype\")",
+ "engine->evaluate(\"Array.prototype\") <=> engine->evaluate(\"false\")",
+ "engine->evaluate(\"Array.prototype\") <=> engine->evaluate(\"0\")",
+ "engine->evaluate(\"Array.prototype\") <=> engine->evaluate(\"0.0\")",
+ "engine->evaluate(\"Array.prototype\") <=> engine->evaluate(\"''\")",
+ "engine->evaluate(\"Function.prototype\") <=> engine->evaluate(\"Function.prototype\")",
+ "engine->evaluate(\"Error.prototype\") <=> engine->evaluate(\"Error.prototype\")",
+ "engine->evaluate(\"Object\") <=> engine->evaluate(\"Object\")",
+ "engine->evaluate(\"Array\") <=> engine->evaluate(\"Array\")",
+ "engine->evaluate(\"Number\") <=> engine->evaluate(\"Number\")",
+ "engine->evaluate(\"Function\") <=> engine->evaluate(\"Function\")",
+ "engine->evaluate(\"new Array()\") <=> QScriptValue(false)",
+ "engine->evaluate(\"new Array()\") <=> QScriptValue(0)",
+ "engine->evaluate(\"new Array()\") <=> QScriptValue(0.0)",
+ "engine->evaluate(\"new Array()\") <=> QScriptValue(QString(\"\"))",
+ "engine->evaluate(\"new Array()\") <=> QScriptValue(QString())",
+ "engine->evaluate(\"new Array()\") <=> QScriptValue(0, false)",
+ "engine->evaluate(\"new Array()\") <=> QScriptValue(0, 0)",
+ "engine->evaluate(\"new Array()\") <=> QScriptValue(0, 0.0)",
+ "engine->evaluate(\"new Array()\") <=> QScriptValue(0, QString(\"\"))",
+ "engine->evaluate(\"new Array()\") <=> QScriptValue(0, QString())",
+ "engine->evaluate(\"new Array()\") <=> QScriptValue(engine, false)",
+ "engine->evaluate(\"new Array()\") <=> QScriptValue(engine, 0)",
+ "engine->evaluate(\"new Array()\") <=> QScriptValue(engine, 0.0)",
+ "engine->evaluate(\"new Array()\") <=> QScriptValue(engine, QString(\"\"))",
+ "engine->evaluate(\"new Array()\") <=> QScriptValue(engine, QString())",
+ "engine->evaluate(\"new Array()\") <=> engine->evaluate(\"false\")",
+ "engine->evaluate(\"new Array()\") <=> engine->evaluate(\"0\")",
+ "engine->evaluate(\"new Array()\") <=> engine->evaluate(\"0.0\")",
+ "engine->evaluate(\"new Array()\") <=> engine->evaluate(\"''\")",
+ "engine->evaluate(\"a = new Object(); a.foo = 22; a.foo\") <=> engine->evaluate(\"a = new Object(); a.foo = 22; a.foo\")",
+ "engine->evaluate(\"undefined\") <=> QScriptValue(QScriptValue::UndefinedValue)",
+ "engine->evaluate(\"undefined\") <=> QScriptValue(QScriptValue::NullValue)",
+ "engine->evaluate(\"undefined\") <=> QScriptValue(0, QScriptValue::UndefinedValue)",
+ "engine->evaluate(\"undefined\") <=> QScriptValue(0, QScriptValue::NullValue)",
+ "engine->evaluate(\"undefined\") <=> QScriptValue(engine, QScriptValue::UndefinedValue)",
+ "engine->evaluate(\"undefined\") <=> QScriptValue(engine, QScriptValue::NullValue)",
+ "engine->evaluate(\"undefined\") <=> engine->evaluate(\"{}\")",
+ "engine->evaluate(\"undefined\") <=> engine->evaluate(\"undefined\")",
+ "engine->evaluate(\"undefined\") <=> engine->evaluate(\"null\")",
+ "engine->evaluate(\"undefined\") <=> engine->nullValue()",
+ "engine->evaluate(\"undefined\") <=> engine->undefinedValue()",
+ "engine->evaluate(\"null\") <=> QScriptValue(QScriptValue::UndefinedValue)",
+ "engine->evaluate(\"null\") <=> QScriptValue(QScriptValue::NullValue)",
+ "engine->evaluate(\"null\") <=> QScriptValue(0, QScriptValue::UndefinedValue)",
+ "engine->evaluate(\"null\") <=> QScriptValue(0, QScriptValue::NullValue)",
+ "engine->evaluate(\"null\") <=> QScriptValue(engine, QScriptValue::UndefinedValue)",
+ "engine->evaluate(\"null\") <=> QScriptValue(engine, QScriptValue::NullValue)",
+ "engine->evaluate(\"null\") <=> engine->evaluate(\"{}\")",
+ "engine->evaluate(\"null\") <=> engine->evaluate(\"undefined\")",
+ "engine->evaluate(\"null\") <=> engine->evaluate(\"null\")",
+ "engine->evaluate(\"null\") <=> engine->nullValue()",
+ "engine->evaluate(\"null\") <=> engine->undefinedValue()",
+ "engine->evaluate(\"true\") <=> QScriptValue(true)",
+ "engine->evaluate(\"true\") <=> QScriptValue(0, true)",
+ "engine->evaluate(\"true\") <=> QScriptValue(engine, true)",
+ "engine->evaluate(\"true\") <=> engine->evaluate(\"true\")",
+ "engine->evaluate(\"false\") <=> QScriptValue(false)",
+ "engine->evaluate(\"false\") <=> QScriptValue(0)",
+ "engine->evaluate(\"false\") <=> QScriptValue(0.0)",
+ "engine->evaluate(\"false\") <=> QScriptValue(QString(\"\"))",
+ "engine->evaluate(\"false\") <=> QScriptValue(QString())",
+ "engine->evaluate(\"false\") <=> QScriptValue(QString(\"0\"))",
+ "engine->evaluate(\"false\") <=> QScriptValue(0, false)",
+ "engine->evaluate(\"false\") <=> QScriptValue(0, 0)",
+ "engine->evaluate(\"false\") <=> QScriptValue(0, 0.0)",
+ "engine->evaluate(\"false\") <=> QScriptValue(0, QString(\"\"))",
+ "engine->evaluate(\"false\") <=> QScriptValue(0, QString())",
+ "engine->evaluate(\"false\") <=> QScriptValue(0, QString(\"0\"))",
+ "engine->evaluate(\"false\") <=> QScriptValue(engine, false)",
+ "engine->evaluate(\"false\") <=> QScriptValue(engine, 0)",
+ "engine->evaluate(\"false\") <=> QScriptValue(engine, 0.0)",
+ "engine->evaluate(\"false\") <=> QScriptValue(engine, QString(\"\"))",
+ "engine->evaluate(\"false\") <=> QScriptValue(engine, QString())",
+ "engine->evaluate(\"false\") <=> QScriptValue(engine, QString(\"0\"))",
+ "engine->evaluate(\"false\") <=> engine->evaluate(\"[]\")",
+ "engine->evaluate(\"false\") <=> engine->evaluate(\"Array.prototype\")",
+ "engine->evaluate(\"false\") <=> engine->evaluate(\"new Array()\")",
+ "engine->evaluate(\"false\") <=> engine->evaluate(\"false\")",
+ "engine->evaluate(\"false\") <=> engine->evaluate(\"0\")",
+ "engine->evaluate(\"false\") <=> engine->evaluate(\"0.0\")",
+ "engine->evaluate(\"false\") <=> engine->evaluate(\"''\")",
+ "engine->evaluate(\"false\") <=> engine->evaluate(\"'0'\")",
+ "engine->evaluate(\"false\") <=> engine->newArray()",
+ "engine->evaluate(\"122\") <=> QScriptValue(int(122))",
+ "engine->evaluate(\"122\") <=> QScriptValue(0, int(122))",
+ "engine->evaluate(\"122\") <=> QScriptValue(engine, int(122))",
+ "engine->evaluate(\"122\") <=> engine->evaluate(\"122\")",
+ "engine->evaluate(\"124\") <=> QScriptValue(uint(124))",
+ "engine->evaluate(\"124\") <=> QScriptValue(0, uint(124))",
+ "engine->evaluate(\"124\") <=> QScriptValue(engine, uint(124))",
+ "engine->evaluate(\"124\") <=> engine->evaluate(\"124\")",
+ "engine->evaluate(\"0\") <=> QScriptValue(false)",
+ "engine->evaluate(\"0\") <=> QScriptValue(0)",
+ "engine->evaluate(\"0\") <=> QScriptValue(0.0)",
+ "engine->evaluate(\"0\") <=> QScriptValue(QString(\"\"))",
+ "engine->evaluate(\"0\") <=> QScriptValue(QString())",
+ "engine->evaluate(\"0\") <=> QScriptValue(QString(\"0\"))",
+ "engine->evaluate(\"0\") <=> QScriptValue(0, false)",
+ "engine->evaluate(\"0\") <=> QScriptValue(0, 0)",
+ "engine->evaluate(\"0\") <=> QScriptValue(0, 0.0)",
+ "engine->evaluate(\"0\") <=> QScriptValue(0, QString(\"\"))",
+ "engine->evaluate(\"0\") <=> QScriptValue(0, QString())",
+ "engine->evaluate(\"0\") <=> QScriptValue(0, QString(\"0\"))",
+ "engine->evaluate(\"0\") <=> QScriptValue(engine, false)",
+ "engine->evaluate(\"0\") <=> QScriptValue(engine, 0)",
+ "engine->evaluate(\"0\") <=> QScriptValue(engine, 0.0)",
+ "engine->evaluate(\"0\") <=> QScriptValue(engine, QString(\"\"))",
+ "engine->evaluate(\"0\") <=> QScriptValue(engine, QString())",
+ "engine->evaluate(\"0\") <=> QScriptValue(engine, QString(\"0\"))",
+ "engine->evaluate(\"0\") <=> engine->evaluate(\"[]\")",
+ "engine->evaluate(\"0\") <=> engine->evaluate(\"Array.prototype\")",
+ "engine->evaluate(\"0\") <=> engine->evaluate(\"new Array()\")",
+ "engine->evaluate(\"0\") <=> engine->evaluate(\"false\")",
+ "engine->evaluate(\"0\") <=> engine->evaluate(\"0\")",
+ "engine->evaluate(\"0\") <=> engine->evaluate(\"0.0\")",
+ "engine->evaluate(\"0\") <=> engine->evaluate(\"''\")",
+ "engine->evaluate(\"0\") <=> engine->evaluate(\"'0'\")",
+ "engine->evaluate(\"0\") <=> engine->newArray()",
+ "engine->evaluate(\"0.0\") <=> QScriptValue(false)",
+ "engine->evaluate(\"0.0\") <=> QScriptValue(0)",
+ "engine->evaluate(\"0.0\") <=> QScriptValue(0.0)",
+ "engine->evaluate(\"0.0\") <=> QScriptValue(QString(\"\"))",
+ "engine->evaluate(\"0.0\") <=> QScriptValue(QString())",
+ "engine->evaluate(\"0.0\") <=> QScriptValue(QString(\"0\"))",
+ "engine->evaluate(\"0.0\") <=> QScriptValue(0, false)",
+ "engine->evaluate(\"0.0\") <=> QScriptValue(0, 0)",
+ "engine->evaluate(\"0.0\") <=> QScriptValue(0, 0.0)",
+ "engine->evaluate(\"0.0\") <=> QScriptValue(0, QString(\"\"))",
+ "engine->evaluate(\"0.0\") <=> QScriptValue(0, QString())",
+ "engine->evaluate(\"0.0\") <=> QScriptValue(0, QString(\"0\"))",
+ "engine->evaluate(\"0.0\") <=> QScriptValue(engine, false)",
+ "engine->evaluate(\"0.0\") <=> QScriptValue(engine, 0)",
+ "engine->evaluate(\"0.0\") <=> QScriptValue(engine, 0.0)",
+ "engine->evaluate(\"0.0\") <=> QScriptValue(engine, QString(\"\"))",
+ "engine->evaluate(\"0.0\") <=> QScriptValue(engine, QString())",
+ "engine->evaluate(\"0.0\") <=> QScriptValue(engine, QString(\"0\"))",
+ "engine->evaluate(\"0.0\") <=> engine->evaluate(\"[]\")",
+ "engine->evaluate(\"0.0\") <=> engine->evaluate(\"Array.prototype\")",
+ "engine->evaluate(\"0.0\") <=> engine->evaluate(\"new Array()\")",
+ "engine->evaluate(\"0.0\") <=> engine->evaluate(\"false\")",
+ "engine->evaluate(\"0.0\") <=> engine->evaluate(\"0\")",
+ "engine->evaluate(\"0.0\") <=> engine->evaluate(\"0.0\")",
+ "engine->evaluate(\"0.0\") <=> engine->evaluate(\"''\")",
+ "engine->evaluate(\"0.0\") <=> engine->evaluate(\"'0'\")",
+ "engine->evaluate(\"0.0\") <=> engine->newArray()",
+ "engine->evaluate(\"123.0\") <=> QScriptValue(123.0)",
+ "engine->evaluate(\"123.0\") <=> QScriptValue(QString(\"123\"))",
+ "engine->evaluate(\"123.0\") <=> QScriptValue(0, 123.0)",
+ "engine->evaluate(\"123.0\") <=> QScriptValue(0, QString(\"123\"))",
+ "engine->evaluate(\"123.0\") <=> QScriptValue(engine, 123.0)",
+ "engine->evaluate(\"123.0\") <=> QScriptValue(engine, QString(\"123\"))",
+ "engine->evaluate(\"123.0\") <=> engine->evaluate(\"123.0\")",
+ "engine->evaluate(\"123.0\") <=> engine->evaluate(\"'123'\")",
+ "engine->evaluate(\"6.37e-8\") <=> QScriptValue(6.37e-8)",
+ "engine->evaluate(\"6.37e-8\") <=> QScriptValue(0, 6.37e-8)",
+ "engine->evaluate(\"6.37e-8\") <=> QScriptValue(engine, 6.37e-8)",
+ "engine->evaluate(\"6.37e-8\") <=> engine->evaluate(\"6.37e-8\")",
+ "engine->evaluate(\"-6.37e-8\") <=> QScriptValue(-6.37e-8)",
+ "engine->evaluate(\"-6.37e-8\") <=> QScriptValue(0, -6.37e-8)",
+ "engine->evaluate(\"-6.37e-8\") <=> QScriptValue(engine, -6.37e-8)",
+ "engine->evaluate(\"-6.37e-8\") <=> engine->evaluate(\"-6.37e-8\")",
+ "engine->evaluate(\"0x43211234\") <=> QScriptValue(0x43211234)",
+ "engine->evaluate(\"0x43211234\") <=> QScriptValue(0, 0x43211234)",
+ "engine->evaluate(\"0x43211234\") <=> QScriptValue(engine, 0x43211234)",
+ "engine->evaluate(\"0x43211234\") <=> engine->evaluate(\"0x43211234\")",
+ "engine->evaluate(\"0x10000\") <=> QScriptValue(0x10000)",
+ "engine->evaluate(\"0x10000\") <=> QScriptValue(0, 0x10000)",
+ "engine->evaluate(\"0x10000\") <=> QScriptValue(engine, 0x10000)",
+ "engine->evaluate(\"0x10000\") <=> engine->evaluate(\"0x10000\")",
+ "engine->evaluate(\"0x10001\") <=> QScriptValue(0x10001)",
+ "engine->evaluate(\"0x10001\") <=> QScriptValue(0, 0x10001)",
+ "engine->evaluate(\"0x10001\") <=> QScriptValue(engine, 0x10001)",
+ "engine->evaluate(\"0x10001\") <=> engine->evaluate(\"0x10001\")",
+ "engine->evaluate(\"Infinity\") <=> QScriptValue(qInf())",
+ "engine->evaluate(\"Infinity\") <=> QScriptValue(\"Infinity\")",
+ "engine->evaluate(\"Infinity\") <=> QScriptValue(0, qInf())",
+ "engine->evaluate(\"Infinity\") <=> QScriptValue(0, \"Infinity\")",
+ "engine->evaluate(\"Infinity\") <=> QScriptValue(engine, qInf())",
+ "engine->evaluate(\"Infinity\") <=> QScriptValue(engine, \"Infinity\")",
+ "engine->evaluate(\"Infinity\") <=> engine->evaluate(\"Infinity\")",
+ "engine->evaluate(\"-Infinity\") <=> QScriptValue(-qInf())",
+ "engine->evaluate(\"-Infinity\") <=> QScriptValue(\"-Infinity\")",
+ "engine->evaluate(\"-Infinity\") <=> QScriptValue(0, -qInf())",
+ "engine->evaluate(\"-Infinity\") <=> QScriptValue(0, \"-Infinity\")",
+ "engine->evaluate(\"-Infinity\") <=> QScriptValue(engine, -qInf())",
+ "engine->evaluate(\"-Infinity\") <=> QScriptValue(engine, \"-Infinity\")",
+ "engine->evaluate(\"-Infinity\") <=> engine->evaluate(\"-Infinity\")",
+ "engine->evaluate(\"'ciao'\") <=> QScriptValue(\"ciao\")",
+ "engine->evaluate(\"'ciao'\") <=> QScriptValue(QString::fromLatin1(\"ciao\"))",
+ "engine->evaluate(\"'ciao'\") <=> QScriptValue(0, \"ciao\")",
+ "engine->evaluate(\"'ciao'\") <=> QScriptValue(0, QString::fromLatin1(\"ciao\"))",
+ "engine->evaluate(\"'ciao'\") <=> QScriptValue(engine, \"ciao\")",
+ "engine->evaluate(\"'ciao'\") <=> QScriptValue(engine, QString::fromLatin1(\"ciao\"))",
+ "engine->evaluate(\"'ciao'\") <=> engine->evaluate(\"'ciao'\")",
+ "engine->evaluate(\"''\") <=> QScriptValue(false)",
+ "engine->evaluate(\"''\") <=> QScriptValue(0)",
+ "engine->evaluate(\"''\") <=> QScriptValue(0.0)",
+ "engine->evaluate(\"''\") <=> QScriptValue(QString(\"\"))",
+ "engine->evaluate(\"''\") <=> QScriptValue(QString())",
+ "engine->evaluate(\"''\") <=> QScriptValue(0, false)",
+ "engine->evaluate(\"''\") <=> QScriptValue(0, 0)",
+ "engine->evaluate(\"''\") <=> QScriptValue(0, 0.0)",
+ "engine->evaluate(\"''\") <=> QScriptValue(0, QString(\"\"))",
+ "engine->evaluate(\"''\") <=> QScriptValue(0, QString())",
+ "engine->evaluate(\"''\") <=> QScriptValue(engine, false)",
+ "engine->evaluate(\"''\") <=> QScriptValue(engine, 0)",
+ "engine->evaluate(\"''\") <=> QScriptValue(engine, 0.0)",
+ "engine->evaluate(\"''\") <=> QScriptValue(engine, QString(\"\"))",
+ "engine->evaluate(\"''\") <=> QScriptValue(engine, QString())",
+ "engine->evaluate(\"''\") <=> engine->evaluate(\"[]\")",
+ "engine->evaluate(\"''\") <=> engine->evaluate(\"Array.prototype\")",
+ "engine->evaluate(\"''\") <=> engine->evaluate(\"new Array()\")",
+ "engine->evaluate(\"''\") <=> engine->evaluate(\"false\")",
+ "engine->evaluate(\"''\") <=> engine->evaluate(\"0\")",
+ "engine->evaluate(\"''\") <=> engine->evaluate(\"0.0\")",
+ "engine->evaluate(\"''\") <=> engine->evaluate(\"''\")",
+ "engine->evaluate(\"''\") <=> engine->newArray()",
+ "engine->evaluate(\"'0'\") <=> QScriptValue(false)",
+ "engine->evaluate(\"'0'\") <=> QScriptValue(0)",
+ "engine->evaluate(\"'0'\") <=> QScriptValue(0.0)",
+ "engine->evaluate(\"'0'\") <=> QScriptValue(QString(\"0\"))",
+ "engine->evaluate(\"'0'\") <=> QScriptValue(0, false)",
+ "engine->evaluate(\"'0'\") <=> QScriptValue(0, 0)",
+ "engine->evaluate(\"'0'\") <=> QScriptValue(0, 0.0)",
+ "engine->evaluate(\"'0'\") <=> QScriptValue(0, QString(\"0\"))",
+ "engine->evaluate(\"'0'\") <=> QScriptValue(engine, false)",
+ "engine->evaluate(\"'0'\") <=> QScriptValue(engine, 0)",
+ "engine->evaluate(\"'0'\") <=> QScriptValue(engine, 0.0)",
+ "engine->evaluate(\"'0'\") <=> QScriptValue(engine, QString(\"0\"))",
+ "engine->evaluate(\"'0'\") <=> engine->evaluate(\"false\")",
+ "engine->evaluate(\"'0'\") <=> engine->evaluate(\"0\")",
+ "engine->evaluate(\"'0'\") <=> engine->evaluate(\"0.0\")",
+ "engine->evaluate(\"'0'\") <=> engine->evaluate(\"'0'\")",
+ "engine->evaluate(\"'123'\") <=> QScriptValue(123.0)",
+ "engine->evaluate(\"'123'\") <=> QScriptValue(QString(\"123\"))",
+ "engine->evaluate(\"'123'\") <=> QScriptValue(0, 123.0)",
+ "engine->evaluate(\"'123'\") <=> QScriptValue(0, QString(\"123\"))",
+ "engine->evaluate(\"'123'\") <=> QScriptValue(engine, 123.0)",
+ "engine->evaluate(\"'123'\") <=> QScriptValue(engine, QString(\"123\"))",
+ "engine->evaluate(\"'123'\") <=> engine->evaluate(\"123.0\")",
+ "engine->evaluate(\"'123'\") <=> engine->evaluate(\"'123'\")",
+ "engine->evaluate(\"'12.4'\") <=> QScriptValue(QString(\"12.4\"))",
+ "engine->evaluate(\"'12.4'\") <=> engine->evaluate(\"'12.4'\")",
+ "engine->nullValue() <=> QScriptValue(QScriptValue::UndefinedValue)",
+ "engine->nullValue() <=> QScriptValue(QScriptValue::NullValue)",
+ "engine->nullValue() <=> QScriptValue(0, QScriptValue::UndefinedValue)",
+ "engine->nullValue() <=> QScriptValue(0, QScriptValue::NullValue)",
+ "engine->nullValue() <=> QScriptValue(engine, QScriptValue::UndefinedValue)",
+ "engine->nullValue() <=> QScriptValue(engine, QScriptValue::NullValue)",
+ "engine->nullValue() <=> engine->evaluate(\"{}\")",
+ "engine->nullValue() <=> engine->evaluate(\"undefined\")",
+ "engine->nullValue() <=> engine->evaluate(\"null\")",
+ "engine->nullValue() <=> engine->nullValue()",
+ "engine->nullValue() <=> engine->undefinedValue()",
+ "engine->undefinedValue() <=> QScriptValue(QScriptValue::UndefinedValue)",
+ "engine->undefinedValue() <=> QScriptValue(QScriptValue::NullValue)",
+ "engine->undefinedValue() <=> QScriptValue(0, QScriptValue::UndefinedValue)",
+ "engine->undefinedValue() <=> QScriptValue(0, QScriptValue::NullValue)",
+ "engine->undefinedValue() <=> QScriptValue(engine, QScriptValue::UndefinedValue)",
+ "engine->undefinedValue() <=> QScriptValue(engine, QScriptValue::NullValue)",
+ "engine->undefinedValue() <=> engine->evaluate(\"{}\")",
+ "engine->undefinedValue() <=> engine->evaluate(\"undefined\")",
+ "engine->undefinedValue() <=> engine->evaluate(\"null\")",
+ "engine->undefinedValue() <=> engine->nullValue()",
+ "engine->undefinedValue() <=> engine->undefinedValue()",
+ "engine->newArray() <=> QScriptValue(false)",
+ "engine->newArray() <=> QScriptValue(0)",
+ "engine->newArray() <=> QScriptValue(0.0)",
+ "engine->newArray() <=> QScriptValue(QString(\"\"))",
+ "engine->newArray() <=> QScriptValue(QString())",
+ "engine->newArray() <=> QScriptValue(0, false)",
+ "engine->newArray() <=> QScriptValue(0, 0)",
+ "engine->newArray() <=> QScriptValue(0, 0.0)",
+ "engine->newArray() <=> QScriptValue(0, QString(\"\"))",
+ "engine->newArray() <=> QScriptValue(0, QString())",
+ "engine->newArray() <=> QScriptValue(engine, false)",
+ "engine->newArray() <=> QScriptValue(engine, 0)",
+ "engine->newArray() <=> QScriptValue(engine, 0.0)",
+ "engine->newArray() <=> QScriptValue(engine, QString(\"\"))",
+ "engine->newArray() <=> QScriptValue(engine, QString())",
+ "engine->newArray() <=> engine->evaluate(\"false\")",
+ "engine->newArray() <=> engine->evaluate(\"0\")",
+ "engine->newArray() <=> engine->evaluate(\"0.0\")",
+ "engine->newArray() <=> engine->evaluate(\"''\")"};
+
+void tst_QScriptValue::equals_data()
+{
+ QTest::addColumn<QScriptValue>("value");
+ QTest::addColumn<QScriptValue>("other");
+ QTest::addColumn<bool>("expected");
+ if (m_engine)
+ delete m_engine;
+ m_engine = new QScriptEngine();
+ QSet<QString> equals;
+ equals.reserve(1111);
+ for (unsigned i = 0; i < 1111; ++i)
+ equals.insert(equals_array[i]);
+ for (unsigned i = 0; i < 135; ++i) {
+ QPair<QString, QScriptValue> value1 = initScriptValues(i);
+ for (unsigned j = 0; j < 135; ++j) {
+ QPair<QString, QScriptValue> value2 = initScriptValues(j);
+ QString tag = QString::fromLatin1("%20 <=> %21").arg(value1.first, value2.first);
+ QTest::newRow(tag.toAscii().constData()) << value1.second << value2.second << equals.contains(tag); }
+ }
+}
+
+void tst_QScriptValue::equals()
+{
+ QFETCH(QScriptValue, value);
+ QFETCH(QScriptValue, other);
+ QFETCH(bool, expected);
+ QEXPECT_FAIL("QScriptValue(qInf()) <=> QScriptValue(\"-Infinity\")", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(qInf()) <=> QScriptValue(0, \"-Infinity\")", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(-qInf()) <=> QScriptValue(\"-Infinity\")", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(-qInf()) <=> QScriptValue(0, \"-Infinity\")", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(\"-Infinity\") <=> QScriptValue(qInf())", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(\"-Infinity\") <=> QScriptValue(-qInf())", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(\"-Infinity\") <=> QScriptValue(0, qInf())", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(\"-Infinity\") <=> QScriptValue(0, -qInf())", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(0, qInf()) <=> QScriptValue(\"-Infinity\")", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(0, qInf()) <=> QScriptValue(0, \"-Infinity\")", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(0, -qInf()) <=> QScriptValue(\"-Infinity\")", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(0, -qInf()) <=> QScriptValue(0, \"-Infinity\")", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(0, \"-Infinity\") <=> QScriptValue(qInf())", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(0, \"-Infinity\") <=> QScriptValue(-qInf())", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(0, \"-Infinity\") <=> QScriptValue(0, qInf())", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(0, \"-Infinity\") <=> QScriptValue(0, -qInf())", "FIXME: WebKit bug 43038", Continue);
+ QCOMPARE(value.equals(other), expected);
+}
+
+static const QString strictlyEquals_array[] = {
+ "QScriptValue() <=> QScriptValue()",
+ "QScriptValue(QScriptValue::UndefinedValue) <=> QScriptValue(QScriptValue::UndefinedValue)",
+ "QScriptValue(QScriptValue::UndefinedValue) <=> QScriptValue(0, QScriptValue::UndefinedValue)",
+ "QScriptValue(QScriptValue::UndefinedValue) <=> QScriptValue(engine, QScriptValue::UndefinedValue)",
+ "QScriptValue(QScriptValue::UndefinedValue) <=> engine->evaluate(\"{}\")",
+ "QScriptValue(QScriptValue::UndefinedValue) <=> engine->evaluate(\"undefined\")",
+ "QScriptValue(QScriptValue::UndefinedValue) <=> engine->undefinedValue()",
+ "QScriptValue(QScriptValue::NullValue) <=> QScriptValue(QScriptValue::NullValue)",
+ "QScriptValue(QScriptValue::NullValue) <=> QScriptValue(0, QScriptValue::NullValue)",
+ "QScriptValue(QScriptValue::NullValue) <=> QScriptValue(engine, QScriptValue::NullValue)",
+ "QScriptValue(QScriptValue::NullValue) <=> engine->evaluate(\"null\")",
+ "QScriptValue(QScriptValue::NullValue) <=> engine->nullValue()",
+ "QScriptValue(true) <=> QScriptValue(true)",
+ "QScriptValue(true) <=> QScriptValue(0, true)",
+ "QScriptValue(true) <=> QScriptValue(engine, true)",
+ "QScriptValue(true) <=> engine->evaluate(\"true\")",
+ "QScriptValue(false) <=> QScriptValue(false)",
+ "QScriptValue(false) <=> QScriptValue(0, false)",
+ "QScriptValue(false) <=> QScriptValue(engine, false)",
+ "QScriptValue(false) <=> engine->evaluate(\"false\")",
+ "QScriptValue(int(122)) <=> QScriptValue(int(122))",
+ "QScriptValue(int(122)) <=> QScriptValue(0, int(122))",
+ "QScriptValue(int(122)) <=> QScriptValue(engine, int(122))",
+ "QScriptValue(int(122)) <=> engine->evaluate(\"122\")",
+ "QScriptValue(uint(124)) <=> QScriptValue(uint(124))",
+ "QScriptValue(uint(124)) <=> QScriptValue(0, uint(124))",
+ "QScriptValue(uint(124)) <=> QScriptValue(engine, uint(124))",
+ "QScriptValue(uint(124)) <=> engine->evaluate(\"124\")",
+ "QScriptValue(0) <=> QScriptValue(0)",
+ "QScriptValue(0) <=> QScriptValue(0.0)",
+ "QScriptValue(0) <=> QScriptValue(0, 0)",
+ "QScriptValue(0) <=> QScriptValue(0, 0.0)",
+ "QScriptValue(0) <=> QScriptValue(engine, 0)",
+ "QScriptValue(0) <=> QScriptValue(engine, 0.0)",
+ "QScriptValue(0) <=> engine->evaluate(\"0\")",
+ "QScriptValue(0) <=> engine->evaluate(\"0.0\")",
+ "QScriptValue(0.0) <=> QScriptValue(0)",
+ "QScriptValue(0.0) <=> QScriptValue(0.0)",
+ "QScriptValue(0.0) <=> QScriptValue(0, 0)",
+ "QScriptValue(0.0) <=> QScriptValue(0, 0.0)",
+ "QScriptValue(0.0) <=> QScriptValue(engine, 0)",
+ "QScriptValue(0.0) <=> QScriptValue(engine, 0.0)",
+ "QScriptValue(0.0) <=> engine->evaluate(\"0\")",
+ "QScriptValue(0.0) <=> engine->evaluate(\"0.0\")",
+ "QScriptValue(123.0) <=> QScriptValue(123.0)",
+ "QScriptValue(123.0) <=> QScriptValue(0, 123.0)",
+ "QScriptValue(123.0) <=> QScriptValue(engine, 123.0)",
+ "QScriptValue(123.0) <=> engine->evaluate(\"123.0\")",
+ "QScriptValue(6.37e-8) <=> QScriptValue(6.37e-8)",
+ "QScriptValue(6.37e-8) <=> QScriptValue(0, 6.37e-8)",
+ "QScriptValue(6.37e-8) <=> QScriptValue(engine, 6.37e-8)",
+ "QScriptValue(6.37e-8) <=> engine->evaluate(\"6.37e-8\")",
+ "QScriptValue(-6.37e-8) <=> QScriptValue(-6.37e-8)",
+ "QScriptValue(-6.37e-8) <=> QScriptValue(0, -6.37e-8)",
+ "QScriptValue(-6.37e-8) <=> QScriptValue(engine, -6.37e-8)",
+ "QScriptValue(-6.37e-8) <=> engine->evaluate(\"-6.37e-8\")",
+ "QScriptValue(0x43211234) <=> QScriptValue(0x43211234)",
+ "QScriptValue(0x43211234) <=> QScriptValue(0, 0x43211234)",
+ "QScriptValue(0x43211234) <=> QScriptValue(engine, 0x43211234)",
+ "QScriptValue(0x43211234) <=> engine->evaluate(\"0x43211234\")",
+ "QScriptValue(0x10000) <=> QScriptValue(0x10000)",
+ "QScriptValue(0x10000) <=> QScriptValue(0, 0x10000)",
+ "QScriptValue(0x10000) <=> QScriptValue(engine, 0x10000)",
+ "QScriptValue(0x10000) <=> engine->evaluate(\"0x10000\")",
+ "QScriptValue(0x10001) <=> QScriptValue(0x10001)",
+ "QScriptValue(0x10001) <=> QScriptValue(0, 0x10001)",
+ "QScriptValue(0x10001) <=> QScriptValue(engine, 0x10001)",
+ "QScriptValue(0x10001) <=> engine->evaluate(\"0x10001\")",
+ "QScriptValue(qInf()) <=> QScriptValue(qInf())",
+ "QScriptValue(qInf()) <=> QScriptValue(0, qInf())",
+ "QScriptValue(qInf()) <=> QScriptValue(engine, qInf())",
+ "QScriptValue(qInf()) <=> engine->evaluate(\"Infinity\")",
+ "QScriptValue(-qInf()) <=> QScriptValue(-qInf())",
+ "QScriptValue(-qInf()) <=> QScriptValue(0, -qInf())",
+ "QScriptValue(-qInf()) <=> QScriptValue(engine, -qInf())",
+ "QScriptValue(-qInf()) <=> engine->evaluate(\"-Infinity\")",
+ "QScriptValue(\"NaN\") <=> QScriptValue(\"NaN\")",
+ "QScriptValue(\"NaN\") <=> QScriptValue(0, \"NaN\")",
+ "QScriptValue(\"NaN\") <=> QScriptValue(engine, \"NaN\")",
+ "QScriptValue(\"Infinity\") <=> QScriptValue(\"Infinity\")",
+ "QScriptValue(\"Infinity\") <=> QScriptValue(0, \"Infinity\")",
+ "QScriptValue(\"Infinity\") <=> QScriptValue(engine, \"Infinity\")",
+ "QScriptValue(\"-Infinity\") <=> QScriptValue(\"-Infinity\")",
+ "QScriptValue(\"-Infinity\") <=> QScriptValue(0, \"-Infinity\")",
+ "QScriptValue(\"-Infinity\") <=> QScriptValue(engine, \"-Infinity\")",
+ "QScriptValue(\"ciao\") <=> QScriptValue(\"ciao\")",
+ "QScriptValue(\"ciao\") <=> QScriptValue(QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(\"ciao\") <=> QScriptValue(0, \"ciao\")",
+ "QScriptValue(\"ciao\") <=> QScriptValue(0, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(\"ciao\") <=> QScriptValue(engine, \"ciao\")",
+ "QScriptValue(\"ciao\") <=> QScriptValue(engine, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(\"ciao\") <=> engine->evaluate(\"'ciao'\")",
+ "QScriptValue(QString::fromLatin1(\"ciao\")) <=> QScriptValue(\"ciao\")",
+ "QScriptValue(QString::fromLatin1(\"ciao\")) <=> QScriptValue(QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(QString::fromLatin1(\"ciao\")) <=> QScriptValue(0, \"ciao\")",
+ "QScriptValue(QString::fromLatin1(\"ciao\")) <=> QScriptValue(0, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(QString::fromLatin1(\"ciao\")) <=> QScriptValue(engine, \"ciao\")",
+ "QScriptValue(QString::fromLatin1(\"ciao\")) <=> QScriptValue(engine, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(QString::fromLatin1(\"ciao\")) <=> engine->evaluate(\"'ciao'\")",
+ "QScriptValue(QString(\"\")) <=> QScriptValue(QString(\"\"))",
+ "QScriptValue(QString(\"\")) <=> QScriptValue(QString())",
+ "QScriptValue(QString(\"\")) <=> QScriptValue(0, QString(\"\"))",
+ "QScriptValue(QString(\"\")) <=> QScriptValue(0, QString())",
+ "QScriptValue(QString(\"\")) <=> QScriptValue(engine, QString(\"\"))",
+ "QScriptValue(QString(\"\")) <=> QScriptValue(engine, QString())",
+ "QScriptValue(QString(\"\")) <=> engine->evaluate(\"''\")",
+ "QScriptValue(QString()) <=> QScriptValue(QString(\"\"))",
+ "QScriptValue(QString()) <=> QScriptValue(QString())",
+ "QScriptValue(QString()) <=> QScriptValue(0, QString(\"\"))",
+ "QScriptValue(QString()) <=> QScriptValue(0, QString())",
+ "QScriptValue(QString()) <=> QScriptValue(engine, QString(\"\"))",
+ "QScriptValue(QString()) <=> QScriptValue(engine, QString())",
+ "QScriptValue(QString()) <=> engine->evaluate(\"''\")",
+ "QScriptValue(QString(\"0\")) <=> QScriptValue(QString(\"0\"))",
+ "QScriptValue(QString(\"0\")) <=> QScriptValue(0, QString(\"0\"))",
+ "QScriptValue(QString(\"0\")) <=> QScriptValue(engine, QString(\"0\"))",
+ "QScriptValue(QString(\"0\")) <=> engine->evaluate(\"'0'\")",
+ "QScriptValue(QString(\"123\")) <=> QScriptValue(QString(\"123\"))",
+ "QScriptValue(QString(\"123\")) <=> QScriptValue(0, QString(\"123\"))",
+ "QScriptValue(QString(\"123\")) <=> QScriptValue(engine, QString(\"123\"))",
+ "QScriptValue(QString(\"123\")) <=> engine->evaluate(\"'123'\")",
+ "QScriptValue(QString(\"12.4\")) <=> QScriptValue(QString(\"12.4\"))",
+ "QScriptValue(QString(\"12.4\")) <=> engine->evaluate(\"'12.4'\")",
+ "QScriptValue(0, QScriptValue::UndefinedValue) <=> QScriptValue(QScriptValue::UndefinedValue)",
+ "QScriptValue(0, QScriptValue::UndefinedValue) <=> QScriptValue(0, QScriptValue::UndefinedValue)",
+ "QScriptValue(0, QScriptValue::UndefinedValue) <=> QScriptValue(engine, QScriptValue::UndefinedValue)",
+ "QScriptValue(0, QScriptValue::UndefinedValue) <=> engine->evaluate(\"{}\")",
+ "QScriptValue(0, QScriptValue::UndefinedValue) <=> engine->evaluate(\"undefined\")",
+ "QScriptValue(0, QScriptValue::UndefinedValue) <=> engine->undefinedValue()",
+ "QScriptValue(0, QScriptValue::NullValue) <=> QScriptValue(QScriptValue::NullValue)",
+ "QScriptValue(0, QScriptValue::NullValue) <=> QScriptValue(0, QScriptValue::NullValue)",
+ "QScriptValue(0, QScriptValue::NullValue) <=> QScriptValue(engine, QScriptValue::NullValue)",
+ "QScriptValue(0, QScriptValue::NullValue) <=> engine->evaluate(\"null\")",
+ "QScriptValue(0, QScriptValue::NullValue) <=> engine->nullValue()",
+ "QScriptValue(0, true) <=> QScriptValue(true)",
+ "QScriptValue(0, true) <=> QScriptValue(0, true)",
+ "QScriptValue(0, true) <=> QScriptValue(engine, true)",
+ "QScriptValue(0, true) <=> engine->evaluate(\"true\")",
+ "QScriptValue(0, false) <=> QScriptValue(false)",
+ "QScriptValue(0, false) <=> QScriptValue(0, false)",
+ "QScriptValue(0, false) <=> QScriptValue(engine, false)",
+ "QScriptValue(0, false) <=> engine->evaluate(\"false\")",
+ "QScriptValue(0, int(122)) <=> QScriptValue(int(122))",
+ "QScriptValue(0, int(122)) <=> QScriptValue(0, int(122))",
+ "QScriptValue(0, int(122)) <=> QScriptValue(engine, int(122))",
+ "QScriptValue(0, int(122)) <=> engine->evaluate(\"122\")",
+ "QScriptValue(0, uint(124)) <=> QScriptValue(uint(124))",
+ "QScriptValue(0, uint(124)) <=> QScriptValue(0, uint(124))",
+ "QScriptValue(0, uint(124)) <=> QScriptValue(engine, uint(124))",
+ "QScriptValue(0, uint(124)) <=> engine->evaluate(\"124\")",
+ "QScriptValue(0, 0) <=> QScriptValue(0)",
+ "QScriptValue(0, 0) <=> QScriptValue(0.0)",
+ "QScriptValue(0, 0) <=> QScriptValue(0, 0)",
+ "QScriptValue(0, 0) <=> QScriptValue(0, 0.0)",
+ "QScriptValue(0, 0) <=> QScriptValue(engine, 0)",
+ "QScriptValue(0, 0) <=> QScriptValue(engine, 0.0)",
+ "QScriptValue(0, 0) <=> engine->evaluate(\"0\")",
+ "QScriptValue(0, 0) <=> engine->evaluate(\"0.0\")",
+ "QScriptValue(0, 0.0) <=> QScriptValue(0)",
+ "QScriptValue(0, 0.0) <=> QScriptValue(0.0)",
+ "QScriptValue(0, 0.0) <=> QScriptValue(0, 0)",
+ "QScriptValue(0, 0.0) <=> QScriptValue(0, 0.0)",
+ "QScriptValue(0, 0.0) <=> QScriptValue(engine, 0)",
+ "QScriptValue(0, 0.0) <=> QScriptValue(engine, 0.0)",
+ "QScriptValue(0, 0.0) <=> engine->evaluate(\"0\")",
+ "QScriptValue(0, 0.0) <=> engine->evaluate(\"0.0\")",
+ "QScriptValue(0, 123.0) <=> QScriptValue(123.0)",
+ "QScriptValue(0, 123.0) <=> QScriptValue(0, 123.0)",
+ "QScriptValue(0, 123.0) <=> QScriptValue(engine, 123.0)",
+ "QScriptValue(0, 123.0) <=> engine->evaluate(\"123.0\")",
+ "QScriptValue(0, 6.37e-8) <=> QScriptValue(6.37e-8)",
+ "QScriptValue(0, 6.37e-8) <=> QScriptValue(0, 6.37e-8)",
+ "QScriptValue(0, 6.37e-8) <=> QScriptValue(engine, 6.37e-8)",
+ "QScriptValue(0, 6.37e-8) <=> engine->evaluate(\"6.37e-8\")",
+ "QScriptValue(0, -6.37e-8) <=> QScriptValue(-6.37e-8)",
+ "QScriptValue(0, -6.37e-8) <=> QScriptValue(0, -6.37e-8)",
+ "QScriptValue(0, -6.37e-8) <=> QScriptValue(engine, -6.37e-8)",
+ "QScriptValue(0, -6.37e-8) <=> engine->evaluate(\"-6.37e-8\")",
+ "QScriptValue(0, 0x43211234) <=> QScriptValue(0x43211234)",
+ "QScriptValue(0, 0x43211234) <=> QScriptValue(0, 0x43211234)",
+ "QScriptValue(0, 0x43211234) <=> QScriptValue(engine, 0x43211234)",
+ "QScriptValue(0, 0x43211234) <=> engine->evaluate(\"0x43211234\")",
+ "QScriptValue(0, 0x10000) <=> QScriptValue(0x10000)",
+ "QScriptValue(0, 0x10000) <=> QScriptValue(0, 0x10000)",
+ "QScriptValue(0, 0x10000) <=> QScriptValue(engine, 0x10000)",
+ "QScriptValue(0, 0x10000) <=> engine->evaluate(\"0x10000\")",
+ "QScriptValue(0, 0x10001) <=> QScriptValue(0x10001)",
+ "QScriptValue(0, 0x10001) <=> QScriptValue(0, 0x10001)",
+ "QScriptValue(0, 0x10001) <=> QScriptValue(engine, 0x10001)",
+ "QScriptValue(0, 0x10001) <=> engine->evaluate(\"0x10001\")",
+ "QScriptValue(0, qInf()) <=> QScriptValue(qInf())",
+ "QScriptValue(0, qInf()) <=> QScriptValue(0, qInf())",
+ "QScriptValue(0, qInf()) <=> QScriptValue(engine, qInf())",
+ "QScriptValue(0, qInf()) <=> engine->evaluate(\"Infinity\")",
+ "QScriptValue(0, -qInf()) <=> QScriptValue(-qInf())",
+ "QScriptValue(0, -qInf()) <=> QScriptValue(0, -qInf())",
+ "QScriptValue(0, -qInf()) <=> QScriptValue(engine, -qInf())",
+ "QScriptValue(0, -qInf()) <=> engine->evaluate(\"-Infinity\")",
+ "QScriptValue(0, \"NaN\") <=> QScriptValue(\"NaN\")",
+ "QScriptValue(0, \"NaN\") <=> QScriptValue(0, \"NaN\")",
+ "QScriptValue(0, \"NaN\") <=> QScriptValue(engine, \"NaN\")",
+ "QScriptValue(0, \"Infinity\") <=> QScriptValue(\"Infinity\")",
+ "QScriptValue(0, \"Infinity\") <=> QScriptValue(0, \"Infinity\")",
+ "QScriptValue(0, \"Infinity\") <=> QScriptValue(engine, \"Infinity\")",
+ "QScriptValue(0, \"-Infinity\") <=> QScriptValue(\"-Infinity\")",
+ "QScriptValue(0, \"-Infinity\") <=> QScriptValue(0, \"-Infinity\")",
+ "QScriptValue(0, \"-Infinity\") <=> QScriptValue(engine, \"-Infinity\")",
+ "QScriptValue(0, \"ciao\") <=> QScriptValue(\"ciao\")",
+ "QScriptValue(0, \"ciao\") <=> QScriptValue(QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(0, \"ciao\") <=> QScriptValue(0, \"ciao\")",
+ "QScriptValue(0, \"ciao\") <=> QScriptValue(0, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(0, \"ciao\") <=> QScriptValue(engine, \"ciao\")",
+ "QScriptValue(0, \"ciao\") <=> QScriptValue(engine, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(0, \"ciao\") <=> engine->evaluate(\"'ciao'\")",
+ "QScriptValue(0, QString::fromLatin1(\"ciao\")) <=> QScriptValue(\"ciao\")",
+ "QScriptValue(0, QString::fromLatin1(\"ciao\")) <=> QScriptValue(QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(0, QString::fromLatin1(\"ciao\")) <=> QScriptValue(0, \"ciao\")",
+ "QScriptValue(0, QString::fromLatin1(\"ciao\")) <=> QScriptValue(0, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(0, QString::fromLatin1(\"ciao\")) <=> QScriptValue(engine, \"ciao\")",
+ "QScriptValue(0, QString::fromLatin1(\"ciao\")) <=> QScriptValue(engine, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(0, QString::fromLatin1(\"ciao\")) <=> engine->evaluate(\"'ciao'\")",
+ "QScriptValue(0, QString(\"\")) <=> QScriptValue(QString(\"\"))",
+ "QScriptValue(0, QString(\"\")) <=> QScriptValue(QString())",
+ "QScriptValue(0, QString(\"\")) <=> QScriptValue(0, QString(\"\"))",
+ "QScriptValue(0, QString(\"\")) <=> QScriptValue(0, QString())",
+ "QScriptValue(0, QString(\"\")) <=> QScriptValue(engine, QString(\"\"))",
+ "QScriptValue(0, QString(\"\")) <=> QScriptValue(engine, QString())",
+ "QScriptValue(0, QString(\"\")) <=> engine->evaluate(\"''\")",
+ "QScriptValue(0, QString()) <=> QScriptValue(QString(\"\"))",
+ "QScriptValue(0, QString()) <=> QScriptValue(QString())",
+ "QScriptValue(0, QString()) <=> QScriptValue(0, QString(\"\"))",
+ "QScriptValue(0, QString()) <=> QScriptValue(0, QString())",
+ "QScriptValue(0, QString()) <=> QScriptValue(engine, QString(\"\"))",
+ "QScriptValue(0, QString()) <=> QScriptValue(engine, QString())",
+ "QScriptValue(0, QString()) <=> engine->evaluate(\"''\")",
+ "QScriptValue(0, QString(\"0\")) <=> QScriptValue(QString(\"0\"))",
+ "QScriptValue(0, QString(\"0\")) <=> QScriptValue(0, QString(\"0\"))",
+ "QScriptValue(0, QString(\"0\")) <=> QScriptValue(engine, QString(\"0\"))",
+ "QScriptValue(0, QString(\"0\")) <=> engine->evaluate(\"'0'\")",
+ "QScriptValue(0, QString(\"123\")) <=> QScriptValue(QString(\"123\"))",
+ "QScriptValue(0, QString(\"123\")) <=> QScriptValue(0, QString(\"123\"))",
+ "QScriptValue(0, QString(\"123\")) <=> QScriptValue(engine, QString(\"123\"))",
+ "QScriptValue(0, QString(\"123\")) <=> engine->evaluate(\"'123'\")",
+ "QScriptValue(0, QString(\"12.3\")) <=> QScriptValue(0, QString(\"12.3\"))",
+ "QScriptValue(engine, QScriptValue::UndefinedValue) <=> QScriptValue(QScriptValue::UndefinedValue)",
+ "QScriptValue(engine, QScriptValue::UndefinedValue) <=> QScriptValue(0, QScriptValue::UndefinedValue)",
+ "QScriptValue(engine, QScriptValue::UndefinedValue) <=> QScriptValue(engine, QScriptValue::UndefinedValue)",
+ "QScriptValue(engine, QScriptValue::UndefinedValue) <=> engine->evaluate(\"{}\")",
+ "QScriptValue(engine, QScriptValue::UndefinedValue) <=> engine->evaluate(\"undefined\")",
+ "QScriptValue(engine, QScriptValue::UndefinedValue) <=> engine->undefinedValue()",
+ "QScriptValue(engine, QScriptValue::NullValue) <=> QScriptValue(QScriptValue::NullValue)",
+ "QScriptValue(engine, QScriptValue::NullValue) <=> QScriptValue(0, QScriptValue::NullValue)",
+ "QScriptValue(engine, QScriptValue::NullValue) <=> QScriptValue(engine, QScriptValue::NullValue)",
+ "QScriptValue(engine, QScriptValue::NullValue) <=> engine->evaluate(\"null\")",
+ "QScriptValue(engine, QScriptValue::NullValue) <=> engine->nullValue()",
+ "QScriptValue(engine, true) <=> QScriptValue(true)",
+ "QScriptValue(engine, true) <=> QScriptValue(0, true)",
+ "QScriptValue(engine, true) <=> QScriptValue(engine, true)",
+ "QScriptValue(engine, true) <=> engine->evaluate(\"true\")",
+ "QScriptValue(engine, false) <=> QScriptValue(false)",
+ "QScriptValue(engine, false) <=> QScriptValue(0, false)",
+ "QScriptValue(engine, false) <=> QScriptValue(engine, false)",
+ "QScriptValue(engine, false) <=> engine->evaluate(\"false\")",
+ "QScriptValue(engine, int(122)) <=> QScriptValue(int(122))",
+ "QScriptValue(engine, int(122)) <=> QScriptValue(0, int(122))",
+ "QScriptValue(engine, int(122)) <=> QScriptValue(engine, int(122))",
+ "QScriptValue(engine, int(122)) <=> engine->evaluate(\"122\")",
+ "QScriptValue(engine, uint(124)) <=> QScriptValue(uint(124))",
+ "QScriptValue(engine, uint(124)) <=> QScriptValue(0, uint(124))",
+ "QScriptValue(engine, uint(124)) <=> QScriptValue(engine, uint(124))",
+ "QScriptValue(engine, uint(124)) <=> engine->evaluate(\"124\")",
+ "QScriptValue(engine, 0) <=> QScriptValue(0)",
+ "QScriptValue(engine, 0) <=> QScriptValue(0.0)",
+ "QScriptValue(engine, 0) <=> QScriptValue(0, 0)",
+ "QScriptValue(engine, 0) <=> QScriptValue(0, 0.0)",
+ "QScriptValue(engine, 0) <=> QScriptValue(engine, 0)",
+ "QScriptValue(engine, 0) <=> QScriptValue(engine, 0.0)",
+ "QScriptValue(engine, 0) <=> engine->evaluate(\"0\")",
+ "QScriptValue(engine, 0) <=> engine->evaluate(\"0.0\")",
+ "QScriptValue(engine, 0.0) <=> QScriptValue(0)",
+ "QScriptValue(engine, 0.0) <=> QScriptValue(0.0)",
+ "QScriptValue(engine, 0.0) <=> QScriptValue(0, 0)",
+ "QScriptValue(engine, 0.0) <=> QScriptValue(0, 0.0)",
+ "QScriptValue(engine, 0.0) <=> QScriptValue(engine, 0)",
+ "QScriptValue(engine, 0.0) <=> QScriptValue(engine, 0.0)",
+ "QScriptValue(engine, 0.0) <=> engine->evaluate(\"0\")",
+ "QScriptValue(engine, 0.0) <=> engine->evaluate(\"0.0\")",
+ "QScriptValue(engine, 123.0) <=> QScriptValue(123.0)",
+ "QScriptValue(engine, 123.0) <=> QScriptValue(0, 123.0)",
+ "QScriptValue(engine, 123.0) <=> QScriptValue(engine, 123.0)",
+ "QScriptValue(engine, 123.0) <=> engine->evaluate(\"123.0\")",
+ "QScriptValue(engine, 6.37e-8) <=> QScriptValue(6.37e-8)",
+ "QScriptValue(engine, 6.37e-8) <=> QScriptValue(0, 6.37e-8)",
+ "QScriptValue(engine, 6.37e-8) <=> QScriptValue(engine, 6.37e-8)",
+ "QScriptValue(engine, 6.37e-8) <=> engine->evaluate(\"6.37e-8\")",
+ "QScriptValue(engine, -6.37e-8) <=> QScriptValue(-6.37e-8)",
+ "QScriptValue(engine, -6.37e-8) <=> QScriptValue(0, -6.37e-8)",
+ "QScriptValue(engine, -6.37e-8) <=> QScriptValue(engine, -6.37e-8)",
+ "QScriptValue(engine, -6.37e-8) <=> engine->evaluate(\"-6.37e-8\")",
+ "QScriptValue(engine, 0x43211234) <=> QScriptValue(0x43211234)",
+ "QScriptValue(engine, 0x43211234) <=> QScriptValue(0, 0x43211234)",
+ "QScriptValue(engine, 0x43211234) <=> QScriptValue(engine, 0x43211234)",
+ "QScriptValue(engine, 0x43211234) <=> engine->evaluate(\"0x43211234\")",
+ "QScriptValue(engine, 0x10000) <=> QScriptValue(0x10000)",
+ "QScriptValue(engine, 0x10000) <=> QScriptValue(0, 0x10000)",
+ "QScriptValue(engine, 0x10000) <=> QScriptValue(engine, 0x10000)",
+ "QScriptValue(engine, 0x10000) <=> engine->evaluate(\"0x10000\")",
+ "QScriptValue(engine, 0x10001) <=> QScriptValue(0x10001)",
+ "QScriptValue(engine, 0x10001) <=> QScriptValue(0, 0x10001)",
+ "QScriptValue(engine, 0x10001) <=> QScriptValue(engine, 0x10001)",
+ "QScriptValue(engine, 0x10001) <=> engine->evaluate(\"0x10001\")",
+ "QScriptValue(engine, qInf()) <=> QScriptValue(qInf())",
+ "QScriptValue(engine, qInf()) <=> QScriptValue(0, qInf())",
+ "QScriptValue(engine, qInf()) <=> QScriptValue(engine, qInf())",
+ "QScriptValue(engine, qInf()) <=> engine->evaluate(\"Infinity\")",
+ "QScriptValue(engine, -qInf()) <=> QScriptValue(-qInf())",
+ "QScriptValue(engine, -qInf()) <=> QScriptValue(0, -qInf())",
+ "QScriptValue(engine, -qInf()) <=> QScriptValue(engine, -qInf())",
+ "QScriptValue(engine, -qInf()) <=> engine->evaluate(\"-Infinity\")",
+ "QScriptValue(engine, \"NaN\") <=> QScriptValue(\"NaN\")",
+ "QScriptValue(engine, \"NaN\") <=> QScriptValue(0, \"NaN\")",
+ "QScriptValue(engine, \"NaN\") <=> QScriptValue(engine, \"NaN\")",
+ "QScriptValue(engine, \"Infinity\") <=> QScriptValue(\"Infinity\")",
+ "QScriptValue(engine, \"Infinity\") <=> QScriptValue(0, \"Infinity\")",
+ "QScriptValue(engine, \"Infinity\") <=> QScriptValue(engine, \"Infinity\")",
+ "QScriptValue(engine, \"-Infinity\") <=> QScriptValue(\"-Infinity\")",
+ "QScriptValue(engine, \"-Infinity\") <=> QScriptValue(0, \"-Infinity\")",
+ "QScriptValue(engine, \"-Infinity\") <=> QScriptValue(engine, \"-Infinity\")",
+ "QScriptValue(engine, \"ciao\") <=> QScriptValue(\"ciao\")",
+ "QScriptValue(engine, \"ciao\") <=> QScriptValue(QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(engine, \"ciao\") <=> QScriptValue(0, \"ciao\")",
+ "QScriptValue(engine, \"ciao\") <=> QScriptValue(0, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(engine, \"ciao\") <=> QScriptValue(engine, \"ciao\")",
+ "QScriptValue(engine, \"ciao\") <=> QScriptValue(engine, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(engine, \"ciao\") <=> engine->evaluate(\"'ciao'\")",
+ "QScriptValue(engine, QString::fromLatin1(\"ciao\")) <=> QScriptValue(\"ciao\")",
+ "QScriptValue(engine, QString::fromLatin1(\"ciao\")) <=> QScriptValue(QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(engine, QString::fromLatin1(\"ciao\")) <=> QScriptValue(0, \"ciao\")",
+ "QScriptValue(engine, QString::fromLatin1(\"ciao\")) <=> QScriptValue(0, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(engine, QString::fromLatin1(\"ciao\")) <=> QScriptValue(engine, \"ciao\")",
+ "QScriptValue(engine, QString::fromLatin1(\"ciao\")) <=> QScriptValue(engine, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(engine, QString::fromLatin1(\"ciao\")) <=> engine->evaluate(\"'ciao'\")",
+ "QScriptValue(engine, QString(\"\")) <=> QScriptValue(QString(\"\"))",
+ "QScriptValue(engine, QString(\"\")) <=> QScriptValue(QString())",
+ "QScriptValue(engine, QString(\"\")) <=> QScriptValue(0, QString(\"\"))",
+ "QScriptValue(engine, QString(\"\")) <=> QScriptValue(0, QString())",
+ "QScriptValue(engine, QString(\"\")) <=> QScriptValue(engine, QString(\"\"))",
+ "QScriptValue(engine, QString(\"\")) <=> QScriptValue(engine, QString())",
+ "QScriptValue(engine, QString(\"\")) <=> engine->evaluate(\"''\")",
+ "QScriptValue(engine, QString()) <=> QScriptValue(QString(\"\"))",
+ "QScriptValue(engine, QString()) <=> QScriptValue(QString())",
+ "QScriptValue(engine, QString()) <=> QScriptValue(0, QString(\"\"))",
+ "QScriptValue(engine, QString()) <=> QScriptValue(0, QString())",
+ "QScriptValue(engine, QString()) <=> QScriptValue(engine, QString(\"\"))",
+ "QScriptValue(engine, QString()) <=> QScriptValue(engine, QString())",
+ "QScriptValue(engine, QString()) <=> engine->evaluate(\"''\")",
+ "QScriptValue(engine, QString(\"0\")) <=> QScriptValue(QString(\"0\"))",
+ "QScriptValue(engine, QString(\"0\")) <=> QScriptValue(0, QString(\"0\"))",
+ "QScriptValue(engine, QString(\"0\")) <=> QScriptValue(engine, QString(\"0\"))",
+ "QScriptValue(engine, QString(\"0\")) <=> engine->evaluate(\"'0'\")",
+ "QScriptValue(engine, QString(\"123\")) <=> QScriptValue(QString(\"123\"))",
+ "QScriptValue(engine, QString(\"123\")) <=> QScriptValue(0, QString(\"123\"))",
+ "QScriptValue(engine, QString(\"123\")) <=> QScriptValue(engine, QString(\"123\"))",
+ "QScriptValue(engine, QString(\"123\")) <=> engine->evaluate(\"'123'\")",
+ "QScriptValue(engine, QString(\"1.23\")) <=> QScriptValue(engine, QString(\"1.23\"))",
+ "engine->evaluate(\"{}\") <=> QScriptValue(QScriptValue::UndefinedValue)",
+ "engine->evaluate(\"{}\") <=> QScriptValue(0, QScriptValue::UndefinedValue)",
+ "engine->evaluate(\"{}\") <=> QScriptValue(engine, QScriptValue::UndefinedValue)",
+ "engine->evaluate(\"{}\") <=> engine->evaluate(\"{}\")",
+ "engine->evaluate(\"{}\") <=> engine->evaluate(\"undefined\")",
+ "engine->evaluate(\"{}\") <=> engine->undefinedValue()",
+ "engine->evaluate(\"Object.prototype\") <=> engine->evaluate(\"Object.prototype\")",
+ "engine->evaluate(\"Date.prototype\") <=> engine->evaluate(\"Date.prototype\")",
+ "engine->evaluate(\"Array.prototype\") <=> engine->evaluate(\"Array.prototype\")",
+ "engine->evaluate(\"Function.prototype\") <=> engine->evaluate(\"Function.prototype\")",
+ "engine->evaluate(\"Error.prototype\") <=> engine->evaluate(\"Error.prototype\")",
+ "engine->evaluate(\"Object\") <=> engine->evaluate(\"Object\")",
+ "engine->evaluate(\"Array\") <=> engine->evaluate(\"Array\")",
+ "engine->evaluate(\"Number\") <=> engine->evaluate(\"Number\")",
+ "engine->evaluate(\"Function\") <=> engine->evaluate(\"Function\")",
+ "engine->evaluate(\"a = new Object(); a.foo = 22; a.foo\") <=> engine->evaluate(\"a = new Object(); a.foo = 22; a.foo\")",
+ "engine->evaluate(\"undefined\") <=> QScriptValue(QScriptValue::UndefinedValue)",
+ "engine->evaluate(\"undefined\") <=> QScriptValue(0, QScriptValue::UndefinedValue)",
+ "engine->evaluate(\"undefined\") <=> QScriptValue(engine, QScriptValue::UndefinedValue)",
+ "engine->evaluate(\"undefined\") <=> engine->evaluate(\"{}\")",
+ "engine->evaluate(\"undefined\") <=> engine->evaluate(\"undefined\")",
+ "engine->evaluate(\"undefined\") <=> engine->undefinedValue()",
+ "engine->evaluate(\"null\") <=> QScriptValue(QScriptValue::NullValue)",
+ "engine->evaluate(\"null\") <=> QScriptValue(0, QScriptValue::NullValue)",
+ "engine->evaluate(\"null\") <=> QScriptValue(engine, QScriptValue::NullValue)",
+ "engine->evaluate(\"null\") <=> engine->evaluate(\"null\")",
+ "engine->evaluate(\"null\") <=> engine->nullValue()",
+ "engine->evaluate(\"true\") <=> QScriptValue(true)",
+ "engine->evaluate(\"true\") <=> QScriptValue(0, true)",
+ "engine->evaluate(\"true\") <=> QScriptValue(engine, true)",
+ "engine->evaluate(\"true\") <=> engine->evaluate(\"true\")",
+ "engine->evaluate(\"false\") <=> QScriptValue(false)",
+ "engine->evaluate(\"false\") <=> QScriptValue(0, false)",
+ "engine->evaluate(\"false\") <=> QScriptValue(engine, false)",
+ "engine->evaluate(\"false\") <=> engine->evaluate(\"false\")",
+ "engine->evaluate(\"122\") <=> QScriptValue(int(122))",
+ "engine->evaluate(\"122\") <=> QScriptValue(0, int(122))",
+ "engine->evaluate(\"122\") <=> QScriptValue(engine, int(122))",
+ "engine->evaluate(\"122\") <=> engine->evaluate(\"122\")",
+ "engine->evaluate(\"124\") <=> QScriptValue(uint(124))",
+ "engine->evaluate(\"124\") <=> QScriptValue(0, uint(124))",
+ "engine->evaluate(\"124\") <=> QScriptValue(engine, uint(124))",
+ "engine->evaluate(\"124\") <=> engine->evaluate(\"124\")",
+ "engine->evaluate(\"0\") <=> QScriptValue(0)",
+ "engine->evaluate(\"0\") <=> QScriptValue(0.0)",
+ "engine->evaluate(\"0\") <=> QScriptValue(0, 0)",
+ "engine->evaluate(\"0\") <=> QScriptValue(0, 0.0)",
+ "engine->evaluate(\"0\") <=> QScriptValue(engine, 0)",
+ "engine->evaluate(\"0\") <=> QScriptValue(engine, 0.0)",
+ "engine->evaluate(\"0\") <=> engine->evaluate(\"0\")",
+ "engine->evaluate(\"0\") <=> engine->evaluate(\"0.0\")",
+ "engine->evaluate(\"0.0\") <=> QScriptValue(0)",
+ "engine->evaluate(\"0.0\") <=> QScriptValue(0.0)",
+ "engine->evaluate(\"0.0\") <=> QScriptValue(0, 0)",
+ "engine->evaluate(\"0.0\") <=> QScriptValue(0, 0.0)",
+ "engine->evaluate(\"0.0\") <=> QScriptValue(engine, 0)",
+ "engine->evaluate(\"0.0\") <=> QScriptValue(engine, 0.0)",
+ "engine->evaluate(\"0.0\") <=> engine->evaluate(\"0\")",
+ "engine->evaluate(\"0.0\") <=> engine->evaluate(\"0.0\")",
+ "engine->evaluate(\"123.0\") <=> QScriptValue(123.0)",
+ "engine->evaluate(\"123.0\") <=> QScriptValue(0, 123.0)",
+ "engine->evaluate(\"123.0\") <=> QScriptValue(engine, 123.0)",
+ "engine->evaluate(\"123.0\") <=> engine->evaluate(\"123.0\")",
+ "engine->evaluate(\"6.37e-8\") <=> QScriptValue(6.37e-8)",
+ "engine->evaluate(\"6.37e-8\") <=> QScriptValue(0, 6.37e-8)",
+ "engine->evaluate(\"6.37e-8\") <=> QScriptValue(engine, 6.37e-8)",
+ "engine->evaluate(\"6.37e-8\") <=> engine->evaluate(\"6.37e-8\")",
+ "engine->evaluate(\"-6.37e-8\") <=> QScriptValue(-6.37e-8)",
+ "engine->evaluate(\"-6.37e-8\") <=> QScriptValue(0, -6.37e-8)",
+ "engine->evaluate(\"-6.37e-8\") <=> QScriptValue(engine, -6.37e-8)",
+ "engine->evaluate(\"-6.37e-8\") <=> engine->evaluate(\"-6.37e-8\")",
+ "engine->evaluate(\"0x43211234\") <=> QScriptValue(0x43211234)",
+ "engine->evaluate(\"0x43211234\") <=> QScriptValue(0, 0x43211234)",
+ "engine->evaluate(\"0x43211234\") <=> QScriptValue(engine, 0x43211234)",
+ "engine->evaluate(\"0x43211234\") <=> engine->evaluate(\"0x43211234\")",
+ "engine->evaluate(\"0x10000\") <=> QScriptValue(0x10000)",
+ "engine->evaluate(\"0x10000\") <=> QScriptValue(0, 0x10000)",
+ "engine->evaluate(\"0x10000\") <=> QScriptValue(engine, 0x10000)",
+ "engine->evaluate(\"0x10000\") <=> engine->evaluate(\"0x10000\")",
+ "engine->evaluate(\"0x10001\") <=> QScriptValue(0x10001)",
+ "engine->evaluate(\"0x10001\") <=> QScriptValue(0, 0x10001)",
+ "engine->evaluate(\"0x10001\") <=> QScriptValue(engine, 0x10001)",
+ "engine->evaluate(\"0x10001\") <=> engine->evaluate(\"0x10001\")",
+ "engine->evaluate(\"Infinity\") <=> QScriptValue(qInf())",
+ "engine->evaluate(\"Infinity\") <=> QScriptValue(0, qInf())",
+ "engine->evaluate(\"Infinity\") <=> QScriptValue(engine, qInf())",
+ "engine->evaluate(\"Infinity\") <=> engine->evaluate(\"Infinity\")",
+ "engine->evaluate(\"-Infinity\") <=> QScriptValue(-qInf())",
+ "engine->evaluate(\"-Infinity\") <=> QScriptValue(0, -qInf())",
+ "engine->evaluate(\"-Infinity\") <=> QScriptValue(engine, -qInf())",
+ "engine->evaluate(\"-Infinity\") <=> engine->evaluate(\"-Infinity\")",
+ "engine->evaluate(\"'ciao'\") <=> QScriptValue(\"ciao\")",
+ "engine->evaluate(\"'ciao'\") <=> QScriptValue(QString::fromLatin1(\"ciao\"))",
+ "engine->evaluate(\"'ciao'\") <=> QScriptValue(0, \"ciao\")",
+ "engine->evaluate(\"'ciao'\") <=> QScriptValue(0, QString::fromLatin1(\"ciao\"))",
+ "engine->evaluate(\"'ciao'\") <=> QScriptValue(engine, \"ciao\")",
+ "engine->evaluate(\"'ciao'\") <=> QScriptValue(engine, QString::fromLatin1(\"ciao\"))",
+ "engine->evaluate(\"'ciao'\") <=> engine->evaluate(\"'ciao'\")",
+ "engine->evaluate(\"''\") <=> QScriptValue(QString(\"\"))",
+ "engine->evaluate(\"''\") <=> QScriptValue(QString())",
+ "engine->evaluate(\"''\") <=> QScriptValue(0, QString(\"\"))",
+ "engine->evaluate(\"''\") <=> QScriptValue(0, QString())",
+ "engine->evaluate(\"''\") <=> QScriptValue(engine, QString(\"\"))",
+ "engine->evaluate(\"''\") <=> QScriptValue(engine, QString())",
+ "engine->evaluate(\"''\") <=> engine->evaluate(\"''\")",
+ "engine->evaluate(\"'0'\") <=> QScriptValue(QString(\"0\"))",
+ "engine->evaluate(\"'0'\") <=> QScriptValue(0, QString(\"0\"))",
+ "engine->evaluate(\"'0'\") <=> QScriptValue(engine, QString(\"0\"))",
+ "engine->evaluate(\"'0'\") <=> engine->evaluate(\"'0'\")",
+ "engine->evaluate(\"'123'\") <=> QScriptValue(QString(\"123\"))",
+ "engine->evaluate(\"'123'\") <=> QScriptValue(0, QString(\"123\"))",
+ "engine->evaluate(\"'123'\") <=> QScriptValue(engine, QString(\"123\"))",
+ "engine->evaluate(\"'123'\") <=> engine->evaluate(\"'123'\")",
+ "engine->evaluate(\"'12.4'\") <=> QScriptValue(QString(\"12.4\"))",
+ "engine->evaluate(\"'12.4'\") <=> engine->evaluate(\"'12.4'\")",
+ "engine->nullValue() <=> QScriptValue(QScriptValue::NullValue)",
+ "engine->nullValue() <=> QScriptValue(0, QScriptValue::NullValue)",
+ "engine->nullValue() <=> QScriptValue(engine, QScriptValue::NullValue)",
+ "engine->nullValue() <=> engine->evaluate(\"null\")",
+ "engine->nullValue() <=> engine->nullValue()",
+ "engine->undefinedValue() <=> QScriptValue(QScriptValue::UndefinedValue)",
+ "engine->undefinedValue() <=> QScriptValue(0, QScriptValue::UndefinedValue)",
+ "engine->undefinedValue() <=> QScriptValue(engine, QScriptValue::UndefinedValue)",
+ "engine->undefinedValue() <=> engine->evaluate(\"{}\")",
+ "engine->undefinedValue() <=> engine->evaluate(\"undefined\")",
+ "engine->undefinedValue() <=> engine->undefinedValue()"};
+
+void tst_QScriptValue::strictlyEquals_data()
+{
+ QTest::addColumn<QScriptValue>("value");
+ QTest::addColumn<QScriptValue>("other");
+ QTest::addColumn<bool>("expected");
+ if (m_engine)
+ delete m_engine;
+ m_engine = new QScriptEngine();
+ QSet<QString> equals;
+ equals.reserve(491);
+ for (unsigned i = 0; i < 491; ++i)
+ equals.insert(strictlyEquals_array[i]);
+ for (unsigned i = 0; i < 135; ++i) {
+ QPair<QString, QScriptValue> value1 = initScriptValues(i);
+ for (unsigned j = 0; j < 135; ++j) {
+ QPair<QString, QScriptValue> value2 = initScriptValues(j);
+ QString tag = QString::fromLatin1("%20 <=> %21").arg(value1.first, value2.first);
+ QTest::newRow(tag.toAscii().constData()) << value1.second << value2.second << equals.contains(tag); }
+ }
+}
+
+void tst_QScriptValue::strictlyEquals()
+{
+ QFETCH(QScriptValue, value);
+ QFETCH(QScriptValue, other);
+ QFETCH(bool, expected);
+ QEXPECT_FAIL("QScriptValue(QScriptValue::UndefinedValue) <=> QScriptValue(QScriptValue::UndefinedValue)", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(QScriptValue::UndefinedValue) <=> QScriptValue(0, QScriptValue::UndefinedValue)", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(QScriptValue::UndefinedValue) <=> QScriptValue(engine, QScriptValue::UndefinedValue)", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(QScriptValue::UndefinedValue) <=> engine->evaluate(\"{}\")", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(QScriptValue::UndefinedValue) <=> engine->evaluate(\"undefined\")", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(QScriptValue::UndefinedValue) <=> engine->undefinedValue()", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(QScriptValue::NullValue) <=> QScriptValue(QScriptValue::NullValue)", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(QScriptValue::NullValue) <=> QScriptValue(0, QScriptValue::NullValue)", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(QScriptValue::NullValue) <=> QScriptValue(engine, QScriptValue::NullValue)", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(QScriptValue::NullValue) <=> engine->evaluate(\"null\")", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(QScriptValue::NullValue) <=> engine->nullValue()", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(true) <=> QScriptValue(true)", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(true) <=> QScriptValue(0, true)", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(false) <=> QScriptValue(false)", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(false) <=> QScriptValue(0, false)", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(0, QScriptValue::UndefinedValue) <=> QScriptValue(QScriptValue::UndefinedValue)", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(0, QScriptValue::UndefinedValue) <=> QScriptValue(0, QScriptValue::UndefinedValue)", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(0, QScriptValue::UndefinedValue) <=> QScriptValue(engine, QScriptValue::UndefinedValue)", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(0, QScriptValue::UndefinedValue) <=> engine->evaluate(\"{}\")", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(0, QScriptValue::UndefinedValue) <=> engine->evaluate(\"undefined\")", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(0, QScriptValue::UndefinedValue) <=> engine->undefinedValue()", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(0, QScriptValue::NullValue) <=> QScriptValue(QScriptValue::NullValue)", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(0, QScriptValue::NullValue) <=> QScriptValue(0, QScriptValue::NullValue)", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(0, QScriptValue::NullValue) <=> QScriptValue(engine, QScriptValue::NullValue)", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(0, QScriptValue::NullValue) <=> engine->evaluate(\"null\")", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(0, QScriptValue::NullValue) <=> engine->nullValue()", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(0, true) <=> QScriptValue(true)", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(0, true) <=> QScriptValue(0, true)", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(0, false) <=> QScriptValue(false)", "FIXME: WebKit bug 43038", Continue);
+ QEXPECT_FAIL("QScriptValue(0, false) <=> QScriptValue(0, false)", "FIXME: WebKit bug 43038", Continue);
+ QCOMPARE(value.strictlyEquals(other), expected);
+}
+
+static const QString instanceOf_array[] = {
+ "engine->evaluate(\"[]\") <=> engine->evaluate(\"Object\")",
+ "engine->evaluate(\"[]\") <=> engine->evaluate(\"Array\")",
+ "engine->evaluate(\"Date.prototype\") <=> engine->evaluate(\"Object\")",
+ "engine->evaluate(\"Array.prototype\") <=> engine->evaluate(\"Object\")",
+ "engine->evaluate(\"Function.prototype\") <=> engine->evaluate(\"Object\")",
+ "engine->evaluate(\"Error.prototype\") <=> engine->evaluate(\"Object\")",
+ "engine->evaluate(\"Object\") <=> engine->evaluate(\"Object\")",
+ "engine->evaluate(\"Object\") <=> engine->evaluate(\"Function\")",
+ "engine->evaluate(\"Array\") <=> engine->evaluate(\"Object\")",
+ "engine->evaluate(\"Array\") <=> engine->evaluate(\"Function\")",
+ "engine->evaluate(\"Number\") <=> engine->evaluate(\"Object\")",
+ "engine->evaluate(\"Number\") <=> engine->evaluate(\"Function\")",
+ "engine->evaluate(\"Function\") <=> engine->evaluate(\"Object\")",
+ "engine->evaluate(\"Function\") <=> engine->evaluate(\"Function\")",
+ "engine->evaluate(\"(function() { return 1; })\") <=> engine->evaluate(\"Object\")",
+ "engine->evaluate(\"(function() { return 1; })\") <=> engine->evaluate(\"Function\")",
+ "engine->evaluate(\"(function() { return 'ciao'; })\") <=> engine->evaluate(\"Object\")",
+ "engine->evaluate(\"(function() { return 'ciao'; })\") <=> engine->evaluate(\"Function\")",
+ "engine->evaluate(\"(function() { throw new Error('foo'); })\") <=> engine->evaluate(\"Object\")",
+ "engine->evaluate(\"(function() { throw new Error('foo'); })\") <=> engine->evaluate(\"Function\")",
+ "engine->evaluate(\"/foo/\") <=> engine->evaluate(\"Object\")",
+ "engine->evaluate(\"new Object()\") <=> engine->evaluate(\"Object\")",
+ "engine->evaluate(\"new Array()\") <=> engine->evaluate(\"Object\")",
+ "engine->evaluate(\"new Array()\") <=> engine->evaluate(\"Array\")",
+ "engine->evaluate(\"new Error()\") <=> engine->evaluate(\"Object\")",
+ "engine->evaluate(\"Undefined\") <=> engine->evaluate(\"Object\")",
+ "engine->evaluate(\"Null\") <=> engine->evaluate(\"Object\")",
+ "engine->evaluate(\"True\") <=> engine->evaluate(\"Object\")",
+ "engine->evaluate(\"False\") <=> engine->evaluate(\"Object\")",
+ "engine->newObject() <=> engine->evaluate(\"Object\")",
+ "engine->newArray() <=> engine->evaluate(\"Object\")",
+ "engine->newArray() <=> engine->evaluate(\"Array\")",
+ "engine->newArray(10) <=> engine->evaluate(\"Object\")",
+ "engine->newArray(10) <=> engine->evaluate(\"Array\")"};
+
+void tst_QScriptValue::instanceOf_data()
+{
+ QTest::addColumn<QScriptValue>("value");
+ QTest::addColumn<QScriptValue>("other");
+ QTest::addColumn<bool>("expected");
+ if (m_engine)
+ delete m_engine;
+ m_engine = new QScriptEngine();
+ QSet<QString> equals;
+ equals.reserve(34);
+ for (unsigned i = 0; i < 34; ++i)
+ equals.insert(instanceOf_array[i]);
+ for (unsigned i = 0; i < 135; ++i) {
+ QPair<QString, QScriptValue> value1 = initScriptValues(i);
+ for (unsigned j = 0; j < 135; ++j) {
+ QPair<QString, QScriptValue> value2 = initScriptValues(j);
+ QString tag = QString::fromLatin1("%20 <=> %21").arg(value1.first, value2.first);
+ QTest::newRow(tag.toAscii().constData()) << value1.second << value2.second << equals.contains(tag); }
+ }
+}
+
+void tst_QScriptValue::instanceOf()
+{
+ QFETCH(QScriptValue, value);
+ QFETCH(QScriptValue, other);
+ QFETCH(bool, expected);
+ QCOMPARE(value.instanceOf(other), expected);
+}
--- /dev/null
+/*
+ Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+ 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.
+*/
+
+/****************************************************************************
+*************** This file has been generated. DO NOT MODIFY! ****************
+****************************************************************************/
+
+#include "tst_qscriptvalue.h"
+
+
+QPair<QString, QScriptValue> tst_QScriptValue::initScriptValues(uint idx)
+{
+ QScriptEngine* engine = m_engine;
+ switch (idx) {
+ case 0: return QPair<QString, QScriptValue>("QScriptValue()", QScriptValue());
+ case 1: return QPair<QString, QScriptValue>("QScriptValue(QScriptValue::UndefinedValue)", QScriptValue(QScriptValue::UndefinedValue));
+ case 2: return QPair<QString, QScriptValue>("QScriptValue(QScriptValue::NullValue)", QScriptValue(QScriptValue::NullValue));
+ case 3: return QPair<QString, QScriptValue>("QScriptValue(true)", QScriptValue(true));
+ case 4: return QPair<QString, QScriptValue>("QScriptValue(false)", QScriptValue(false));
+ case 5: return QPair<QString, QScriptValue>("QScriptValue(int(122))", QScriptValue(int(122)));
+ case 6: return QPair<QString, QScriptValue>("QScriptValue(uint(124))", QScriptValue(uint(124)));
+ case 7: return QPair<QString, QScriptValue>("QScriptValue(0)", QScriptValue(0));
+ case 8: return QPair<QString, QScriptValue>("QScriptValue(0.0)", QScriptValue(0.0));
+ case 9: return QPair<QString, QScriptValue>("QScriptValue(123.0)", QScriptValue(123.0));
+ case 10: return QPair<QString, QScriptValue>("QScriptValue(6.37e-8)", QScriptValue(6.37e-8));
+ case 11: return QPair<QString, QScriptValue>("QScriptValue(-6.37e-8)", QScriptValue(-6.37e-8));
+ case 12: return QPair<QString, QScriptValue>("QScriptValue(0x43211234)", QScriptValue(0x43211234));
+ case 13: return QPair<QString, QScriptValue>("QScriptValue(0x10000)", QScriptValue(0x10000));
+ case 14: return QPair<QString, QScriptValue>("QScriptValue(0x10001)", QScriptValue(0x10001));
+ case 15: return QPair<QString, QScriptValue>("QScriptValue(qSNaN())", QScriptValue(qSNaN()));
+ case 16: return QPair<QString, QScriptValue>("QScriptValue(qQNaN())", QScriptValue(qQNaN()));
+ case 17: return QPair<QString, QScriptValue>("QScriptValue(qInf())", QScriptValue(qInf()));
+ case 18: return QPair<QString, QScriptValue>("QScriptValue(-qInf())", QScriptValue(-qInf()));
+ case 19: return QPair<QString, QScriptValue>("QScriptValue(\"NaN\")", QScriptValue("NaN"));
+ case 20: return QPair<QString, QScriptValue>("QScriptValue(\"Infinity\")", QScriptValue("Infinity"));
+ case 21: return QPair<QString, QScriptValue>("QScriptValue(\"-Infinity\")", QScriptValue("-Infinity"));
+ case 22: return QPair<QString, QScriptValue>("QScriptValue(\"ciao\")", QScriptValue("ciao"));
+ case 23: return QPair<QString, QScriptValue>("QScriptValue(QString::fromLatin1(\"ciao\"))", QScriptValue(QString::fromLatin1("ciao")));
+ case 24: return QPair<QString, QScriptValue>("QScriptValue(QString(\"\"))", QScriptValue(QString("")));
+ case 25: return QPair<QString, QScriptValue>("QScriptValue(QString())", QScriptValue(QString()));
+ case 26: return QPair<QString, QScriptValue>("QScriptValue(QString(\"0\"))", QScriptValue(QString("0")));
+ case 27: return QPair<QString, QScriptValue>("QScriptValue(QString(\"123\"))", QScriptValue(QString("123")));
+ case 28: return QPair<QString, QScriptValue>("QScriptValue(QString(\"12.4\"))", QScriptValue(QString("12.4")));
+ case 29: return QPair<QString, QScriptValue>("QScriptValue(0, QScriptValue::UndefinedValue)", QScriptValue(0, QScriptValue::UndefinedValue));
+ case 30: return QPair<QString, QScriptValue>("QScriptValue(0, QScriptValue::NullValue)", QScriptValue(0, QScriptValue::NullValue));
+ case 31: return QPair<QString, QScriptValue>("QScriptValue(0, true)", QScriptValue(0, true));
+ case 32: return QPair<QString, QScriptValue>("QScriptValue(0, false)", QScriptValue(0, false));
+ case 33: return QPair<QString, QScriptValue>("QScriptValue(0, int(122))", QScriptValue(0, int(122)));
+ case 34: return QPair<QString, QScriptValue>("QScriptValue(0, uint(124))", QScriptValue(0, uint(124)));
+ case 35: return QPair<QString, QScriptValue>("QScriptValue(0, 0)", QScriptValue(0, 0));
+ case 36: return QPair<QString, QScriptValue>("QScriptValue(0, 0.0)", QScriptValue(0, 0.0));
+ case 37: return QPair<QString, QScriptValue>("QScriptValue(0, 123.0)", QScriptValue(0, 123.0));
+ case 38: return QPair<QString, QScriptValue>("QScriptValue(0, 6.37e-8)", QScriptValue(0, 6.37e-8));
+ case 39: return QPair<QString, QScriptValue>("QScriptValue(0, -6.37e-8)", QScriptValue(0, -6.37e-8));
+ case 40: return QPair<QString, QScriptValue>("QScriptValue(0, 0x43211234)", QScriptValue(0, 0x43211234));
+ case 41: return QPair<QString, QScriptValue>("QScriptValue(0, 0x10000)", QScriptValue(0, 0x10000));
+ case 42: return QPair<QString, QScriptValue>("QScriptValue(0, 0x10001)", QScriptValue(0, 0x10001));
+ case 43: return QPair<QString, QScriptValue>("QScriptValue(0, qSNaN())", QScriptValue(0, qSNaN()));
+ case 44: return QPair<QString, QScriptValue>("QScriptValue(0, qQNaN())", QScriptValue(0, qQNaN()));
+ case 45: return QPair<QString, QScriptValue>("QScriptValue(0, qInf())", QScriptValue(0, qInf()));
+ case 46: return QPair<QString, QScriptValue>("QScriptValue(0, -qInf())", QScriptValue(0, -qInf()));
+ case 47: return QPair<QString, QScriptValue>("QScriptValue(0, \"NaN\")", QScriptValue(0, "NaN"));
+ case 48: return QPair<QString, QScriptValue>("QScriptValue(0, \"Infinity\")", QScriptValue(0, "Infinity"));
+ case 49: return QPair<QString, QScriptValue>("QScriptValue(0, \"-Infinity\")", QScriptValue(0, "-Infinity"));
+ case 50: return QPair<QString, QScriptValue>("QScriptValue(0, \"ciao\")", QScriptValue(0, "ciao"));
+ case 51: return QPair<QString, QScriptValue>("QScriptValue(0, QString::fromLatin1(\"ciao\"))", QScriptValue(0, QString::fromLatin1("ciao")));
+ case 52: return QPair<QString, QScriptValue>("QScriptValue(0, QString(\"\"))", QScriptValue(0, QString("")));
+ case 53: return QPair<QString, QScriptValue>("QScriptValue(0, QString())", QScriptValue(0, QString()));
+ case 54: return QPair<QString, QScriptValue>("QScriptValue(0, QString(\"0\"))", QScriptValue(0, QString("0")));
+ case 55: return QPair<QString, QScriptValue>("QScriptValue(0, QString(\"123\"))", QScriptValue(0, QString("123")));
+ case 56: return QPair<QString, QScriptValue>("QScriptValue(0, QString(\"12.3\"))", QScriptValue(0, QString("12.3")));
+ case 57: return QPair<QString, QScriptValue>("QScriptValue(engine, QScriptValue::UndefinedValue)", QScriptValue(engine, QScriptValue::UndefinedValue));
+ case 58: return QPair<QString, QScriptValue>("QScriptValue(engine, QScriptValue::NullValue)", QScriptValue(engine, QScriptValue::NullValue));
+ case 59: return QPair<QString, QScriptValue>("QScriptValue(engine, true)", QScriptValue(engine, true));
+ case 60: return QPair<QString, QScriptValue>("QScriptValue(engine, false)", QScriptValue(engine, false));
+ case 61: return QPair<QString, QScriptValue>("QScriptValue(engine, int(122))", QScriptValue(engine, int(122)));
+ case 62: return QPair<QString, QScriptValue>("QScriptValue(engine, uint(124))", QScriptValue(engine, uint(124)));
+ case 63: return QPair<QString, QScriptValue>("QScriptValue(engine, 0)", QScriptValue(engine, 0));
+ case 64: return QPair<QString, QScriptValue>("QScriptValue(engine, 0.0)", QScriptValue(engine, 0.0));
+ case 65: return QPair<QString, QScriptValue>("QScriptValue(engine, 123.0)", QScriptValue(engine, 123.0));
+ case 66: return QPair<QString, QScriptValue>("QScriptValue(engine, 6.37e-8)", QScriptValue(engine, 6.37e-8));
+ case 67: return QPair<QString, QScriptValue>("QScriptValue(engine, -6.37e-8)", QScriptValue(engine, -6.37e-8));
+ case 68: return QPair<QString, QScriptValue>("QScriptValue(engine, 0x43211234)", QScriptValue(engine, 0x43211234));
+ case 69: return QPair<QString, QScriptValue>("QScriptValue(engine, 0x10000)", QScriptValue(engine, 0x10000));
+ case 70: return QPair<QString, QScriptValue>("QScriptValue(engine, 0x10001)", QScriptValue(engine, 0x10001));
+ case 71: return QPair<QString, QScriptValue>("QScriptValue(engine, qSNaN())", QScriptValue(engine, qSNaN()));
+ case 72: return QPair<QString, QScriptValue>("QScriptValue(engine, qQNaN())", QScriptValue(engine, qQNaN()));
+ case 73: return QPair<QString, QScriptValue>("QScriptValue(engine, qInf())", QScriptValue(engine, qInf()));
+ case 74: return QPair<QString, QScriptValue>("QScriptValue(engine, -qInf())", QScriptValue(engine, -qInf()));
+ case 75: return QPair<QString, QScriptValue>("QScriptValue(engine, \"NaN\")", QScriptValue(engine, "NaN"));
+ case 76: return QPair<QString, QScriptValue>("QScriptValue(engine, \"Infinity\")", QScriptValue(engine, "Infinity"));
+ case 77: return QPair<QString, QScriptValue>("QScriptValue(engine, \"-Infinity\")", QScriptValue(engine, "-Infinity"));
+ case 78: return QPair<QString, QScriptValue>("QScriptValue(engine, \"ciao\")", QScriptValue(engine, "ciao"));
+ case 79: return QPair<QString, QScriptValue>("QScriptValue(engine, QString::fromLatin1(\"ciao\"))", QScriptValue(engine, QString::fromLatin1("ciao")));
+ case 80: return QPair<QString, QScriptValue>("QScriptValue(engine, QString(\"\"))", QScriptValue(engine, QString("")));
+ case 81: return QPair<QString, QScriptValue>("QScriptValue(engine, QString())", QScriptValue(engine, QString()));
+ case 82: return QPair<QString, QScriptValue>("QScriptValue(engine, QString(\"0\"))", QScriptValue(engine, QString("0")));
+ case 83: return QPair<QString, QScriptValue>("QScriptValue(engine, QString(\"123\"))", QScriptValue(engine, QString("123")));
+ case 84: return QPair<QString, QScriptValue>("QScriptValue(engine, QString(\"1.23\"))", QScriptValue(engine, QString("1.23")));
+ case 85: return QPair<QString, QScriptValue>("engine->evaluate(\"[]\")", engine->evaluate("[]"));
+ case 86: return QPair<QString, QScriptValue>("engine->evaluate(\"{}\")", engine->evaluate("{}"));
+ case 87: return QPair<QString, QScriptValue>("engine->evaluate(\"Object.prototype\")", engine->evaluate("Object.prototype"));
+ case 88: return QPair<QString, QScriptValue>("engine->evaluate(\"Date.prototype\")", engine->evaluate("Date.prototype"));
+ case 89: return QPair<QString, QScriptValue>("engine->evaluate(\"Array.prototype\")", engine->evaluate("Array.prototype"));
+ case 90: return QPair<QString, QScriptValue>("engine->evaluate(\"Function.prototype\")", engine->evaluate("Function.prototype"));
+ case 91: return QPair<QString, QScriptValue>("engine->evaluate(\"Error.prototype\")", engine->evaluate("Error.prototype"));
+ case 92: return QPair<QString, QScriptValue>("engine->evaluate(\"Object\")", engine->evaluate("Object"));
+ case 93: return QPair<QString, QScriptValue>("engine->evaluate(\"Array\")", engine->evaluate("Array"));
+ case 94: return QPair<QString, QScriptValue>("engine->evaluate(\"Number\")", engine->evaluate("Number"));
+ case 95: return QPair<QString, QScriptValue>("engine->evaluate(\"Function\")", engine->evaluate("Function"));
+ case 96: return QPair<QString, QScriptValue>("engine->evaluate(\"(function() { return 1; })\")", engine->evaluate("(function() { return 1; })"));
+ case 97: return QPair<QString, QScriptValue>("engine->evaluate(\"(function() { return 'ciao'; })\")", engine->evaluate("(function() { return 'ciao'; })"));
+ case 98: return QPair<QString, QScriptValue>("engine->evaluate(\"(function() { throw new Error('foo'); })\")", engine->evaluate("(function() { throw new Error('foo'); })"));
+ case 99: return QPair<QString, QScriptValue>("engine->evaluate(\"/foo/\")", engine->evaluate("/foo/"));
+ case 100: return QPair<QString, QScriptValue>("engine->evaluate(\"new Object()\")", engine->evaluate("new Object()"));
+ case 101: return QPair<QString, QScriptValue>("engine->evaluate(\"new Array()\")", engine->evaluate("new Array()"));
+ case 102: return QPair<QString, QScriptValue>("engine->evaluate(\"new Error()\")", engine->evaluate("new Error()"));
+ case 103: return QPair<QString, QScriptValue>("engine->evaluate(\"a = new Object(); a.foo = 22; a.foo\")", engine->evaluate("a = new Object(); a.foo = 22; a.foo"));
+ case 104: return QPair<QString, QScriptValue>("engine->evaluate(\"Undefined\")", engine->evaluate("Undefined"));
+ case 105: return QPair<QString, QScriptValue>("engine->evaluate(\"Null\")", engine->evaluate("Null"));
+ case 106: return QPair<QString, QScriptValue>("engine->evaluate(\"True\")", engine->evaluate("True"));
+ case 107: return QPair<QString, QScriptValue>("engine->evaluate(\"False\")", engine->evaluate("False"));
+ case 108: return QPair<QString, QScriptValue>("engine->evaluate(\"undefined\")", engine->evaluate("undefined"));
+ case 109: return QPair<QString, QScriptValue>("engine->evaluate(\"null\")", engine->evaluate("null"));
+ case 110: return QPair<QString, QScriptValue>("engine->evaluate(\"true\")", engine->evaluate("true"));
+ case 111: return QPair<QString, QScriptValue>("engine->evaluate(\"false\")", engine->evaluate("false"));
+ case 112: return QPair<QString, QScriptValue>("engine->evaluate(\"122\")", engine->evaluate("122"));
+ case 113: return QPair<QString, QScriptValue>("engine->evaluate(\"124\")", engine->evaluate("124"));
+ case 114: return QPair<QString, QScriptValue>("engine->evaluate(\"0\")", engine->evaluate("0"));
+ case 115: return QPair<QString, QScriptValue>("engine->evaluate(\"0.0\")", engine->evaluate("0.0"));
+ case 116: return QPair<QString, QScriptValue>("engine->evaluate(\"123.0\")", engine->evaluate("123.0"));
+ case 117: return QPair<QString, QScriptValue>("engine->evaluate(\"6.37e-8\")", engine->evaluate("6.37e-8"));
+ case 118: return QPair<QString, QScriptValue>("engine->evaluate(\"-6.37e-8\")", engine->evaluate("-6.37e-8"));
+ case 119: return QPair<QString, QScriptValue>("engine->evaluate(\"0x43211234\")", engine->evaluate("0x43211234"));
+ case 120: return QPair<QString, QScriptValue>("engine->evaluate(\"0x10000\")", engine->evaluate("0x10000"));
+ case 121: return QPair<QString, QScriptValue>("engine->evaluate(\"0x10001\")", engine->evaluate("0x10001"));
+ case 122: return QPair<QString, QScriptValue>("engine->evaluate(\"NaN\")", engine->evaluate("NaN"));
+ case 123: return QPair<QString, QScriptValue>("engine->evaluate(\"Infinity\")", engine->evaluate("Infinity"));
+ case 124: return QPair<QString, QScriptValue>("engine->evaluate(\"-Infinity\")", engine->evaluate("-Infinity"));
+ case 125: return QPair<QString, QScriptValue>("engine->evaluate(\"'ciao'\")", engine->evaluate("'ciao'"));
+ case 126: return QPair<QString, QScriptValue>("engine->evaluate(\"''\")", engine->evaluate("''"));
+ case 127: return QPair<QString, QScriptValue>("engine->evaluate(\"'0'\")", engine->evaluate("'0'"));
+ case 128: return QPair<QString, QScriptValue>("engine->evaluate(\"'123'\")", engine->evaluate("'123'"));
+ case 129: return QPair<QString, QScriptValue>("engine->evaluate(\"'12.4'\")", engine->evaluate("'12.4'"));
+ case 130: return QPair<QString, QScriptValue>("engine->nullValue()", engine->nullValue());
+ case 131: return QPair<QString, QScriptValue>("engine->undefinedValue()", engine->undefinedValue());
+ case 132: return QPair<QString, QScriptValue>("engine->newObject()", engine->newObject());
+ case 133: return QPair<QString, QScriptValue>("engine->newArray()", engine->newArray());
+ case 134: return QPair<QString, QScriptValue>("engine->newArray(10)", engine->newArray(10));
+ }
+ Q_ASSERT(false);
+ return qMakePair(QString(), QScriptValue());
+}
--- /dev/null
+/*
+ Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+ 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.
+*/
+
+
+/****************************************************************************
+*************** This file has been generated. DO NOT MODIFY! ****************
+****************************************************************************/
+
+#include "tst_qscriptvalue.h"
+
+
+static const QString isValid_array[] = {
+ "QScriptValue(QScriptValue::UndefinedValue)",
+ "QScriptValue(QScriptValue::NullValue)",
+ "QScriptValue(true)",
+ "QScriptValue(false)",
+ "QScriptValue(int(122))",
+ "QScriptValue(uint(124))",
+ "QScriptValue(0)",
+ "QScriptValue(0.0)",
+ "QScriptValue(123.0)",
+ "QScriptValue(6.37e-8)",
+ "QScriptValue(-6.37e-8)",
+ "QScriptValue(0x43211234)",
+ "QScriptValue(0x10000)",
+ "QScriptValue(0x10001)",
+ "QScriptValue(qSNaN())",
+ "QScriptValue(qQNaN())",
+ "QScriptValue(qInf())",
+ "QScriptValue(-qInf())",
+ "QScriptValue(\"NaN\")",
+ "QScriptValue(\"Infinity\")",
+ "QScriptValue(\"-Infinity\")",
+ "QScriptValue(\"ciao\")",
+ "QScriptValue(QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(QString(\"\"))",
+ "QScriptValue(QString())",
+ "QScriptValue(QString(\"0\"))",
+ "QScriptValue(QString(\"123\"))",
+ "QScriptValue(QString(\"12.4\"))",
+ "QScriptValue(0, QScriptValue::UndefinedValue)",
+ "QScriptValue(0, QScriptValue::NullValue)",
+ "QScriptValue(0, true)",
+ "QScriptValue(0, false)",
+ "QScriptValue(0, int(122))",
+ "QScriptValue(0, uint(124))",
+ "QScriptValue(0, 0)",
+ "QScriptValue(0, 0.0)",
+ "QScriptValue(0, 123.0)",
+ "QScriptValue(0, 6.37e-8)",
+ "QScriptValue(0, -6.37e-8)",
+ "QScriptValue(0, 0x43211234)",
+ "QScriptValue(0, 0x10000)",
+ "QScriptValue(0, 0x10001)",
+ "QScriptValue(0, qSNaN())",
+ "QScriptValue(0, qQNaN())",
+ "QScriptValue(0, qInf())",
+ "QScriptValue(0, -qInf())",
+ "QScriptValue(0, \"NaN\")",
+ "QScriptValue(0, \"Infinity\")",
+ "QScriptValue(0, \"-Infinity\")",
+ "QScriptValue(0, \"ciao\")",
+ "QScriptValue(0, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(0, QString(\"\"))",
+ "QScriptValue(0, QString())",
+ "QScriptValue(0, QString(\"0\"))",
+ "QScriptValue(0, QString(\"123\"))",
+ "QScriptValue(0, QString(\"12.3\"))",
+ "QScriptValue(engine, QScriptValue::UndefinedValue)",
+ "QScriptValue(engine, QScriptValue::NullValue)",
+ "QScriptValue(engine, true)",
+ "QScriptValue(engine, false)",
+ "QScriptValue(engine, int(122))",
+ "QScriptValue(engine, uint(124))",
+ "QScriptValue(engine, 0)",
+ "QScriptValue(engine, 0.0)",
+ "QScriptValue(engine, 123.0)",
+ "QScriptValue(engine, 6.37e-8)",
+ "QScriptValue(engine, -6.37e-8)",
+ "QScriptValue(engine, 0x43211234)",
+ "QScriptValue(engine, 0x10000)",
+ "QScriptValue(engine, 0x10001)",
+ "QScriptValue(engine, qSNaN())",
+ "QScriptValue(engine, qQNaN())",
+ "QScriptValue(engine, qInf())",
+ "QScriptValue(engine, -qInf())",
+ "QScriptValue(engine, \"NaN\")",
+ "QScriptValue(engine, \"Infinity\")",
+ "QScriptValue(engine, \"-Infinity\")",
+ "QScriptValue(engine, \"ciao\")",
+ "QScriptValue(engine, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(engine, QString(\"\"))",
+ "QScriptValue(engine, QString())",
+ "QScriptValue(engine, QString(\"0\"))",
+ "QScriptValue(engine, QString(\"123\"))",
+ "QScriptValue(engine, QString(\"1.23\"))",
+ "engine->evaluate(\"[]\")",
+ "engine->evaluate(\"{}\")",
+ "engine->evaluate(\"Object.prototype\")",
+ "engine->evaluate(\"Date.prototype\")",
+ "engine->evaluate(\"Array.prototype\")",
+ "engine->evaluate(\"Function.prototype\")",
+ "engine->evaluate(\"Error.prototype\")",
+ "engine->evaluate(\"Object\")",
+ "engine->evaluate(\"Array\")",
+ "engine->evaluate(\"Number\")",
+ "engine->evaluate(\"Function\")",
+ "engine->evaluate(\"(function() { return 1; })\")",
+ "engine->evaluate(\"(function() { return 'ciao'; })\")",
+ "engine->evaluate(\"(function() { throw new Error('foo'); })\")",
+ "engine->evaluate(\"/foo/\")",
+ "engine->evaluate(\"new Object()\")",
+ "engine->evaluate(\"new Array()\")",
+ "engine->evaluate(\"new Error()\")",
+ "engine->evaluate(\"a = new Object(); a.foo = 22; a.foo\")",
+ "engine->evaluate(\"Undefined\")",
+ "engine->evaluate(\"Null\")",
+ "engine->evaluate(\"True\")",
+ "engine->evaluate(\"False\")",
+ "engine->evaluate(\"undefined\")",
+ "engine->evaluate(\"null\")",
+ "engine->evaluate(\"true\")",
+ "engine->evaluate(\"false\")",
+ "engine->evaluate(\"122\")",
+ "engine->evaluate(\"124\")",
+ "engine->evaluate(\"0\")",
+ "engine->evaluate(\"0.0\")",
+ "engine->evaluate(\"123.0\")",
+ "engine->evaluate(\"6.37e-8\")",
+ "engine->evaluate(\"-6.37e-8\")",
+ "engine->evaluate(\"0x43211234\")",
+ "engine->evaluate(\"0x10000\")",
+ "engine->evaluate(\"0x10001\")",
+ "engine->evaluate(\"NaN\")",
+ "engine->evaluate(\"Infinity\")",
+ "engine->evaluate(\"-Infinity\")",
+ "engine->evaluate(\"'ciao'\")",
+ "engine->evaluate(\"''\")",
+ "engine->evaluate(\"'0'\")",
+ "engine->evaluate(\"'123'\")",
+ "engine->evaluate(\"'12.4'\")",
+ "engine->nullValue()",
+ "engine->undefinedValue()",
+ "engine->newObject()",
+ "engine->newArray()",
+ "engine->newArray(10)"};
+
+void tst_QScriptValue::isValid_data()
+{
+ QTest::addColumn<QScriptValue>("value");
+ QTest::addColumn<bool>("expected");
+ if (m_engine)
+ delete m_engine;
+ m_engine = new QScriptEngine();
+ QSet<QString> expectedValue;
+ expectedValue.reserve(134);
+ for (uint i = 0; i < 134; ++i)
+ expectedValue.insert(isValid_array[i]);
+ for (uint i = 0; i < 135; ++i) {
+ QPair<QString, QScriptValue> testcase = initScriptValues(i);
+ QTest::newRow(testcase.first.toAscii().constData()) << testcase.second << expectedValue.contains(testcase.first);
+ }
+}
+
+void tst_QScriptValue::isValid()
+{
+ QFETCH(QScriptValue, value);
+ QFETCH(bool, expected);
+ QCOMPARE(value.isValid(), expected);
+ QCOMPARE(value.isValid(), expected);
+}
+
+static const QString isBool_array[] = {
+ "QScriptValue(true)",
+ "QScriptValue(false)",
+ "QScriptValue(0, true)",
+ "QScriptValue(0, false)",
+ "QScriptValue(engine, true)",
+ "QScriptValue(engine, false)",
+ "engine->evaluate(\"true\")",
+ "engine->evaluate(\"false\")"};
+
+void tst_QScriptValue::isBool_data()
+{
+ QTest::addColumn<QScriptValue>("value");
+ QTest::addColumn<bool>("expected");
+ if (m_engine)
+ delete m_engine;
+ m_engine = new QScriptEngine();
+ QSet<QString> expectedValue;
+ expectedValue.reserve(8);
+ for (uint i = 0; i < 8; ++i)
+ expectedValue.insert(isBool_array[i]);
+ for (uint i = 0; i < 135; ++i) {
+ QPair<QString, QScriptValue> testcase = initScriptValues(i);
+ QTest::newRow(testcase.first.toAscii().constData()) << testcase.second << expectedValue.contains(testcase.first);
+ }
+}
+
+void tst_QScriptValue::isBool()
+{
+ QFETCH(QScriptValue, value);
+ QFETCH(bool, expected);
+ QCOMPARE(value.isBool(), expected);
+ QCOMPARE(value.isBool(), expected);
+}
+
+static const QString isBoolean_array[] = {
+ "QScriptValue(true)",
+ "QScriptValue(false)",
+ "QScriptValue(0, true)",
+ "QScriptValue(0, false)",
+ "QScriptValue(engine, true)",
+ "QScriptValue(engine, false)",
+ "engine->evaluate(\"true\")",
+ "engine->evaluate(\"false\")"};
+
+void tst_QScriptValue::isBoolean_data()
+{
+ QTest::addColumn<QScriptValue>("value");
+ QTest::addColumn<bool>("expected");
+ if (m_engine)
+ delete m_engine;
+ m_engine = new QScriptEngine();
+ QSet<QString> expectedValue;
+ expectedValue.reserve(8);
+ for (uint i = 0; i < 8; ++i)
+ expectedValue.insert(isBoolean_array[i]);
+ for (uint i = 0; i < 135; ++i) {
+ QPair<QString, QScriptValue> testcase = initScriptValues(i);
+ QTest::newRow(testcase.first.toAscii().constData()) << testcase.second << expectedValue.contains(testcase.first);
+ }
+}
+
+void tst_QScriptValue::isBoolean()
+{
+ QFETCH(QScriptValue, value);
+ QFETCH(bool, expected);
+ QCOMPARE(value.isBoolean(), expected);
+ QCOMPARE(value.isBoolean(), expected);
+}
+
+static const QString isNumber_array[] = {
+ "QScriptValue(int(122))",
+ "QScriptValue(uint(124))",
+ "QScriptValue(0)",
+ "QScriptValue(0.0)",
+ "QScriptValue(123.0)",
+ "QScriptValue(6.37e-8)",
+ "QScriptValue(-6.37e-8)",
+ "QScriptValue(0x43211234)",
+ "QScriptValue(0x10000)",
+ "QScriptValue(0x10001)",
+ "QScriptValue(qSNaN())",
+ "QScriptValue(qQNaN())",
+ "QScriptValue(qInf())",
+ "QScriptValue(-qInf())",
+ "QScriptValue(0, int(122))",
+ "QScriptValue(0, uint(124))",
+ "QScriptValue(0, 0)",
+ "QScriptValue(0, 0.0)",
+ "QScriptValue(0, 123.0)",
+ "QScriptValue(0, 6.37e-8)",
+ "QScriptValue(0, -6.37e-8)",
+ "QScriptValue(0, 0x43211234)",
+ "QScriptValue(0, 0x10000)",
+ "QScriptValue(0, 0x10001)",
+ "QScriptValue(0, qSNaN())",
+ "QScriptValue(0, qQNaN())",
+ "QScriptValue(0, qInf())",
+ "QScriptValue(0, -qInf())",
+ "QScriptValue(engine, int(122))",
+ "QScriptValue(engine, uint(124))",
+ "QScriptValue(engine, 0)",
+ "QScriptValue(engine, 0.0)",
+ "QScriptValue(engine, 123.0)",
+ "QScriptValue(engine, 6.37e-8)",
+ "QScriptValue(engine, -6.37e-8)",
+ "QScriptValue(engine, 0x43211234)",
+ "QScriptValue(engine, 0x10000)",
+ "QScriptValue(engine, 0x10001)",
+ "QScriptValue(engine, qSNaN())",
+ "QScriptValue(engine, qQNaN())",
+ "QScriptValue(engine, qInf())",
+ "QScriptValue(engine, -qInf())",
+ "engine->evaluate(\"a = new Object(); a.foo = 22; a.foo\")",
+ "engine->evaluate(\"122\")",
+ "engine->evaluate(\"124\")",
+ "engine->evaluate(\"0\")",
+ "engine->evaluate(\"0.0\")",
+ "engine->evaluate(\"123.0\")",
+ "engine->evaluate(\"6.37e-8\")",
+ "engine->evaluate(\"-6.37e-8\")",
+ "engine->evaluate(\"0x43211234\")",
+ "engine->evaluate(\"0x10000\")",
+ "engine->evaluate(\"0x10001\")",
+ "engine->evaluate(\"NaN\")",
+ "engine->evaluate(\"Infinity\")",
+ "engine->evaluate(\"-Infinity\")"};
+
+void tst_QScriptValue::isNumber_data()
+{
+ QTest::addColumn<QScriptValue>("value");
+ QTest::addColumn<bool>("expected");
+ if (m_engine)
+ delete m_engine;
+ m_engine = new QScriptEngine();
+ QSet<QString> expectedValue;
+ expectedValue.reserve(56);
+ for (uint i = 0; i < 56; ++i)
+ expectedValue.insert(isNumber_array[i]);
+ for (uint i = 0; i < 135; ++i) {
+ QPair<QString, QScriptValue> testcase = initScriptValues(i);
+ QTest::newRow(testcase.first.toAscii().constData()) << testcase.second << expectedValue.contains(testcase.first);
+ }
+}
+
+void tst_QScriptValue::isNumber()
+{
+ QFETCH(QScriptValue, value);
+ QFETCH(bool, expected);
+ QCOMPARE(value.isNumber(), expected);
+ QCOMPARE(value.isNumber(), expected);
+}
+
+static const QString isFunction_array[] = {
+ "engine->evaluate(\"Function.prototype\")",
+ "engine->evaluate(\"Object\")",
+ "engine->evaluate(\"Array\")",
+ "engine->evaluate(\"Number\")",
+ "engine->evaluate(\"Function\")",
+ "engine->evaluate(\"(function() { return 1; })\")",
+ "engine->evaluate(\"(function() { return 'ciao'; })\")",
+ "engine->evaluate(\"(function() { throw new Error('foo'); })\")",
+ "engine->evaluate(\"/foo/\")"};
+
+void tst_QScriptValue::isFunction_data()
+{
+ QTest::addColumn<QScriptValue>("value");
+ QTest::addColumn<bool>("expected");
+ if (m_engine)
+ delete m_engine;
+ m_engine = new QScriptEngine();
+ QSet<QString> expectedValue;
+ expectedValue.reserve(9);
+ for (uint i = 0; i < 9; ++i)
+ expectedValue.insert(isFunction_array[i]);
+ for (uint i = 0; i < 135; ++i) {
+ QPair<QString, QScriptValue> testcase = initScriptValues(i);
+ QTest::newRow(testcase.first.toAscii().constData()) << testcase.second << expectedValue.contains(testcase.first);
+ }
+}
+
+void tst_QScriptValue::isFunction()
+{
+ QFETCH(QScriptValue, value);
+ QFETCH(bool, expected);
+ QCOMPARE(value.isFunction(), expected);
+ QCOMPARE(value.isFunction(), expected);
+}
+
+static const QString isNull_array[] = {
+ "QScriptValue(QScriptValue::NullValue)",
+ "QScriptValue(0, QScriptValue::NullValue)",
+ "QScriptValue(engine, QScriptValue::NullValue)",
+ "engine->evaluate(\"null\")",
+ "engine->nullValue()"};
+
+void tst_QScriptValue::isNull_data()
+{
+ QTest::addColumn<QScriptValue>("value");
+ QTest::addColumn<bool>("expected");
+ if (m_engine)
+ delete m_engine;
+ m_engine = new QScriptEngine();
+ QSet<QString> expectedValue;
+ expectedValue.reserve(5);
+ for (uint i = 0; i < 5; ++i)
+ expectedValue.insert(isNull_array[i]);
+ for (uint i = 0; i < 135; ++i) {
+ QPair<QString, QScriptValue> testcase = initScriptValues(i);
+ QTest::newRow(testcase.first.toAscii().constData()) << testcase.second << expectedValue.contains(testcase.first);
+ }
+}
+
+void tst_QScriptValue::isNull()
+{
+ QFETCH(QScriptValue, value);
+ QFETCH(bool, expected);
+ QCOMPARE(value.isNull(), expected);
+ QCOMPARE(value.isNull(), expected);
+}
+
+static const QString isString_array[] = {
+ "QScriptValue(\"NaN\")",
+ "QScriptValue(\"Infinity\")",
+ "QScriptValue(\"-Infinity\")",
+ "QScriptValue(\"ciao\")",
+ "QScriptValue(QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(QString(\"\"))",
+ "QScriptValue(QString())",
+ "QScriptValue(QString(\"0\"))",
+ "QScriptValue(QString(\"123\"))",
+ "QScriptValue(QString(\"12.4\"))",
+ "QScriptValue(0, \"NaN\")",
+ "QScriptValue(0, \"Infinity\")",
+ "QScriptValue(0, \"-Infinity\")",
+ "QScriptValue(0, \"ciao\")",
+ "QScriptValue(0, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(0, QString(\"\"))",
+ "QScriptValue(0, QString())",
+ "QScriptValue(0, QString(\"0\"))",
+ "QScriptValue(0, QString(\"123\"))",
+ "QScriptValue(0, QString(\"12.3\"))",
+ "QScriptValue(engine, \"NaN\")",
+ "QScriptValue(engine, \"Infinity\")",
+ "QScriptValue(engine, \"-Infinity\")",
+ "QScriptValue(engine, \"ciao\")",
+ "QScriptValue(engine, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(engine, QString(\"\"))",
+ "QScriptValue(engine, QString())",
+ "QScriptValue(engine, QString(\"0\"))",
+ "QScriptValue(engine, QString(\"123\"))",
+ "QScriptValue(engine, QString(\"1.23\"))",
+ "engine->evaluate(\"'ciao'\")",
+ "engine->evaluate(\"''\")",
+ "engine->evaluate(\"'0'\")",
+ "engine->evaluate(\"'123'\")",
+ "engine->evaluate(\"'12.4'\")"};
+
+void tst_QScriptValue::isString_data()
+{
+ QTest::addColumn<QScriptValue>("value");
+ QTest::addColumn<bool>("expected");
+ if (m_engine)
+ delete m_engine;
+ m_engine = new QScriptEngine();
+ QSet<QString> expectedValue;
+ expectedValue.reserve(35);
+ for (uint i = 0; i < 35; ++i)
+ expectedValue.insert(isString_array[i]);
+ for (uint i = 0; i < 135; ++i) {
+ QPair<QString, QScriptValue> testcase = initScriptValues(i);
+ QTest::newRow(testcase.first.toAscii().constData()) << testcase.second << expectedValue.contains(testcase.first);
+ }
+}
+
+void tst_QScriptValue::isString()
+{
+ QFETCH(QScriptValue, value);
+ QFETCH(bool, expected);
+ QCOMPARE(value.isString(), expected);
+ QCOMPARE(value.isString(), expected);
+}
+
+static const QString isUndefined_array[] = {
+ "QScriptValue(QScriptValue::UndefinedValue)",
+ "QScriptValue(0, QScriptValue::UndefinedValue)",
+ "QScriptValue(engine, QScriptValue::UndefinedValue)",
+ "engine->evaluate(\"{}\")",
+ "engine->evaluate(\"undefined\")",
+ "engine->undefinedValue()"};
+
+void tst_QScriptValue::isUndefined_data()
+{
+ QTest::addColumn<QScriptValue>("value");
+ QTest::addColumn<bool>("expected");
+ if (m_engine)
+ delete m_engine;
+ m_engine = new QScriptEngine();
+ QSet<QString> expectedValue;
+ expectedValue.reserve(6);
+ for (uint i = 0; i < 6; ++i)
+ expectedValue.insert(isUndefined_array[i]);
+ for (uint i = 0; i < 135; ++i) {
+ QPair<QString, QScriptValue> testcase = initScriptValues(i);
+ QTest::newRow(testcase.first.toAscii().constData()) << testcase.second << expectedValue.contains(testcase.first);
+ }
+}
+
+void tst_QScriptValue::isUndefined()
+{
+ QFETCH(QScriptValue, value);
+ QFETCH(bool, expected);
+ QCOMPARE(value.isUndefined(), expected);
+ QCOMPARE(value.isUndefined(), expected);
+}
+
+
+
+
+static const QString isObject_array[] = {
+ "engine->evaluate(\"[]\")",
+ "engine->evaluate(\"Object.prototype\")",
+ "engine->evaluate(\"Date.prototype\")",
+ "engine->evaluate(\"Array.prototype\")",
+ "engine->evaluate(\"Function.prototype\")",
+ "engine->evaluate(\"Error.prototype\")",
+ "engine->evaluate(\"Object\")",
+ "engine->evaluate(\"Array\")",
+ "engine->evaluate(\"Number\")",
+ "engine->evaluate(\"Function\")",
+ "engine->evaluate(\"(function() { return 1; })\")",
+ "engine->evaluate(\"(function() { return 'ciao'; })\")",
+ "engine->evaluate(\"(function() { throw new Error('foo'); })\")",
+ "engine->evaluate(\"/foo/\")",
+ "engine->evaluate(\"new Object()\")",
+ "engine->evaluate(\"new Array()\")",
+ "engine->evaluate(\"new Error()\")",
+ "engine->evaluate(\"Undefined\")",
+ "engine->evaluate(\"Null\")",
+ "engine->evaluate(\"True\")",
+ "engine->evaluate(\"False\")",
+ "engine->newObject()",
+ "engine->newArray()",
+ "engine->newArray(10)"};
+
+void tst_QScriptValue::isObject_data()
+{
+ QTest::addColumn<QScriptValue>("value");
+ QTest::addColumn<bool>("expected");
+ if (m_engine)
+ delete m_engine;
+ m_engine = new QScriptEngine();
+ QSet<QString> expectedValue;
+ expectedValue.reserve(24);
+ for (uint i = 0; i < 24; ++i)
+ expectedValue.insert(isObject_array[i]);
+ for (uint i = 0; i < 135; ++i) {
+ QPair<QString, QScriptValue> testcase = initScriptValues(i);
+ QTest::newRow(testcase.first.toAscii().constData()) << testcase.second << expectedValue.contains(testcase.first);
+ }
+}
+
+void tst_QScriptValue::isObject()
+{
+ QFETCH(QScriptValue, value);
+ QFETCH(bool, expected);
+ QCOMPARE(value.isObject(), expected);
+ QCOMPARE(value.isObject(), expected);
+}
+
+static const QString isArray_array[] = {
+ "engine->evaluate(\"[]\")",
+ "engine->evaluate(\"Array.prototype\")",
+ "engine->evaluate(\"new Array()\")",
+ "engine->newArray()",
+ "engine->newArray(10)"};
+
+void tst_QScriptValue::isArray_data()
+{
+ QTest::addColumn<QScriptValue>("value");
+ QTest::addColumn<bool>("expected");
+ if (m_engine)
+ delete m_engine;
+ m_engine = new QScriptEngine();
+ QSet<QString> expectedValue;
+ expectedValue.reserve(5);
+ for (uint i = 0; i < 5; ++i)
+ expectedValue.insert(isArray_array[i]);
+ for (uint i = 0; i < 135; ++i) {
+ QPair<QString, QScriptValue> testcase = initScriptValues(i);
+ QTest::newRow(testcase.first.toAscii().constData()) << testcase.second << expectedValue.contains(testcase.first);
+ }
+}
+
+void tst_QScriptValue::isArray()
+{
+ QFETCH(QScriptValue, value);
+ QFETCH(bool, expected);
+ QCOMPARE(value.isArray(), expected);
+ QCOMPARE(value.isArray(), expected);
+}
+
+static const QString isError_array[] = {
+ "engine->evaluate(\"Error.prototype\")",
+ "engine->evaluate(\"new Error()\")",
+ "engine->evaluate(\"Undefined\")",
+ "engine->evaluate(\"Null\")",
+ "engine->evaluate(\"True\")",
+ "engine->evaluate(\"False\")"};
+
+void tst_QScriptValue::isError_data()
+{
+ QTest::addColumn<QScriptValue>("value");
+ QTest::addColumn<bool>("expected");
+ if (m_engine)
+ delete m_engine;
+ m_engine = new QScriptEngine();
+ QSet<QString> expectedValue;
+ expectedValue.reserve(6);
+ for (uint i = 0; i < 6; ++i)
+ expectedValue.insert(isError_array[i]);
+ for (uint i = 0; i < 135; ++i) {
+ QPair<QString, QScriptValue> testcase = initScriptValues(i);
+ QTest::newRow(testcase.first.toAscii().constData()) << testcase.second << expectedValue.contains(testcase.first);
+ }
+}
+
+void tst_QScriptValue::isError()
+{
+ QFETCH(QScriptValue, value);
+ QFETCH(bool, expected);
+ QCOMPARE(value.isError(), expected);
+ QCOMPARE(value.isError(), expected);
+}
--- /dev/null
+/*
+ Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+ 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.
+*/
+
+/****************************************************************************
+*************** This file has been generated. DO NOT MODIFY! ****************
+****************************************************************************/
+
+#include "tst_qscriptvalue.h"
+
+static const QString toString_tagArray[] = {
+ "QScriptValue()",
+ "QScriptValue(QScriptValue::UndefinedValue)",
+ "QScriptValue(QScriptValue::NullValue)",
+ "QScriptValue(true)",
+ "QScriptValue(false)",
+ "QScriptValue(int(122))",
+ "QScriptValue(uint(124))",
+ "QScriptValue(0)",
+ "QScriptValue(0.0)",
+ "QScriptValue(123.0)",
+ "QScriptValue(6.37e-8)",
+ "QScriptValue(-6.37e-8)",
+ "QScriptValue(0x43211234)",
+ "QScriptValue(0x10000)",
+ "QScriptValue(0x10001)",
+ "QScriptValue(qSNaN())",
+ "QScriptValue(qQNaN())",
+ "QScriptValue(qInf())",
+ "QScriptValue(-qInf())",
+ "QScriptValue(\"NaN\")",
+ "QScriptValue(\"Infinity\")",
+ "QScriptValue(\"-Infinity\")",
+ "QScriptValue(\"ciao\")",
+ "QScriptValue(QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(QString(\"\"))",
+ "QScriptValue(QString())",
+ "QScriptValue(QString(\"0\"))",
+ "QScriptValue(QString(\"123\"))",
+ "QScriptValue(QString(\"12.4\"))",
+ "QScriptValue(0, QScriptValue::UndefinedValue)",
+ "QScriptValue(0, QScriptValue::NullValue)",
+ "QScriptValue(0, true)",
+ "QScriptValue(0, false)",
+ "QScriptValue(0, int(122))",
+ "QScriptValue(0, uint(124))",
+ "QScriptValue(0, 0)",
+ "QScriptValue(0, 0.0)",
+ "QScriptValue(0, 123.0)",
+ "QScriptValue(0, 6.37e-8)",
+ "QScriptValue(0, -6.37e-8)",
+ "QScriptValue(0, 0x43211234)",
+ "QScriptValue(0, 0x10000)",
+ "QScriptValue(0, 0x10001)",
+ "QScriptValue(0, qSNaN())",
+ "QScriptValue(0, qQNaN())",
+ "QScriptValue(0, qInf())",
+ "QScriptValue(0, -qInf())",
+ "QScriptValue(0, \"NaN\")",
+ "QScriptValue(0, \"Infinity\")",
+ "QScriptValue(0, \"-Infinity\")",
+ "QScriptValue(0, \"ciao\")",
+ "QScriptValue(0, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(0, QString(\"\"))",
+ "QScriptValue(0, QString())",
+ "QScriptValue(0, QString(\"0\"))",
+ "QScriptValue(0, QString(\"123\"))",
+ "QScriptValue(0, QString(\"12.3\"))",
+ "QScriptValue(engine, QScriptValue::UndefinedValue)",
+ "QScriptValue(engine, QScriptValue::NullValue)",
+ "QScriptValue(engine, true)",
+ "QScriptValue(engine, false)",
+ "QScriptValue(engine, int(122))",
+ "QScriptValue(engine, uint(124))",
+ "QScriptValue(engine, 0)",
+ "QScriptValue(engine, 0.0)",
+ "QScriptValue(engine, 123.0)",
+ "QScriptValue(engine, 6.37e-8)",
+ "QScriptValue(engine, -6.37e-8)",
+ "QScriptValue(engine, 0x43211234)",
+ "QScriptValue(engine, 0x10000)",
+ "QScriptValue(engine, 0x10001)",
+ "QScriptValue(engine, qSNaN())",
+ "QScriptValue(engine, qQNaN())",
+ "QScriptValue(engine, qInf())",
+ "QScriptValue(engine, -qInf())",
+ "QScriptValue(engine, \"NaN\")",
+ "QScriptValue(engine, \"Infinity\")",
+ "QScriptValue(engine, \"-Infinity\")",
+ "QScriptValue(engine, \"ciao\")",
+ "QScriptValue(engine, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(engine, QString(\"\"))",
+ "QScriptValue(engine, QString())",
+ "QScriptValue(engine, QString(\"0\"))",
+ "QScriptValue(engine, QString(\"123\"))",
+ "QScriptValue(engine, QString(\"1.23\"))",
+ "engine->evaluate(\"[]\")",
+ "engine->evaluate(\"{}\")",
+ "engine->evaluate(\"Object.prototype\")",
+ "engine->evaluate(\"Date.prototype\")",
+ "engine->evaluate(\"Array.prototype\")",
+ "engine->evaluate(\"Function.prototype\")",
+ "engine->evaluate(\"Error.prototype\")",
+ "engine->evaluate(\"Object\")",
+ "engine->evaluate(\"Array\")",
+ "engine->evaluate(\"Number\")",
+ "engine->evaluate(\"Function\")",
+ "engine->evaluate(\"(function() { return 1; })\")",
+ "engine->evaluate(\"(function() { return 'ciao'; })\")",
+ "engine->evaluate(\"(function() { throw new Error('foo'); })\")",
+ "engine->evaluate(\"/foo/\")",
+ "engine->evaluate(\"new Object()\")",
+ "engine->evaluate(\"new Array()\")",
+ "engine->evaluate(\"new Error()\")",
+ "engine->evaluate(\"a = new Object(); a.foo = 22; a.foo\")",
+ "engine->evaluate(\"Undefined\")",
+ "engine->evaluate(\"Null\")",
+ "engine->evaluate(\"True\")",
+ "engine->evaluate(\"False\")",
+ "engine->evaluate(\"undefined\")",
+ "engine->evaluate(\"null\")",
+ "engine->evaluate(\"true\")",
+ "engine->evaluate(\"false\")",
+ "engine->evaluate(\"122\")",
+ "engine->evaluate(\"124\")",
+ "engine->evaluate(\"0\")",
+ "engine->evaluate(\"0.0\")",
+ "engine->evaluate(\"123.0\")",
+ "engine->evaluate(\"6.37e-8\")",
+ "engine->evaluate(\"-6.37e-8\")",
+ "engine->evaluate(\"0x43211234\")",
+ "engine->evaluate(\"0x10000\")",
+ "engine->evaluate(\"0x10001\")",
+ "engine->evaluate(\"NaN\")",
+ "engine->evaluate(\"Infinity\")",
+ "engine->evaluate(\"-Infinity\")",
+ "engine->evaluate(\"'ciao'\")",
+ "engine->evaluate(\"''\")",
+ "engine->evaluate(\"'0'\")",
+ "engine->evaluate(\"'123'\")",
+ "engine->evaluate(\"'12.4'\")",
+ "engine->nullValue()",
+ "engine->undefinedValue()",
+ "engine->newObject()",
+ "engine->newArray()",
+ "engine->newArray(10)"};
+
+static const QString toString_valueArray[] = {
+ "", "undefined",
+ "null", "true",
+ "false", "122",
+ "124", "0",
+ "0", "123",
+ "6.37e-8", "-6.37e-8",
+ "1126240820", "65536",
+ "65537", "NaN",
+ "NaN", "Infinity",
+ "-Infinity", "NaN",
+ "Infinity", "-Infinity",
+ "ciao", "ciao",
+ "", "",
+ "0", "123",
+ "12.4", "undefined",
+ "null", "true",
+ "false", "122",
+ "124", "0",
+ "0", "123",
+ "6.37e-8", "-6.37e-8",
+ "1126240820", "65536",
+ "65537", "NaN",
+ "NaN", "Infinity",
+ "-Infinity", "NaN",
+ "Infinity", "-Infinity",
+ "ciao", "ciao",
+ "", "",
+ "0", "123",
+ "12.3", "undefined",
+ "null", "true",
+ "false", "122",
+ "124", "0",
+ "0", "123",
+ "6.37e-8", "-6.37e-8",
+ "1126240820", "65536",
+ "65537", "NaN",
+ "NaN", "Infinity",
+ "-Infinity", "NaN",
+ "Infinity", "-Infinity",
+ "ciao", "ciao",
+ "", "",
+ "0", "123",
+ "1.23", "",
+ "undefined", "[object Object]",
+ "Invalid Date", "",
+ "function () {\n [native code]\n}", "Error: Unknown error",
+ "function Object() {\n [native code]\n}", "function Array() {\n [native code]\n}",
+ "function Number() {\n [native code]\n}", "function Function() {\n [native code]\n}",
+ "function () { return 1; }", "function () { return 'ciao'; }",
+ "function () { throw new Error('foo'); }", "/foo/",
+ "[object Object]", "",
+ "Error: Unknown error", "22",
+ "ReferenceError: Can't find variable: Undefined", "ReferenceError: Can't find variable: Null",
+ "ReferenceError: Can't find variable: True", "ReferenceError: Can't find variable: False",
+ "undefined", "null",
+ "true", "false",
+ "122", "124",
+ "0", "0",
+ "123", "6.37e-8",
+ "-6.37e-8", "1126240820",
+ "65536", "65537",
+ "NaN", "Infinity",
+ "-Infinity", "ciao",
+ "", "0",
+ "123", "12.4",
+ "null", "undefined",
+ "[object Object]", "",
+ ",,,,,,,,,"};
+
+void tst_QScriptValue::toString_data()
+{
+ QTest::addColumn<QScriptValue>("value");
+ QTest::addColumn<QString>("expected");
+ if (m_engine)
+ delete m_engine;
+ m_engine = new QScriptEngine();
+ QHash<QString, QString> expectedValue;
+ expectedValue.reserve(135);
+ for (uint i = 0; i < 135; ++i)
+ expectedValue.insert(toString_tagArray[i], toString_valueArray[i]);
+ for (uint i = 0; i < 135; ++i) {
+ QPair<QString, QScriptValue> testcase = initScriptValues(i);
+ QTest::newRow(testcase.first.toAscii().constData()) << testcase.second << expectedValue[testcase.first];
+ }
+}
+
+void tst_QScriptValue::toString()
+{
+ QFETCH(QScriptValue, value);
+ QFETCH(QString, expected);
+ QCOMPARE(value.toString(), expected);
+ QCOMPARE(value.toString(), expected);
+}
+
+static const QString toNumber_tagArray[] = {
+ "QScriptValue()",
+ "QScriptValue(QScriptValue::UndefinedValue)",
+ "QScriptValue(QScriptValue::NullValue)",
+ "QScriptValue(true)",
+ "QScriptValue(false)",
+ "QScriptValue(int(122))",
+ "QScriptValue(uint(124))",
+ "QScriptValue(0)",
+ "QScriptValue(0.0)",
+ "QScriptValue(123.0)",
+ "QScriptValue(6.37e-8)",
+ "QScriptValue(-6.37e-8)",
+ "QScriptValue(0x43211234)",
+ "QScriptValue(0x10000)",
+ "QScriptValue(0x10001)",
+ "QScriptValue(qSNaN())",
+ "QScriptValue(qQNaN())",
+ "QScriptValue(qInf())",
+ "QScriptValue(-qInf())",
+ "QScriptValue(\"NaN\")",
+ "QScriptValue(\"Infinity\")",
+ "QScriptValue(\"-Infinity\")",
+ "QScriptValue(\"ciao\")",
+ "QScriptValue(QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(QString(\"\"))",
+ "QScriptValue(QString())",
+ "QScriptValue(QString(\"0\"))",
+ "QScriptValue(QString(\"123\"))",
+ "QScriptValue(QString(\"12.4\"))",
+ "QScriptValue(0, QScriptValue::UndefinedValue)",
+ "QScriptValue(0, QScriptValue::NullValue)",
+ "QScriptValue(0, true)",
+ "QScriptValue(0, false)",
+ "QScriptValue(0, int(122))",
+ "QScriptValue(0, uint(124))",
+ "QScriptValue(0, 0)",
+ "QScriptValue(0, 0.0)",
+ "QScriptValue(0, 123.0)",
+ "QScriptValue(0, 6.37e-8)",
+ "QScriptValue(0, -6.37e-8)",
+ "QScriptValue(0, 0x43211234)",
+ "QScriptValue(0, 0x10000)",
+ "QScriptValue(0, 0x10001)",
+ "QScriptValue(0, qSNaN())",
+ "QScriptValue(0, qQNaN())",
+ "QScriptValue(0, qInf())",
+ "QScriptValue(0, -qInf())",
+ "QScriptValue(0, \"NaN\")",
+ "QScriptValue(0, \"Infinity\")",
+ "QScriptValue(0, \"-Infinity\")",
+ "QScriptValue(0, \"ciao\")",
+ "QScriptValue(0, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(0, QString(\"\"))",
+ "QScriptValue(0, QString())",
+ "QScriptValue(0, QString(\"0\"))",
+ "QScriptValue(0, QString(\"123\"))",
+ "QScriptValue(0, QString(\"12.3\"))",
+ "QScriptValue(engine, QScriptValue::UndefinedValue)",
+ "QScriptValue(engine, QScriptValue::NullValue)",
+ "QScriptValue(engine, true)",
+ "QScriptValue(engine, false)",
+ "QScriptValue(engine, int(122))",
+ "QScriptValue(engine, uint(124))",
+ "QScriptValue(engine, 0)",
+ "QScriptValue(engine, 0.0)",
+ "QScriptValue(engine, 123.0)",
+ "QScriptValue(engine, 6.37e-8)",
+ "QScriptValue(engine, -6.37e-8)",
+ "QScriptValue(engine, 0x43211234)",
+ "QScriptValue(engine, 0x10000)",
+ "QScriptValue(engine, 0x10001)",
+ "QScriptValue(engine, qSNaN())",
+ "QScriptValue(engine, qQNaN())",
+ "QScriptValue(engine, qInf())",
+ "QScriptValue(engine, -qInf())",
+ "QScriptValue(engine, \"NaN\")",
+ "QScriptValue(engine, \"Infinity\")",
+ "QScriptValue(engine, \"-Infinity\")",
+ "QScriptValue(engine, \"ciao\")",
+ "QScriptValue(engine, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(engine, QString(\"\"))",
+ "QScriptValue(engine, QString())",
+ "QScriptValue(engine, QString(\"0\"))",
+ "QScriptValue(engine, QString(\"123\"))",
+ "QScriptValue(engine, QString(\"1.23\"))",
+ "engine->evaluate(\"[]\")",
+ "engine->evaluate(\"{}\")",
+ "engine->evaluate(\"Object.prototype\")",
+ "engine->evaluate(\"Date.prototype\")",
+ "engine->evaluate(\"Array.prototype\")",
+ "engine->evaluate(\"Function.prototype\")",
+ "engine->evaluate(\"Error.prototype\")",
+ "engine->evaluate(\"Object\")",
+ "engine->evaluate(\"Array\")",
+ "engine->evaluate(\"Number\")",
+ "engine->evaluate(\"Function\")",
+ "engine->evaluate(\"(function() { return 1; })\")",
+ "engine->evaluate(\"(function() { return 'ciao'; })\")",
+ "engine->evaluate(\"(function() { throw new Error('foo'); })\")",
+ "engine->evaluate(\"/foo/\")",
+ "engine->evaluate(\"new Object()\")",
+ "engine->evaluate(\"new Array()\")",
+ "engine->evaluate(\"new Error()\")",
+ "engine->evaluate(\"a = new Object(); a.foo = 22; a.foo\")",
+ "engine->evaluate(\"Undefined\")",
+ "engine->evaluate(\"Null\")",
+ "engine->evaluate(\"True\")",
+ "engine->evaluate(\"False\")",
+ "engine->evaluate(\"undefined\")",
+ "engine->evaluate(\"null\")",
+ "engine->evaluate(\"true\")",
+ "engine->evaluate(\"false\")",
+ "engine->evaluate(\"122\")",
+ "engine->evaluate(\"124\")",
+ "engine->evaluate(\"0\")",
+ "engine->evaluate(\"0.0\")",
+ "engine->evaluate(\"123.0\")",
+ "engine->evaluate(\"6.37e-8\")",
+ "engine->evaluate(\"-6.37e-8\")",
+ "engine->evaluate(\"0x43211234\")",
+ "engine->evaluate(\"0x10000\")",
+ "engine->evaluate(\"0x10001\")",
+ "engine->evaluate(\"NaN\")",
+ "engine->evaluate(\"Infinity\")",
+ "engine->evaluate(\"-Infinity\")",
+ "engine->evaluate(\"'ciao'\")",
+ "engine->evaluate(\"''\")",
+ "engine->evaluate(\"'0'\")",
+ "engine->evaluate(\"'123'\")",
+ "engine->evaluate(\"'12.4'\")",
+ "engine->nullValue()",
+ "engine->undefinedValue()",
+ "engine->newObject()",
+ "engine->newArray()",
+ "engine->newArray(10)"};
+
+static const qsreal toNumber_valueArray[] = {
+ 0, qQNaN(), 0, 1, 0, 122, 124, 0, 0, 123,
+ 6.369999999999999e-08, -6.369999999999999e-08, 1126240820, 65536, 65537, qQNaN(), qQNaN(), qInf(), qInf(), qQNaN(),
+ qInf(), qInf(), qQNaN(), qQNaN(), 0, 0, 0, 123, 12.4, qQNaN(),
+ 0, 1, 0, 122, 124, 0, 0, 123, 6.369999999999999e-08, -6.369999999999999e-08,
+ 1126240820, 65536, 65537, qQNaN(), qQNaN(), qInf(), qInf(), qQNaN(), qInf(), qInf(),
+ qQNaN(), qQNaN(), 0, 0, 0, 123, 12.3, qQNaN(), 0, 1,
+ 0, 122, 124, 0, 0, 123, 6.369999999999999e-08, -6.369999999999999e-08, 1126240820, 65536,
+ 65537, qQNaN(), qQNaN(), qInf(), qInf(), qQNaN(), qInf(), qInf(), qQNaN(), qQNaN(),
+ 0, 0, 0, 123, 1.23, 0, qQNaN(), qQNaN(), qQNaN(), 0,
+ qQNaN(), qQNaN(), qQNaN(), qQNaN(), qQNaN(), qQNaN(), qQNaN(), qQNaN(), qQNaN(), qQNaN(),
+ qQNaN(), 0, qQNaN(), 22, qQNaN(), qQNaN(), qQNaN(), qQNaN(), qQNaN(), 0,
+ 1, 0, 122, 124, 0, 0, 123, 6.369999999999999e-08, -6.369999999999999e-08, 1126240820,
+ 65536, 65537, qQNaN(), qInf(), qInf(), qQNaN(), 0, 0, 123, 12.4,
+ 0, qQNaN(), qQNaN(), 0, qQNaN()};
+
+void tst_QScriptValue::toNumber_data()
+{
+ QTest::addColumn<QScriptValue>("value");
+ QTest::addColumn<qsreal>("expected");
+ if (m_engine)
+ delete m_engine;
+ m_engine = new QScriptEngine();
+ QHash<QString, qsreal> expectedValue;
+ expectedValue.reserve(135);
+ for (uint i = 0; i < 135; ++i)
+ expectedValue.insert(toNumber_tagArray[i], toNumber_valueArray[i]);
+ for (uint i = 0; i < 135; ++i) {
+ QPair<QString, QScriptValue> testcase = initScriptValues(i);
+ QTest::newRow(testcase.first.toAscii().constData()) << testcase.second << expectedValue[testcase.first];
+ }
+}
+
+void tst_QScriptValue::toNumber()
+{
+ QFETCH(QScriptValue, value);
+ QFETCH(qsreal, expected);
+ if (qIsNaN(expected)) {
+ QVERIFY(qIsNaN(value.toNumber()));
+ return;
+ }
+ if (qIsInf(expected)) {
+ QVERIFY(qIsInf(value.toNumber()));
+ QVERIFY(qIsInf(value.toNumber()));
+ return;
+ }
+ QCOMPARE(value.toNumber(), expected);
+ QCOMPARE(value.toNumber(), expected);
+}
+
+static const QString toBool_tagArray[] = {
+ "QScriptValue()",
+ "QScriptValue(QScriptValue::UndefinedValue)",
+ "QScriptValue(QScriptValue::NullValue)",
+ "QScriptValue(true)",
+ "QScriptValue(false)",
+ "QScriptValue(int(122))",
+ "QScriptValue(uint(124))",
+ "QScriptValue(0)",
+ "QScriptValue(0.0)",
+ "QScriptValue(123.0)",
+ "QScriptValue(6.37e-8)",
+ "QScriptValue(-6.37e-8)",
+ "QScriptValue(0x43211234)",
+ "QScriptValue(0x10000)",
+ "QScriptValue(0x10001)",
+ "QScriptValue(qSNaN())",
+ "QScriptValue(qQNaN())",
+ "QScriptValue(qInf())",
+ "QScriptValue(-qInf())",
+ "QScriptValue(\"NaN\")",
+ "QScriptValue(\"Infinity\")",
+ "QScriptValue(\"-Infinity\")",
+ "QScriptValue(\"ciao\")",
+ "QScriptValue(QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(QString(\"\"))",
+ "QScriptValue(QString())",
+ "QScriptValue(QString(\"0\"))",
+ "QScriptValue(QString(\"123\"))",
+ "QScriptValue(QString(\"12.4\"))",
+ "QScriptValue(0, QScriptValue::UndefinedValue)",
+ "QScriptValue(0, QScriptValue::NullValue)",
+ "QScriptValue(0, true)",
+ "QScriptValue(0, false)",
+ "QScriptValue(0, int(122))",
+ "QScriptValue(0, uint(124))",
+ "QScriptValue(0, 0)",
+ "QScriptValue(0, 0.0)",
+ "QScriptValue(0, 123.0)",
+ "QScriptValue(0, 6.37e-8)",
+ "QScriptValue(0, -6.37e-8)",
+ "QScriptValue(0, 0x43211234)",
+ "QScriptValue(0, 0x10000)",
+ "QScriptValue(0, 0x10001)",
+ "QScriptValue(0, qSNaN())",
+ "QScriptValue(0, qQNaN())",
+ "QScriptValue(0, qInf())",
+ "QScriptValue(0, -qInf())",
+ "QScriptValue(0, \"NaN\")",
+ "QScriptValue(0, \"Infinity\")",
+ "QScriptValue(0, \"-Infinity\")",
+ "QScriptValue(0, \"ciao\")",
+ "QScriptValue(0, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(0, QString(\"\"))",
+ "QScriptValue(0, QString())",
+ "QScriptValue(0, QString(\"0\"))",
+ "QScriptValue(0, QString(\"123\"))",
+ "QScriptValue(0, QString(\"12.3\"))",
+ "QScriptValue(engine, QScriptValue::UndefinedValue)",
+ "QScriptValue(engine, QScriptValue::NullValue)",
+ "QScriptValue(engine, true)",
+ "QScriptValue(engine, false)",
+ "QScriptValue(engine, int(122))",
+ "QScriptValue(engine, uint(124))",
+ "QScriptValue(engine, 0)",
+ "QScriptValue(engine, 0.0)",
+ "QScriptValue(engine, 123.0)",
+ "QScriptValue(engine, 6.37e-8)",
+ "QScriptValue(engine, -6.37e-8)",
+ "QScriptValue(engine, 0x43211234)",
+ "QScriptValue(engine, 0x10000)",
+ "QScriptValue(engine, 0x10001)",
+ "QScriptValue(engine, qSNaN())",
+ "QScriptValue(engine, qQNaN())",
+ "QScriptValue(engine, qInf())",
+ "QScriptValue(engine, -qInf())",
+ "QScriptValue(engine, \"NaN\")",
+ "QScriptValue(engine, \"Infinity\")",
+ "QScriptValue(engine, \"-Infinity\")",
+ "QScriptValue(engine, \"ciao\")",
+ "QScriptValue(engine, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(engine, QString(\"\"))",
+ "QScriptValue(engine, QString())",
+ "QScriptValue(engine, QString(\"0\"))",
+ "QScriptValue(engine, QString(\"123\"))",
+ "QScriptValue(engine, QString(\"1.23\"))",
+ "engine->evaluate(\"[]\")",
+ "engine->evaluate(\"{}\")",
+ "engine->evaluate(\"Object.prototype\")",
+ "engine->evaluate(\"Date.prototype\")",
+ "engine->evaluate(\"Array.prototype\")",
+ "engine->evaluate(\"Function.prototype\")",
+ "engine->evaluate(\"Error.prototype\")",
+ "engine->evaluate(\"Object\")",
+ "engine->evaluate(\"Array\")",
+ "engine->evaluate(\"Number\")",
+ "engine->evaluate(\"Function\")",
+ "engine->evaluate(\"(function() { return 1; })\")",
+ "engine->evaluate(\"(function() { return 'ciao'; })\")",
+ "engine->evaluate(\"(function() { throw new Error('foo'); })\")",
+ "engine->evaluate(\"/foo/\")",
+ "engine->evaluate(\"new Object()\")",
+ "engine->evaluate(\"new Array()\")",
+ "engine->evaluate(\"new Error()\")",
+ "engine->evaluate(\"a = new Object(); a.foo = 22; a.foo\")",
+ "engine->evaluate(\"Undefined\")",
+ "engine->evaluate(\"Null\")",
+ "engine->evaluate(\"True\")",
+ "engine->evaluate(\"False\")",
+ "engine->evaluate(\"undefined\")",
+ "engine->evaluate(\"null\")",
+ "engine->evaluate(\"true\")",
+ "engine->evaluate(\"false\")",
+ "engine->evaluate(\"122\")",
+ "engine->evaluate(\"124\")",
+ "engine->evaluate(\"0\")",
+ "engine->evaluate(\"0.0\")",
+ "engine->evaluate(\"123.0\")",
+ "engine->evaluate(\"6.37e-8\")",
+ "engine->evaluate(\"-6.37e-8\")",
+ "engine->evaluate(\"0x43211234\")",
+ "engine->evaluate(\"0x10000\")",
+ "engine->evaluate(\"0x10001\")",
+ "engine->evaluate(\"NaN\")",
+ "engine->evaluate(\"Infinity\")",
+ "engine->evaluate(\"-Infinity\")",
+ "engine->evaluate(\"'ciao'\")",
+ "engine->evaluate(\"''\")",
+ "engine->evaluate(\"'0'\")",
+ "engine->evaluate(\"'123'\")",
+ "engine->evaluate(\"'12.4'\")",
+ "engine->nullValue()",
+ "engine->undefinedValue()",
+ "engine->newObject()",
+ "engine->newArray()",
+ "engine->newArray(10)"};
+
+static const bool toBool_valueArray[] = {
+ false, false,
+ false, true,
+ false, true,
+ true, false,
+ false, true,
+ true, true,
+ true, true,
+ true, false,
+ false, true,
+ true, true,
+ true, true,
+ true, true,
+ false, false,
+ true, true,
+ true, false,
+ false, true,
+ false, true,
+ true, false,
+ false, true,
+ true, true,
+ true, true,
+ true, false,
+ false, true,
+ true, true,
+ true, true,
+ true, true,
+ false, false,
+ true, true,
+ true, false,
+ false, true,
+ false, true,
+ true, false,
+ false, true,
+ true, true,
+ true, true,
+ true, false,
+ false, true,
+ true, true,
+ true, true,
+ true, true,
+ false, false,
+ true, true,
+ true, true,
+ false, true,
+ true, true,
+ true, true,
+ true, true,
+ true, true,
+ true, true,
+ true, true,
+ true, true,
+ true, true,
+ true, true,
+ true, true,
+ false, false,
+ true, false,
+ true, true,
+ false, false,
+ true, true,
+ true, true,
+ true, true,
+ false, true,
+ true, true,
+ false, true,
+ true, true,
+ false, false,
+ true, true,
+ true};
+
+void tst_QScriptValue::toBool_data()
+{
+ QTest::addColumn<QScriptValue>("value");
+ QTest::addColumn<bool>("expected");
+ if (m_engine)
+ delete m_engine;
+ m_engine = new QScriptEngine();
+ QHash<QString, bool> expectedValue;
+ expectedValue.reserve(135);
+ for (uint i = 0; i < 135; ++i)
+ expectedValue.insert(toBool_tagArray[i], toBool_valueArray[i]);
+ for (uint i = 0; i < 135; ++i) {
+ QPair<QString, QScriptValue> testcase = initScriptValues(i);
+ QTest::newRow(testcase.first.toAscii().constData()) << testcase.second << expectedValue[testcase.first];
+ }
+}
+
+void tst_QScriptValue::toBool()
+{
+ QFETCH(QScriptValue, value);
+ QFETCH(bool, expected);
+ QCOMPARE(value.toBool(), expected);
+ QCOMPARE(value.toBool(), expected);
+}
+
+static const QString toBoolean_tagArray[] = {
+ "QScriptValue()",
+ "QScriptValue(QScriptValue::UndefinedValue)",
+ "QScriptValue(QScriptValue::NullValue)",
+ "QScriptValue(true)",
+ "QScriptValue(false)",
+ "QScriptValue(int(122))",
+ "QScriptValue(uint(124))",
+ "QScriptValue(0)",
+ "QScriptValue(0.0)",
+ "QScriptValue(123.0)",
+ "QScriptValue(6.37e-8)",
+ "QScriptValue(-6.37e-8)",
+ "QScriptValue(0x43211234)",
+ "QScriptValue(0x10000)",
+ "QScriptValue(0x10001)",
+ "QScriptValue(qSNaN())",
+ "QScriptValue(qQNaN())",
+ "QScriptValue(qInf())",
+ "QScriptValue(-qInf())",
+ "QScriptValue(\"NaN\")",
+ "QScriptValue(\"Infinity\")",
+ "QScriptValue(\"-Infinity\")",
+ "QScriptValue(\"ciao\")",
+ "QScriptValue(QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(QString(\"\"))",
+ "QScriptValue(QString())",
+ "QScriptValue(QString(\"0\"))",
+ "QScriptValue(QString(\"123\"))",
+ "QScriptValue(QString(\"12.4\"))",
+ "QScriptValue(0, QScriptValue::UndefinedValue)",
+ "QScriptValue(0, QScriptValue::NullValue)",
+ "QScriptValue(0, true)",
+ "QScriptValue(0, false)",
+ "QScriptValue(0, int(122))",
+ "QScriptValue(0, uint(124))",
+ "QScriptValue(0, 0)",
+ "QScriptValue(0, 0.0)",
+ "QScriptValue(0, 123.0)",
+ "QScriptValue(0, 6.37e-8)",
+ "QScriptValue(0, -6.37e-8)",
+ "QScriptValue(0, 0x43211234)",
+ "QScriptValue(0, 0x10000)",
+ "QScriptValue(0, 0x10001)",
+ "QScriptValue(0, qSNaN())",
+ "QScriptValue(0, qQNaN())",
+ "QScriptValue(0, qInf())",
+ "QScriptValue(0, -qInf())",
+ "QScriptValue(0, \"NaN\")",
+ "QScriptValue(0, \"Infinity\")",
+ "QScriptValue(0, \"-Infinity\")",
+ "QScriptValue(0, \"ciao\")",
+ "QScriptValue(0, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(0, QString(\"\"))",
+ "QScriptValue(0, QString())",
+ "QScriptValue(0, QString(\"0\"))",
+ "QScriptValue(0, QString(\"123\"))",
+ "QScriptValue(0, QString(\"12.3\"))",
+ "QScriptValue(engine, QScriptValue::UndefinedValue)",
+ "QScriptValue(engine, QScriptValue::NullValue)",
+ "QScriptValue(engine, true)",
+ "QScriptValue(engine, false)",
+ "QScriptValue(engine, int(122))",
+ "QScriptValue(engine, uint(124))",
+ "QScriptValue(engine, 0)",
+ "QScriptValue(engine, 0.0)",
+ "QScriptValue(engine, 123.0)",
+ "QScriptValue(engine, 6.37e-8)",
+ "QScriptValue(engine, -6.37e-8)",
+ "QScriptValue(engine, 0x43211234)",
+ "QScriptValue(engine, 0x10000)",
+ "QScriptValue(engine, 0x10001)",
+ "QScriptValue(engine, qSNaN())",
+ "QScriptValue(engine, qQNaN())",
+ "QScriptValue(engine, qInf())",
+ "QScriptValue(engine, -qInf())",
+ "QScriptValue(engine, \"NaN\")",
+ "QScriptValue(engine, \"Infinity\")",
+ "QScriptValue(engine, \"-Infinity\")",
+ "QScriptValue(engine, \"ciao\")",
+ "QScriptValue(engine, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(engine, QString(\"\"))",
+ "QScriptValue(engine, QString())",
+ "QScriptValue(engine, QString(\"0\"))",
+ "QScriptValue(engine, QString(\"123\"))",
+ "QScriptValue(engine, QString(\"1.23\"))",
+ "engine->evaluate(\"[]\")",
+ "engine->evaluate(\"{}\")",
+ "engine->evaluate(\"Object.prototype\")",
+ "engine->evaluate(\"Date.prototype\")",
+ "engine->evaluate(\"Array.prototype\")",
+ "engine->evaluate(\"Function.prototype\")",
+ "engine->evaluate(\"Error.prototype\")",
+ "engine->evaluate(\"Object\")",
+ "engine->evaluate(\"Array\")",
+ "engine->evaluate(\"Number\")",
+ "engine->evaluate(\"Function\")",
+ "engine->evaluate(\"(function() { return 1; })\")",
+ "engine->evaluate(\"(function() { return 'ciao'; })\")",
+ "engine->evaluate(\"(function() { throw new Error('foo'); })\")",
+ "engine->evaluate(\"/foo/\")",
+ "engine->evaluate(\"new Object()\")",
+ "engine->evaluate(\"new Array()\")",
+ "engine->evaluate(\"new Error()\")",
+ "engine->evaluate(\"a = new Object(); a.foo = 22; a.foo\")",
+ "engine->evaluate(\"Undefined\")",
+ "engine->evaluate(\"Null\")",
+ "engine->evaluate(\"True\")",
+ "engine->evaluate(\"False\")",
+ "engine->evaluate(\"undefined\")",
+ "engine->evaluate(\"null\")",
+ "engine->evaluate(\"true\")",
+ "engine->evaluate(\"false\")",
+ "engine->evaluate(\"122\")",
+ "engine->evaluate(\"124\")",
+ "engine->evaluate(\"0\")",
+ "engine->evaluate(\"0.0\")",
+ "engine->evaluate(\"123.0\")",
+ "engine->evaluate(\"6.37e-8\")",
+ "engine->evaluate(\"-6.37e-8\")",
+ "engine->evaluate(\"0x43211234\")",
+ "engine->evaluate(\"0x10000\")",
+ "engine->evaluate(\"0x10001\")",
+ "engine->evaluate(\"NaN\")",
+ "engine->evaluate(\"Infinity\")",
+ "engine->evaluate(\"-Infinity\")",
+ "engine->evaluate(\"'ciao'\")",
+ "engine->evaluate(\"''\")",
+ "engine->evaluate(\"'0'\")",
+ "engine->evaluate(\"'123'\")",
+ "engine->evaluate(\"'12.4'\")",
+ "engine->nullValue()",
+ "engine->undefinedValue()",
+ "engine->newObject()",
+ "engine->newArray()",
+ "engine->newArray(10)"};
+
+static const bool toBoolean_valueArray[] = {
+ false, false,
+ false, true,
+ false, true,
+ true, false,
+ false, true,
+ true, true,
+ true, true,
+ true, false,
+ false, true,
+ true, true,
+ true, true,
+ true, true,
+ false, false,
+ true, true,
+ true, false,
+ false, true,
+ false, true,
+ true, false,
+ false, true,
+ true, true,
+ true, true,
+ true, false,
+ false, true,
+ true, true,
+ true, true,
+ true, true,
+ false, false,
+ true, true,
+ true, false,
+ false, true,
+ false, true,
+ true, false,
+ false, true,
+ true, true,
+ true, true,
+ true, false,
+ false, true,
+ true, true,
+ true, true,
+ true, true,
+ false, false,
+ true, true,
+ true, true,
+ false, true,
+ true, true,
+ true, true,
+ true, true,
+ true, true,
+ true, true,
+ true, true,
+ true, true,
+ true, true,
+ true, true,
+ true, true,
+ false, false,
+ true, false,
+ true, true,
+ false, false,
+ true, true,
+ true, true,
+ true, true,
+ false, true,
+ true, true,
+ false, true,
+ true, true,
+ false, false,
+ true, true,
+ true};
+
+void tst_QScriptValue::toBoolean_data()
+{
+ QTest::addColumn<QScriptValue>("value");
+ QTest::addColumn<bool>("expected");
+ if (m_engine)
+ delete m_engine;
+ m_engine = new QScriptEngine();
+ QHash<QString, bool> expectedValue;
+ expectedValue.reserve(135);
+ for (uint i = 0; i < 135; ++i)
+ expectedValue.insert(toBoolean_tagArray[i], toBoolean_valueArray[i]);
+ for (uint i = 0; i < 135; ++i) {
+ QPair<QString, QScriptValue> testcase = initScriptValues(i);
+ QTest::newRow(testcase.first.toAscii().constData()) << testcase.second << expectedValue[testcase.first];
+ }
+}
+
+void tst_QScriptValue::toBoolean()
+{
+ QFETCH(QScriptValue, value);
+ QFETCH(bool, expected);
+ QCOMPARE(value.toBoolean(), expected);
+ QCOMPARE(value.toBoolean(), expected);
+}
+
+static const QString toInteger_tagArray[] = {
+ "QScriptValue()",
+ "QScriptValue(QScriptValue::UndefinedValue)",
+ "QScriptValue(QScriptValue::NullValue)",
+ "QScriptValue(true)",
+ "QScriptValue(false)",
+ "QScriptValue(int(122))",
+ "QScriptValue(uint(124))",
+ "QScriptValue(0)",
+ "QScriptValue(0.0)",
+ "QScriptValue(123.0)",
+ "QScriptValue(6.37e-8)",
+ "QScriptValue(-6.37e-8)",
+ "QScriptValue(0x43211234)",
+ "QScriptValue(0x10000)",
+ "QScriptValue(0x10001)",
+ "QScriptValue(qSNaN())",
+ "QScriptValue(qQNaN())",
+ "QScriptValue(qInf())",
+ "QScriptValue(-qInf())",
+ "QScriptValue(\"NaN\")",
+ "QScriptValue(\"Infinity\")",
+ "QScriptValue(\"-Infinity\")",
+ "QScriptValue(\"ciao\")",
+ "QScriptValue(QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(QString(\"\"))",
+ "QScriptValue(QString())",
+ "QScriptValue(QString(\"0\"))",
+ "QScriptValue(QString(\"123\"))",
+ "QScriptValue(QString(\"12.4\"))",
+ "QScriptValue(0, QScriptValue::UndefinedValue)",
+ "QScriptValue(0, QScriptValue::NullValue)",
+ "QScriptValue(0, true)",
+ "QScriptValue(0, false)",
+ "QScriptValue(0, int(122))",
+ "QScriptValue(0, uint(124))",
+ "QScriptValue(0, 0)",
+ "QScriptValue(0, 0.0)",
+ "QScriptValue(0, 123.0)",
+ "QScriptValue(0, 6.37e-8)",
+ "QScriptValue(0, -6.37e-8)",
+ "QScriptValue(0, 0x43211234)",
+ "QScriptValue(0, 0x10000)",
+ "QScriptValue(0, 0x10001)",
+ "QScriptValue(0, qSNaN())",
+ "QScriptValue(0, qQNaN())",
+ "QScriptValue(0, qInf())",
+ "QScriptValue(0, -qInf())",
+ "QScriptValue(0, \"NaN\")",
+ "QScriptValue(0, \"Infinity\")",
+ "QScriptValue(0, \"-Infinity\")",
+ "QScriptValue(0, \"ciao\")",
+ "QScriptValue(0, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(0, QString(\"\"))",
+ "QScriptValue(0, QString())",
+ "QScriptValue(0, QString(\"0\"))",
+ "QScriptValue(0, QString(\"123\"))",
+ "QScriptValue(0, QString(\"12.3\"))",
+ "QScriptValue(engine, QScriptValue::UndefinedValue)",
+ "QScriptValue(engine, QScriptValue::NullValue)",
+ "QScriptValue(engine, true)",
+ "QScriptValue(engine, false)",
+ "QScriptValue(engine, int(122))",
+ "QScriptValue(engine, uint(124))",
+ "QScriptValue(engine, 0)",
+ "QScriptValue(engine, 0.0)",
+ "QScriptValue(engine, 123.0)",
+ "QScriptValue(engine, 6.37e-8)",
+ "QScriptValue(engine, -6.37e-8)",
+ "QScriptValue(engine, 0x43211234)",
+ "QScriptValue(engine, 0x10000)",
+ "QScriptValue(engine, 0x10001)",
+ "QScriptValue(engine, qSNaN())",
+ "QScriptValue(engine, qQNaN())",
+ "QScriptValue(engine, qInf())",
+ "QScriptValue(engine, -qInf())",
+ "QScriptValue(engine, \"NaN\")",
+ "QScriptValue(engine, \"Infinity\")",
+ "QScriptValue(engine, \"-Infinity\")",
+ "QScriptValue(engine, \"ciao\")",
+ "QScriptValue(engine, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(engine, QString(\"\"))",
+ "QScriptValue(engine, QString())",
+ "QScriptValue(engine, QString(\"0\"))",
+ "QScriptValue(engine, QString(\"123\"))",
+ "QScriptValue(engine, QString(\"1.23\"))",
+ "engine->evaluate(\"[]\")",
+ "engine->evaluate(\"{}\")",
+ "engine->evaluate(\"Object.prototype\")",
+ "engine->evaluate(\"Date.prototype\")",
+ "engine->evaluate(\"Array.prototype\")",
+ "engine->evaluate(\"Function.prototype\")",
+ "engine->evaluate(\"Error.prototype\")",
+ "engine->evaluate(\"Object\")",
+ "engine->evaluate(\"Array\")",
+ "engine->evaluate(\"Number\")",
+ "engine->evaluate(\"Function\")",
+ "engine->evaluate(\"(function() { return 1; })\")",
+ "engine->evaluate(\"(function() { return 'ciao'; })\")",
+ "engine->evaluate(\"(function() { throw new Error('foo'); })\")",
+ "engine->evaluate(\"/foo/\")",
+ "engine->evaluate(\"new Object()\")",
+ "engine->evaluate(\"new Array()\")",
+ "engine->evaluate(\"new Error()\")",
+ "engine->evaluate(\"a = new Object(); a.foo = 22; a.foo\")",
+ "engine->evaluate(\"Undefined\")",
+ "engine->evaluate(\"Null\")",
+ "engine->evaluate(\"True\")",
+ "engine->evaluate(\"False\")",
+ "engine->evaluate(\"undefined\")",
+ "engine->evaluate(\"null\")",
+ "engine->evaluate(\"true\")",
+ "engine->evaluate(\"false\")",
+ "engine->evaluate(\"122\")",
+ "engine->evaluate(\"124\")",
+ "engine->evaluate(\"0\")",
+ "engine->evaluate(\"0.0\")",
+ "engine->evaluate(\"123.0\")",
+ "engine->evaluate(\"6.37e-8\")",
+ "engine->evaluate(\"-6.37e-8\")",
+ "engine->evaluate(\"0x43211234\")",
+ "engine->evaluate(\"0x10000\")",
+ "engine->evaluate(\"0x10001\")",
+ "engine->evaluate(\"NaN\")",
+ "engine->evaluate(\"Infinity\")",
+ "engine->evaluate(\"-Infinity\")",
+ "engine->evaluate(\"'ciao'\")",
+ "engine->evaluate(\"''\")",
+ "engine->evaluate(\"'0'\")",
+ "engine->evaluate(\"'123'\")",
+ "engine->evaluate(\"'12.4'\")",
+ "engine->nullValue()",
+ "engine->undefinedValue()",
+ "engine->newObject()",
+ "engine->newArray()",
+ "engine->newArray(10)"};
+
+static const qsreal toInteger_valueArray[] = {
+ 0, 0, 0, 1, 0, 122, 124, 0, 0, 123,
+ 0, 0, 1126240820, 65536, 65537, 0, 0, qInf(), qInf(), 0,
+ qInf(), qInf(), 0, 0, 0, 0, 0, 123, 12, 0,
+ 0, 1, 0, 122, 124, 0, 0, 123, 0, 0,
+ 1126240820, 65536, 65537, 0, 0, qInf(), qInf(), 0, qInf(), qInf(),
+ 0, 0, 0, 0, 0, 123, 12, 0, 0, 1,
+ 0, 122, 124, 0, 0, 123, 0, 0, 1126240820, 65536,
+ 65537, 0, 0, qInf(), qInf(), 0, qInf(), qInf(), 0, 0,
+ 0, 0, 0, 123, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 22, 0, 0, 0, 0, 0, 0,
+ 1, 0, 122, 124, 0, 0, 123, 0, 0, 1126240820,
+ 65536, 65537, 0, qInf(), qInf(), 0, 0, 0, 123, 12,
+ 0, 0, 0, 0, 0};
+
+void tst_QScriptValue::toInteger_data()
+{
+ QTest::addColumn<QScriptValue>("value");
+ QTest::addColumn<qsreal>("expected");
+ if (m_engine)
+ delete m_engine;
+ m_engine = new QScriptEngine();
+ QHash<QString, qsreal> expectedValue;
+ expectedValue.reserve(135);
+ for (uint i = 0; i < 135; ++i)
+ expectedValue.insert(toInteger_tagArray[i], toInteger_valueArray[i]);
+ for (uint i = 0; i < 135; ++i) {
+ QPair<QString, QScriptValue> testcase = initScriptValues(i);
+ QTest::newRow(testcase.first.toAscii().constData()) << testcase.second << expectedValue[testcase.first];
+ }
+}
+
+void tst_QScriptValue::toInteger()
+{
+ QFETCH(QScriptValue, value);
+ QFETCH(qsreal, expected);
+ if (qIsInf(expected)) {
+ QVERIFY(qIsInf(value.toInteger()));
+ QVERIFY(qIsInf(value.toInteger()));
+ return;
+ }
+ QCOMPARE(value.toInteger(), expected);
+ QCOMPARE(value.toInteger(), expected);
+}
+
+static const QString toInt32_tagArray[] = {
+ "QScriptValue()",
+ "QScriptValue(QScriptValue::UndefinedValue)",
+ "QScriptValue(QScriptValue::NullValue)",
+ "QScriptValue(true)",
+ "QScriptValue(false)",
+ "QScriptValue(int(122))",
+ "QScriptValue(uint(124))",
+ "QScriptValue(0)",
+ "QScriptValue(0.0)",
+ "QScriptValue(123.0)",
+ "QScriptValue(6.37e-8)",
+ "QScriptValue(-6.37e-8)",
+ "QScriptValue(0x43211234)",
+ "QScriptValue(0x10000)",
+ "QScriptValue(0x10001)",
+ "QScriptValue(qSNaN())",
+ "QScriptValue(qQNaN())",
+ "QScriptValue(qInf())",
+ "QScriptValue(-qInf())",
+ "QScriptValue(\"NaN\")",
+ "QScriptValue(\"Infinity\")",
+ "QScriptValue(\"-Infinity\")",
+ "QScriptValue(\"ciao\")",
+ "QScriptValue(QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(QString(\"\"))",
+ "QScriptValue(QString())",
+ "QScriptValue(QString(\"0\"))",
+ "QScriptValue(QString(\"123\"))",
+ "QScriptValue(QString(\"12.4\"))",
+ "QScriptValue(0, QScriptValue::UndefinedValue)",
+ "QScriptValue(0, QScriptValue::NullValue)",
+ "QScriptValue(0, true)",
+ "QScriptValue(0, false)",
+ "QScriptValue(0, int(122))",
+ "QScriptValue(0, uint(124))",
+ "QScriptValue(0, 0)",
+ "QScriptValue(0, 0.0)",
+ "QScriptValue(0, 123.0)",
+ "QScriptValue(0, 6.37e-8)",
+ "QScriptValue(0, -6.37e-8)",
+ "QScriptValue(0, 0x43211234)",
+ "QScriptValue(0, 0x10000)",
+ "QScriptValue(0, 0x10001)",
+ "QScriptValue(0, qSNaN())",
+ "QScriptValue(0, qQNaN())",
+ "QScriptValue(0, qInf())",
+ "QScriptValue(0, -qInf())",
+ "QScriptValue(0, \"NaN\")",
+ "QScriptValue(0, \"Infinity\")",
+ "QScriptValue(0, \"-Infinity\")",
+ "QScriptValue(0, \"ciao\")",
+ "QScriptValue(0, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(0, QString(\"\"))",
+ "QScriptValue(0, QString())",
+ "QScriptValue(0, QString(\"0\"))",
+ "QScriptValue(0, QString(\"123\"))",
+ "QScriptValue(0, QString(\"12.3\"))",
+ "QScriptValue(engine, QScriptValue::UndefinedValue)",
+ "QScriptValue(engine, QScriptValue::NullValue)",
+ "QScriptValue(engine, true)",
+ "QScriptValue(engine, false)",
+ "QScriptValue(engine, int(122))",
+ "QScriptValue(engine, uint(124))",
+ "QScriptValue(engine, 0)",
+ "QScriptValue(engine, 0.0)",
+ "QScriptValue(engine, 123.0)",
+ "QScriptValue(engine, 6.37e-8)",
+ "QScriptValue(engine, -6.37e-8)",
+ "QScriptValue(engine, 0x43211234)",
+ "QScriptValue(engine, 0x10000)",
+ "QScriptValue(engine, 0x10001)",
+ "QScriptValue(engine, qSNaN())",
+ "QScriptValue(engine, qQNaN())",
+ "QScriptValue(engine, qInf())",
+ "QScriptValue(engine, -qInf())",
+ "QScriptValue(engine, \"NaN\")",
+ "QScriptValue(engine, \"Infinity\")",
+ "QScriptValue(engine, \"-Infinity\")",
+ "QScriptValue(engine, \"ciao\")",
+ "QScriptValue(engine, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(engine, QString(\"\"))",
+ "QScriptValue(engine, QString())",
+ "QScriptValue(engine, QString(\"0\"))",
+ "QScriptValue(engine, QString(\"123\"))",
+ "QScriptValue(engine, QString(\"1.23\"))",
+ "engine->evaluate(\"[]\")",
+ "engine->evaluate(\"{}\")",
+ "engine->evaluate(\"Object.prototype\")",
+ "engine->evaluate(\"Date.prototype\")",
+ "engine->evaluate(\"Array.prototype\")",
+ "engine->evaluate(\"Function.prototype\")",
+ "engine->evaluate(\"Error.prototype\")",
+ "engine->evaluate(\"Object\")",
+ "engine->evaluate(\"Array\")",
+ "engine->evaluate(\"Number\")",
+ "engine->evaluate(\"Function\")",
+ "engine->evaluate(\"(function() { return 1; })\")",
+ "engine->evaluate(\"(function() { return 'ciao'; })\")",
+ "engine->evaluate(\"(function() { throw new Error('foo'); })\")",
+ "engine->evaluate(\"/foo/\")",
+ "engine->evaluate(\"new Object()\")",
+ "engine->evaluate(\"new Array()\")",
+ "engine->evaluate(\"new Error()\")",
+ "engine->evaluate(\"a = new Object(); a.foo = 22; a.foo\")",
+ "engine->evaluate(\"Undefined\")",
+ "engine->evaluate(\"Null\")",
+ "engine->evaluate(\"True\")",
+ "engine->evaluate(\"False\")",
+ "engine->evaluate(\"undefined\")",
+ "engine->evaluate(\"null\")",
+ "engine->evaluate(\"true\")",
+ "engine->evaluate(\"false\")",
+ "engine->evaluate(\"122\")",
+ "engine->evaluate(\"124\")",
+ "engine->evaluate(\"0\")",
+ "engine->evaluate(\"0.0\")",
+ "engine->evaluate(\"123.0\")",
+ "engine->evaluate(\"6.37e-8\")",
+ "engine->evaluate(\"-6.37e-8\")",
+ "engine->evaluate(\"0x43211234\")",
+ "engine->evaluate(\"0x10000\")",
+ "engine->evaluate(\"0x10001\")",
+ "engine->evaluate(\"NaN\")",
+ "engine->evaluate(\"Infinity\")",
+ "engine->evaluate(\"-Infinity\")",
+ "engine->evaluate(\"'ciao'\")",
+ "engine->evaluate(\"''\")",
+ "engine->evaluate(\"'0'\")",
+ "engine->evaluate(\"'123'\")",
+ "engine->evaluate(\"'12.4'\")",
+ "engine->nullValue()",
+ "engine->undefinedValue()",
+ "engine->newObject()",
+ "engine->newArray()",
+ "engine->newArray(10)"};
+
+static const qint32 toInt32_valueArray[] = {
+ 0, 0,
+ 0, 1,
+ 0, 122,
+ 124, 0,
+ 0, 123,
+ 0, 0,
+ 1126240820, 65536,
+ 65537, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 123,
+ 12, 0,
+ 0, 1,
+ 0, 122,
+ 124, 0,
+ 0, 123,
+ 0, 0,
+ 1126240820, 65536,
+ 65537, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 123,
+ 12, 0,
+ 0, 1,
+ 0, 122,
+ 124, 0,
+ 0, 123,
+ 0, 0,
+ 1126240820, 65536,
+ 65537, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 123,
+ 1, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 22,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 1, 0,
+ 122, 124,
+ 0, 0,
+ 123, 0,
+ 0, 1126240820,
+ 65536, 65537,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 123, 12,
+ 0, 0,
+ 0, 0,
+ 0};
+
+void tst_QScriptValue::toInt32_data()
+{
+ QTest::addColumn<QScriptValue>("value");
+ QTest::addColumn<qint32>("expected");
+ if (m_engine)
+ delete m_engine;
+ m_engine = new QScriptEngine();
+ QHash<QString, qint32> expectedValue;
+ expectedValue.reserve(135);
+ for (uint i = 0; i < 135; ++i)
+ expectedValue.insert(toInt32_tagArray[i], toInt32_valueArray[i]);
+ for (uint i = 0; i < 135; ++i) {
+ QPair<QString, QScriptValue> testcase = initScriptValues(i);
+ QTest::newRow(testcase.first.toAscii().constData()) << testcase.second << expectedValue[testcase.first];
+ }
+}
+
+void tst_QScriptValue::toInt32()
+{
+ QFETCH(QScriptValue, value);
+ QFETCH(qint32, expected);
+ QCOMPARE(value.toInt32(), expected);
+ QCOMPARE(value.toInt32(), expected);
+}
+
+static const QString toUInt32_tagArray[] = {
+ "QScriptValue()",
+ "QScriptValue(QScriptValue::UndefinedValue)",
+ "QScriptValue(QScriptValue::NullValue)",
+ "QScriptValue(true)",
+ "QScriptValue(false)",
+ "QScriptValue(int(122))",
+ "QScriptValue(uint(124))",
+ "QScriptValue(0)",
+ "QScriptValue(0.0)",
+ "QScriptValue(123.0)",
+ "QScriptValue(6.37e-8)",
+ "QScriptValue(-6.37e-8)",
+ "QScriptValue(0x43211234)",
+ "QScriptValue(0x10000)",
+ "QScriptValue(0x10001)",
+ "QScriptValue(qSNaN())",
+ "QScriptValue(qQNaN())",
+ "QScriptValue(qInf())",
+ "QScriptValue(-qInf())",
+ "QScriptValue(\"NaN\")",
+ "QScriptValue(\"Infinity\")",
+ "QScriptValue(\"-Infinity\")",
+ "QScriptValue(\"ciao\")",
+ "QScriptValue(QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(QString(\"\"))",
+ "QScriptValue(QString())",
+ "QScriptValue(QString(\"0\"))",
+ "QScriptValue(QString(\"123\"))",
+ "QScriptValue(QString(\"12.4\"))",
+ "QScriptValue(0, QScriptValue::UndefinedValue)",
+ "QScriptValue(0, QScriptValue::NullValue)",
+ "QScriptValue(0, true)",
+ "QScriptValue(0, false)",
+ "QScriptValue(0, int(122))",
+ "QScriptValue(0, uint(124))",
+ "QScriptValue(0, 0)",
+ "QScriptValue(0, 0.0)",
+ "QScriptValue(0, 123.0)",
+ "QScriptValue(0, 6.37e-8)",
+ "QScriptValue(0, -6.37e-8)",
+ "QScriptValue(0, 0x43211234)",
+ "QScriptValue(0, 0x10000)",
+ "QScriptValue(0, 0x10001)",
+ "QScriptValue(0, qSNaN())",
+ "QScriptValue(0, qQNaN())",
+ "QScriptValue(0, qInf())",
+ "QScriptValue(0, -qInf())",
+ "QScriptValue(0, \"NaN\")",
+ "QScriptValue(0, \"Infinity\")",
+ "QScriptValue(0, \"-Infinity\")",
+ "QScriptValue(0, \"ciao\")",
+ "QScriptValue(0, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(0, QString(\"\"))",
+ "QScriptValue(0, QString())",
+ "QScriptValue(0, QString(\"0\"))",
+ "QScriptValue(0, QString(\"123\"))",
+ "QScriptValue(0, QString(\"12.3\"))",
+ "QScriptValue(engine, QScriptValue::UndefinedValue)",
+ "QScriptValue(engine, QScriptValue::NullValue)",
+ "QScriptValue(engine, true)",
+ "QScriptValue(engine, false)",
+ "QScriptValue(engine, int(122))",
+ "QScriptValue(engine, uint(124))",
+ "QScriptValue(engine, 0)",
+ "QScriptValue(engine, 0.0)",
+ "QScriptValue(engine, 123.0)",
+ "QScriptValue(engine, 6.37e-8)",
+ "QScriptValue(engine, -6.37e-8)",
+ "QScriptValue(engine, 0x43211234)",
+ "QScriptValue(engine, 0x10000)",
+ "QScriptValue(engine, 0x10001)",
+ "QScriptValue(engine, qSNaN())",
+ "QScriptValue(engine, qQNaN())",
+ "QScriptValue(engine, qInf())",
+ "QScriptValue(engine, -qInf())",
+ "QScriptValue(engine, \"NaN\")",
+ "QScriptValue(engine, \"Infinity\")",
+ "QScriptValue(engine, \"-Infinity\")",
+ "QScriptValue(engine, \"ciao\")",
+ "QScriptValue(engine, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(engine, QString(\"\"))",
+ "QScriptValue(engine, QString())",
+ "QScriptValue(engine, QString(\"0\"))",
+ "QScriptValue(engine, QString(\"123\"))",
+ "QScriptValue(engine, QString(\"1.23\"))",
+ "engine->evaluate(\"[]\")",
+ "engine->evaluate(\"{}\")",
+ "engine->evaluate(\"Object.prototype\")",
+ "engine->evaluate(\"Date.prototype\")",
+ "engine->evaluate(\"Array.prototype\")",
+ "engine->evaluate(\"Function.prototype\")",
+ "engine->evaluate(\"Error.prototype\")",
+ "engine->evaluate(\"Object\")",
+ "engine->evaluate(\"Array\")",
+ "engine->evaluate(\"Number\")",
+ "engine->evaluate(\"Function\")",
+ "engine->evaluate(\"(function() { return 1; })\")",
+ "engine->evaluate(\"(function() { return 'ciao'; })\")",
+ "engine->evaluate(\"(function() { throw new Error('foo'); })\")",
+ "engine->evaluate(\"/foo/\")",
+ "engine->evaluate(\"new Object()\")",
+ "engine->evaluate(\"new Array()\")",
+ "engine->evaluate(\"new Error()\")",
+ "engine->evaluate(\"a = new Object(); a.foo = 22; a.foo\")",
+ "engine->evaluate(\"Undefined\")",
+ "engine->evaluate(\"Null\")",
+ "engine->evaluate(\"True\")",
+ "engine->evaluate(\"False\")",
+ "engine->evaluate(\"undefined\")",
+ "engine->evaluate(\"null\")",
+ "engine->evaluate(\"true\")",
+ "engine->evaluate(\"false\")",
+ "engine->evaluate(\"122\")",
+ "engine->evaluate(\"124\")",
+ "engine->evaluate(\"0\")",
+ "engine->evaluate(\"0.0\")",
+ "engine->evaluate(\"123.0\")",
+ "engine->evaluate(\"6.37e-8\")",
+ "engine->evaluate(\"-6.37e-8\")",
+ "engine->evaluate(\"0x43211234\")",
+ "engine->evaluate(\"0x10000\")",
+ "engine->evaluate(\"0x10001\")",
+ "engine->evaluate(\"NaN\")",
+ "engine->evaluate(\"Infinity\")",
+ "engine->evaluate(\"-Infinity\")",
+ "engine->evaluate(\"'ciao'\")",
+ "engine->evaluate(\"''\")",
+ "engine->evaluate(\"'0'\")",
+ "engine->evaluate(\"'123'\")",
+ "engine->evaluate(\"'12.4'\")",
+ "engine->nullValue()",
+ "engine->undefinedValue()",
+ "engine->newObject()",
+ "engine->newArray()",
+ "engine->newArray(10)"};
+
+static const quint32 toUInt32_valueArray[] = {
+ 0, 0,
+ 0, 1,
+ 0, 122,
+ 124, 0,
+ 0, 123,
+ 0, 0,
+ 1126240820, 65536,
+ 65537, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 123,
+ 12, 0,
+ 0, 1,
+ 0, 122,
+ 124, 0,
+ 0, 123,
+ 0, 0,
+ 1126240820, 65536,
+ 65537, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 123,
+ 12, 0,
+ 0, 1,
+ 0, 122,
+ 124, 0,
+ 0, 123,
+ 0, 0,
+ 1126240820, 65536,
+ 65537, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 123,
+ 1, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 22,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 1, 0,
+ 122, 124,
+ 0, 0,
+ 123, 0,
+ 0, 1126240820,
+ 65536, 65537,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 123, 12,
+ 0, 0,
+ 0, 0,
+ 0};
+
+void tst_QScriptValue::toUInt32_data()
+{
+ QTest::addColumn<QScriptValue>("value");
+ QTest::addColumn<quint32>("expected");
+ if (m_engine)
+ delete m_engine;
+ m_engine = new QScriptEngine();
+ QHash<QString, quint32> expectedValue;
+ expectedValue.reserve(135);
+ for (uint i = 0; i < 135; ++i)
+ expectedValue.insert(toUInt32_tagArray[i], toUInt32_valueArray[i]);
+ for (uint i = 0; i < 135; ++i) {
+ QPair<QString, QScriptValue> testcase = initScriptValues(i);
+ QTest::newRow(testcase.first.toAscii().constData()) << testcase.second << expectedValue[testcase.first];
+ }
+}
+
+void tst_QScriptValue::toUInt32()
+{
+ QFETCH(QScriptValue, value);
+ QFETCH(quint32, expected);
+ QCOMPARE(value.toUInt32(), expected);
+ QCOMPARE(value.toUInt32(), expected);
+}
+
+static const QString toUInt16_tagArray[] = {
+ "QScriptValue()",
+ "QScriptValue(QScriptValue::UndefinedValue)",
+ "QScriptValue(QScriptValue::NullValue)",
+ "QScriptValue(true)",
+ "QScriptValue(false)",
+ "QScriptValue(int(122))",
+ "QScriptValue(uint(124))",
+ "QScriptValue(0)",
+ "QScriptValue(0.0)",
+ "QScriptValue(123.0)",
+ "QScriptValue(6.37e-8)",
+ "QScriptValue(-6.37e-8)",
+ "QScriptValue(0x43211234)",
+ "QScriptValue(0x10000)",
+ "QScriptValue(0x10001)",
+ "QScriptValue(qSNaN())",
+ "QScriptValue(qQNaN())",
+ "QScriptValue(qInf())",
+ "QScriptValue(-qInf())",
+ "QScriptValue(\"NaN\")",
+ "QScriptValue(\"Infinity\")",
+ "QScriptValue(\"-Infinity\")",
+ "QScriptValue(\"ciao\")",
+ "QScriptValue(QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(QString(\"\"))",
+ "QScriptValue(QString())",
+ "QScriptValue(QString(\"0\"))",
+ "QScriptValue(QString(\"123\"))",
+ "QScriptValue(QString(\"12.4\"))",
+ "QScriptValue(0, QScriptValue::UndefinedValue)",
+ "QScriptValue(0, QScriptValue::NullValue)",
+ "QScriptValue(0, true)",
+ "QScriptValue(0, false)",
+ "QScriptValue(0, int(122))",
+ "QScriptValue(0, uint(124))",
+ "QScriptValue(0, 0)",
+ "QScriptValue(0, 0.0)",
+ "QScriptValue(0, 123.0)",
+ "QScriptValue(0, 6.37e-8)",
+ "QScriptValue(0, -6.37e-8)",
+ "QScriptValue(0, 0x43211234)",
+ "QScriptValue(0, 0x10000)",
+ "QScriptValue(0, 0x10001)",
+ "QScriptValue(0, qSNaN())",
+ "QScriptValue(0, qQNaN())",
+ "QScriptValue(0, qInf())",
+ "QScriptValue(0, -qInf())",
+ "QScriptValue(0, \"NaN\")",
+ "QScriptValue(0, \"Infinity\")",
+ "QScriptValue(0, \"-Infinity\")",
+ "QScriptValue(0, \"ciao\")",
+ "QScriptValue(0, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(0, QString(\"\"))",
+ "QScriptValue(0, QString())",
+ "QScriptValue(0, QString(\"0\"))",
+ "QScriptValue(0, QString(\"123\"))",
+ "QScriptValue(0, QString(\"12.3\"))",
+ "QScriptValue(engine, QScriptValue::UndefinedValue)",
+ "QScriptValue(engine, QScriptValue::NullValue)",
+ "QScriptValue(engine, true)",
+ "QScriptValue(engine, false)",
+ "QScriptValue(engine, int(122))",
+ "QScriptValue(engine, uint(124))",
+ "QScriptValue(engine, 0)",
+ "QScriptValue(engine, 0.0)",
+ "QScriptValue(engine, 123.0)",
+ "QScriptValue(engine, 6.37e-8)",
+ "QScriptValue(engine, -6.37e-8)",
+ "QScriptValue(engine, 0x43211234)",
+ "QScriptValue(engine, 0x10000)",
+ "QScriptValue(engine, 0x10001)",
+ "QScriptValue(engine, qSNaN())",
+ "QScriptValue(engine, qQNaN())",
+ "QScriptValue(engine, qInf())",
+ "QScriptValue(engine, -qInf())",
+ "QScriptValue(engine, \"NaN\")",
+ "QScriptValue(engine, \"Infinity\")",
+ "QScriptValue(engine, \"-Infinity\")",
+ "QScriptValue(engine, \"ciao\")",
+ "QScriptValue(engine, QString::fromLatin1(\"ciao\"))",
+ "QScriptValue(engine, QString(\"\"))",
+ "QScriptValue(engine, QString())",
+ "QScriptValue(engine, QString(\"0\"))",
+ "QScriptValue(engine, QString(\"123\"))",
+ "QScriptValue(engine, QString(\"1.23\"))",
+ "engine->evaluate(\"[]\")",
+ "engine->evaluate(\"{}\")",
+ "engine->evaluate(\"Object.prototype\")",
+ "engine->evaluate(\"Date.prototype\")",
+ "engine->evaluate(\"Array.prototype\")",
+ "engine->evaluate(\"Function.prototype\")",
+ "engine->evaluate(\"Error.prototype\")",
+ "engine->evaluate(\"Object\")",
+ "engine->evaluate(\"Array\")",
+ "engine->evaluate(\"Number\")",
+ "engine->evaluate(\"Function\")",
+ "engine->evaluate(\"(function() { return 1; })\")",
+ "engine->evaluate(\"(function() { return 'ciao'; })\")",
+ "engine->evaluate(\"(function() { throw new Error('foo'); })\")",
+ "engine->evaluate(\"/foo/\")",
+ "engine->evaluate(\"new Object()\")",
+ "engine->evaluate(\"new Array()\")",
+ "engine->evaluate(\"new Error()\")",
+ "engine->evaluate(\"a = new Object(); a.foo = 22; a.foo\")",
+ "engine->evaluate(\"Undefined\")",
+ "engine->evaluate(\"Null\")",
+ "engine->evaluate(\"True\")",
+ "engine->evaluate(\"False\")",
+ "engine->evaluate(\"undefined\")",
+ "engine->evaluate(\"null\")",
+ "engine->evaluate(\"true\")",
+ "engine->evaluate(\"false\")",
+ "engine->evaluate(\"122\")",
+ "engine->evaluate(\"124\")",
+ "engine->evaluate(\"0\")",
+ "engine->evaluate(\"0.0\")",
+ "engine->evaluate(\"123.0\")",
+ "engine->evaluate(\"6.37e-8\")",
+ "engine->evaluate(\"-6.37e-8\")",
+ "engine->evaluate(\"0x43211234\")",
+ "engine->evaluate(\"0x10000\")",
+ "engine->evaluate(\"0x10001\")",
+ "engine->evaluate(\"NaN\")",
+ "engine->evaluate(\"Infinity\")",
+ "engine->evaluate(\"-Infinity\")",
+ "engine->evaluate(\"'ciao'\")",
+ "engine->evaluate(\"''\")",
+ "engine->evaluate(\"'0'\")",
+ "engine->evaluate(\"'123'\")",
+ "engine->evaluate(\"'12.4'\")",
+ "engine->nullValue()",
+ "engine->undefinedValue()",
+ "engine->newObject()",
+ "engine->newArray()",
+ "engine->newArray(10)"};
+
+static const quint16 toUInt16_valueArray[] = {
+ 0, 0,
+ 0, 1,
+ 0, 122,
+ 124, 0,
+ 0, 123,
+ 0, 0,
+ 4660, 0,
+ 1, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 123,
+ 12, 0,
+ 0, 1,
+ 0, 122,
+ 124, 0,
+ 0, 123,
+ 0, 0,
+ 4660, 0,
+ 1, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 123,
+ 12, 0,
+ 0, 1,
+ 0, 122,
+ 124, 0,
+ 0, 123,
+ 0, 0,
+ 4660, 0,
+ 1, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 123,
+ 1, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 22,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 1, 0,
+ 122, 124,
+ 0, 0,
+ 123, 0,
+ 0, 4660,
+ 0, 1,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 123, 12,
+ 0, 0,
+ 0, 0,
+ 0};
+
+void tst_QScriptValue::toUInt16_data()
+{
+ QTest::addColumn<QScriptValue>("value");
+ QTest::addColumn<quint16>("expected");
+ if (m_engine)
+ delete m_engine;
+ m_engine = new QScriptEngine();
+ QHash<QString, quint16> expectedValue;
+ expectedValue.reserve(135);
+ for (uint i = 0; i < 135; ++i)
+ expectedValue.insert(toUInt16_tagArray[i], toUInt16_valueArray[i]);
+ for (uint i = 0; i < 135; ++i) {
+ QPair<QString, QScriptValue> testcase = initScriptValues(i);
+ QTest::newRow(testcase.first.toAscii().constData()) << testcase.second << expectedValue[testcase.first];
+ }
+}
+
+void tst_QScriptValue::toUInt16()
+{
+ QFETCH(QScriptValue, value);
+ QFETCH(quint16, expected);
+ QCOMPARE(value.toUInt16(), expected);
+ QCOMPARE(value.toUInt16(), expected);
+}
--- /dev/null
+TEMPLATE = app
+TARGET = tst_qscriptvalueiterator
+QT += testlib
+include(../tests.pri)
+
+SOURCES += tst_qscriptvalueiterator.cpp
+
--- /dev/null
+/*
+ Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+ 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.
+*/
+
+#ifndef tst_qscriptvalueiterator_h
+#define tst_qscriptvalueiterator_h
+
+#include "qscriptengine.h"
+#include "qscriptvalue.h"
+#include "qscriptvalueiterator.h"
+#include <QtCore/qhash.h>
+#include <QtTest/QtTest>
+
+class tst_QScriptValueIterator : public QObject {
+ Q_OBJECT
+
+public:
+ tst_QScriptValueIterator();
+ virtual ~tst_QScriptValueIterator();
+
+private slots:
+ void iterateForward_data();
+ void iterateForward();
+ void iterateBackward_data();
+ void iterateBackward();
+ void iterateArray_data();
+ void iterateArray();
+ void iterateBackAndForth();
+ void setValue();
+ void remove();
+ void removeMixed();
+ void removeUndeletable();
+ void iterateString();
+ void assignObjectToIterator();
+};
+
+tst_QScriptValueIterator::tst_QScriptValueIterator()
+{
+}
+
+tst_QScriptValueIterator::~tst_QScriptValueIterator()
+{
+}
+
+void tst_QScriptValueIterator::iterateForward_data()
+{
+ QTest::addColumn<QStringList>("propertyNames");
+ QTest::addColumn<QStringList>("propertyValues");
+
+ QTest::newRow("no properties")
+ << QStringList() << QStringList();
+ QTest::newRow("foo=bar")
+ << (QStringList() << "foo")
+ << (QStringList() << "bar");
+ QTest::newRow("foo=bar, baz=123")
+ << (QStringList() << "foo" << "baz")
+ << (QStringList() << "bar" << "123");
+ QTest::newRow("foo=bar, baz=123, rab=oof")
+ << (QStringList() << "foo" << "baz" << "rab")
+ << (QStringList() << "bar" << "123" << "oof");
+}
+
+void tst_QScriptValueIterator::iterateForward()
+{
+ QFETCH(QStringList, propertyNames);
+ QFETCH(QStringList, propertyValues);
+ QMap<QString, QString> pmap;
+ Q_ASSERT(propertyNames.size() == propertyValues.size());
+
+ QScriptEngine engine;
+ QScriptValue object = engine.newObject();
+ for (int i = 0; i < propertyNames.size(); ++i) {
+ QString name = propertyNames.at(i);
+ QString value = propertyValues.at(i);
+ pmap.insert(name, value);
+ object.setProperty(name, QScriptValue(&engine, value));
+ }
+ QScriptValue otherObject = engine.newObject();
+ otherObject.setProperty("foo", QScriptValue(&engine, 123456));
+ otherObject.setProperty("protoProperty", QScriptValue(&engine, 654321));
+ object.setPrototype(otherObject); // should not affect iterator
+
+ QStringList lst;
+ QScriptValueIterator it(object);
+ while (!pmap.isEmpty()) {
+ QCOMPARE(it.hasNext(), true);
+ QCOMPARE(it.hasNext(), true);
+ it.next();
+ QString name = it.name();
+ QCOMPARE(pmap.contains(name), true);
+ QCOMPARE(it.name(), name);
+ QCOMPARE(it.flags(), object.propertyFlags(name));
+ QCOMPARE(it.value().strictlyEquals(QScriptValue(&engine, pmap.value(name))), true);
+ QCOMPARE(it.scriptName(), engine.toStringHandle(name));
+ pmap.remove(name);
+ lst.append(name);
+ }
+
+ QCOMPARE(it.hasNext(), false);
+ QCOMPARE(it.hasNext(), false);
+
+ it.toFront();
+ for (int i = 0; i < lst.count(); ++i) {
+ QCOMPARE(it.hasNext(), true);
+ it.next();
+ QCOMPARE(it.name(), lst.at(i));
+ }
+
+ for (int i = 0; i < lst.count(); ++i) {
+ QCOMPARE(it.hasPrevious(), true);
+ it.previous();
+ QCOMPARE(it.name(), lst.at(lst.count()-1-i));
+ }
+ QCOMPARE(it.hasPrevious(), false);
+}
+
+void tst_QScriptValueIterator::iterateBackward_data()
+{
+ iterateForward_data();
+}
+
+void tst_QScriptValueIterator::iterateBackward()
+{
+ QFETCH(QStringList, propertyNames);
+ QFETCH(QStringList, propertyValues);
+ QMap<QString, QString> pmap;
+ Q_ASSERT(propertyNames.size() == propertyValues.size());
+
+ QScriptEngine engine;
+ QScriptValue object = engine.newObject();
+ for (int i = 0; i < propertyNames.size(); ++i) {
+ QString name = propertyNames.at(i);
+ QString value = propertyValues.at(i);
+ pmap.insert(name, value);
+ object.setProperty(name, QScriptValue(&engine, value));
+ }
+
+ QStringList lst;
+ QScriptValueIterator it(object);
+ it.toBack();
+ while (!pmap.isEmpty()) {
+ QCOMPARE(it.hasPrevious(), true);
+ QCOMPARE(it.hasPrevious(), true);
+ it.previous();
+ QString name = it.name();
+ QCOMPARE(pmap.contains(name), true);
+ QCOMPARE(it.name(), name);
+ QCOMPARE(it.flags(), object.propertyFlags(name));
+ QCOMPARE(it.value().strictlyEquals(QScriptValue(&engine, pmap.value(name))), true);
+ pmap.remove(name);
+ lst.append(name);
+ }
+
+ QCOMPARE(it.hasPrevious(), false);
+ QCOMPARE(it.hasPrevious(), false);
+
+ it.toBack();
+ for (int i = 0; i < lst.count(); ++i) {
+ QCOMPARE(it.hasPrevious(), true);
+ it.previous();
+ QCOMPARE(it.name(), lst.at(i));
+ }
+
+ for (int i = 0; i < lst.count(); ++i) {
+ QCOMPARE(it.hasNext(), true);
+ it.next();
+ QCOMPARE(it.name(), lst.at(lst.count()-1-i));
+ }
+ QCOMPARE(it.hasNext(), false);
+}
+
+void tst_QScriptValueIterator::iterateArray_data()
+{
+ QTest::addColumn<QStringList>("inputPropertyNames");
+ QTest::addColumn<QStringList>("inputPropertyValues");
+ QTest::addColumn<QStringList>("propertyNames");
+ QTest::addColumn<QStringList>("propertyValues");
+ QTest::newRow("no elements") << QStringList() << QStringList() << QStringList() << QStringList();
+
+ QTest::newRow("0=foo, 1=barr")
+ << (QStringList() << "0" << "1")
+ << (QStringList() << "foo" << "bar")
+ << (QStringList() << "0" << "1")
+ << (QStringList() << "foo" << "bar");
+
+ QTest::newRow("0=foo, 3=barr")
+ << (QStringList() << "0" << "1" << "2" << "3")
+ << (QStringList() << "foo" << "" << "" << "bar")
+ << (QStringList() << "0" << "1" << "2" << "3")
+ << (QStringList() << "foo" << "" << "" << "bar");
+}
+
+void tst_QScriptValueIterator::iterateArray()
+{
+ QFETCH(QStringList, inputPropertyNames);
+ QFETCH(QStringList, inputPropertyValues);
+ QFETCH(QStringList, propertyNames);
+ QFETCH(QStringList, propertyValues);
+
+ QScriptEngine engine;
+ QScriptValue array = engine.newArray();
+ for (int i = 0; i < inputPropertyNames.size(); ++i)
+ array.setProperty(inputPropertyNames.at(i), inputPropertyValues.at(i));
+
+ int length = array.property("length").toInt32();
+ QCOMPARE(length, propertyNames.size());
+ QScriptValueIterator it(array);
+ for (int i = 0; i < length; ++i) {
+ QCOMPARE(it.hasNext(), true);
+ it.next();
+ QCOMPARE(it.name(), propertyNames.at(i));
+ QCOMPARE(it.flags(), array.propertyFlags(propertyNames.at(i)));
+ QVERIFY(it.value().strictlyEquals(array.property(propertyNames.at(i))));
+ QCOMPARE(it.value().toString(), propertyValues.at(i));
+ }
+ QVERIFY(it.hasNext());
+ it.next();
+ QCOMPARE(it.name(), QString::fromLatin1("length"));
+ QVERIFY(it.value().isNumber());
+ QCOMPARE(it.value().toInt32(), length);
+ QCOMPARE(it.flags(), QScriptValue::PropertyFlags(QScriptValue::SkipInEnumeration | QScriptValue::Undeletable));
+
+ it.previous();
+ QCOMPARE(it.hasPrevious(), length > 0);
+ for (int i = length - 1; i >= 0; --i) {
+ it.previous();
+ QCOMPARE(it.name(), propertyNames.at(i));
+ QCOMPARE(it.flags(), array.propertyFlags(propertyNames.at(i)));
+ QVERIFY(it.value().strictlyEquals(array.property(propertyNames.at(i))));
+ QCOMPARE(it.value().toString(), propertyValues.at(i));
+ QCOMPARE(it.hasPrevious(), i > 0);
+ }
+ QCOMPARE(it.hasPrevious(), false);
+
+ // hasNext() and hasPrevious() cache their result; verify that the result is in sync
+ if (length > 1) {
+ QVERIFY(it.hasNext());
+ it.next();
+ QCOMPARE(it.name(), QString::fromLatin1("0"));
+ QVERIFY(it.hasNext());
+ it.previous();
+ QCOMPARE(it.name(), QString::fromLatin1("0"));
+ QVERIFY(!it.hasPrevious());
+ it.next();
+ QCOMPARE(it.name(), QString::fromLatin1("0"));
+ QVERIFY(it.hasPrevious());
+ it.next();
+ QCOMPARE(it.name(), QString::fromLatin1("1"));
+ }
+ {
+ // same test as object:
+ QScriptValue originalArray = engine.newArray();
+ for (int i = 0; i < inputPropertyNames.size(); ++i)
+ originalArray.setProperty(inputPropertyNames.at(i), inputPropertyValues.at(i));
+
+ QScriptValue array = originalArray.toObject();
+ int length = array.property("length").toInt32();
+ QCOMPARE(length, propertyNames.size());
+ QScriptValueIterator it(array);
+ for (int i = 0; i < length; ++i) {
+ QCOMPARE(it.hasNext(), true);
+ it.next();
+ QCOMPARE(it.name(), propertyNames.at(i));
+ QCOMPARE(it.flags(), array.propertyFlags(propertyNames.at(i)));
+ QVERIFY(it.value().strictlyEquals(array.property(propertyNames.at(i))));
+ QCOMPARE(it.value().toString(), propertyValues.at(i));
+ }
+ QCOMPARE(it.hasNext(), true);
+ it.next();
+ QCOMPARE(it.name(), QString::fromLatin1("length"));
+ }
+}
+
+void tst_QScriptValueIterator::iterateBackAndForth()
+{
+ QScriptEngine engine;
+ {
+ QScriptValue object = engine.newObject();
+ object.setProperty("foo", QScriptValue(&engine, "bar"));
+ object.setProperty("rab", QScriptValue(&engine, "oof"),
+ QScriptValue::SkipInEnumeration); // should not affect iterator
+ QScriptValueIterator it(object);
+ QVERIFY(it.hasNext());
+ it.next();
+ QCOMPARE(it.name(), QLatin1String("foo"));
+ QVERIFY(it.hasPrevious());
+ it.previous();
+ QCOMPARE(it.name(), QLatin1String("foo"));
+ QVERIFY(it.hasNext());
+ it.next();
+ QCOMPARE(it.name(), QLatin1String("foo"));
+ QVERIFY(it.hasPrevious());
+ it.previous();
+ QCOMPARE(it.name(), QLatin1String("foo"));
+ QVERIFY(it.hasNext());
+ it.next();
+ QCOMPARE(it.name(), QLatin1String("foo"));
+ QVERIFY(it.hasNext());
+ it.next();
+ QCOMPARE(it.name(), QLatin1String("rab"));
+ QVERIFY(it.hasPrevious());
+ it.previous();
+ QCOMPARE(it.name(), QLatin1String("rab"));
+ QVERIFY(it.hasNext());
+ it.next();
+ QCOMPARE(it.name(), QLatin1String("rab"));
+ QVERIFY(it.hasPrevious());
+ it.previous();
+ QCOMPARE(it.name(), QLatin1String("rab"));
+ }
+ {
+ // hasNext() and hasPrevious() cache their result; verify that the result is in sync
+ QScriptValue object = engine.newObject();
+ object.setProperty("foo", QScriptValue(&engine, "bar"));
+ object.setProperty("rab", QScriptValue(&engine, "oof"));
+ QScriptValueIterator it(object);
+ QVERIFY(it.hasNext());
+ it.next();
+ QCOMPARE(it.name(), QString::fromLatin1("foo"));
+ QVERIFY(it.hasNext());
+ it.previous();
+ QCOMPARE(it.name(), QString::fromLatin1("foo"));
+ QVERIFY(!it.hasPrevious());
+ it.next();
+ QCOMPARE(it.name(), QString::fromLatin1("foo"));
+ QVERIFY(it.hasPrevious());
+ it.next();
+ QCOMPARE(it.name(), QString::fromLatin1("rab"));
+ }
+}
+
+void tst_QScriptValueIterator::setValue()
+{
+ QScriptEngine engine;
+ QScriptValue object = engine.newObject();
+ object.setProperty("foo", QScriptValue(&engine, "bar"));
+ QScriptValueIterator it(object);
+ it.next();
+ QCOMPARE(it.name(), QLatin1String("foo"));
+ it.setValue(QScriptValue(&engine, "baz"));
+ QCOMPARE(it.value().strictlyEquals(QScriptValue(&engine, QLatin1String("baz"))), true);
+ QCOMPARE(object.property("foo").toString(), QLatin1String("baz"));
+ it.setValue(QScriptValue(&engine, "zab"));
+ QCOMPARE(it.value().strictlyEquals(QScriptValue(&engine, QLatin1String("zab"))), true);
+ QCOMPARE(object.property("foo").toString(), QLatin1String("zab"));
+}
+
+void tst_QScriptValueIterator::remove()
+{
+ QScriptEngine engine;
+ QScriptValue object = engine.newObject();
+ object.setProperty("foo", QScriptValue(&engine, "bar"),
+ QScriptValue::SkipInEnumeration); // should not affect iterator
+ object.setProperty("rab", QScriptValue(&engine, "oof"));
+ QScriptValueIterator it(object);
+ it.next();
+ QCOMPARE(it.name(), QLatin1String("foo"));
+ it.remove();
+ QCOMPARE(it.hasPrevious(), false);
+ QCOMPARE(object.property("foo").isValid(), false);
+ QCOMPARE(object.property("rab").toString(), QLatin1String("oof"));
+ it.next();
+ QCOMPARE(it.name(), QLatin1String("rab"));
+ QCOMPARE(it.value().toString(), QLatin1String("oof"));
+ QCOMPARE(it.hasNext(), false);
+ it.remove();
+ QCOMPARE(object.property("rab").isValid(), false);
+ QCOMPARE(it.hasPrevious(), false);
+ QCOMPARE(it.hasNext(), false);
+}
+
+void tst_QScriptValueIterator::removeMixed()
+{
+ // This test checks if QScriptValueIterator behaives correctly if an object's property got deleted
+ // in different way.
+ QScriptEngine engine;
+ QScriptValue object = engine.evaluate("o = new Object; o");
+ object.setProperty("a", QScriptValue(124), QScriptValue::SkipInEnumeration);
+ object.setProperty("b", QScriptValue(816));
+ object.setProperty("c", QScriptValue(3264));
+ QScriptValueIterator it(object);
+ it.next();
+ it.next();
+ QCOMPARE(it.name(), QLatin1String("b"));
+ QCOMPARE(it.hasPrevious(), true);
+ QCOMPARE(it.hasNext(), true);
+ // Remove 'a'
+ object.setProperty("a", QScriptValue());
+ QEXPECT_FAIL("", "That would be a significant behavioral and performance change, new QtScript API should be developed (QTBUG-12087)", Abort);
+ QCOMPARE(it.hasPrevious(), false);
+ QCOMPARE(it.hasNext(), true);
+ // Remove 'c'
+ engine.evaluate("delete o.c");
+ QCOMPARE(it.hasPrevious(), false);
+ QCOMPARE(it.hasNext(), false);
+ // Remove 'b'
+ object.setProperty("b", QScriptValue());
+ QCOMPARE(it.hasPrevious(), false);
+ QCOMPARE(it.hasNext(), false);
+ QCOMPARE(it.name(), QString());
+ QCOMPARE(it.value().toString(), QString());
+
+ // Try to remove a removed property.
+ it.remove();
+ QCOMPARE(it.hasPrevious(), false);
+ QCOMPARE(it.hasNext(), false);
+ QCOMPARE(it.name(), QString());
+ QCOMPARE(it.value().toString(), QString());
+
+ for (int i = 0; i < 2; ++i) {
+ it.next();
+ QCOMPARE(it.hasPrevious(), false);
+ QCOMPARE(it.hasNext(), false);
+ QCOMPARE(it.name(), QString());
+ QCOMPARE(it.value().toString(), QString());
+ }
+
+ for (int i = 0; i < 2; ++i) {
+ it.previous();
+ QCOMPARE(it.hasPrevious(), false);
+ QCOMPARE(it.hasNext(), false);
+ QCOMPARE(it.name(), QString());
+ QCOMPARE(it.value().toString(), QString());
+ }
+}
+
+void tst_QScriptValueIterator::removeUndeletable()
+{
+ // Undeletable property can't be deleted via iterator.
+ QScriptEngine engine;
+ QScriptValue object = engine.evaluate("o = new Object; o");
+ object.setProperty("a", QScriptValue(&engine, 124));
+ object.setProperty("b", QScriptValue(&engine, 816), QScriptValue::Undeletable);
+ QVERIFY(object.property("b").isValid());
+ QScriptValueIterator it(object);
+ it.next();
+ it.next();
+ it.remove();
+ it.toFront();
+ QVERIFY(it.hasNext());
+ QVERIFY(object.property("b").isValid());
+}
+
+void tst_QScriptValueIterator::iterateString()
+{
+ QScriptEngine engine;
+ QScriptValue str = QScriptValue(&engine, QString::fromLatin1("ciao"));
+ QVERIFY(str.isString());
+ QScriptValue obj = str.toObject();
+ int length = obj.property("length").toInt32();
+ QCOMPARE(length, 4);
+ QScriptValueIterator it(obj);
+ for (int i = 0; i < length; ++i) {
+ QCOMPARE(it.hasNext(), true);
+ QString indexStr = QScriptValue(&engine, i).toString();
+ it.next();
+ QCOMPARE(it.name(), indexStr);
+ QCOMPARE(it.flags(), obj.propertyFlags(indexStr));
+ QCOMPARE(it.value().strictlyEquals(obj.property(indexStr)), true);
+ }
+ QVERIFY(it.hasNext());
+ it.next();
+ QCOMPARE(it.name(), QString::fromLatin1("length"));
+ QVERIFY(it.value().isNumber());
+ QCOMPARE(it.value().toInt32(), length);
+ QCOMPARE(it.flags(), QScriptValue::PropertyFlags(QScriptValue::ReadOnly | QScriptValue::SkipInEnumeration | QScriptValue::Undeletable));
+
+ it.previous();
+ QCOMPARE(it.hasPrevious(), length > 0);
+ for (int i = length - 1; i >= 0; --i) {
+ it.previous();
+ QString indexStr = QScriptValue(&engine, i).toString();
+ QCOMPARE(it.name(), indexStr);
+ QCOMPARE(it.flags(), obj.propertyFlags(indexStr));
+ QCOMPARE(it.value().strictlyEquals(obj.property(indexStr)), true);
+ QCOMPARE(it.hasPrevious(), i > 0);
+ }
+ QCOMPARE(it.hasPrevious(), false);
+}
+
+void tst_QScriptValueIterator::assignObjectToIterator()
+{
+ QScriptEngine eng;
+ QScriptValue obj1 = eng.newObject();
+ obj1.setProperty("foo", 123);
+ QScriptValue obj2 = eng.newObject();
+ obj2.setProperty("bar", 456);
+
+ QScriptValueIterator it(obj1);
+ QVERIFY(it.hasNext());
+ it.next();
+ it = obj2;
+ QVERIFY(it.hasNext());
+ it.next();
+ QCOMPARE(it.name(), QString::fromLatin1("bar"));
+
+ it = obj1;
+ QVERIFY(it.hasNext());
+ it.next();
+ QCOMPARE(it.name(), QString::fromLatin1("foo"));
+
+ it = obj2;
+ QVERIFY(it.hasNext());
+ it.next();
+ QCOMPARE(it.name(), QString::fromLatin1("bar"));
+
+ it = obj2;
+ QVERIFY(it.hasNext());
+ it.next();
+ QCOMPARE(it.name(), QString::fromLatin1("bar"));
+}
+
+QTEST_MAIN(tst_QScriptValueIterator)
+#include "tst_qscriptvalueiterator.moc"
+
+#endif // tst_qscriptvalueiterator_h
TEMPLATE = subdirs
SUBDIRS = qscriptengine \
qscriptvalue \
+ qscriptvalueiterator \
qscriptstring
#include "JSValue.h"
#include "JSCell.h"
+#include "JSObject.h"
+#include "ScopeChain.h"
using std::min;
result = ArgList(m_args + startIndex, m_argCount - startIndex);
}
-void MarkedArgumentBuffer::markLists(MarkStack& markStack, ListSet& markSet)
+void MarkedArgumentBuffer::markLists(HeapRootVisitor& heapRootMarker, ListSet& markSet)
{
ListSet::iterator end = markSet.end();
for (ListSet::iterator it = markSet.begin(); it != end; ++it) {
MarkedArgumentBuffer* list = *it;
- markStack.appendValues(reinterpret_cast<JSValue*>(list->m_buffer), list->m_size);
+ heapRootMarker.mark(reinterpret_cast<JSValue*>(list->m_buffer), list->m_size);
}
}
// our Vector's inline capacity, though, our values move to the
// heap, where they do need explicit marking.
if (!m_markSet) {
- // We can only register for explicit marking once we know which heap
- // is the current one, i.e., when a non-immediate value is appended.
+ // FIXME: Even if v is not a JSCell*, if previous values in the buffer
+ // are, then they won't be marked!
if (Heap* heap = Heap::heap(v)) {
ListSet& markSet = heap->markListSet();
markSet.add(this);
#ifndef ArgList_h
#define ArgList_h
+#include "CallFrame.h"
#include "Register.h"
+#include "WriteBarrier.h"
#include <wtf/HashSet.h>
-#include <wtf/Noncopyable.h>
#include <wtf/Vector.h>
namespace JSC {
class MarkStack;
+ typedef MarkStack SlotVisitor;
- class MarkedArgumentBuffer : public Noncopyable {
+ class MarkedArgumentBuffer {
+ WTF_MAKE_NONCOPYABLE(MarkedArgumentBuffer);
private:
static const unsigned inlineCapacity = 8;
typedef Vector<Register, inlineCapacity> VectorType;
{
}
- void initialize(Register* buffer, size_t size)
+ void initialize(WriteBarrier<Unknown>* buffer, size_t size)
{
ASSERT(!m_markSet);
ASSERT(isEmpty());
- m_buffer = buffer;
+ m_buffer = reinterpret_cast<Register*>(buffer);
m_size = size;
#ifndef NDEBUG
m_isReadOnly = true;
const_iterator begin() const { return m_buffer; }
const_iterator end() const { return m_buffer + m_size; }
- static void markLists(MarkStack&, ListSet&);
+ static void markLists(HeapRootVisitor&, ListSet&);
private:
void slowAppend(JSValue);
{
}
+ ArgList(ExecState* exec)
+ : m_args(reinterpret_cast<JSValue*>(&exec[exec->hostThisRegister() + 1]))
+ , m_argCount(exec->argumentCount())
+ {
+ }
+
ArgList(JSValue* args, unsigned argCount)
: m_args(args)
, m_argCount(argCount)
ASSERT_CLASS_FITS_IN_CELL(Arguments);
-const ClassInfo Arguments::info = { "Arguments", 0, 0, 0 };
+const ClassInfo Arguments::s_info = { "Arguments", &JSNonFinalObject::s_info, 0, 0 };
Arguments::~Arguments()
{
delete [] d->extraArguments;
}
-void Arguments::markChildren(MarkStack& markStack)
+void Arguments::visitChildren(SlotVisitor& visitor)
{
- JSObject::markChildren(markStack);
+ ASSERT_GC_OBJECT_INHERITS(this, &s_info);
+ COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
+ ASSERT(structure()->typeInfo().overridesVisitChildren());
+ JSObject::visitChildren(visitor);
if (d->registerArray)
- markStack.appendValues(reinterpret_cast<JSValue*>(d->registerArray.get()), d->numParameters);
+ visitor.appendValues(d->registerArray.get(), d->numParameters);
if (d->extraArguments) {
unsigned numExtraArguments = d->numArguments - d->numParameters;
- markStack.appendValues(reinterpret_cast<JSValue*>(d->extraArguments), numExtraArguments);
+ visitor.appendValues(d->extraArguments, numExtraArguments);
}
- markStack.append(d->callee);
+ visitor.append(&d->callee);
if (d->activation)
- markStack.append(d->activation);
+ visitor.append(&d->activation);
}
void Arguments::copyToRegisters(ExecState* exec, Register* buffer, uint32_t maxSize)
unsigned parametersLength = min(min(d->numParameters, d->numArguments), maxSize);
unsigned i = 0;
for (; i < parametersLength; ++i)
- buffer[i] = d->registers[d->firstParameterIndex + i].jsValue();
+ buffer[i] = d->registers[d->firstParameterIndex + i].get();
for (; i < d->numArguments; ++i)
- buffer[i] = d->extraArguments[i - d->numParameters].jsValue();
+ buffer[i] = d->extraArguments[i - d->numParameters].get();
return;
}
unsigned i = 0;
for (; i < parametersLength; ++i) {
if (!d->deletedArguments[i])
- buffer[i] = d->registers[d->firstParameterIndex + i].jsValue();
+ buffer[i] = d->registers[d->firstParameterIndex + i].get();
else
buffer[i] = get(exec, i);
}
for (; i < d->numArguments; ++i) {
if (!d->deletedArguments[i])
- buffer[i] = d->extraArguments[i - d->numParameters].jsValue();
+ buffer[i] = d->extraArguments[i - d->numParameters].get();
else
buffer[i] = get(exec, i);
}
unsigned parametersLength = min(d->numParameters, d->numArguments);
unsigned i = 0;
for (; i < parametersLength; ++i)
- args.append(d->registers[d->firstParameterIndex + i].jsValue());
+ args.append(d->registers[d->firstParameterIndex + i].get());
for (; i < d->numArguments; ++i)
- args.append(d->extraArguments[i - d->numParameters].jsValue());
+ args.append(d->extraArguments[i - d->numParameters].get());
return;
}
unsigned i = 0;
for (; i < parametersLength; ++i) {
if (!d->deletedArguments[i])
- args.append(d->registers[d->firstParameterIndex + i].jsValue());
+ args.append(d->registers[d->firstParameterIndex + i].get());
else
args.append(get(exec, i));
}
for (; i < d->numArguments; ++i) {
if (!d->deletedArguments[i])
- args.append(d->extraArguments[i - d->numParameters].jsValue());
+ args.append(d->extraArguments[i - d->numParameters].get());
else
args.append(get(exec, i));
}
{
if (i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
if (i < d->numParameters) {
- slot.setRegisterSlot(&d->registers[d->firstParameterIndex + i]);
+ slot.setValue(d->registers[d->firstParameterIndex + i].get());
} else
- slot.setValue(d->extraArguments[i - d->numParameters].jsValue());
+ slot.setValue(d->extraArguments[i - d->numParameters].get());
return true;
}
- return JSObject::getOwnPropertySlot(exec, Identifier(exec, UString::from(i)), slot);
+ return JSObject::getOwnPropertySlot(exec, Identifier(exec, UString::number(i)), slot);
+}
+
+void Arguments::createStrictModeCallerIfNecessary(ExecState* exec)
+{
+ if (d->overrodeCaller)
+ return;
+
+ d->overrodeCaller = true;
+ PropertyDescriptor descriptor;
+ JSValue thrower = createTypeErrorFunction(exec, "Unable to access caller of strict mode function");
+ descriptor.setAccessorDescriptor(thrower, thrower, DontEnum | DontDelete | Getter | Setter);
+ defineOwnProperty(exec, exec->propertyNames().caller, descriptor, false);
+}
+
+void Arguments::createStrictModeCalleeIfNecessary(ExecState* exec)
+{
+ if (d->overrodeCallee)
+ return;
+
+ d->overrodeCallee = true;
+ PropertyDescriptor descriptor;
+ JSValue thrower = createTypeErrorFunction(exec, "Unable to access callee of strict mode function");
+ descriptor.setAccessorDescriptor(thrower, thrower, DontEnum | DontDelete | Getter | Setter);
+ defineOwnProperty(exec, exec->propertyNames().callee, descriptor, false);
}
bool Arguments::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
{
bool isArrayIndex;
- unsigned i = propertyName.toArrayIndex(&isArrayIndex);
+ unsigned i = propertyName.toArrayIndex(isArrayIndex);
if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
if (i < d->numParameters) {
- slot.setRegisterSlot(&d->registers[d->firstParameterIndex + i]);
+ slot.setValue(d->registers[d->firstParameterIndex + i].get());
} else
- slot.setValue(d->extraArguments[i - d->numParameters].jsValue());
+ slot.setValue(d->extraArguments[i - d->numParameters].get());
return true;
}
if (propertyName == exec->propertyNames().length && LIKELY(!d->overrodeLength)) {
- slot.setValue(jsNumber(exec, d->numArguments));
+ slot.setValue(jsNumber(d->numArguments));
return true;
}
if (propertyName == exec->propertyNames().callee && LIKELY(!d->overrodeCallee)) {
- slot.setValue(d->callee);
- return true;
+ if (!d->isStrictMode) {
+ slot.setValue(d->callee.get());
+ return true;
+ }
+ createStrictModeCalleeIfNecessary(exec);
}
+ if (propertyName == exec->propertyNames().caller && d->isStrictMode)
+ createStrictModeCallerIfNecessary(exec);
+
return JSObject::getOwnPropertySlot(exec, propertyName, slot);
}
bool Arguments::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
{
bool isArrayIndex;
- unsigned i = propertyName.toArrayIndex(&isArrayIndex);
+ unsigned i = propertyName.toArrayIndex(isArrayIndex);
if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
if (i < d->numParameters) {
- descriptor.setDescriptor(d->registers[d->firstParameterIndex + i].jsValue(), DontEnum);
+ descriptor.setDescriptor(d->registers[d->firstParameterIndex + i].get(), DontEnum);
} else
- descriptor.setDescriptor(d->extraArguments[i - d->numParameters].jsValue(), DontEnum);
+ descriptor.setDescriptor(d->extraArguments[i - d->numParameters].get(), DontEnum);
return true;
}
if (propertyName == exec->propertyNames().length && LIKELY(!d->overrodeLength)) {
- descriptor.setDescriptor(jsNumber(exec, d->numArguments), DontEnum);
+ descriptor.setDescriptor(jsNumber(d->numArguments), DontEnum);
return true;
}
if (propertyName == exec->propertyNames().callee && LIKELY(!d->overrodeCallee)) {
- descriptor.setDescriptor(d->callee, DontEnum);
- return true;
+ if (!d->isStrictMode) {
+ descriptor.setDescriptor(d->callee.get(), DontEnum);
+ return true;
+ }
+ createStrictModeCalleeIfNecessary(exec);
}
+
+ if (propertyName == exec->propertyNames().caller && d->isStrictMode)
+ createStrictModeCallerIfNecessary(exec);
return JSObject::getOwnPropertyDescriptor(exec, propertyName, descriptor);
}
if (mode == IncludeDontEnumProperties) {
for (unsigned i = 0; i < d->numArguments; ++i) {
if (!d->deletedArguments || !d->deletedArguments[i])
- propertyNames.add(Identifier(exec, UString::from(i)));
+ propertyNames.add(Identifier(exec, UString::number(i)));
}
propertyNames.add(exec->propertyNames().callee);
propertyNames.add(exec->propertyNames().length);
JSObject::getOwnPropertyNames(exec, propertyNames, mode);
}
-void Arguments::put(ExecState* exec, unsigned i, JSValue value, PutPropertySlot& slot)
+void Arguments::put(ExecState* exec, unsigned i, JSValue value)
{
if (i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
if (i < d->numParameters)
- d->registers[d->firstParameterIndex + i] = JSValue(value);
+ d->registers[d->firstParameterIndex + i].set(exec->globalData(), d->activation ? static_cast<JSCell*>(d->activation.get()) : static_cast<JSCell*>(this), value);
else
- d->extraArguments[i - d->numParameters] = JSValue(value);
+ d->extraArguments[i - d->numParameters].set(exec->globalData(), this, value);
return;
}
- JSObject::put(exec, Identifier(exec, UString::from(i)), value, slot);
+ PutPropertySlot slot;
+ JSObject::put(exec, Identifier(exec, UString::number(i)), value, slot);
}
void Arguments::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
{
bool isArrayIndex;
- unsigned i = propertyName.toArrayIndex(&isArrayIndex);
+ unsigned i = propertyName.toArrayIndex(isArrayIndex);
if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
if (i < d->numParameters)
- d->registers[d->firstParameterIndex + i] = JSValue(value);
+ d->registers[d->firstParameterIndex + i].set(exec->globalData(), d->activation ? static_cast<JSCell*>(d->activation.get()) : static_cast<JSCell*>(this), value);
else
- d->extraArguments[i - d->numParameters] = JSValue(value);
+ d->extraArguments[i - d->numParameters].set(exec->globalData(), this, value);
return;
}
if (propertyName == exec->propertyNames().length && !d->overrodeLength) {
d->overrodeLength = true;
- putDirect(propertyName, value, DontEnum);
+ putDirect(exec->globalData(), propertyName, value, DontEnum);
return;
}
if (propertyName == exec->propertyNames().callee && !d->overrodeCallee) {
- d->overrodeCallee = true;
- putDirect(propertyName, value, DontEnum);
- return;
+ if (!d->isStrictMode) {
+ d->overrodeCallee = true;
+ putDirect(exec->globalData(), propertyName, value, DontEnum);
+ return;
+ }
+ createStrictModeCalleeIfNecessary(exec);
}
+ if (propertyName == exec->propertyNames().caller && d->isStrictMode)
+ createStrictModeCallerIfNecessary(exec);
+
JSObject::put(exec, propertyName, value, slot);
}
{
if (i < d->numArguments) {
if (!d->deletedArguments) {
- d->deletedArguments.set(new bool[d->numArguments]);
+ d->deletedArguments = adoptArrayPtr(new bool[d->numArguments]);
memset(d->deletedArguments.get(), 0, sizeof(bool) * d->numArguments);
}
if (!d->deletedArguments[i]) {
}
}
- return JSObject::deleteProperty(exec, Identifier(exec, UString::from(i)));
+ return JSObject::deleteProperty(exec, Identifier(exec, UString::number(i)));
}
bool Arguments::deleteProperty(ExecState* exec, const Identifier& propertyName)
{
bool isArrayIndex;
- unsigned i = propertyName.toArrayIndex(&isArrayIndex);
+ unsigned i = propertyName.toArrayIndex(isArrayIndex);
if (isArrayIndex && i < d->numArguments) {
if (!d->deletedArguments) {
- d->deletedArguments.set(new bool[d->numArguments]);
+ d->deletedArguments = adoptArrayPtr(new bool[d->numArguments]);
memset(d->deletedArguments.get(), 0, sizeof(bool) * d->numArguments);
}
if (!d->deletedArguments[i]) {
}
if (propertyName == exec->propertyNames().callee && !d->overrodeCallee) {
- d->overrodeCallee = true;
- return true;
+ if (!d->isStrictMode) {
+ d->overrodeCallee = true;
+ return true;
+ }
+ createStrictModeCalleeIfNecessary(exec);
}
+
+ if (propertyName == exec->propertyNames().caller && !d->isStrictMode)
+ createStrictModeCallerIfNecessary(exec);
return JSObject::deleteProperty(exec, propertyName);
}
#include "JSGlobalObject.h"
#include "Interpreter.h"
#include "ObjectConstructor.h"
-#include "PrototypeFunction.h"
namespace JSC {
- struct ArgumentsData : Noncopyable {
- JSActivation* activation;
+ struct ArgumentsData {
+ WTF_MAKE_NONCOPYABLE(ArgumentsData); WTF_MAKE_FAST_ALLOCATED;
+ public:
+ ArgumentsData() { }
+ WriteBarrier<JSActivation> activation;
unsigned numParameters;
ptrdiff_t firstParameterIndex;
unsigned numArguments;
- Register* registers;
- OwnArrayPtr<Register> registerArray;
+ WriteBarrier<Unknown>* registers;
+ OwnArrayPtr<WriteBarrier<Unknown> > registerArray;
- Register* extraArguments;
+ WriteBarrier<Unknown>* extraArguments;
OwnArrayPtr<bool> deletedArguments;
- Register extraArgumentsFixedBuffer[4];
+ WriteBarrier<Unknown> extraArgumentsFixedBuffer[4];
- JSFunction* callee;
+ WriteBarrier<JSFunction> callee;
bool overrodeLength : 1;
bool overrodeCallee : 1;
+ bool overrodeCaller : 1;
+ bool isStrictMode : 1;
};
- class Arguments : public JSObject {
+ class Arguments : public JSNonFinalObject {
public:
// Use an enum because otherwise gcc insists on doing a memory
// read.
Arguments(CallFrame*, NoParametersType);
virtual ~Arguments();
- static const ClassInfo info;
+ static const ClassInfo s_info;
- virtual void markChildren(MarkStack&);
+ virtual void visitChildren(SlotVisitor&);
void fillArgList(ExecState*, MarkedArgumentBuffer&);
}
void copyToRegisters(ExecState* exec, Register* buffer, uint32_t maxSize);
- void copyRegisters();
+ void copyRegisters(JSGlobalData&);
bool isTornOff() const { return d->registerArray; }
- void setActivation(JSActivation* activation)
+ void setActivation(JSGlobalData& globalData, JSActivation* activation)
{
- d->activation = activation;
+ ASSERT(!d->registerArray);
+ d->activation.set(globalData, this, activation);
d->registers = &activation->registerAt(0);
}
- static PassRefPtr<Structure> createStructure(JSValue prototype)
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
+ return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
}
protected:
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesMarkChildren | OverridesGetPropertyNames | JSObject::StructureFlags;
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | JSObject::StructureFlags;
private:
void getArgumentsData(CallFrame*, JSFunction*&, ptrdiff_t& firstParameterIndex, Register*& argv, int& argc);
virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties);
virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
- virtual void put(ExecState*, unsigned propertyName, JSValue, PutPropertySlot&);
+ virtual void put(ExecState*, unsigned propertyName, JSValue);
virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
virtual bool deleteProperty(ExecState*, unsigned propertyName);
-
- virtual const ClassInfo* classInfo() const { return &info; }
+ void createStrictModeCallerIfNecessary(ExecState*);
+ void createStrictModeCalleeIfNecessary(ExecState*);
void init(CallFrame*);
inline Arguments* asArguments(JSValue value)
{
- ASSERT(asObject(value)->inherits(&Arguments::info));
+ ASSERT(asObject(value)->inherits(&Arguments::s_info));
return static_cast<Arguments*>(asObject(value));
}
ALWAYS_INLINE void Arguments::getArgumentsData(CallFrame* callFrame, JSFunction*& function, ptrdiff_t& firstParameterIndex, Register*& argv, int& argc)
{
- function = callFrame->callee();
+ function = asFunction(callFrame->callee());
int numParameters = function->jsExecutable()->parameterCount();
- argc = callFrame->argumentCount();
+ argc = callFrame->argumentCountIncludingThis();
if (argc <= numParameters)
argv = callFrame->registers() - RegisterFile::CallFrameHeaderSize - numParameters;
}
inline Arguments::Arguments(CallFrame* callFrame)
- : JSObject(callFrame->lexicalGlobalObject()->argumentsStructure())
- , d(new ArgumentsData)
+ : JSNonFinalObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure())
+ , d(adoptPtr(new ArgumentsData))
{
+ ASSERT(inherits(&s_info));
+
JSFunction* callee;
ptrdiff_t firstParameterIndex;
Register* argv;
d->firstParameterIndex = firstParameterIndex;
d->numArguments = numArguments;
- d->activation = 0;
- d->registers = callFrame->registers();
+ d->registers = reinterpret_cast<WriteBarrier<Unknown>*>(callFrame->registers());
- Register* extraArguments;
+ WriteBarrier<Unknown>* extraArguments;
if (d->numArguments <= d->numParameters)
extraArguments = 0;
else {
unsigned numExtraArguments = d->numArguments - d->numParameters;
- if (numExtraArguments > sizeof(d->extraArgumentsFixedBuffer) / sizeof(Register))
- extraArguments = new Register[numExtraArguments];
+ if (numExtraArguments > sizeof(d->extraArgumentsFixedBuffer) / sizeof(WriteBarrier<Unknown>))
+ extraArguments = new WriteBarrier<Unknown>[numExtraArguments];
else
extraArguments = d->extraArgumentsFixedBuffer;
for (unsigned i = 0; i < numExtraArguments; ++i)
- extraArguments[i] = argv[d->numParameters + i];
+ extraArguments[i].set(callFrame->globalData(), this, argv[d->numParameters + i].jsValue());
}
d->extraArguments = extraArguments;
- d->callee = callee;
+ d->callee.set(callFrame->globalData(), this, callee);
d->overrodeLength = false;
d->overrodeCallee = false;
+ d->overrodeCaller = false;
+ d->isStrictMode = callFrame->codeBlock()->isStrictMode();
+ if (d->isStrictMode)
+ copyRegisters(callFrame->globalData());
}
inline Arguments::Arguments(CallFrame* callFrame, NoParametersType)
- : JSObject(callFrame->lexicalGlobalObject()->argumentsStructure())
- , d(new ArgumentsData)
+ : JSNonFinalObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure())
+ , d(adoptPtr(new ArgumentsData))
{
- ASSERT(!callFrame->callee()->jsExecutable()->parameterCount());
+ ASSERT(inherits(&s_info));
+ ASSERT(!asFunction(callFrame->callee())->jsExecutable()->parameterCount());
- unsigned numArguments = callFrame->argumentCount() - 1;
+ unsigned numArguments = callFrame->argumentCount();
d->numParameters = 0;
d->numArguments = numArguments;
- d->activation = 0;
- Register* extraArguments;
+ WriteBarrier<Unknown>* extraArguments;
if (numArguments > sizeof(d->extraArgumentsFixedBuffer) / sizeof(Register))
- extraArguments = new Register[numArguments];
+ extraArguments = new WriteBarrier<Unknown>[numArguments];
else
extraArguments = d->extraArgumentsFixedBuffer;
Register* argv = callFrame->registers() - RegisterFile::CallFrameHeaderSize - numArguments - 1;
for (unsigned i = 0; i < numArguments; ++i)
- extraArguments[i] = argv[i];
+ extraArguments[i].set(callFrame->globalData(), this, argv[i].jsValue());
d->extraArguments = extraArguments;
- d->callee = callFrame->callee();
+ d->callee.set(callFrame->globalData(), this, asFunction(callFrame->callee()));
d->overrodeLength = false;
d->overrodeCallee = false;
+ d->overrodeCaller = false;
+ d->isStrictMode = callFrame->codeBlock()->isStrictMode();
+ if (d->isStrictMode)
+ copyRegisters(callFrame->globalData());
}
- inline void Arguments::copyRegisters()
+ inline void Arguments::copyRegisters(JSGlobalData& globalData)
{
ASSERT(!isTornOff());
int registerOffset = d->numParameters + RegisterFile::CallFrameHeaderSize;
size_t registerArraySize = d->numParameters;
- Register* registerArray = new Register[registerArraySize];
- memcpy(registerArray, d->registers - registerOffset, registerArraySize * sizeof(Register));
- d->registerArray.set(registerArray);
- d->registers = registerArray + registerOffset;
+ OwnArrayPtr<WriteBarrier<Unknown> > registerArray = adoptArrayPtr(new WriteBarrier<Unknown>[registerArraySize]);
+ for (size_t i = 0; i < registerArraySize; i++)
+ registerArray[i].set(globalData, this, d->registers[i - registerOffset].get());
+ d->registers = registerArray.get() + registerOffset;
+ d->registerArray = registerArray.release();
}
// This JSActivation function is defined here so it can get at Arguments::setRegisters.
- inline void JSActivation::copyRegisters(Arguments* arguments)
+ inline void JSActivation::copyRegisters(JSGlobalData& globalData)
{
- ASSERT(!d()->registerArray);
+ ASSERT(!m_registerArray);
- size_t numParametersMinusThis = d()->functionExecutable->generatedBytecode().m_numParameters - 1;
- size_t numVars = d()->functionExecutable->generatedBytecode().m_numVars;
- size_t numLocals = numVars + numParametersMinusThis;
+ size_t numLocals = m_numCapturedVars + m_numParametersMinusThis;
if (!numLocals)
return;
- int registerOffset = numParametersMinusThis + RegisterFile::CallFrameHeaderSize;
+ int registerOffset = m_numParametersMinusThis + RegisterFile::CallFrameHeaderSize;
size_t registerArraySize = numLocals + RegisterFile::CallFrameHeaderSize;
- Register* registerArray = copyRegisterArray(d()->registers - registerOffset, registerArraySize);
- setRegisters(registerArray + registerOffset, registerArray);
- if (arguments && !arguments->isTornOff())
- static_cast<Arguments*>(arguments)->setActivation(this);
- }
-
- ALWAYS_INLINE Arguments* Register::arguments() const
- {
- if (jsValue() == JSValue())
- return 0;
- return asArguments(jsValue());
+ OwnArrayPtr<WriteBarrier<Unknown> > registerArray = copyRegisterArray(globalData, m_registers - registerOffset, registerArraySize, m_numParametersMinusThis + 1);
+ WriteBarrier<Unknown>* registers = registerArray.get() + registerOffset;
+ setRegisters(registers, registerArray.release());
}
-
} // namespace JSC
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2003, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2007, 2008, 2011 Apple Inc. All rights reserved.
* Copyright (C) 2003 Peter Kelly (pmk@post.com)
* Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
*
#include "ArrayPrototype.h"
#include "Error.h"
+#include "ExceptionHelpers.h"
#include "JSArray.h"
#include "JSFunction.h"
#include "Lookup.h"
-#include "PrototypeFunction.h"
namespace JSC {
+static EncodedJSValue JSC_HOST_CALL arrayConstructorIsArray(ExecState*);
+
+}
+
+#include "ArrayConstructor.lut.h"
+
+namespace JSC {
+
+const ClassInfo ArrayConstructor::s_info = { "Function", &InternalFunction::s_info, 0, ExecState::arrayConstructorTable };
+
+/* Source for ArrayConstructor.lut.h
+@begin arrayConstructorTable
+ isArray arrayConstructorIsArray DontEnum|Function 1
+@end
+*/
+
ASSERT_CLASS_FITS_IN_CELL(ArrayConstructor);
-
-static JSValue JSC_HOST_CALL arrayConstructorIsArray(ExecState*, JSObject*, JSValue, const ArgList&);
-ArrayConstructor::ArrayConstructor(ExecState* exec, NonNullPassRefPtr<Structure> structure, ArrayPrototype* arrayPrototype, Structure* prototypeFunctionStructure)
- : InternalFunction(&exec->globalData(), structure, Identifier(exec, arrayPrototype->classInfo()->className))
+ArrayConstructor::ArrayConstructor(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, ArrayPrototype* arrayPrototype)
+ : InternalFunction(&exec->globalData(), globalObject, structure, Identifier(exec, arrayPrototype->classInfo()->className))
{
- // ECMA 15.4.3.1 Array.prototype
- putDirectWithoutTransition(exec->propertyNames().prototype, arrayPrototype, DontEnum | DontDelete | ReadOnly);
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().prototype, arrayPrototype, DontEnum | DontDelete | ReadOnly);
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(1), ReadOnly | DontEnum | DontDelete);
+}
- // no. of arguments for constructor
- putDirectWithoutTransition(exec->propertyNames().length, jsNumber(exec, 1), ReadOnly | DontEnum | DontDelete);
+bool ArrayConstructor::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot &slot)
+{
+ return getStaticFunctionSlot<InternalFunction>(exec, ExecState::arrayConstructorTable(exec), this, propertyName, slot);
+}
- // ES5
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().isArray, arrayConstructorIsArray), DontEnum);
+bool ArrayConstructor::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ return getStaticFunctionDescriptor<InternalFunction>(exec, ExecState::arrayConstructorTable(exec), this, propertyName, descriptor);
}
+// ------------------------------ Functions ---------------------------
+
static inline JSObject* constructArrayWithSizeQuirk(ExecState* exec, const ArgList& args)
{
+ JSGlobalObject* globalObject = asInternalFunction(exec->callee())->globalObject();
+
// a single numeric argument denotes the array size (!)
if (args.size() == 1 && args.at(0).isNumber()) {
uint32_t n = args.at(0).toUInt32(exec);
if (n != args.at(0).toNumber(exec))
- return throwError(exec, RangeError, "Array size is not a small enough positive integer.");
- return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), n);
+ return throwError(exec, createRangeError(exec, "Array size is not a small enough positive integer."));
+ return new (exec) JSArray(exec->globalData(), globalObject->arrayStructure(), n, CreateInitialized);
}
// otherwise the array is constructed with the arguments in it
- return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), args);
+ return new (exec) JSArray(exec->globalData(), globalObject->arrayStructure(), args);
}
-static JSObject* constructWithArrayConstructor(ExecState* exec, JSObject*, const ArgList& args)
+static EncodedJSValue JSC_HOST_CALL constructWithArrayConstructor(ExecState* exec)
{
- return constructArrayWithSizeQuirk(exec, args);
+ ArgList args(exec);
+ return JSValue::encode(constructArrayWithSizeQuirk(exec, args));
}
-// ECMA 15.4.2
ConstructType ArrayConstructor::getConstructData(ConstructData& constructData)
{
constructData.native.function = constructWithArrayConstructor;
return ConstructTypeHost;
}
-static JSValue JSC_HOST_CALL callArrayConstructor(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+static EncodedJSValue JSC_HOST_CALL callArrayConstructor(ExecState* exec)
{
- return constructArrayWithSizeQuirk(exec, args);
+ ArgList args(exec);
+ return JSValue::encode(constructArrayWithSizeQuirk(exec, args));
}
-// ECMA 15.6.1
CallType ArrayConstructor::getCallData(CallData& callData)
{
// equivalent to 'new Array(....)'
return CallTypeHost;
}
-JSValue JSC_HOST_CALL arrayConstructorIsArray(ExecState*, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL arrayConstructorIsArray(ExecState* exec)
{
- return jsBoolean(args.at(0).inherits(&JSArray::info));
+ return JSValue::encode(jsBoolean(exec->argument(0).inherits(&JSArray::s_info)));
}
} // namespace JSC
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008, 2011 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
class ArrayConstructor : public InternalFunction {
public:
- ArrayConstructor(ExecState*, NonNullPassRefPtr<Structure>, ArrayPrototype*, Structure*);
+ ArrayConstructor(ExecState*, JSGlobalObject*, Structure*, ArrayPrototype*);
+
+ static const ClassInfo s_info;
+
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
+ {
+ return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
+ }
+
+ protected:
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InternalFunction::StructureFlags;
+
+ private:
+ virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
+ virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
virtual ConstructType getConstructData(ConstructData&);
virtual CallType getCallData(CallData&);
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2003, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2007, 2008, 2009, 2011 Apple Inc. All rights reserved.
* Copyright (C) 2003 Peter Kelly (pmk@post.com)
* Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
*
#include "Lookup.h"
#include "ObjectPrototype.h"
#include "Operations.h"
+#include "StringRecursionChecker.h"
#include <algorithm>
#include <wtf/Assertions.h>
#include <wtf/HashSet.h>
ASSERT_CLASS_FITS_IN_CELL(ArrayPrototype);
-static JSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL arrayProtoFuncToLocaleString(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL arrayProtoFuncConcat(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL arrayProtoFuncPop(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL arrayProtoFuncPush(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL arrayProtoFuncReverse(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL arrayProtoFuncShift(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL arrayProtoFuncSlice(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL arrayProtoFuncUnShift(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL arrayProtoFuncEvery(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL arrayProtoFuncForEach(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL arrayProtoFuncSome(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL arrayProtoFuncIndexOf(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL arrayProtoFuncFilter(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL arrayProtoFuncMap(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL arrayProtoFuncReduce(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL arrayProtoFuncReduceRight(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL arrayProtoFuncLastIndexOf(ExecState*, JSObject*, JSValue, const ArgList&);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncToLocaleString(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncConcat(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncPop(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncPush(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncReverse(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncShift(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncSlice(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncUnShift(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncEvery(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncForEach(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncSome(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncIndexOf(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncFilter(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncMap(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduce(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduceRight(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncLastIndexOf(ExecState*);
}
if (callType != CallTypeJS)
return false;
-#if ENABLE(JIT)
- // If the JIT is enabled then we need to preserve the invariant that every
- // function with a CodeBlock also has JIT code.
- CodeBlock* codeBlock = 0;
-#if ENABLE(INTERPRETER)
- if (!exec->globalData().canUseJIT())
- codeBlock = &callData.js.functionExecutable->bytecode(exec, callData.js.scopeChain);
- else
-#endif
- {
- callData.js.functionExecutable->jitCode(exec, callData.js.scopeChain);
- codeBlock = &callData.js.functionExecutable->generatedBytecode();
- }
-#else
- CodeBlock* codeBlock = &callData.js.functionExecutable->bytecode(exec, callData.js.scopeChain);
-#endif
+ FunctionExecutable* executable = callData.js.functionExecutable;
- return codeBlock->isNumericCompareFunction();
+ JSObject* error = executable->compileForCall(exec, callData.js.scopeChain);
+ if (error)
+ return false;
+
+ return executable->generatedBytecodeForCall().isNumericCompareFunction();
}
// ------------------------------ ArrayPrototype ----------------------------
-const ClassInfo ArrayPrototype::info = {"Array", &JSArray::info, 0, ExecState::arrayTable};
+const ClassInfo ArrayPrototype::s_info = {"Array", &JSArray::s_info, 0, ExecState::arrayPrototypeTable};
/* Source for ArrayPrototype.lut.h
-@begin arrayTable 16
+@begin arrayPrototypeTable 16
toString arrayProtoFuncToString DontEnum|Function 0
toLocaleString arrayProtoFuncToLocaleString DontEnum|Function 0
concat arrayProtoFuncConcat DontEnum|Function 1
*/
// ECMA 15.4.4
-ArrayPrototype::ArrayPrototype(NonNullPassRefPtr<Structure> structure)
- : JSArray(structure)
+ArrayPrototype::ArrayPrototype(JSGlobalObject* globalObject, Structure* structure)
+ : JSArray(globalObject->globalData(), structure)
{
+ ASSERT(inherits(&s_info));
+ putAnonymousValue(globalObject->globalData(), 0, globalObject);
}
bool ArrayPrototype::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
{
- return getStaticFunctionSlot<JSArray>(exec, ExecState::arrayTable(exec), this, propertyName, slot);
+ return getStaticFunctionSlot<JSArray>(exec, ExecState::arrayPrototypeTable(exec), this, propertyName, slot);
}
bool ArrayPrototype::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
{
- return getStaticFunctionDescriptor<JSArray>(exec, ExecState::arrayTable(exec), this, propertyName, descriptor);
+ return getStaticFunctionDescriptor<JSArray>(exec, ExecState::arrayPrototypeTable(exec), this, propertyName, descriptor);
}
// ------------------------------ Array Functions ----------------------------
obj->put(exec, propertyName, value, slot);
}
-JSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+static unsigned argumentClampedIndexFromStartOrEnd(ExecState* exec, int argument, unsigned length, unsigned undefinedValue = 0)
+{
+ JSValue value = exec->argument(argument);
+ if (value.isUndefined())
+ return undefinedValue;
+
+ double indexDouble = value.toInteger(exec);
+ if (indexDouble < 0) {
+ indexDouble += length;
+ return indexDouble < 0 ? 0 : static_cast<unsigned>(indexDouble);
+ }
+ return indexDouble > length ? length : static_cast<unsigned>(indexDouble);
+}
+
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState* exec)
{
+ JSValue thisValue = exec->hostThisValue();
+
bool isRealArray = isJSArray(&exec->globalData(), thisValue);
- if (!isRealArray && !thisValue.inherits(&JSArray::info))
- return throwError(exec, TypeError);
+ if (!isRealArray && !thisValue.inherits(&JSArray::s_info))
+ return throwVMTypeError(exec);
JSArray* thisObj = asArray(thisValue);
- HashSet<JSObject*>& arrayVisitedElements = exec->globalData().arrayVisitedElements;
- if (arrayVisitedElements.size() >= MaxSmallThreadReentryDepth) {
- if (arrayVisitedElements.size() >= exec->globalData().maxReentryDepth)
- return throwError(exec, RangeError, "Maximum call stack size exceeded.");
- }
+ unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
- bool alreadyVisited = !arrayVisitedElements.add(thisObj).second;
- if (alreadyVisited)
- return jsEmptyString(exec); // return an empty string, avoiding infinite recursion.
+ StringRecursionChecker checker(exec, thisObj);
+ if (EncodedJSValue earlyReturnValue = checker.earlyReturnValue())
+ return earlyReturnValue;
- unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
unsigned totalSize = length ? length - 1 : 0;
- Vector<RefPtr<UString::Rep>, 256> strBuffer(length);
+#if OS(SYMBIAN)
+ // Symbian has very limited stack size available.
+ // This function could be called recursively and allocating 1K on stack here cause
+ // stack overflow on Symbian devices.
+ Vector<RefPtr<StringImpl> > strBuffer(length);
+#else
+ Vector<RefPtr<StringImpl>, 256> strBuffer(length);
+#endif
for (unsigned k = 0; k < length; k++) {
JSValue element;
if (isRealArray && thisObj->canGetIndex(k))
continue;
UString str = element.toString(exec);
- strBuffer[k] = str.rep();
- totalSize += str.size();
+ strBuffer[k] = str.impl();
+ totalSize += str.length();
if (!strBuffer.data()) {
throwOutOfMemoryError(exec);
if (exec->hadException())
break;
}
- arrayVisitedElements.remove(thisObj);
if (!totalSize)
- return jsEmptyString(exec);
+ return JSValue::encode(jsEmptyString(exec));
Vector<UChar> buffer;
buffer.reserveCapacity(totalSize);
if (!buffer.data())
- return throwOutOfMemoryError(exec);
+ return JSValue::encode(throwOutOfMemoryError(exec));
for (unsigned i = 0; i < length; i++) {
if (i)
buffer.append(',');
- if (RefPtr<UString::Rep> rep = strBuffer[i])
+ if (RefPtr<StringImpl> rep = strBuffer[i])
buffer.append(rep->characters(), rep->length());
}
ASSERT(buffer.size() == totalSize);
- return jsString(exec, UString::adopt(buffer));
+ return JSValue::encode(jsString(exec, UString::adopt(buffer)));
}
-JSValue JSC_HOST_CALL arrayProtoFuncToLocaleString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncToLocaleString(ExecState* exec)
{
- if (!thisValue.inherits(&JSArray::info))
- return throwError(exec, TypeError);
+ JSValue thisValue = exec->hostThisValue();
+
+ if (!thisValue.inherits(&JSArray::s_info))
+ return throwVMTypeError(exec);
JSObject* thisObj = asArray(thisValue);
- HashSet<JSObject*>& arrayVisitedElements = exec->globalData().arrayVisitedElements;
- if (arrayVisitedElements.size() >= MaxSmallThreadReentryDepth) {
- if (arrayVisitedElements.size() >= exec->globalData().maxReentryDepth)
- return throwError(exec, RangeError, "Maximum call stack size exceeded.");
- }
+ unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
- bool alreadyVisited = !arrayVisitedElements.add(thisObj).second;
- if (alreadyVisited)
- return jsEmptyString(exec); // return an empty string, avoding infinite recursion.
+ StringRecursionChecker checker(exec, thisObj);
+ if (EncodedJSValue earlyReturnValue = checker.earlyReturnValue())
+ return earlyReturnValue;
JSStringBuilder strBuffer;
- unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
for (unsigned k = 0; k < length; k++) {
if (k >= 1)
strBuffer.append(',');
JSValue conversionFunction = o->get(exec, exec->propertyNames().toLocaleString);
UString str;
CallData callData;
- CallType callType = conversionFunction.getCallData(callData);
+ CallType callType = getCallData(conversionFunction, callData);
if (callType != CallTypeNone)
str = call(exec, conversionFunction, callType, callData, element, exec->emptyList()).toString(exec);
else
strBuffer.append(str);
}
}
- arrayVisitedElements.remove(thisObj);
- return strBuffer.build(exec);
+
+ return JSValue::encode(strBuffer.build(exec));
}
-JSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec)
{
- JSObject* thisObj = thisValue.toThisObject(exec);
-
- HashSet<JSObject*>& arrayVisitedElements = exec->globalData().arrayVisitedElements;
- if (arrayVisitedElements.size() >= MaxSmallThreadReentryDepth) {
- if (arrayVisitedElements.size() >= exec->globalData().maxReentryDepth)
- return throwError(exec, RangeError, "Maximum call stack size exceeded.");
- }
+ JSObject* thisObj = exec->hostThisValue().toThisObject(exec);
+ unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
- bool alreadyVisited = !arrayVisitedElements.add(thisObj).second;
- if (alreadyVisited)
- return jsEmptyString(exec); // return an empty string, avoding infinite recursion.
+ StringRecursionChecker checker(exec, thisObj);
+ if (EncodedJSValue earlyReturnValue = checker.earlyReturnValue())
+ return earlyReturnValue;
JSStringBuilder strBuffer;
UString separator;
- if (!args.at(0).isUndefined())
- separator = args.at(0).toString(exec);
+ if (!exec->argument(0).isUndefined())
+ separator = exec->argument(0).toString(exec);
- unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
unsigned k = 0;
if (isJSArray(&exec->globalData(), thisObj)) {
JSArray* array = asArray(thisObj);
- for (; k < length; k++) {
- if (!array->canGetIndex(k))
- break;
- if (k >= 1) {
- if (separator.isNull())
- strBuffer.append(',');
- else
- strBuffer.append(separator);
- }
+
+ if (length) {
+ if (!array->canGetIndex(k))
+ goto skipFirstLoop;
JSValue element = array->getIndex(k);
if (!element.isUndefinedOrNull())
strBuffer.append(element.toString(exec));
+ k++;
+ }
+
+ if (separator.isNull()) {
+ for (; k < length; k++) {
+ if (!array->canGetIndex(k))
+ break;
+ strBuffer.append(',');
+ JSValue element = array->getIndex(k);
+ if (!element.isUndefinedOrNull())
+ strBuffer.append(element.toString(exec));
+ }
+ } else {
+ for (; k < length; k++) {
+ if (!array->canGetIndex(k))
+ break;
+ strBuffer.append(separator);
+ JSValue element = array->getIndex(k);
+ if (!element.isUndefinedOrNull())
+ strBuffer.append(element.toString(exec));
+ }
}
}
+ skipFirstLoop:
for (; k < length; k++) {
if (k >= 1) {
if (separator.isNull())
if (!element.isUndefinedOrNull())
strBuffer.append(element.toString(exec));
}
- arrayVisitedElements.remove(thisObj);
- return strBuffer.build(exec);
+
+ return JSValue::encode(strBuffer.build(exec));
}
-JSValue JSC_HOST_CALL arrayProtoFuncConcat(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncConcat(ExecState* exec)
{
+ JSValue thisValue = exec->hostThisValue();
JSArray* arr = constructEmptyArray(exec);
- int n = 0;
+ unsigned n = 0;
JSValue curArg = thisValue.toThisObject(exec);
- ArgList::const_iterator it = args.begin();
- ArgList::const_iterator end = args.end();
+ size_t i = 0;
+ size_t argCount = exec->argumentCount();
while (1) {
- if (curArg.inherits(&JSArray::info)) {
+ if (curArg.inherits(&JSArray::s_info)) {
unsigned length = curArg.get(exec, exec->propertyNames().length).toUInt32(exec);
JSObject* curObject = curArg.toObject(exec);
for (unsigned k = 0; k < length; ++k) {
arr->put(exec, n, curArg);
n++;
}
- if (it == end)
+ if (i == argCount)
break;
- curArg = (*it);
- ++it;
+ curArg = (exec->argument(i));
+ ++i;
}
arr->setLength(n);
- return arr;
+ return JSValue::encode(arr);
}
-JSValue JSC_HOST_CALL arrayProtoFuncPop(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncPop(ExecState* exec)
{
+ JSValue thisValue = exec->hostThisValue();
+
if (isJSArray(&exec->globalData(), thisValue))
- return asArray(thisValue)->pop();
+ return JSValue::encode(asArray(thisValue)->pop());
JSObject* thisObj = thisValue.toThisObject(exec);
- JSValue result;
unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ JSValue result;
if (length == 0) {
- putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(exec, length));
+ putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(length));
result = jsUndefined();
} else {
result = thisObj->get(exec, length - 1);
thisObj->deleteProperty(exec, length - 1);
- putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(exec, length - 1));
+ putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(length - 1));
}
- return result;
+ return JSValue::encode(result);
}
-JSValue JSC_HOST_CALL arrayProtoFuncPush(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncPush(ExecState* exec)
{
- if (isJSArray(&exec->globalData(), thisValue) && args.size() == 1) {
+ JSValue thisValue = exec->hostThisValue();
+
+ if (isJSArray(&exec->globalData(), thisValue) && exec->argumentCount() == 1) {
JSArray* array = asArray(thisValue);
- array->push(exec, *args.begin());
- return jsNumber(exec, array->length());
+ array->push(exec, exec->argument(0));
+ return JSValue::encode(jsNumber(array->length()));
}
JSObject* thisObj = thisValue.toThisObject(exec);
unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
- for (unsigned n = 0; n < args.size(); n++)
- thisObj->put(exec, length + n, args.at(n));
- length += args.size();
- putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(exec, length));
- return jsNumber(exec, length);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ for (unsigned n = 0; n < exec->argumentCount(); n++)
+ thisObj->put(exec, length + n, exec->argument(n));
+ length += exec->argumentCount();
+ putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(length));
+ return JSValue::encode(jsNumber(length));
}
-JSValue JSC_HOST_CALL arrayProtoFuncReverse(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncReverse(ExecState* exec)
{
- JSObject* thisObj = thisValue.toThisObject(exec);
+ JSObject* thisObj = exec->hostThisValue().toThisObject(exec);
unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
- unsigned middle = length / 2;
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ unsigned middle = length / 2;
for (unsigned k = 0; k < middle; k++) {
unsigned lk1 = length - k - 1;
JSValue obj2 = getProperty(exec, thisObj, lk1);
else
thisObj->deleteProperty(exec, lk1);
}
- return thisObj;
+ return JSValue::encode(thisObj);
}
-JSValue JSC_HOST_CALL arrayProtoFuncShift(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncShift(ExecState* exec)
{
- JSObject* thisObj = thisValue.toThisObject(exec);
+ JSObject* thisObj = exec->hostThisValue().toThisObject(exec);
JSValue result;
unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
if (length == 0) {
- putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(exec, length));
+ putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(length));
result = jsUndefined();
} else {
result = thisObj->get(exec, 0);
- for (unsigned k = 1; k < length; k++) {
- if (JSValue obj = getProperty(exec, thisObj, k))
- thisObj->put(exec, k - 1, obj);
- else
- thisObj->deleteProperty(exec, k - 1);
+ if (isJSArray(&exec->globalData(), thisObj))
+ ((JSArray *)thisObj)->shiftCount(exec, 1);
+ else {
+ for (unsigned k = 1; k < length; k++) {
+ if (JSValue obj = getProperty(exec, thisObj, k))
+ thisObj->put(exec, k - 1, obj);
+ else
+ thisObj->deleteProperty(exec, k - 1);
+ }
+ thisObj->deleteProperty(exec, length - 1);
}
- thisObj->deleteProperty(exec, length - 1);
- putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(exec, length - 1));
+ putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(length - 1));
}
- return result;
+ return JSValue::encode(result);
}
-JSValue JSC_HOST_CALL arrayProtoFuncSlice(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncSlice(ExecState* exec)
{
// http://developer.netscape.com/docs/manuals/js/client/jsref/array.htm#1193713 or 15.4.4.10
-
- JSObject* thisObj = thisValue.toThisObject(exec);
+ JSObject* thisObj = exec->hostThisValue().toThisObject(exec);
// We return a new array
JSArray* resObj = constructEmptyArray(exec);
JSValue result = resObj;
- double begin = args.at(0).toInteger(exec);
+
unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
- if (begin >= 0) {
- if (begin > length)
- begin = length;
- } else {
- begin += length;
- if (begin < 0)
- begin = 0;
- }
- double end;
- if (args.at(1).isUndefined())
- end = length;
- else {
- end = args.at(1).toInteger(exec);
- if (end < 0) {
- end += length;
- if (end < 0)
- end = 0;
- } else {
- if (end > length)
- end = length;
- }
- }
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ unsigned begin = argumentClampedIndexFromStartOrEnd(exec, 0, length);
+ unsigned end = argumentClampedIndexFromStartOrEnd(exec, 1, length, length);
- int n = 0;
- int b = static_cast<int>(begin);
- int e = static_cast<int>(end);
- for (int k = b; k < e; k++, n++) {
+ unsigned n = 0;
+ for (unsigned k = begin; k < end; k++, n++) {
if (JSValue v = getProperty(exec, thisObj, k))
resObj->put(exec, n, v);
}
resObj->setLength(n);
- return result;
+ return JSValue::encode(result);
}
-JSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState* exec)
{
- JSObject* thisObj = thisValue.toThisObject(exec);
+ JSObject* thisObj = exec->hostThisValue().toThisObject(exec);
+ unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
+ if (!length || exec->hadException())
+ return JSValue::encode(thisObj);
- JSValue function = args.at(0);
+ JSValue function = exec->argument(0);
CallData callData;
- CallType callType = function.getCallData(callData);
+ CallType callType = getCallData(function, callData);
- if (thisObj->classInfo() == &JSArray::info) {
+ if (thisObj->classInfo() == &JSArray::s_info) {
if (isNumericCompareFunction(exec, callType, callData))
asArray(thisObj)->sortNumeric(exec, function, callType, callData);
else if (callType != CallTypeNone)
asArray(thisObj)->sort(exec, function, callType, callData);
else
asArray(thisObj)->sort(exec);
- return thisObj;
+ return JSValue::encode(thisObj);
}
- unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
-
- if (!length)
- return thisObj;
-
// "Min" sort. Not the fastest, but definitely less code than heapsort
// or quicksort, and much less swapping than bubblesort/insertionsort.
for (unsigned i = 0; i < length - 1; ++i) {
JSValue iObj = thisObj->get(exec, i);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
unsigned themin = i;
JSValue minObj = iObj;
for (unsigned j = i + 1; j < length; ++j) {
JSValue jObj = thisObj->get(exec, j);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
double compareResult;
if (jObj.isUndefined())
compareResult = 1; // don't check minObj because there's no need to differentiate == (0) from > (1)
thisObj->put(exec, themin, iObj);
}
}
- return thisObj;
+ return JSValue::encode(thisObj);
}
-JSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec)
{
- JSObject* thisObj = thisValue.toThisObject(exec);
-
// 15.4.4.12
- JSArray* resObj = constructEmptyArray(exec);
- JSValue result = resObj;
-
- // FIXME: Firefox returns an empty array.
- if (!args.size())
- return jsUndefined();
+ JSObject* thisObj = exec->hostThisValue().toThisObject(exec);
unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
- double relativeBegin = args.at(0).toInteger(exec);
- unsigned begin;
- if (relativeBegin < 0) {
- relativeBegin += length;
- begin = (relativeBegin < 0) ? 0 : static_cast<unsigned>(relativeBegin);
- } else
- begin = std::min<unsigned>(static_cast<unsigned>(relativeBegin), length);
-
- unsigned deleteCount;
- if (args.size() > 1)
- deleteCount = std::min<int>(std::max<int>(args.at(1).toUInt32(exec), 0), length - begin);
- else
- deleteCount = length - begin;
-
- for (unsigned k = 0; k < deleteCount; k++) {
- if (JSValue v = getProperty(exec, thisObj, k + begin))
- resObj->put(exec, k, v);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ if (!exec->argumentCount())
+ return JSValue::encode(constructEmptyArray(exec));
+
+ unsigned begin = argumentClampedIndexFromStartOrEnd(exec, 0, length);
+
+ unsigned deleteCount = length - begin;
+ if (exec->argumentCount() > 1) {
+ double deleteDouble = exec->argument(1).toInteger(exec);
+ if (deleteDouble < 0)
+ deleteCount = 0;
+ else if (deleteDouble > length - begin)
+ deleteCount = length - begin;
+ else
+ deleteCount = static_cast<unsigned>(deleteDouble);
}
+
+ JSArray* resObj = new (exec) JSArray(exec->globalData(), exec->lexicalGlobalObject()->arrayStructure(), deleteCount, CreateCompact);
+ JSValue result = resObj;
+ JSGlobalData& globalData = exec->globalData();
+ for (unsigned k = 0; k < deleteCount; k++)
+ resObj->uncheckedSetIndex(globalData, k, getProperty(exec, thisObj, k + begin));
+
resObj->setLength(deleteCount);
- unsigned additionalArgs = std::max<int>(args.size() - 2, 0);
+ unsigned additionalArgs = std::max<int>(exec->argumentCount() - 2, 0);
if (additionalArgs != deleteCount) {
if (additionalArgs < deleteCount) {
- for (unsigned k = begin; k < length - deleteCount; ++k) {
- if (JSValue v = getProperty(exec, thisObj, k + deleteCount))
- thisObj->put(exec, k + additionalArgs, v);
- else
- thisObj->deleteProperty(exec, k + additionalArgs);
+ if ((!begin) && (isJSArray(&exec->globalData(), thisObj)))
+ ((JSArray *)thisObj)->shiftCount(exec, deleteCount - additionalArgs);
+ else {
+ for (unsigned k = begin; k < length - deleteCount; ++k) {
+ if (JSValue v = getProperty(exec, thisObj, k + deleteCount))
+ thisObj->put(exec, k + additionalArgs, v);
+ else
+ thisObj->deleteProperty(exec, k + additionalArgs);
+ }
+ for (unsigned k = length; k > length - deleteCount + additionalArgs; --k)
+ thisObj->deleteProperty(exec, k - 1);
}
- for (unsigned k = length; k > length - deleteCount + additionalArgs; --k)
- thisObj->deleteProperty(exec, k - 1);
} else {
- for (unsigned k = length - deleteCount; k > begin; --k) {
- if (JSValue obj = getProperty(exec, thisObj, k + deleteCount - 1))
- thisObj->put(exec, k + additionalArgs - 1, obj);
- else
- thisObj->deleteProperty(exec, k + additionalArgs - 1);
+ if ((!begin) && (isJSArray(&exec->globalData(), thisObj)))
+ ((JSArray *)thisObj)->unshiftCount(exec, additionalArgs - deleteCount);
+ else {
+ for (unsigned k = length - deleteCount; k > begin; --k) {
+ if (JSValue obj = getProperty(exec, thisObj, k + deleteCount - 1))
+ thisObj->put(exec, k + additionalArgs - 1, obj);
+ else
+ thisObj->deleteProperty(exec, k + additionalArgs - 1);
+ }
}
}
}
for (unsigned k = 0; k < additionalArgs; ++k)
- thisObj->put(exec, k + begin, args.at(k + 2));
+ thisObj->put(exec, k + begin, exec->argument(k + 2));
- putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(exec, length - deleteCount + additionalArgs));
- return result;
+ putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(length - deleteCount + additionalArgs));
+ return JSValue::encode(result);
}
-JSValue JSC_HOST_CALL arrayProtoFuncUnShift(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncUnShift(ExecState* exec)
{
- JSObject* thisObj = thisValue.toThisObject(exec);
-
// 15.4.4.13
+
+ JSObject* thisObj = exec->hostThisValue().toThisObject(exec);
unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
- unsigned nrArgs = args.size();
- if (nrArgs) {
- for (unsigned k = length; k > 0; --k) {
- if (JSValue v = getProperty(exec, thisObj, k - 1))
- thisObj->put(exec, k + nrArgs - 1, v);
- else
- thisObj->deleteProperty(exec, k + nrArgs - 1);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ unsigned nrArgs = exec->argumentCount();
+ if ((nrArgs) && (length)) {
+ if (isJSArray(&exec->globalData(), thisObj))
+ ((JSArray *)thisObj)->unshiftCount(exec, nrArgs);
+ else {
+ for (unsigned k = length; k > 0; --k) {
+ if (JSValue v = getProperty(exec, thisObj, k - 1))
+ thisObj->put(exec, k + nrArgs - 1, v);
+ else
+ thisObj->deleteProperty(exec, k + nrArgs - 1);
+ }
}
}
for (unsigned k = 0; k < nrArgs; ++k)
- thisObj->put(exec, k, args.at(k));
- JSValue result = jsNumber(exec, length + nrArgs);
+ thisObj->put(exec, k, exec->argument(k));
+ JSValue result = jsNumber(length + nrArgs);
putProperty(exec, thisObj, exec->propertyNames().length, result);
- return result;
+ return JSValue::encode(result);
}
-JSValue JSC_HOST_CALL arrayProtoFuncFilter(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncFilter(ExecState* exec)
{
- JSObject* thisObj = thisValue.toThisObject(exec);
+ JSObject* thisObj = exec->hostThisValue().toThisObject(exec);
+ unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
- JSValue function = args.at(0);
+ JSValue function = exec->argument(0);
CallData callData;
- CallType callType = function.getCallData(callData);
+ CallType callType = getCallData(function, callData);
if (callType == CallTypeNone)
- return throwError(exec, TypeError);
+ return throwVMTypeError(exec);
- JSObject* applyThis = args.at(1).isUndefinedOrNull() ? exec->globalThisValue() : args.at(1).toObject(exec);
+ JSObject* applyThis = exec->argument(1).isUndefinedOrNull() ? exec->globalThisValue() : exec->argument(1).toObject(exec);
JSArray* resultArray = constructEmptyArray(exec);
unsigned filterIndex = 0;
- unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
unsigned k = 0;
if (callType == CallTypeJS && isJSArray(&exec->globalData(), thisObj)) {
JSFunction* f = asFunction(function);
JSArray* array = asArray(thisObj);
- CachedCall cachedCall(exec, f, 3, exec->exceptionSlot());
+ CachedCall cachedCall(exec, f, 3);
for (; k < length && !exec->hadException(); ++k) {
if (!array->canGetIndex(k))
break;
JSValue v = array->getIndex(k);
cachedCall.setThis(applyThis);
cachedCall.setArgument(0, v);
- cachedCall.setArgument(1, jsNumber(exec, k));
+ cachedCall.setArgument(1, jsNumber(k));
cachedCall.setArgument(2, thisObj);
JSValue result = cachedCall.call();
resultArray->put(exec, filterIndex++, v);
}
if (k == length)
- return resultArray;
+ return JSValue::encode(resultArray);
}
for (; k < length && !exec->hadException(); ++k) {
PropertySlot slot(thisObj);
-
if (!thisObj->getPropertySlot(exec, k, slot))
continue;
-
JSValue v = slot.getValue(exec, k);
- MarkedArgumentBuffer eachArguments;
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ MarkedArgumentBuffer eachArguments;
eachArguments.append(v);
- eachArguments.append(jsNumber(exec, k));
+ eachArguments.append(jsNumber(k));
eachArguments.append(thisObj);
JSValue result = call(exec, function, callType, callData, applyThis, eachArguments);
-
if (result.toBoolean(exec))
resultArray->put(exec, filterIndex++, v);
}
- return resultArray;
+ return JSValue::encode(resultArray);
}
-JSValue JSC_HOST_CALL arrayProtoFuncMap(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncMap(ExecState* exec)
{
- JSObject* thisObj = thisValue.toThisObject(exec);
+ JSObject* thisObj = exec->hostThisValue().toThisObject(exec);
+ unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
- JSValue function = args.at(0);
+ JSValue function = exec->argument(0);
CallData callData;
- CallType callType = function.getCallData(callData);
+ CallType callType = getCallData(function, callData);
if (callType == CallTypeNone)
- return throwError(exec, TypeError);
+ return throwVMTypeError(exec);
- JSObject* applyThis = args.at(1).isUndefinedOrNull() ? exec->globalThisValue() : args.at(1).toObject(exec);
-
- unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
+ JSObject* applyThis = exec->argument(1).isUndefinedOrNull() ? exec->globalThisValue() : exec->argument(1).toObject(exec);
JSArray* resultArray = constructEmptyArray(exec, length);
unsigned k = 0;
if (callType == CallTypeJS && isJSArray(&exec->globalData(), thisObj)) {
JSFunction* f = asFunction(function);
JSArray* array = asArray(thisObj);
- CachedCall cachedCall(exec, f, 3, exec->exceptionSlot());
+ CachedCall cachedCall(exec, f, 3);
for (; k < length && !exec->hadException(); ++k) {
if (UNLIKELY(!array->canGetIndex(k)))
break;
cachedCall.setThis(applyThis);
cachedCall.setArgument(0, array->getIndex(k));
- cachedCall.setArgument(1, jsNumber(exec, k));
+ cachedCall.setArgument(1, jsNumber(k));
cachedCall.setArgument(2, thisObj);
resultArray->JSArray::put(exec, k, cachedCall.call());
PropertySlot slot(thisObj);
if (!thisObj->getPropertySlot(exec, k, slot))
continue;
-
JSValue v = slot.getValue(exec, k);
- MarkedArgumentBuffer eachArguments;
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ MarkedArgumentBuffer eachArguments;
eachArguments.append(v);
- eachArguments.append(jsNumber(exec, k));
+ eachArguments.append(jsNumber(k));
eachArguments.append(thisObj);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
JSValue result = call(exec, function, callType, callData, applyThis, eachArguments);
resultArray->put(exec, k, result);
}
- return resultArray;
+ return JSValue::encode(resultArray);
}
// Documentation for these three is available at:
// http://developer-test.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:forEach
// http://developer-test.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:some
-JSValue JSC_HOST_CALL arrayProtoFuncEvery(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncEvery(ExecState* exec)
{
- JSObject* thisObj = thisValue.toThisObject(exec);
+ JSObject* thisObj = exec->hostThisValue().toThisObject(exec);
+ unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
- JSValue function = args.at(0);
+ JSValue function = exec->argument(0);
CallData callData;
- CallType callType = function.getCallData(callData);
+ CallType callType = getCallData(function, callData);
if (callType == CallTypeNone)
- return throwError(exec, TypeError);
+ return throwVMTypeError(exec);
- JSObject* applyThis = args.at(1).isUndefinedOrNull() ? exec->globalThisValue() : args.at(1).toObject(exec);
+ JSObject* applyThis = exec->argument(1).isUndefinedOrNull() ? exec->globalThisValue() : exec->argument(1).toObject(exec);
JSValue result = jsBoolean(true);
- unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
unsigned k = 0;
if (callType == CallTypeJS && isJSArray(&exec->globalData(), thisObj)) {
JSFunction* f = asFunction(function);
JSArray* array = asArray(thisObj);
- CachedCall cachedCall(exec, f, 3, exec->exceptionSlot());
+ CachedCall cachedCall(exec, f, 3);
for (; k < length && !exec->hadException(); ++k) {
if (UNLIKELY(!array->canGetIndex(k)))
break;
cachedCall.setThis(applyThis);
cachedCall.setArgument(0, array->getIndex(k));
- cachedCall.setArgument(1, jsNumber(exec, k));
+ cachedCall.setArgument(1, jsNumber(k));
cachedCall.setArgument(2, thisObj);
JSValue result = cachedCall.call();
if (!result.toBoolean(cachedCall.newCallFrame(exec)))
- return jsBoolean(false);
+ return JSValue::encode(jsBoolean(false));
}
}
for (; k < length && !exec->hadException(); ++k) {
PropertySlot slot(thisObj);
-
if (!thisObj->getPropertySlot(exec, k, slot))
continue;
MarkedArgumentBuffer eachArguments;
-
eachArguments.append(slot.getValue(exec, k));
- eachArguments.append(jsNumber(exec, k));
+ eachArguments.append(jsNumber(k));
eachArguments.append(thisObj);
- bool predicateResult = call(exec, function, callType, callData, applyThis, eachArguments).toBoolean(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ bool predicateResult = call(exec, function, callType, callData, applyThis, eachArguments).toBoolean(exec);
if (!predicateResult) {
result = jsBoolean(false);
break;
}
}
- return result;
+ return JSValue::encode(result);
}
-JSValue JSC_HOST_CALL arrayProtoFuncForEach(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncForEach(ExecState* exec)
{
- JSObject* thisObj = thisValue.toThisObject(exec);
+ JSObject* thisObj = exec->hostThisValue().toThisObject(exec);
+ unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
- JSValue function = args.at(0);
+ JSValue function = exec->argument(0);
CallData callData;
- CallType callType = function.getCallData(callData);
+ CallType callType = getCallData(function, callData);
if (callType == CallTypeNone)
- return throwError(exec, TypeError);
+ return throwVMTypeError(exec);
- JSObject* applyThis = args.at(1).isUndefinedOrNull() ? exec->globalThisValue() : args.at(1).toObject(exec);
+ JSObject* applyThis = exec->argument(1).isUndefinedOrNull() ? exec->globalThisValue() : exec->argument(1).toObject(exec);
- unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
unsigned k = 0;
if (callType == CallTypeJS && isJSArray(&exec->globalData(), thisObj)) {
JSFunction* f = asFunction(function);
JSArray* array = asArray(thisObj);
- CachedCall cachedCall(exec, f, 3, exec->exceptionSlot());
+ CachedCall cachedCall(exec, f, 3);
for (; k < length && !exec->hadException(); ++k) {
if (UNLIKELY(!array->canGetIndex(k)))
break;
cachedCall.setThis(applyThis);
cachedCall.setArgument(0, array->getIndex(k));
- cachedCall.setArgument(1, jsNumber(exec, k));
+ cachedCall.setArgument(1, jsNumber(k));
cachedCall.setArgument(2, thisObj);
cachedCall.call();
MarkedArgumentBuffer eachArguments;
eachArguments.append(slot.getValue(exec, k));
- eachArguments.append(jsNumber(exec, k));
+ eachArguments.append(jsNumber(k));
eachArguments.append(thisObj);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
call(exec, function, callType, callData, applyThis, eachArguments);
}
- return jsUndefined();
+ return JSValue::encode(jsUndefined());
}
-JSValue JSC_HOST_CALL arrayProtoFuncSome(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncSome(ExecState* exec)
{
- JSObject* thisObj = thisValue.toThisObject(exec);
+ JSObject* thisObj = exec->hostThisValue().toThisObject(exec);
+ unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
- JSValue function = args.at(0);
+ JSValue function = exec->argument(0);
CallData callData;
- CallType callType = function.getCallData(callData);
+ CallType callType = getCallData(function, callData);
if (callType == CallTypeNone)
- return throwError(exec, TypeError);
+ return throwVMTypeError(exec);
- JSObject* applyThis = args.at(1).isUndefinedOrNull() ? exec->globalThisValue() : args.at(1).toObject(exec);
+ JSObject* applyThis = exec->argument(1).isUndefinedOrNull() ? exec->globalThisValue() : exec->argument(1).toObject(exec);
JSValue result = jsBoolean(false);
- unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
unsigned k = 0;
if (callType == CallTypeJS && isJSArray(&exec->globalData(), thisObj)) {
JSFunction* f = asFunction(function);
JSArray* array = asArray(thisObj);
- CachedCall cachedCall(exec, f, 3, exec->exceptionSlot());
+ CachedCall cachedCall(exec, f, 3);
for (; k < length && !exec->hadException(); ++k) {
if (UNLIKELY(!array->canGetIndex(k)))
break;
cachedCall.setThis(applyThis);
cachedCall.setArgument(0, array->getIndex(k));
- cachedCall.setArgument(1, jsNumber(exec, k));
+ cachedCall.setArgument(1, jsNumber(k));
cachedCall.setArgument(2, thisObj);
JSValue result = cachedCall.call();
if (result.toBoolean(cachedCall.newCallFrame(exec)))
- return jsBoolean(true);
+ return JSValue::encode(jsBoolean(true));
}
}
for (; k < length && !exec->hadException(); ++k) {
MarkedArgumentBuffer eachArguments;
eachArguments.append(slot.getValue(exec, k));
- eachArguments.append(jsNumber(exec, k));
+ eachArguments.append(jsNumber(k));
eachArguments.append(thisObj);
- bool predicateResult = call(exec, function, callType, callData, applyThis, eachArguments).toBoolean(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ bool predicateResult = call(exec, function, callType, callData, applyThis, eachArguments).toBoolean(exec);
if (predicateResult) {
result = jsBoolean(true);
break;
}
}
- return result;
+ return JSValue::encode(result);
}
-JSValue JSC_HOST_CALL arrayProtoFuncReduce(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduce(ExecState* exec)
{
- JSObject* thisObj = thisValue.toThisObject(exec);
-
- JSValue function = args.at(0);
+ JSObject* thisObj = exec->hostThisValue().toThisObject(exec);
+ unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ JSValue function = exec->argument(0);
CallData callData;
- CallType callType = function.getCallData(callData);
+ CallType callType = getCallData(function, callData);
if (callType == CallTypeNone)
- return throwError(exec, TypeError);
+ return throwVMTypeError(exec);
unsigned i = 0;
JSValue rv;
- unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
- if (!length && args.size() == 1)
- return throwError(exec, TypeError);
+ if (!length && exec->argumentCount() == 1)
+ return throwVMTypeError(exec);
+
JSArray* array = 0;
if (isJSArray(&exec->globalData(), thisObj))
array = asArray(thisObj);
- if (args.size() >= 2)
- rv = args.at(1);
+ if (exec->argumentCount() >= 2)
+ rv = exec->argument(1);
else if (array && array->canGetIndex(0)){
rv = array->getIndex(0);
i = 1;
break;
}
if (!rv)
- return throwError(exec, TypeError);
+ return throwVMTypeError(exec);
i++;
}
if (callType == CallTypeJS && array) {
- CachedCall cachedCall(exec, asFunction(function), 4, exec->exceptionSlot());
+ CachedCall cachedCall(exec, asFunction(function), 4);
for (; i < length && !exec->hadException(); ++i) {
cachedCall.setThis(jsNull());
cachedCall.setArgument(0, rv);
else
break; // length has been made unsafe while we enumerate fallback to slow path
cachedCall.setArgument(1, v);
- cachedCall.setArgument(2, jsNumber(exec, i));
+ cachedCall.setArgument(2, jsNumber(i));
cachedCall.setArgument(3, array);
rv = cachedCall.call();
}
if (i == length) // only return if we reached the end of the array
- return rv;
+ return JSValue::encode(rv);
}
for (; i < length && !exec->hadException(); ++i) {
JSValue prop = getProperty(exec, thisObj, i);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
if (!prop)
continue;
MarkedArgumentBuffer eachArguments;
eachArguments.append(rv);
eachArguments.append(prop);
- eachArguments.append(jsNumber(exec, i));
+ eachArguments.append(jsNumber(i));
eachArguments.append(thisObj);
rv = call(exec, function, callType, callData, jsNull(), eachArguments);
}
- return rv;
+ return JSValue::encode(rv);
}
-JSValue JSC_HOST_CALL arrayProtoFuncReduceRight(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduceRight(ExecState* exec)
{
- JSObject* thisObj = thisValue.toThisObject(exec);
-
- JSValue function = args.at(0);
+ JSObject* thisObj = exec->hostThisValue().toThisObject(exec);
+ unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ JSValue function = exec->argument(0);
CallData callData;
- CallType callType = function.getCallData(callData);
+ CallType callType = getCallData(function, callData);
if (callType == CallTypeNone)
- return throwError(exec, TypeError);
+ return throwVMTypeError(exec);
unsigned i = 0;
JSValue rv;
- unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
- if (!length && args.size() == 1)
- return throwError(exec, TypeError);
+ if (!length && exec->argumentCount() == 1)
+ return throwVMTypeError(exec);
+
JSArray* array = 0;
if (isJSArray(&exec->globalData(), thisObj))
array = asArray(thisObj);
- if (args.size() >= 2)
- rv = args.at(1);
+ if (exec->argumentCount() >= 2)
+ rv = exec->argument(1);
else if (array && array->canGetIndex(length - 1)){
rv = array->getIndex(length - 1);
i = 1;
break;
}
if (!rv)
- return throwError(exec, TypeError);
+ return throwVMTypeError(exec);
i++;
}
if (callType == CallTypeJS && array) {
- CachedCall cachedCall(exec, asFunction(function), 4, exec->exceptionSlot());
+ CachedCall cachedCall(exec, asFunction(function), 4);
for (; i < length && !exec->hadException(); ++i) {
unsigned idx = length - i - 1;
cachedCall.setThis(jsNull());
if (UNLIKELY(!array->canGetIndex(idx)))
break; // length has been made unsafe while we enumerate fallback to slow path
cachedCall.setArgument(1, array->getIndex(idx));
- cachedCall.setArgument(2, jsNumber(exec, idx));
+ cachedCall.setArgument(2, jsNumber(idx));
cachedCall.setArgument(3, array);
rv = cachedCall.call();
}
if (i == length) // only return if we reached the end of the array
- return rv;
+ return JSValue::encode(rv);
}
for (; i < length && !exec->hadException(); ++i) {
unsigned idx = length - i - 1;
JSValue prop = getProperty(exec, thisObj, idx);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
if (!prop)
continue;
MarkedArgumentBuffer eachArguments;
eachArguments.append(rv);
eachArguments.append(prop);
- eachArguments.append(jsNumber(exec, idx));
+ eachArguments.append(jsNumber(idx));
eachArguments.append(thisObj);
rv = call(exec, function, callType, callData, jsNull(), eachArguments);
}
- return rv;
+ return JSValue::encode(rv);
}
-JSValue JSC_HOST_CALL arrayProtoFuncIndexOf(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncIndexOf(ExecState* exec)
{
- // JavaScript 1.5 Extension by Mozilla
- // Documentation: http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf
-
- JSObject* thisObj = thisValue.toThisObject(exec);
-
- unsigned index = 0;
- double d = args.at(1).toInteger(exec);
+ // 15.4.4.14
+ JSObject* thisObj = exec->hostThisValue().toThisObject(exec);
unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
- if (d < 0)
- d += length;
- if (d > 0) {
- if (d > length)
- index = length;
- else
- index = static_cast<unsigned>(d);
- }
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
- JSValue searchElement = args.at(0);
+ unsigned index = argumentClampedIndexFromStartOrEnd(exec, 1, length);
+ JSValue searchElement = exec->argument(0);
for (; index < length; ++index) {
JSValue e = getProperty(exec, thisObj, index);
if (!e)
continue;
if (JSValue::strictEqual(exec, searchElement, e))
- return jsNumber(exec, index);
+ return JSValue::encode(jsNumber(index));
}
- return jsNumber(exec, -1);
+ return JSValue::encode(jsNumber(-1));
}
-JSValue JSC_HOST_CALL arrayProtoFuncLastIndexOf(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncLastIndexOf(ExecState* exec)
{
- // JavaScript 1.6 Extension by Mozilla
- // Documentation: http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:lastIndexOf
-
- JSObject* thisObj = thisValue.toThisObject(exec);
-
+ // 15.4.4.15
+ JSObject* thisObj = exec->hostThisValue().toThisObject(exec);
unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
- int index = length - 1;
- double d = args.at(1).toIntegerPreserveNaN(exec);
-
- if (d < 0) {
- d += length;
- if (d < 0)
- return jsNumber(exec, -1);
+ if (!length)
+ return JSValue::encode(jsNumber(-1));
+
+ unsigned index = length - 1;
+ JSValue fromValue = exec->argument(1);
+ if (!fromValue.isUndefined()) {
+ double fromDouble = fromValue.toInteger(exec);
+ if (fromDouble < 0) {
+ fromDouble += length;
+ if (fromDouble < 0)
+ return JSValue::encode(jsNumber(-1));
+ }
+ if (fromDouble < length)
+ index = static_cast<unsigned>(fromDouble);
}
- if (d < length)
- index = static_cast<int>(d);
- JSValue searchElement = args.at(0);
- for (; index >= 0; --index) {
+ JSValue searchElement = exec->argument(0);
+ do {
+ ASSERT(index < length);
JSValue e = getProperty(exec, thisObj, index);
if (!e)
continue;
if (JSValue::strictEqual(exec, searchElement, e))
- return jsNumber(exec, index);
- }
+ return JSValue::encode(jsNumber(index));
+ } while (index--);
- return jsNumber(exec, -1);
+ return JSValue::encode(jsNumber(-1));
}
} // namespace JSC
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2011 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
class ArrayPrototype : public JSArray {
public:
- explicit ArrayPrototype(NonNullPassRefPtr<Structure>);
+ explicit ArrayPrototype(JSGlobalObject*, Structure*);
bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
- virtual const ClassInfo* classInfo() const { return &info; }
- static const ClassInfo info;
+ static const ClassInfo s_info;
+
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
+ {
+ return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
+ }
+
+ protected:
+ static const unsigned AnonymousSlotCount = JSArray::AnonymousSlotCount + 1;
};
} // namespace JSC
#ifndef BatchedTransitionOptimizer_h
#define BatchedTransitionOptimizer_h
-#include <wtf/Noncopyable.h>
#include "JSObject.h"
namespace JSC {
- class BatchedTransitionOptimizer : public Noncopyable {
+ class BatchedTransitionOptimizer {
+ WTF_MAKE_NONCOPYABLE(BatchedTransitionOptimizer);
public:
- BatchedTransitionOptimizer(JSObject* object)
- : m_object(object)
+ BatchedTransitionOptimizer(JSGlobalData& globalData, JSObject* object)
+ : m_globalData(&globalData)
+ , m_object(object)
{
- if (!m_object->structure()->isDictionary())
- m_object->setStructure(Structure::toCacheableDictionaryTransition(m_object->structure()));
}
~BatchedTransitionOptimizer()
{
- m_object->flattenDictionaryObject();
+ if (m_object->structure()->isDictionary())
+ m_object->flattenDictionaryObject(*m_globalData);
}
private:
+ JSGlobalData* m_globalData;
JSObject* m_object;
};
ASSERT_CLASS_FITS_IN_CELL(BooleanConstructor);
-BooleanConstructor::BooleanConstructor(ExecState* exec, NonNullPassRefPtr<Structure> structure, BooleanPrototype* booleanPrototype)
- : InternalFunction(&exec->globalData(), structure, Identifier(exec, booleanPrototype->classInfo()->className))
+BooleanConstructor::BooleanConstructor(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, BooleanPrototype* booleanPrototype)
+ : InternalFunction(&exec->globalData(), globalObject, structure, Identifier(exec, booleanPrototype->classInfo()->className))
{
- putDirectWithoutTransition(exec->propertyNames().prototype, booleanPrototype, DontEnum | DontDelete | ReadOnly);
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().prototype, booleanPrototype, DontEnum | DontDelete | ReadOnly);
// no. of arguments for constructor
- putDirectWithoutTransition(exec->propertyNames().length, jsNumber(exec, 1), ReadOnly | DontDelete | DontEnum);
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(1), ReadOnly | DontDelete | DontEnum);
}
// ECMA 15.6.2
JSObject* constructBoolean(ExecState* exec, const ArgList& args)
{
- BooleanObject* obj = new (exec) BooleanObject(exec->lexicalGlobalObject()->booleanObjectStructure());
- obj->setInternalValue(jsBoolean(args.at(0).toBoolean(exec)));
+ BooleanObject* obj = new (exec) BooleanObject(exec->globalData(), asInternalFunction(exec->callee())->globalObject()->booleanObjectStructure());
+ obj->setInternalValue(exec->globalData(), jsBoolean(args.at(0).toBoolean(exec)));
return obj;
}
-static JSObject* constructWithBooleanConstructor(ExecState* exec, JSObject*, const ArgList& args)
+static EncodedJSValue JSC_HOST_CALL constructWithBooleanConstructor(ExecState* exec)
{
- return constructBoolean(exec, args);
+ ArgList args(exec);
+ return JSValue::encode(constructBoolean(exec, args));
}
ConstructType BooleanConstructor::getConstructData(ConstructData& constructData)
}
// ECMA 15.6.1
-static JSValue JSC_HOST_CALL callBooleanConstructor(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+static EncodedJSValue JSC_HOST_CALL callBooleanConstructor(ExecState* exec)
{
- return jsBoolean(args.at(0).toBoolean(exec));
+ return JSValue::encode(jsBoolean(exec->argument(0).toBoolean(exec)));
}
CallType BooleanConstructor::getCallData(CallData& callData)
return CallTypeHost;
}
-JSObject* constructBooleanFromImmediateBoolean(ExecState* exec, JSValue immediateBooleanValue)
+JSObject* constructBooleanFromImmediateBoolean(ExecState* exec, JSGlobalObject* globalObject, JSValue immediateBooleanValue)
{
- BooleanObject* obj = new (exec) BooleanObject(exec->lexicalGlobalObject()->booleanObjectStructure());
- obj->setInternalValue(immediateBooleanValue);
+ BooleanObject* obj = new (exec) BooleanObject(exec->globalData(), globalObject->booleanObjectStructure());
+ obj->setInternalValue(exec->globalData(), immediateBooleanValue);
return obj;
}
class BooleanConstructor : public InternalFunction {
public:
- BooleanConstructor(ExecState*, NonNullPassRefPtr<Structure>, BooleanPrototype*);
+ BooleanConstructor(ExecState*, JSGlobalObject*, Structure*, BooleanPrototype*);
private:
virtual ConstructType getConstructData(ConstructData&);
virtual CallType getCallData(CallData&);
};
- JSObject* constructBooleanFromImmediateBoolean(ExecState*, JSValue);
+ JSObject* constructBooleanFromImmediateBoolean(ExecState*, JSGlobalObject*, JSValue);
JSObject* constructBoolean(ExecState*, const ArgList&);
} // namespace JSC
ASSERT_CLASS_FITS_IN_CELL(BooleanObject);
-const ClassInfo BooleanObject::info = { "Boolean", 0, 0, 0 };
+const ClassInfo BooleanObject::s_info = { "Boolean", &JSWrapperObject::s_info, 0, 0 };
-BooleanObject::BooleanObject(NonNullPassRefPtr<Structure> structure)
- : JSWrapperObject(structure)
+BooleanObject::BooleanObject(JSGlobalData& globalData, Structure* structure)
+ : JSWrapperObject(globalData, structure)
{
+ ASSERT(inherits(&s_info));
}
} // namespace JSC
class BooleanObject : public JSWrapperObject {
public:
- explicit BooleanObject(NonNullPassRefPtr<Structure>);
+ explicit BooleanObject(JSGlobalData&, Structure*);
- virtual const ClassInfo* classInfo() const { return &info; }
- static const ClassInfo info;
+ static const ClassInfo s_info;
- static PassRefPtr<Structure> createStructure(JSValue prototype)
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
+ return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
}
};
inline BooleanObject* asBooleanObject(JSValue value)
{
- ASSERT(asObject(value)->inherits(&BooleanObject::info));
+ ASSERT(asObject(value)->inherits(&BooleanObject::s_info));
return static_cast<BooleanObject*>(asObject(value));
}
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2003, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2008, 2011 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
#include "BooleanPrototype.h"
#include "Error.h"
+#include "ExceptionHelpers.h"
#include "JSFunction.h"
#include "JSString.h"
#include "ObjectPrototype.h"
-#include "PrototypeFunction.h"
namespace JSC {
-ASSERT_CLASS_FITS_IN_CELL(BooleanPrototype);
+static EncodedJSValue JSC_HOST_CALL booleanProtoFuncToString(ExecState*);
+static EncodedJSValue JSC_HOST_CALL booleanProtoFuncValueOf(ExecState*);
+
+}
+
+#include "BooleanPrototype.lut.h"
+
+namespace JSC {
-// Functions
-static JSValue JSC_HOST_CALL booleanProtoFuncToString(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL booleanProtoFuncValueOf(ExecState*, JSObject*, JSValue, const ArgList&);
+const ClassInfo BooleanPrototype::s_info = { "Boolean", &BooleanObject::s_info, 0, ExecState::booleanPrototypeTable };
-// ECMA 15.6.4
+/* Source for BooleanPrototype.lut.h
+@begin booleanPrototypeTable
+ toString booleanProtoFuncToString DontEnum|Function 0
+ valueOf booleanProtoFuncValueOf DontEnum|Function 0
+@end
+*/
-BooleanPrototype::BooleanPrototype(ExecState* exec, NonNullPassRefPtr<Structure> structure, Structure* prototypeFunctionStructure)
- : BooleanObject(structure)
+ASSERT_CLASS_FITS_IN_CELL(BooleanPrototype);
+
+BooleanPrototype::BooleanPrototype(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
+ : BooleanObject(exec->globalData(), structure)
{
- setInternalValue(jsBoolean(false));
+ setInternalValue(exec->globalData(), jsBoolean(false));
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 0, exec->propertyNames().toString, booleanProtoFuncToString), DontEnum);
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 0, exec->propertyNames().valueOf, booleanProtoFuncValueOf), DontEnum);
+ ASSERT(inherits(&s_info));
+ putAnonymousValue(globalObject->globalData(), 0, globalObject);
}
+bool BooleanPrototype::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot &slot)
+{
+ return getStaticFunctionSlot<BooleanObject>(exec, ExecState::booleanPrototypeTable(exec), this, propertyName, slot);
+}
-// ------------------------------ Functions --------------------------
+bool BooleanPrototype::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ return getStaticFunctionDescriptor<BooleanObject>(exec, ExecState::booleanPrototypeTable(exec), this, propertyName, descriptor);
+}
-// ECMA 15.6.4.2 + 15.6.4.3
+// ------------------------------ Functions ---------------------------
-JSValue JSC_HOST_CALL booleanProtoFuncToString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL booleanProtoFuncToString(ExecState* exec)
{
+ JSValue thisValue = exec->hostThisValue();
if (thisValue == jsBoolean(false))
- return jsNontrivialString(exec, "false");
+ return JSValue::encode(jsNontrivialString(exec, "false"));
if (thisValue == jsBoolean(true))
- return jsNontrivialString(exec, "true");
+ return JSValue::encode(jsNontrivialString(exec, "true"));
- if (!thisValue.inherits(&BooleanObject::info))
- return throwError(exec, TypeError);
+ if (!thisValue.inherits(&BooleanObject::s_info))
+ return throwVMTypeError(exec);
if (asBooleanObject(thisValue)->internalValue() == jsBoolean(false))
- return jsNontrivialString(exec, "false");
+ return JSValue::encode(jsNontrivialString(exec, "false"));
ASSERT(asBooleanObject(thisValue)->internalValue() == jsBoolean(true));
- return jsNontrivialString(exec, "true");
+ return JSValue::encode(jsNontrivialString(exec, "true"));
}
-JSValue JSC_HOST_CALL booleanProtoFuncValueOf(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL booleanProtoFuncValueOf(ExecState* exec)
{
+ JSValue thisValue = exec->hostThisValue();
if (thisValue.isBoolean())
- return thisValue;
+ return JSValue::encode(thisValue);
- if (!thisValue.inherits(&BooleanObject::info))
- return throwError(exec, TypeError);
+ if (!thisValue.inherits(&BooleanObject::s_info))
+ return throwVMTypeError(exec);
- return asBooleanObject(thisValue)->internalValue();
+ return JSValue::encode(asBooleanObject(thisValue)->internalValue());
}
} // namespace JSC
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2011 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
class BooleanPrototype : public BooleanObject {
public:
- BooleanPrototype(ExecState*, NonNullPassRefPtr<Structure>, Structure* prototypeFunctionStructure);
+ BooleanPrototype(ExecState*, JSGlobalObject*, Structure*);
+
+ static const ClassInfo s_info;
+
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
+ {
+ return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
+ }
+
+ protected:
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | BooleanObject::StructureFlags;
+ static const unsigned AnonymousSlotCount = BooleanObject::AnonymousSlotCount + 1;
+
+ private:
+ virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
+ virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
};
} // namespace JSC
fastFree(m_cache);
}
- JSValue operator() (ExecState* exec, double operand)
+ JSValue operator() (double operand)
{
if (UNLIKELY(!m_cache))
initialize();
CacheEntry* entry = &m_cache[hash(operand)];
if (entry->operand == operand)
- return jsDoubleNumber(exec, entry->result);
+ return jsDoubleNumber(entry->result);
double result = orignalFunction(operand);
entry->operand = operand;
entry->result = result;
- return jsDoubleNumber(exec, result);
+ return jsDoubleNumber(result);
}
private:
#include "config.h"
#include "CallData.h"
+#include "Executable.h"
+#include "Interpreter.h"
#include "JSFunction.h"
namespace JSC {
JSValue call(ExecState* exec, JSValue functionObject, CallType callType, const CallData& callData, JSValue thisValue, const ArgList& args)
{
- if (callType == CallTypeHost)
- return callData.native.function(exec, asObject(functionObject), thisValue, args);
- ASSERT(callType == CallTypeJS);
- // FIXME: Can this be done more efficiently using the callData?
- return asFunction(functionObject)->call(exec, thisValue, args);
+ ASSERT(callType == CallTypeJS || callType == CallTypeHost);
+ return exec->interpreter()->executeCall(exec, asObject(functionObject), callType, callData, thisValue, args);
}
} // namespace JSC
#ifndef CallData_h
#define CallData_h
-#include "NativeFunctionWrapper.h"
+#include "JSValue.h"
namespace JSC {
class ExecState;
class FunctionExecutable;
class JSObject;
- class JSValue;
class ScopeChainNode;
enum CallType {
CallTypeJS
};
- typedef JSValue (JSC_HOST_CALL *NativeFunction)(ExecState*, JSObject*, JSValue thisValue, const ArgList&);
+ typedef EncodedJSValue (JSC_HOST_CALL *NativeFunction)(ExecState*);
union CallData {
struct {
+++ /dev/null
-/*
- * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
- * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#include "config.h"
-#include "Collector.h"
-
-#include "ArgList.h"
-#include "CallFrame.h"
-#include "CodeBlock.h"
-#include "CollectorHeapIterator.h"
-#include "Interpreter.h"
-#include "JSArray.h"
-#include "JSGlobalObject.h"
-#include "JSLock.h"
-#include "JSONObject.h"
-#include "JSString.h"
-#include "JSValue.h"
-#include "JSZombie.h"
-#include "MarkStack.h"
-#include "Nodes.h"
-#include "Tracing.h"
-#include <algorithm>
-#include <limits.h>
-#include <setjmp.h>
-#include <stdlib.h>
-#include <wtf/FastMalloc.h>
-#include <wtf/HashCountedSet.h>
-#include <wtf/UnusedParam.h>
-#include <wtf/VMTags.h>
-
-#if OS(DARWIN)
-
-#include <mach/mach_init.h>
-#include <mach/mach_port.h>
-#include <mach/task.h>
-#include <mach/thread_act.h>
-#include <mach/vm_map.h>
-
-#elif OS(WINDOWS)
-
-#include <windows.h>
-#include <malloc.h>
-
-#elif OS(HAIKU)
-
-#include <OS.h>
-
-#elif OS(UNIX)
-
-#include <stdlib.h>
-#if !OS(HAIKU)
-#include <sys/mman.h>
-#endif
-#include <unistd.h>
-
-#if OS(SOLARIS)
-#include <thread.h>
-#else
-#include <pthread.h>
-#endif
-
-#if HAVE(PTHREAD_NP_H)
-#include <pthread_np.h>
-#endif
-
-#if OS(QNX)
-#include <fcntl.h>
-#include <sys/procfs.h>
-#include <stdio.h>
-#include <errno.h>
-#endif
-
-#endif
-
-#define COLLECT_ON_EVERY_ALLOCATION 0
-
-using std::max;
-
-namespace JSC {
-
-// tunable parameters
-
-const size_t GROWTH_FACTOR = 2;
-const size_t LOW_WATER_FACTOR = 4;
-const size_t ALLOCATIONS_PER_COLLECTION = 3600;
-// This value has to be a macro to be used in max() without introducing
-// a PIC branch in Mach-O binaries, see <rdar://problem/5971391>.
-#define MIN_ARRAY_SIZE (static_cast<size_t>(14))
-
-#if ENABLE(JSC_MULTIPLE_THREADS)
-
-#if OS(DARWIN)
-typedef mach_port_t PlatformThread;
-#elif OS(WINDOWS)
-typedef HANDLE PlatformThread;
-#endif
-
-class Heap::Thread {
-public:
- Thread(pthread_t pthread, const PlatformThread& platThread, void* base)
- : posixThread(pthread)
- , platformThread(platThread)
- , stackBase(base)
- {
- }
-
- Thread* next;
- pthread_t posixThread;
- PlatformThread platformThread;
- void* stackBase;
-};
-
-#endif
-
-Heap::Heap(JSGlobalData* globalData)
- : m_markListSet(0)
-#if ENABLE(JSC_MULTIPLE_THREADS)
- , m_registeredThreads(0)
- , m_currentThreadRegistrar(0)
-#endif
-#if OS(SYMBIAN)
- , m_blockallocator(JSCCOLLECTOR_VIRTUALMEM_RESERVATION, BLOCK_SIZE)
-#endif
- , m_globalData(globalData)
-{
- ASSERT(globalData);
- memset(&m_heap, 0, sizeof(CollectorHeap));
- allocateBlock();
-}
-
-Heap::~Heap()
-{
- // The destroy function must already have been called, so assert this.
- ASSERT(!m_globalData);
-}
-
-void Heap::destroy()
-{
- JSLock lock(SilenceAssertionsOnly);
-
- if (!m_globalData)
- return;
-
- ASSERT(!m_globalData->dynamicGlobalObject);
- ASSERT(!isBusy());
-
- // The global object is not GC protected at this point, so sweeping may delete it
- // (and thus the global data) before other objects that may use the global data.
- RefPtr<JSGlobalData> protect(m_globalData);
-
- delete m_markListSet;
- m_markListSet = 0;
-
- freeBlocks();
-
-#if ENABLE(JSC_MULTIPLE_THREADS)
- if (m_currentThreadRegistrar) {
- int error = pthread_key_delete(m_currentThreadRegistrar);
- ASSERT_UNUSED(error, !error);
- }
-
- MutexLocker registeredThreadsLock(m_registeredThreadsMutex);
- for (Heap::Thread* t = m_registeredThreads; t;) {
- Heap::Thread* next = t->next;
- delete t;
- t = next;
- }
-#endif
-#if OS(SYMBIAN)
- m_blockallocator.destroy();
-#endif
- m_globalData = 0;
-}
-
-NEVER_INLINE CollectorBlock* Heap::allocateBlock()
-{
-#if OS(DARWIN)
- vm_address_t address = 0;
- vm_map(current_task(), &address, BLOCK_SIZE, BLOCK_OFFSET_MASK, VM_FLAGS_ANYWHERE | VM_TAG_FOR_COLLECTOR_MEMORY, MEMORY_OBJECT_NULL, 0, FALSE, VM_PROT_DEFAULT, VM_PROT_DEFAULT, VM_INHERIT_DEFAULT);
-#elif OS(SYMBIAN)
- void* address = m_blockallocator.alloc();
- if (!address)
- CRASH();
-#elif OS(WINCE)
- void* address = VirtualAlloc(NULL, BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
-#elif OS(WINDOWS)
-#if COMPILER(MINGW) && !COMPILER(MINGW64)
- void* address = __mingw_aligned_malloc(BLOCK_SIZE, BLOCK_SIZE);
-#else
- void* address = _aligned_malloc(BLOCK_SIZE, BLOCK_SIZE);
-#endif
- memset(address, 0, BLOCK_SIZE);
-#elif HAVE(POSIX_MEMALIGN)
- void* address;
- posix_memalign(&address, BLOCK_SIZE, BLOCK_SIZE);
-#else
-
-#if ENABLE(JSC_MULTIPLE_THREADS)
-#error Need to initialize pagesize safely.
-#endif
- static size_t pagesize = getpagesize();
-
- size_t extra = 0;
- if (BLOCK_SIZE > pagesize)
- extra = BLOCK_SIZE - pagesize;
-
- void* mmapResult = mmap(NULL, BLOCK_SIZE + extra, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
- uintptr_t address = reinterpret_cast<uintptr_t>(mmapResult);
-
- size_t adjust = 0;
- if ((address & BLOCK_OFFSET_MASK) != 0)
- adjust = BLOCK_SIZE - (address & BLOCK_OFFSET_MASK);
-
- if (adjust > 0)
- munmap(reinterpret_cast<char*>(address), adjust);
-
- if (adjust < extra)
- munmap(reinterpret_cast<char*>(address + adjust + BLOCK_SIZE), extra - adjust);
-
- address += adjust;
-#endif
-
- // Initialize block.
-
- CollectorBlock* block = reinterpret_cast<CollectorBlock*>(address);
- block->heap = this;
- clearMarkBits(block);
-
- Structure* dummyMarkableCellStructure = m_globalData->dummyMarkableCellStructure.get();
- for (size_t i = 0; i < HeapConstants::cellsPerBlock; ++i)
- new (block->cells + i) JSCell(dummyMarkableCellStructure);
-
- // Add block to blocks vector.
-
- size_t numBlocks = m_heap.numBlocks;
- if (m_heap.usedBlocks == numBlocks) {
- static const size_t maxNumBlocks = ULONG_MAX / sizeof(CollectorBlock*) / GROWTH_FACTOR;
- if (numBlocks > maxNumBlocks)
- CRASH();
- numBlocks = max(MIN_ARRAY_SIZE, numBlocks * GROWTH_FACTOR);
- m_heap.numBlocks = numBlocks;
- m_heap.blocks = static_cast<CollectorBlock**>(fastRealloc(m_heap.blocks, numBlocks * sizeof(CollectorBlock*)));
- }
- m_heap.blocks[m_heap.usedBlocks++] = block;
-
- return block;
-}
-
-NEVER_INLINE void Heap::freeBlock(size_t block)
-{
- m_heap.didShrink = true;
-
- ObjectIterator it(m_heap, block);
- ObjectIterator end(m_heap, block + 1);
- for ( ; it != end; ++it)
- (*it)->~JSCell();
- freeBlockPtr(m_heap.blocks[block]);
-
- // swap with the last block so we compact as we go
- m_heap.blocks[block] = m_heap.blocks[m_heap.usedBlocks - 1];
- m_heap.usedBlocks--;
-
- if (m_heap.numBlocks > MIN_ARRAY_SIZE && m_heap.usedBlocks < m_heap.numBlocks / LOW_WATER_FACTOR) {
- m_heap.numBlocks = m_heap.numBlocks / GROWTH_FACTOR;
- m_heap.blocks = static_cast<CollectorBlock**>(fastRealloc(m_heap.blocks, m_heap.numBlocks * sizeof(CollectorBlock*)));
- }
-}
-
-NEVER_INLINE void Heap::freeBlockPtr(CollectorBlock* block)
-{
-#if OS(DARWIN)
- vm_deallocate(current_task(), reinterpret_cast<vm_address_t>(block), BLOCK_SIZE);
-#elif OS(SYMBIAN)
- m_blockallocator.free(reinterpret_cast<void*>(block));
-#elif OS(WINCE)
- VirtualFree(block, 0, MEM_RELEASE);
-#elif OS(WINDOWS)
-#if COMPILER(MINGW) && !COMPILER(MINGW64)
- __mingw_aligned_free(block);
-#else
- _aligned_free(block);
-#endif
-#elif HAVE(POSIX_MEMALIGN)
- free(block);
-#else
- munmap(reinterpret_cast<char*>(block), BLOCK_SIZE);
-#endif
-}
-
-void Heap::freeBlocks()
-{
- ProtectCountSet protectedValuesCopy = m_protectedValues;
-
- clearMarkBits();
- ProtectCountSet::iterator protectedValuesEnd = protectedValuesCopy.end();
- for (ProtectCountSet::iterator it = protectedValuesCopy.begin(); it != protectedValuesEnd; ++it)
- markCell(it->first);
-
- m_heap.nextCell = 0;
- m_heap.nextBlock = 0;
- DeadObjectIterator it(m_heap, m_heap.nextBlock, m_heap.nextCell);
- DeadObjectIterator end(m_heap, m_heap.usedBlocks);
- for ( ; it != end; ++it)
- (*it)->~JSCell();
-
- ASSERT(!protectedObjectCount());
-
- protectedValuesEnd = protectedValuesCopy.end();
- for (ProtectCountSet::iterator it = protectedValuesCopy.begin(); it != protectedValuesEnd; ++it)
- it->first->~JSCell();
-
- for (size_t block = 0; block < m_heap.usedBlocks; ++block)
- freeBlockPtr(m_heap.blocks[block]);
-
- fastFree(m_heap.blocks);
-
- memset(&m_heap, 0, sizeof(CollectorHeap));
-}
-
-void Heap::recordExtraCost(size_t cost)
-{
- // Our frequency of garbage collection tries to balance memory use against speed
- // by collecting based on the number of newly created values. However, for values
- // that hold on to a great deal of memory that's not in the form of other JS values,
- // that is not good enough - in some cases a lot of those objects can pile up and
- // use crazy amounts of memory without a GC happening. So we track these extra
- // memory costs. Only unusually large objects are noted, and we only keep track
- // of this extra cost until the next GC. In garbage collected languages, most values
- // are either very short lived temporaries, or have extremely long lifetimes. So
- // if a large value survives one garbage collection, there is not much point to
- // collecting more frequently as long as it stays alive.
-
- if (m_heap.extraCost > maxExtraCost && m_heap.extraCost > m_heap.usedBlocks * BLOCK_SIZE / 2) {
- // If the last iteration through the heap deallocated blocks, we need
- // to clean up remaining garbage before marking. Otherwise, the conservative
- // marking mechanism might follow a pointer to unmapped memory.
- if (m_heap.didShrink)
- sweep();
- reset();
- }
- m_heap.extraCost += cost;
-}
-
-void* Heap::allocate(size_t s)
-{
- typedef HeapConstants::Block Block;
- typedef HeapConstants::Cell Cell;
-
- ASSERT(JSLock::lockCount() > 0);
- ASSERT(JSLock::currentThreadIsHoldingLock());
- ASSERT_UNUSED(s, s <= HeapConstants::cellSize);
-
- ASSERT(m_heap.operationInProgress == NoOperation);
-
-#if COLLECT_ON_EVERY_ALLOCATION
- collectAllGarbage();
- ASSERT(m_heap.operationInProgress == NoOperation);
-#endif
-
-allocate:
-
- // Fast case: find the next garbage cell and recycle it.
-
- do {
- ASSERT(m_heap.nextBlock < m_heap.usedBlocks);
- Block* block = reinterpret_cast<Block*>(m_heap.blocks[m_heap.nextBlock]);
- do {
- ASSERT(m_heap.nextCell < HeapConstants::cellsPerBlock);
- if (!block->marked.get(m_heap.nextCell)) { // Always false for the last cell in the block
- Cell* cell = block->cells + m_heap.nextCell;
-
- m_heap.operationInProgress = Allocation;
- JSCell* imp = reinterpret_cast<JSCell*>(cell);
- imp->~JSCell();
- m_heap.operationInProgress = NoOperation;
-
- ++m_heap.nextCell;
- return cell;
- }
- } while (++m_heap.nextCell != HeapConstants::cellsPerBlock);
- m_heap.nextCell = 0;
- } while (++m_heap.nextBlock != m_heap.usedBlocks);
-
- // Slow case: reached the end of the heap. Mark live objects and start over.
-
- reset();
- goto allocate;
-}
-
-void Heap::resizeBlocks()
-{
- m_heap.didShrink = false;
-
- size_t usedCellCount = markedCells();
- size_t minCellCount = usedCellCount + max(ALLOCATIONS_PER_COLLECTION, usedCellCount);
- size_t minBlockCount = (minCellCount + HeapConstants::cellsPerBlock - 1) / HeapConstants::cellsPerBlock;
-
- size_t maxCellCount = 1.25f * minCellCount;
- size_t maxBlockCount = (maxCellCount + HeapConstants::cellsPerBlock - 1) / HeapConstants::cellsPerBlock;
-
- if (m_heap.usedBlocks < minBlockCount)
- growBlocks(minBlockCount);
- else if (m_heap.usedBlocks > maxBlockCount)
- shrinkBlocks(maxBlockCount);
-}
-
-void Heap::growBlocks(size_t neededBlocks)
-{
- ASSERT(m_heap.usedBlocks < neededBlocks);
- while (m_heap.usedBlocks < neededBlocks)
- allocateBlock();
-}
-
-void Heap::shrinkBlocks(size_t neededBlocks)
-{
- ASSERT(m_heap.usedBlocks > neededBlocks);
-
- // Clear the always-on last bit, so isEmpty() isn't fooled by it.
- for (size_t i = 0; i < m_heap.usedBlocks; ++i)
- m_heap.blocks[i]->marked.clear(HeapConstants::cellsPerBlock - 1);
-
- for (size_t i = 0; i != m_heap.usedBlocks && m_heap.usedBlocks != neededBlocks; ) {
- if (m_heap.blocks[i]->marked.isEmpty()) {
- freeBlock(i);
- } else
- ++i;
- }
-
- // Reset the always-on last bit.
- for (size_t i = 0; i < m_heap.usedBlocks; ++i)
- m_heap.blocks[i]->marked.set(HeapConstants::cellsPerBlock - 1);
-}
-
-#if OS(WINCE)
-JS_EXPORTDATA void* g_stackBase = 0;
-
-inline bool isPageWritable(void* page)
-{
- MEMORY_BASIC_INFORMATION memoryInformation;
- DWORD result = VirtualQuery(page, &memoryInformation, sizeof(memoryInformation));
-
- // return false on error, including ptr outside memory
- if (result != sizeof(memoryInformation))
- return false;
-
- DWORD protect = memoryInformation.Protect & ~(PAGE_GUARD | PAGE_NOCACHE);
- return protect == PAGE_READWRITE
- || protect == PAGE_WRITECOPY
- || protect == PAGE_EXECUTE_READWRITE
- || protect == PAGE_EXECUTE_WRITECOPY;
-}
-
-static void* getStackBase(void* previousFrame)
-{
- // find the address of this stack frame by taking the address of a local variable
- bool isGrowingDownward;
- void* thisFrame = (void*)(&isGrowingDownward);
-
- isGrowingDownward = previousFrame < &thisFrame;
- static DWORD pageSize = 0;
- if (!pageSize) {
- SYSTEM_INFO systemInfo;
- GetSystemInfo(&systemInfo);
- pageSize = systemInfo.dwPageSize;
- }
-
- // scan all of memory starting from this frame, and return the last writeable page found
- register char* currentPage = (char*)((DWORD)thisFrame & ~(pageSize - 1));
- if (isGrowingDownward) {
- while (currentPage > 0) {
- // check for underflow
- if (currentPage >= (char*)pageSize)
- currentPage -= pageSize;
- else
- currentPage = 0;
- if (!isPageWritable(currentPage))
- return currentPage + pageSize;
- }
- return 0;
- } else {
- while (true) {
- // guaranteed to complete because isPageWritable returns false at end of memory
- currentPage += pageSize;
- if (!isPageWritable(currentPage))
- return currentPage;
- }
- }
-}
-#endif
-
-#if OS(QNX)
-static inline void *currentThreadStackBaseQNX()
-{
- static void* stackBase = 0;
- static size_t stackSize = 0;
- static pthread_t stackThread;
- pthread_t thread = pthread_self();
- if (stackBase == 0 || thread != stackThread) {
- struct _debug_thread_info threadInfo;
- memset(&threadInfo, 0, sizeof(threadInfo));
- threadInfo.tid = pthread_self();
- int fd = open("/proc/self", O_RDONLY);
- if (fd == -1) {
- LOG_ERROR("Unable to open /proc/self (errno: %d)", errno);
- return 0;
- }
- devctl(fd, DCMD_PROC_TIDSTATUS, &threadInfo, sizeof(threadInfo), 0);
- close(fd);
- stackBase = reinterpret_cast<void*>(threadInfo.stkbase);
- stackSize = threadInfo.stksize;
- ASSERT(stackBase);
- stackThread = thread;
- }
- return static_cast<char*>(stackBase) + stackSize;
-}
-#endif
-
-static inline void* currentThreadStackBase()
-{
-#if OS(DARWIN)
- pthread_t thread = pthread_self();
- return pthread_get_stackaddr_np(thread);
-#elif OS(WINDOWS) && CPU(X86) && COMPILER(MSVC)
- // offset 0x18 from the FS segment register gives a pointer to
- // the thread information block for the current thread
- NT_TIB* pTib;
- __asm {
- MOV EAX, FS:[18h]
- MOV pTib, EAX
- }
- return static_cast<void*>(pTib->StackBase);
-#elif OS(WINDOWS) && CPU(X86) && COMPILER(GCC)
- // offset 0x18 from the FS segment register gives a pointer to
- // the thread information block for the current thread
- NT_TIB* pTib;
- asm ( "movl %%fs:0x18, %0\n"
- : "=r" (pTib)
- );
- return static_cast<void*>(pTib->StackBase);
-#elif OS(WINDOWS) && CPU(X86_64)
- PNT_TIB64 pTib = reinterpret_cast<PNT_TIB64>(NtCurrentTeb());
- return reinterpret_cast<void*>(pTib->StackBase);
-#elif OS(QNX)
- AtomicallyInitializedStatic(Mutex&, mutex = *new Mutex);
- MutexLocker locker(mutex);
- return currentThreadStackBaseQNX();
-#elif OS(SOLARIS)
- stack_t s;
- thr_stksegment(&s);
- return s.ss_sp;
-#elif OS(OPENBSD)
- pthread_t thread = pthread_self();
- stack_t stack;
- pthread_stackseg_np(thread, &stack);
- return stack.ss_sp;
-#elif OS(SYMBIAN)
- TThreadStackInfo info;
- RThread thread;
- thread.StackInfo(info);
- return (void*)info.iBase;
-#elif OS(HAIKU)
- thread_info threadInfo;
- get_thread_info(find_thread(NULL), &threadInfo);
- return threadInfo.stack_end;
-#elif OS(UNIX)
- AtomicallyInitializedStatic(Mutex&, mutex = *new Mutex);
- MutexLocker locker(mutex);
- static void* stackBase = 0;
- static size_t stackSize = 0;
- static pthread_t stackThread;
- pthread_t thread = pthread_self();
- if (stackBase == 0 || thread != stackThread) {
- pthread_attr_t sattr;
- pthread_attr_init(&sattr);
-#if HAVE(PTHREAD_NP_H) || OS(NETBSD)
- // e.g. on FreeBSD 5.4, neundorf@kde.org
- pthread_attr_get_np(thread, &sattr);
-#else
- // FIXME: this function is non-portable; other POSIX systems may have different np alternatives
- pthread_getattr_np(thread, &sattr);
-#endif
- int rc = pthread_attr_getstack(&sattr, &stackBase, &stackSize);
- (void)rc; // FIXME: Deal with error code somehow? Seems fatal.
- ASSERT(stackBase);
- pthread_attr_destroy(&sattr);
- stackThread = thread;
- }
- return static_cast<char*>(stackBase) + stackSize;
-#elif OS(WINCE)
- AtomicallyInitializedStatic(Mutex&, mutex = *new Mutex);
- MutexLocker locker(mutex);
- if (g_stackBase)
- return g_stackBase;
- else {
- int dummy;
- return getStackBase(&dummy);
- }
-#else
-#error Need a way to get the stack base on this platform
-#endif
-}
-
-#if ENABLE(JSC_MULTIPLE_THREADS)
-
-static inline PlatformThread getCurrentPlatformThread()
-{
-#if OS(DARWIN)
- return pthread_mach_thread_np(pthread_self());
-#elif OS(WINDOWS)
- return pthread_getw32threadhandle_np(pthread_self());
-#endif
-}
-
-void Heap::makeUsableFromMultipleThreads()
-{
- if (m_currentThreadRegistrar)
- return;
-
- int error = pthread_key_create(&m_currentThreadRegistrar, unregisterThread);
- if (error)
- CRASH();
-}
-
-void Heap::registerThread()
-{
- ASSERT(!m_globalData->exclusiveThread || m_globalData->exclusiveThread == currentThread());
-
- if (!m_currentThreadRegistrar || pthread_getspecific(m_currentThreadRegistrar))
- return;
-
- pthread_setspecific(m_currentThreadRegistrar, this);
- Heap::Thread* thread = new Heap::Thread(pthread_self(), getCurrentPlatformThread(), currentThreadStackBase());
-
- MutexLocker lock(m_registeredThreadsMutex);
-
- thread->next = m_registeredThreads;
- m_registeredThreads = thread;
-}
-
-void Heap::unregisterThread(void* p)
-{
- if (p)
- static_cast<Heap*>(p)->unregisterThread();
-}
-
-void Heap::unregisterThread()
-{
- pthread_t currentPosixThread = pthread_self();
-
- MutexLocker lock(m_registeredThreadsMutex);
-
- if (pthread_equal(currentPosixThread, m_registeredThreads->posixThread)) {
- Thread* t = m_registeredThreads;
- m_registeredThreads = m_registeredThreads->next;
- delete t;
- } else {
- Heap::Thread* last = m_registeredThreads;
- Heap::Thread* t;
- for (t = m_registeredThreads->next; t; t = t->next) {
- if (pthread_equal(t->posixThread, currentPosixThread)) {
- last->next = t->next;
- break;
- }
- last = t;
- }
- ASSERT(t); // If t is NULL, we never found ourselves in the list.
- delete t;
- }
-}
-
-#else // ENABLE(JSC_MULTIPLE_THREADS)
-
-void Heap::registerThread()
-{
-}
-
-#endif
-
-inline bool isPointerAligned(void* p)
-{
- return (((intptr_t)(p) & (sizeof(char*) - 1)) == 0);
-}
-
-// Cell size needs to be a power of two for isPossibleCell to be valid.
-COMPILE_ASSERT(sizeof(CollectorCell) % 2 == 0, Collector_cell_size_is_power_of_two);
-
-#if USE(JSVALUE32)
-static bool isHalfCellAligned(void *p)
-{
- return (((intptr_t)(p) & (CELL_MASK >> 1)) == 0);
-}
-
-static inline bool isPossibleCell(void* p)
-{
- return isHalfCellAligned(p) && p;
-}
-
-#else
-
-static inline bool isCellAligned(void *p)
-{
- return (((intptr_t)(p) & CELL_MASK) == 0);
-}
-
-static inline bool isPossibleCell(void* p)
-{
- return isCellAligned(p) && p;
-}
-#endif // USE(JSVALUE32)
-
-void Heap::markConservatively(MarkStack& markStack, void* start, void* end)
-{
- if (start > end) {
- void* tmp = start;
- start = end;
- end = tmp;
- }
-
- ASSERT((static_cast<char*>(end) - static_cast<char*>(start)) < 0x1000000);
- ASSERT(isPointerAligned(start));
- ASSERT(isPointerAligned(end));
-
- char** p = static_cast<char**>(start);
- char** e = static_cast<char**>(end);
-
- CollectorBlock** blocks = m_heap.blocks;
- while (p != e) {
- char* x = *p++;
- if (isPossibleCell(x)) {
- size_t usedBlocks;
- uintptr_t xAsBits = reinterpret_cast<uintptr_t>(x);
- xAsBits &= CELL_ALIGN_MASK;
-
- uintptr_t offset = xAsBits & BLOCK_OFFSET_MASK;
- const size_t lastCellOffset = sizeof(CollectorCell) * (CELLS_PER_BLOCK - 1);
- if (offset > lastCellOffset)
- continue;
-
- CollectorBlock* blockAddr = reinterpret_cast<CollectorBlock*>(xAsBits - offset);
- usedBlocks = m_heap.usedBlocks;
- for (size_t block = 0; block < usedBlocks; block++) {
- if (blocks[block] != blockAddr)
- continue;
- markStack.append(reinterpret_cast<JSCell*>(xAsBits));
- markStack.drain();
- }
- }
- }
-}
-
-void NEVER_INLINE Heap::markCurrentThreadConservativelyInternal(MarkStack& markStack)
-{
- void* dummy;
- void* stackPointer = &dummy;
- void* stackBase = currentThreadStackBase();
- markConservatively(markStack, stackPointer, stackBase);
-}
-
-#if COMPILER(GCC)
-#define REGISTER_BUFFER_ALIGNMENT __attribute__ ((aligned (sizeof(void*))))
-#else
-#define REGISTER_BUFFER_ALIGNMENT
-#endif
-
-void Heap::markCurrentThreadConservatively(MarkStack& markStack)
-{
- // setjmp forces volatile registers onto the stack
- jmp_buf registers REGISTER_BUFFER_ALIGNMENT;
-#if COMPILER(MSVC)
-#pragma warning(push)
-#pragma warning(disable: 4611)
-#endif
- setjmp(registers);
-#if COMPILER(MSVC)
-#pragma warning(pop)
-#endif
-
- markCurrentThreadConservativelyInternal(markStack);
-}
-
-#if ENABLE(JSC_MULTIPLE_THREADS)
-
-static inline void suspendThread(const PlatformThread& platformThread)
-{
-#if OS(DARWIN)
- thread_suspend(platformThread);
-#elif OS(WINDOWS)
- SuspendThread(platformThread);
-#else
-#error Need a way to suspend threads on this platform
-#endif
-}
-
-static inline void resumeThread(const PlatformThread& platformThread)
-{
-#if OS(DARWIN)
- thread_resume(platformThread);
-#elif OS(WINDOWS)
- ResumeThread(platformThread);
-#else
-#error Need a way to resume threads on this platform
-#endif
-}
-
-typedef unsigned long usword_t; // word size, assumed to be either 32 or 64 bit
-
-#if OS(DARWIN)
-
-#if CPU(X86)
-typedef i386_thread_state_t PlatformThreadRegisters;
-#elif CPU(X86_64)
-typedef x86_thread_state64_t PlatformThreadRegisters;
-#elif CPU(PPC)
-typedef ppc_thread_state_t PlatformThreadRegisters;
-#elif CPU(PPC64)
-typedef ppc_thread_state64_t PlatformThreadRegisters;
-#elif CPU(ARM)
-typedef arm_thread_state_t PlatformThreadRegisters;
-#else
-#error Unknown Architecture
-#endif
-
-#elif OS(WINDOWS) && CPU(X86)
-typedef CONTEXT PlatformThreadRegisters;
-#else
-#error Need a thread register struct for this platform
-#endif
-
-static size_t getPlatformThreadRegisters(const PlatformThread& platformThread, PlatformThreadRegisters& regs)
-{
-#if OS(DARWIN)
-
-#if CPU(X86)
- unsigned user_count = sizeof(regs)/sizeof(int);
- thread_state_flavor_t flavor = i386_THREAD_STATE;
-#elif CPU(X86_64)
- unsigned user_count = x86_THREAD_STATE64_COUNT;
- thread_state_flavor_t flavor = x86_THREAD_STATE64;
-#elif CPU(PPC)
- unsigned user_count = PPC_THREAD_STATE_COUNT;
- thread_state_flavor_t flavor = PPC_THREAD_STATE;
-#elif CPU(PPC64)
- unsigned user_count = PPC_THREAD_STATE64_COUNT;
- thread_state_flavor_t flavor = PPC_THREAD_STATE64;
-#elif CPU(ARM)
- unsigned user_count = ARM_THREAD_STATE_COUNT;
- thread_state_flavor_t flavor = ARM_THREAD_STATE;
-#else
-#error Unknown Architecture
-#endif
-
- kern_return_t result = thread_get_state(platformThread, flavor, (thread_state_t)®s, &user_count);
- if (result != KERN_SUCCESS) {
- WTFReportFatalError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION,
- "JavaScript garbage collection failed because thread_get_state returned an error (%d). This is probably the result of running inside Rosetta, which is not supported.", result);
- CRASH();
- }
- return user_count * sizeof(usword_t);
-// end OS(DARWIN)
-
-#elif OS(WINDOWS) && CPU(X86)
- regs.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL | CONTEXT_SEGMENTS;
- GetThreadContext(platformThread, ®s);
- return sizeof(CONTEXT);
-#else
-#error Need a way to get thread registers on this platform
-#endif
-}
-
-static inline void* otherThreadStackPointer(const PlatformThreadRegisters& regs)
-{
-#if OS(DARWIN)
-
-#if __DARWIN_UNIX03
-
-#if CPU(X86)
- return reinterpret_cast<void*>(regs.__esp);
-#elif CPU(X86_64)
- return reinterpret_cast<void*>(regs.__rsp);
-#elif CPU(PPC) || CPU(PPC64)
- return reinterpret_cast<void*>(regs.__r1);
-#elif CPU(ARM)
- return reinterpret_cast<void*>(regs.__sp);
-#else
-#error Unknown Architecture
-#endif
-
-#else // !__DARWIN_UNIX03
-
-#if CPU(X86)
- return reinterpret_cast<void*>(regs.esp);
-#elif CPU(X86_64)
- return reinterpret_cast<void*>(regs.rsp);
-#elif CPU(PPC) || CPU(PPC64)
- return reinterpret_cast<void*>(regs.r1);
-#else
-#error Unknown Architecture
-#endif
-
-#endif // __DARWIN_UNIX03
-
-// end OS(DARWIN)
-#elif CPU(X86) && OS(WINDOWS)
- return reinterpret_cast<void*>((uintptr_t) regs.Esp);
-#else
-#error Need a way to get the stack pointer for another thread on this platform
-#endif
-}
-
-void Heap::markOtherThreadConservatively(MarkStack& markStack, Thread* thread)
-{
- suspendThread(thread->platformThread);
-
- PlatformThreadRegisters regs;
- size_t regSize = getPlatformThreadRegisters(thread->platformThread, regs);
-
- // mark the thread's registers
- markConservatively(markStack, static_cast<void*>(®s), static_cast<void*>(reinterpret_cast<char*>(®s) + regSize));
-
- void* stackPointer = otherThreadStackPointer(regs);
- markConservatively(markStack, stackPointer, thread->stackBase);
-
- resumeThread(thread->platformThread);
-}
-
-#endif
-
-void Heap::markStackObjectsConservatively(MarkStack& markStack)
-{
- markCurrentThreadConservatively(markStack);
-
-#if ENABLE(JSC_MULTIPLE_THREADS)
-
- if (m_currentThreadRegistrar) {
-
- MutexLocker lock(m_registeredThreadsMutex);
-
-#ifndef NDEBUG
- // Forbid malloc during the mark phase. Marking a thread suspends it, so
- // a malloc inside markChildren() would risk a deadlock with a thread that had been
- // suspended while holding the malloc lock.
- fastMallocForbid();
-#endif
- // It is safe to access the registeredThreads list, because we earlier asserted that locks are being held,
- // and since this is a shared heap, they are real locks.
- for (Thread* thread = m_registeredThreads; thread; thread = thread->next) {
- if (!pthread_equal(thread->posixThread, pthread_self()))
- markOtherThreadConservatively(markStack, thread);
- }
-#ifndef NDEBUG
- fastMallocAllow();
-#endif
- }
-#endif
-}
-
-void Heap::protect(JSValue k)
-{
- ASSERT(k);
- ASSERT(JSLock::currentThreadIsHoldingLock() || !m_globalData->isSharedInstance());
-
- if (!k.isCell())
- return;
-
- m_protectedValues.add(k.asCell());
-}
-
-bool Heap::unprotect(JSValue k)
-{
- ASSERT(k);
- ASSERT(JSLock::currentThreadIsHoldingLock() || !m_globalData->isSharedInstance());
-
- if (!k.isCell())
- return false;
-
- return m_protectedValues.remove(k.asCell());
-}
-
-void Heap::markProtectedObjects(MarkStack& markStack)
-{
- ProtectCountSet::iterator end = m_protectedValues.end();
- for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it) {
- markStack.append(it->first);
- markStack.drain();
- }
-}
-
-void Heap::pushTempSortVector(Vector<ValueStringPair>* tempVector)
-{
- m_tempSortingVectors.append(tempVector);
-}
-
-void Heap::popTempSortVector(Vector<ValueStringPair>* tempVector)
-{
- ASSERT_UNUSED(tempVector, tempVector == m_tempSortingVectors.last());
- m_tempSortingVectors.removeLast();
-}
-
-void Heap::markTempSortVectors(MarkStack& markStack)
-{
- typedef Vector<Vector<ValueStringPair>* > VectorOfValueStringVectors;
-
- VectorOfValueStringVectors::iterator end = m_tempSortingVectors.end();
- for (VectorOfValueStringVectors::iterator it = m_tempSortingVectors.begin(); it != end; ++it) {
- Vector<ValueStringPair>* tempSortingVector = *it;
-
- Vector<ValueStringPair>::iterator vectorEnd = tempSortingVector->end();
- for (Vector<ValueStringPair>::iterator vectorIt = tempSortingVector->begin(); vectorIt != vectorEnd; ++vectorIt)
- if (vectorIt->first)
- markStack.append(vectorIt->first);
- markStack.drain();
- }
-}
-
-void Heap::clearMarkBits()
-{
- for (size_t i = 0; i < m_heap.usedBlocks; ++i)
- clearMarkBits(m_heap.blocks[i]);
-}
-
-void Heap::clearMarkBits(CollectorBlock* block)
-{
- // allocate assumes that the last cell in every block is marked.
- block->marked.clearAll();
- block->marked.set(HeapConstants::cellsPerBlock - 1);
-}
-
-size_t Heap::markedCells(size_t startBlock, size_t startCell) const
-{
- ASSERT(startBlock <= m_heap.usedBlocks);
- ASSERT(startCell < HeapConstants::cellsPerBlock);
-
- if (startBlock >= m_heap.usedBlocks)
- return 0;
-
- size_t result = 0;
- result += m_heap.blocks[startBlock]->marked.count(startCell);
- for (size_t i = startBlock + 1; i < m_heap.usedBlocks; ++i)
- result += m_heap.blocks[i]->marked.count();
-
- return result;
-}
-
-void Heap::sweep()
-{
- ASSERT(m_heap.operationInProgress == NoOperation);
- if (m_heap.operationInProgress != NoOperation)
- CRASH();
- m_heap.operationInProgress = Collection;
-
-#if !ENABLE(JSC_ZOMBIES)
- Structure* dummyMarkableCellStructure = m_globalData->dummyMarkableCellStructure.get();
-#endif
-
- DeadObjectIterator it(m_heap, m_heap.nextBlock, m_heap.nextCell);
- DeadObjectIterator end(m_heap, m_heap.usedBlocks);
- for ( ; it != end; ++it) {
- JSCell* cell = *it;
-#if ENABLE(JSC_ZOMBIES)
- if (!cell->isZombie()) {
- const ClassInfo* info = cell->classInfo();
- cell->~JSCell();
- new (cell) JSZombie(info, JSZombie::leakedZombieStructure());
- Heap::markCell(cell);
- }
-#else
- cell->~JSCell();
- // Callers of sweep assume it's safe to mark any cell in the heap.
- new (cell) JSCell(dummyMarkableCellStructure);
-#endif
- }
-
- m_heap.operationInProgress = NoOperation;
-}
-
-void Heap::markRoots()
-{
-#ifndef NDEBUG
- if (m_globalData->isSharedInstance()) {
- ASSERT(JSLock::lockCount() > 0);
- ASSERT(JSLock::currentThreadIsHoldingLock());
- }
-#endif
-
- ASSERT(m_heap.operationInProgress == NoOperation);
- if (m_heap.operationInProgress != NoOperation)
- CRASH();
-
- m_heap.operationInProgress = Collection;
-
- MarkStack& markStack = m_globalData->markStack;
-
- // Reset mark bits.
- clearMarkBits();
-
- // Mark stack roots.
- markStackObjectsConservatively(markStack);
- m_globalData->interpreter->registerFile().markCallFrames(markStack, this);
-
- // Mark explicitly registered roots.
- markProtectedObjects(markStack);
-
- // Mark temporary vector for Array sorting
- markTempSortVectors(markStack);
-
- // Mark misc. other roots.
- if (m_markListSet && m_markListSet->size())
- MarkedArgumentBuffer::markLists(markStack, *m_markListSet);
- if (m_globalData->exception)
- markStack.append(m_globalData->exception);
- if (m_globalData->functionCodeBlockBeingReparsed)
- m_globalData->functionCodeBlockBeingReparsed->markAggregate(markStack);
- if (m_globalData->firstStringifierToMark)
- JSONObject::markStringifiers(markStack, m_globalData->firstStringifierToMark);
-
- // Mark the small strings cache last, since it will clear itself if nothing
- // else has marked it.
- m_globalData->smallStrings.markChildren(markStack);
-
- markStack.drain();
- markStack.compact();
-
- m_heap.operationInProgress = NoOperation;
-}
-
-size_t Heap::objectCount() const
-{
- return m_heap.nextBlock * HeapConstants::cellsPerBlock // allocated full blocks
- + m_heap.nextCell // allocated cells in current block
- + markedCells(m_heap.nextBlock, m_heap.nextCell) // marked cells in remainder of m_heap
- - m_heap.usedBlocks; // 1 cell per block is a dummy sentinel
-}
-
-void Heap::addToStatistics(Heap::Statistics& statistics) const
-{
- statistics.size += m_heap.usedBlocks * BLOCK_SIZE;
- statistics.free += m_heap.usedBlocks * BLOCK_SIZE - (objectCount() * HeapConstants::cellSize);
-}
-
-Heap::Statistics Heap::statistics() const
-{
- Statistics statistics = { 0, 0 };
- addToStatistics(statistics);
- return statistics;
-}
-
-size_t Heap::globalObjectCount()
-{
- size_t count = 0;
- if (JSGlobalObject* head = m_globalData->head) {
- JSGlobalObject* o = head;
- do {
- ++count;
- o = o->next();
- } while (o != head);
- }
- return count;
-}
-
-size_t Heap::protectedGlobalObjectCount()
-{
- size_t count = 0;
- if (JSGlobalObject* head = m_globalData->head) {
- JSGlobalObject* o = head;
- do {
- if (m_protectedValues.contains(o))
- ++count;
- o = o->next();
- } while (o != head);
- }
-
- return count;
-}
-
-size_t Heap::protectedObjectCount()
-{
- return m_protectedValues.size();
-}
-
-static const char* typeName(JSCell* cell)
-{
- if (cell->isString())
- return "string";
-#if USE(JSVALUE32)
- if (cell->isNumber())
- return "number";
-#endif
- if (cell->isGetterSetter())
- return "Getter-Setter";
- if (cell->isAPIValueWrapper())
- return "API wrapper";
- if (cell->isPropertyNameIterator())
- return "For-in iterator";
- if (!cell->isObject())
- return "[empty cell]";
- const ClassInfo* info = cell->classInfo();
- return info ? info->className : "Object";
-}
-
-HashCountedSet<const char*>* Heap::protectedObjectTypeCounts()
-{
- HashCountedSet<const char*>* counts = new HashCountedSet<const char*>;
-
- ProtectCountSet::iterator end = m_protectedValues.end();
- for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it)
- counts->add(typeName(it->first));
-
- return counts;
-}
-
-HashCountedSet<const char*>* Heap::objectTypeCounts()
-{
- HashCountedSet<const char*>* counts = new HashCountedSet<const char*>;
-
- LiveObjectIterator it = primaryHeapBegin();
- LiveObjectIterator heapEnd = primaryHeapEnd();
- for ( ; it != heapEnd; ++it)
- counts->add(typeName(*it));
-
- return counts;
-}
-
-bool Heap::isBusy()
-{
- return m_heap.operationInProgress != NoOperation;
-}
-
-void Heap::reset()
-{
- JAVASCRIPTCORE_GC_BEGIN();
-
- markRoots();
-
- JAVASCRIPTCORE_GC_MARKED();
-
- m_heap.nextCell = 0;
- m_heap.nextBlock = 0;
- m_heap.nextNumber = 0;
- m_heap.extraCost = 0;
-#if ENABLE(JSC_ZOMBIES)
- sweep();
-#endif
- resizeBlocks();
-
- JAVASCRIPTCORE_GC_END();
-}
-
-void Heap::collectAllGarbage()
-{
- JAVASCRIPTCORE_GC_BEGIN();
-
- // If the last iteration through the heap deallocated blocks, we need
- // to clean up remaining garbage before marking. Otherwise, the conservative
- // marking mechanism might follow a pointer to unmapped memory.
- if (m_heap.didShrink)
- sweep();
-
- markRoots();
-
- JAVASCRIPTCORE_GC_MARKED();
-
- m_heap.nextCell = 0;
- m_heap.nextBlock = 0;
- m_heap.nextNumber = 0;
- m_heap.extraCost = 0;
- sweep();
- resizeBlocks();
-
- JAVASCRIPTCORE_GC_END();
-}
-
-LiveObjectIterator Heap::primaryHeapBegin()
-{
- return LiveObjectIterator(m_heap, 0);
-}
-
-LiveObjectIterator Heap::primaryHeapEnd()
-{
- return LiveObjectIterator(m_heap, m_heap.usedBlocks);
-}
-
-} // namespace JSC
+++ /dev/null
-/*
- * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2001 Peter Kelly (pmk@post.com)
- * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#ifndef Collector_h
-#define Collector_h
-
-#include "JSValue.h"
-#include <stddef.h>
-#include <string.h>
-#include <wtf/HashCountedSet.h>
-#include <wtf/HashSet.h>
-#include <wtf/Noncopyable.h>
-#include <wtf/OwnPtr.h>
-#include <wtf/StdLibExtras.h>
-#include <wtf/Threading.h>
-
-#if ENABLE(JSC_MULTIPLE_THREADS)
-#include <pthread.h>
-#endif
-
-#if OS(SYMBIAN)
-#include <wtf/symbian/BlockAllocatorSymbian.h>
-#endif
-
-#define ASSERT_CLASS_FITS_IN_CELL(class) COMPILE_ASSERT(sizeof(class) <= CELL_SIZE, class_fits_in_cell)
-
-namespace JSC {
-
- class CollectorBlock;
- class JSCell;
- class JSGlobalData;
- class JSValue;
- class MarkedArgumentBuffer;
- class MarkStack;
-
- enum OperationInProgress { NoOperation, Allocation, Collection };
-
- class LiveObjectIterator;
-
- struct CollectorHeap {
- size_t nextBlock;
- size_t nextCell;
- CollectorBlock** blocks;
-
- void* nextNumber;
-
- size_t numBlocks;
- size_t usedBlocks;
-
- size_t extraCost;
- bool didShrink;
-
- OperationInProgress operationInProgress;
- };
-
- class Heap : public Noncopyable {
- public:
- class Thread;
-
- void destroy();
-
- void* allocateNumber(size_t);
- void* allocate(size_t);
-
- bool isBusy(); // true if an allocation or collection is in progress
- void collectAllGarbage();
-
- static const size_t minExtraCost = 256;
- static const size_t maxExtraCost = 1024 * 1024;
-
- void reportExtraMemoryCost(size_t cost);
-
- size_t objectCount() const;
- struct Statistics {
- size_t size;
- size_t free;
- };
- Statistics statistics() const;
-
- void protect(JSValue);
- // Returns true if the value is no longer protected by any protect pointers
- // (though it may still be alive due to heap/stack references).
- bool unprotect(JSValue);
-
- static Heap* heap(JSValue); // 0 for immediate values
- static Heap* heap(JSCell*);
-
- size_t globalObjectCount();
- size_t protectedObjectCount();
- size_t protectedGlobalObjectCount();
- HashCountedSet<const char*>* protectedObjectTypeCounts();
- HashCountedSet<const char*>* objectTypeCounts();
-
- void registerThread(); // Only needs to be called by clients that can use the same heap from multiple threads.
-
- static bool isCellMarked(const JSCell*);
- static void markCell(JSCell*);
-
- void markConservatively(MarkStack&, void* start, void* end);
-
- void pushTempSortVector(WTF::Vector<ValueStringPair>*);
- void popTempSortVector(WTF::Vector<ValueStringPair>*);
-
- HashSet<MarkedArgumentBuffer*>& markListSet() { if (!m_markListSet) m_markListSet = new HashSet<MarkedArgumentBuffer*>; return *m_markListSet; }
-
- JSGlobalData* globalData() const { return m_globalData; }
- static bool isNumber(JSCell*);
-
- LiveObjectIterator primaryHeapBegin();
- LiveObjectIterator primaryHeapEnd();
-
- private:
- void reset();
- void sweep();
- static CollectorBlock* cellBlock(const JSCell*);
- static size_t cellOffset(const JSCell*);
-
- friend class JSGlobalData;
- Heap(JSGlobalData*);
- ~Heap();
-
- NEVER_INLINE CollectorBlock* allocateBlock();
- NEVER_INLINE void freeBlock(size_t);
- NEVER_INLINE void freeBlockPtr(CollectorBlock*);
- void freeBlocks();
- void resizeBlocks();
- void growBlocks(size_t neededBlocks);
- void shrinkBlocks(size_t neededBlocks);
- void clearMarkBits();
- void clearMarkBits(CollectorBlock*);
- size_t markedCells(size_t startBlock = 0, size_t startCell = 0) const;
-
- void recordExtraCost(size_t);
-
- void addToStatistics(Statistics&) const;
-
- void markRoots();
- void markProtectedObjects(MarkStack&);
- void markTempSortVectors(MarkStack&);
- void markCurrentThreadConservatively(MarkStack&);
- void markCurrentThreadConservativelyInternal(MarkStack&);
- void markOtherThreadConservatively(MarkStack&, Thread*);
- void markStackObjectsConservatively(MarkStack&);
-
- typedef HashCountedSet<JSCell*> ProtectCountSet;
-
- CollectorHeap m_heap;
-
- ProtectCountSet m_protectedValues;
- WTF::Vector<WTF::Vector<ValueStringPair>* > m_tempSortingVectors;
-
- HashSet<MarkedArgumentBuffer*>* m_markListSet;
-
-#if ENABLE(JSC_MULTIPLE_THREADS)
- void makeUsableFromMultipleThreads();
-
- static void unregisterThread(void*);
- void unregisterThread();
-
- Mutex m_registeredThreadsMutex;
- Thread* m_registeredThreads;
- pthread_key_t m_currentThreadRegistrar;
-#endif
-
-#if OS(SYMBIAN)
- // Allocates collector blocks with correct alignment
- WTF::AlignedBlockAllocator m_blockallocator;
-#endif
-
- JSGlobalData* m_globalData;
- };
-
- // tunable parameters
- template<size_t bytesPerWord> struct CellSize;
-
- // cell size needs to be a power of two for certain optimizations in collector.cpp
-#if USE(JSVALUE32)
- template<> struct CellSize<sizeof(uint32_t)> { static const size_t m_value = 32; };
-#else
- template<> struct CellSize<sizeof(uint32_t)> { static const size_t m_value = 64; };
-#endif
- template<> struct CellSize<sizeof(uint64_t)> { static const size_t m_value = 64; };
-
- const size_t BLOCK_SIZE = 64 * 1024; // 64k
-
- // derived constants
- const size_t BLOCK_OFFSET_MASK = BLOCK_SIZE - 1;
- const size_t BLOCK_MASK = ~BLOCK_OFFSET_MASK;
- const size_t MINIMUM_CELL_SIZE = CellSize<sizeof(void*)>::m_value;
- const size_t CELL_ARRAY_LENGTH = (MINIMUM_CELL_SIZE / sizeof(double)) + (MINIMUM_CELL_SIZE % sizeof(double) != 0 ? sizeof(double) : 0);
- const size_t CELL_SIZE = CELL_ARRAY_LENGTH * sizeof(double);
- const size_t SMALL_CELL_SIZE = CELL_SIZE / 2;
- const size_t CELL_MASK = CELL_SIZE - 1;
- const size_t CELL_ALIGN_MASK = ~CELL_MASK;
- const size_t CELLS_PER_BLOCK = (BLOCK_SIZE - sizeof(Heap*)) * 8 * CELL_SIZE / (8 * CELL_SIZE + 1) / CELL_SIZE; // one bitmap byte can represent 8 cells.
-
- const size_t BITMAP_SIZE = (CELLS_PER_BLOCK + 7) / 8;
- const size_t BITMAP_WORDS = (BITMAP_SIZE + 3) / sizeof(uint32_t);
-
- struct CollectorBitmap {
- uint32_t bits[BITMAP_WORDS];
- bool get(size_t n) const { return !!(bits[n >> 5] & (1 << (n & 0x1F))); }
- void set(size_t n) { bits[n >> 5] |= (1 << (n & 0x1F)); }
- void clear(size_t n) { bits[n >> 5] &= ~(1 << (n & 0x1F)); }
- void clearAll() { memset(bits, 0, sizeof(bits)); }
- size_t count(size_t startCell = 0)
- {
- size_t result = 0;
- for ( ; (startCell & 0x1F) != 0; ++startCell) {
- if (get(startCell))
- ++result;
- }
- for (size_t i = startCell >> 5; i < BITMAP_WORDS; ++i)
- result += WTF::bitCount(bits[i]);
- return result;
- }
- size_t isEmpty() // Much more efficient than testing count() == 0.
- {
- for (size_t i = 0; i < BITMAP_WORDS; ++i)
- if (bits[i] != 0)
- return false;
- return true;
- }
- };
-
- struct CollectorCell {
- double memory[CELL_ARRAY_LENGTH];
- };
-
- class CollectorBlock {
- public:
- CollectorCell cells[CELLS_PER_BLOCK];
- CollectorBitmap marked;
- Heap* heap;
- };
-
- struct HeapConstants {
- static const size_t cellSize = CELL_SIZE;
- static const size_t cellsPerBlock = CELLS_PER_BLOCK;
- typedef CollectorCell Cell;
- typedef CollectorBlock Block;
- };
-
- inline CollectorBlock* Heap::cellBlock(const JSCell* cell)
- {
- return reinterpret_cast<CollectorBlock*>(reinterpret_cast<uintptr_t>(cell) & BLOCK_MASK);
- }
-
- inline size_t Heap::cellOffset(const JSCell* cell)
- {
- return (reinterpret_cast<uintptr_t>(cell) & BLOCK_OFFSET_MASK) / CELL_SIZE;
- }
-
- inline bool Heap::isCellMarked(const JSCell* cell)
- {
- return cellBlock(cell)->marked.get(cellOffset(cell));
- }
-
- inline void Heap::markCell(JSCell* cell)
- {
- cellBlock(cell)->marked.set(cellOffset(cell));
- }
-
- inline void Heap::reportExtraMemoryCost(size_t cost)
- {
- if (cost > minExtraCost)
- recordExtraCost(cost);
- }
-
- inline void* Heap::allocateNumber(size_t s)
- {
- if (void* result = m_heap.nextNumber) {
- m_heap.nextNumber = 0;
- return result;
- }
-
- void* result = allocate(s);
- m_heap.nextNumber = static_cast<char*>(result) + (CELL_SIZE / 2);
- return result;
- }
-
-} // namespace JSC
-
-#endif /* Collector_h */
+++ /dev/null
-/*
- * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "Collector.h"
-
-#ifndef CollectorHeapIterator_h
-#define CollectorHeapIterator_h
-
-namespace JSC {
-
- class CollectorHeapIterator {
- public:
- bool operator!=(const CollectorHeapIterator& other);
- JSCell* operator*() const;
-
- protected:
- CollectorHeapIterator(CollectorHeap&, size_t startBlock, size_t startCell);
- void advance(size_t max);
-
- CollectorHeap& m_heap;
- size_t m_block;
- size_t m_cell;
- };
-
- class LiveObjectIterator : public CollectorHeapIterator {
- public:
- LiveObjectIterator(CollectorHeap&, size_t startBlock, size_t startCell = 0);
- LiveObjectIterator& operator++();
- };
-
- class DeadObjectIterator : public CollectorHeapIterator {
- public:
- DeadObjectIterator(CollectorHeap&, size_t startBlock, size_t startCell = 0);
- DeadObjectIterator& operator++();
- };
-
- class ObjectIterator : public CollectorHeapIterator {
- public:
- ObjectIterator(CollectorHeap&, size_t startBlock, size_t startCell = 0);
- ObjectIterator& operator++();
- };
-
- inline CollectorHeapIterator::CollectorHeapIterator(CollectorHeap& heap, size_t startBlock, size_t startCell)
- : m_heap(heap)
- , m_block(startBlock)
- , m_cell(startCell)
- {
- }
-
- inline bool CollectorHeapIterator::operator!=(const CollectorHeapIterator& other)
- {
- return m_block != other.m_block || m_cell != other.m_cell;
- }
-
- inline JSCell* CollectorHeapIterator::operator*() const
- {
- return reinterpret_cast<JSCell*>(m_heap.blocks[m_block]->cells + m_cell);
- }
-
- // Iterators advance up to the next-to-last -- and not the last -- cell in a
- // block, since the last cell is a dummy sentinel.
- inline void CollectorHeapIterator::advance(size_t max)
- {
- ++m_cell;
- if (m_cell == max) {
- m_cell = 0;
- ++m_block;
- }
- }
-
- inline LiveObjectIterator::LiveObjectIterator(CollectorHeap& heap, size_t startBlock, size_t startCell)
- : CollectorHeapIterator(heap, startBlock, startCell - 1)
- {
- ++(*this);
- }
-
- inline LiveObjectIterator& LiveObjectIterator::operator++()
- {
- advance(HeapConstants::cellsPerBlock - 1);
- if (m_block < m_heap.nextBlock || (m_block == m_heap.nextBlock && m_cell < m_heap.nextCell))
- return *this;
-
- while (m_block < m_heap.usedBlocks && !m_heap.blocks[m_block]->marked.get(m_cell))
- advance(HeapConstants::cellsPerBlock - 1);
- return *this;
- }
-
- inline DeadObjectIterator::DeadObjectIterator(CollectorHeap& heap, size_t startBlock, size_t startCell)
- : CollectorHeapIterator(heap, startBlock, startCell - 1)
- {
- ++(*this);
- }
-
- inline DeadObjectIterator& DeadObjectIterator::operator++()
- {
- do {
- advance(HeapConstants::cellsPerBlock - 1);
- ASSERT(m_block > m_heap.nextBlock || (m_block == m_heap.nextBlock && m_cell >= m_heap.nextCell));
- } while (m_block < m_heap.usedBlocks && m_heap.blocks[m_block]->marked.get(m_cell));
- return *this;
- }
-
- inline ObjectIterator::ObjectIterator(CollectorHeap& heap, size_t startBlock, size_t startCell)
- : CollectorHeapIterator(heap, startBlock, startCell - 1)
- {
- ++(*this);
- }
-
- inline ObjectIterator& ObjectIterator::operator++()
- {
- advance(HeapConstants::cellsPerBlock - 1);
- return *this;
- }
-
-} // namespace JSC
-
-#endif // CollectorHeapIterator_h
static const char* const nullCString = 0;
#define INITIALIZE_PROPERTY_NAME(name) , name(globalData, #name)
+#define INITIALIZE_KEYWORD(name) , name##Keyword(globalData, #name)
CommonIdentifiers::CommonIdentifiers(JSGlobalData* globalData)
: nullIdentifier(globalData, nullCString)
, emptyIdentifier(globalData, "")
, underscoreProto(globalData, "__proto__")
, thisIdentifier(globalData, "this")
+ , useStrictIdentifier(globalData, "use strict")
+ JSC_COMMON_IDENTIFIERS_EACH_KEYWORD(INITIALIZE_KEYWORD)
JSC_COMMON_IDENTIFIERS_EACH_PROPERTY_NAME(INITIALIZE_PROPERTY_NAME)
{
}
macro(compile) \
macro(configurable) \
macro(constructor) \
- macro(create) \
- macro(defineProperty) \
- macro(defineProperties) \
macro(enumerable) \
macro(eval) \
macro(exec) \
macro(fromCharCode) \
macro(global) \
macro(get) \
- macro(getPrototypeOf) \
- macro(getOwnPropertyDescriptor) \
- macro(getOwnPropertyNames) \
macro(hasOwnProperty) \
macro(ignoreCase) \
macro(index) \
macro(input) \
macro(isArray) \
macro(isPrototypeOf) \
- macro(keys) \
macro(length) \
macro(message) \
macro(multiline) \
macro(writable) \
macro(displayName)
+#define JSC_COMMON_IDENTIFIERS_EACH_KEYWORD(macro) \
+ macro(null) \
+ macro(true) \
+ macro(false) \
+ macro(break) \
+ macro(case) \
+ macro(catch) \
+ macro(const) \
+ macro(default) \
+ macro(finally) \
+ macro(for) \
+ macro(instanceof) \
+ macro(new) \
+ macro(var) \
+ macro(continue) \
+ macro(function) \
+ macro(return) \
+ macro(void) \
+ macro(delete) \
+ macro(if) \
+ macro(this) \
+ macro(do) \
+ macro(while) \
+ macro(else) \
+ macro(in) \
+ macro(switch) \
+ macro(throw) \
+ macro(try) \
+ macro(typeof) \
+ macro(with) \
+ macro(debugger) \
+ macro(class) \
+ macro(enum) \
+ macro(export) \
+ macro(extends) \
+ macro(import) \
+ macro(super)
+
namespace JSC {
- class CommonIdentifiers : public Noncopyable {
+ class CommonIdentifiers {
+ WTF_MAKE_NONCOPYABLE(CommonIdentifiers); WTF_MAKE_FAST_ALLOCATED;
private:
CommonIdentifiers(JSGlobalData*);
friend class JSGlobalData;
const Identifier emptyIdentifier;
const Identifier underscoreProto;
const Identifier thisIdentifier;
+ const Identifier useStrictIdentifier;
+
+#define JSC_IDENTIFIER_DECLARE_KEYWORD_NAME_GLOBAL(name) const Identifier name##Keyword;
+ JSC_COMMON_IDENTIFIERS_EACH_KEYWORD(JSC_IDENTIFIER_DECLARE_KEYWORD_NAME_GLOBAL)
+#undef JSC_IDENTIFIER_DECLARE_KEYWORD_NAME_GLOBAL
+
#define JSC_IDENTIFIER_DECLARE_PROPERTY_NAME_GLOBAL(name) const Identifier name;
JSC_COMMON_IDENTIFIERS_EACH_PROPERTY_NAME(JSC_IDENTIFIER_DECLARE_PROPERTY_NAME_GLOBAL)
#undef JSC_IDENTIFIER_DECLARE_PROPERTY_NAME_GLOBAL
JSLock lock(exec);
ASSERT(exec->globalData().identifierTable == wtfThreadData().currentIdentifierTable());
- RefPtr<ProgramExecutable> program = ProgramExecutable::create(exec, source);
+ ProgramExecutable* program = ProgramExecutable::create(exec, source);
JSObject* error = program->checkSyntax(exec);
if (error)
return Completion(Throw, error);
return Completion(Normal);
}
-Completion evaluate(ExecState* exec, ScopeChain& scopeChain, const SourceCode& source, JSValue thisValue)
+Completion evaluate(ExecState* exec, ScopeChainNode* scopeChain, const SourceCode& source, JSValue thisValue)
{
JSLock lock(exec);
ASSERT(exec->globalData().identifierTable == wtfThreadData().currentIdentifierTable());
- RefPtr<ProgramExecutable> program = ProgramExecutable::create(exec, source);
- JSObject* error = program->compile(exec, scopeChain.node());
- if (error)
- return Completion(Throw, error);
+ ProgramExecutable* program = ProgramExecutable::create(exec, source);
+ if (!program) {
+ JSValue exception = exec->globalData().exception;
+ exec->globalData().exception = JSValue();
+ return Completion(Throw, exception);
+ }
JSObject* thisObj = (!thisValue || thisValue.isUndefinedOrNull()) ? exec->dynamicGlobalObject() : thisValue.toObject(exec);
- JSValue exception;
- JSValue result = exec->interpreter()->execute(program.get(), exec, scopeChain.node(), thisObj, &exception);
+ JSValue result = exec->interpreter()->execute(program, exec, scopeChain, thisObj);
+
+ if (exec->hadException()) {
+ JSValue exception = exec->exception();
+ exec->clearException();
- if (exception) {
ComplType exceptionType = Throw;
if (exception.isObject())
exceptionType = asObject(exception)->exceptionType();
namespace JSC {
class ExecState;
- class ScopeChain;
+ class ScopeChainNode;
class SourceCode;
enum ComplType { Normal, Break, Continue, ReturnValue, Throw, Interrupted, Terminated };
};
Completion checkSyntax(ExecState*, const SourceCode&);
- Completion evaluate(ExecState*, ScopeChain&, const SourceCode&, JSValue thisValue = JSValue());
+ Completion evaluate(ExecState*, ScopeChainNode*, const SourceCode&, JSValue thisValue = JSValue());
} // namespace JSC
#include "config.h"
#include "ConstructData.h"
+#include "Executable.h"
+#include "Interpreter.h"
#include "JSFunction.h"
+#include "JSGlobalObject.h"
namespace JSC {
-JSObject* construct(ExecState* exec, JSValue object, ConstructType constructType, const ConstructData& constructData, const ArgList& args)
+JSObject* construct(ExecState* exec, JSValue constructorObject, ConstructType constructType, const ConstructData& constructData, const ArgList& args)
{
- if (constructType == ConstructTypeHost)
- return constructData.native.function(exec, asObject(object), args);
- ASSERT(constructType == ConstructTypeJS);
- // FIXME: Can this be done more efficiently using the constructData?
- return asFunction(object)->construct(exec, args);
+ ASSERT(constructType == ConstructTypeJS || constructType == ConstructTypeHost);
+ return exec->interpreter()->executeConstruct(exec, asObject(constructorObject), constructType, constructData, args);
}
} // namespace JSC
#ifndef ConstructData_h
#define ConstructData_h
+#include "JSValue.h"
+
namespace JSC {
class ArgList;
class ExecState;
class FunctionExecutable;
class JSObject;
- class JSValue;
class ScopeChainNode;
enum ConstructType {
ConstructTypeJS
};
- typedef JSObject* (*NativeConstructor)(ExecState*, JSObject*, const ArgList&);
+ typedef EncodedJSValue (JSC_HOST_CALL *NativeConstructor)(ExecState*);
union ConstructData {
struct {
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2011 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
#include "JSString.h"
#include "JSStringBuilder.h"
#include "ObjectPrototype.h"
-#include "PrototypeFunction.h"
#include <math.h>
#include <time.h>
#include <wtf/DateMath.h>
namespace JSC {
-ASSERT_CLASS_FITS_IN_CELL(DateConstructor);
+static EncodedJSValue JSC_HOST_CALL dateParse(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateNow(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateUTC(ExecState*);
+
+}
+
+#include "DateConstructor.lut.h"
+
+namespace JSC {
+
+const ClassInfo DateConstructor::s_info = { "Function", &InternalFunction::s_info, 0, ExecState::dateConstructorTable };
-static JSValue JSC_HOST_CALL dateParse(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateNow(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateUTC(ExecState*, JSObject*, JSValue, const ArgList&);
+/* Source for DateConstructor.lut.h
+@begin dateConstructorTable
+ parse dateParse DontEnum|Function 1
+ UTC dateUTC DontEnum|Function 7
+ now dateNow DontEnum|Function 0
+@end
+*/
-DateConstructor::DateConstructor(ExecState* exec, NonNullPassRefPtr<Structure> structure, Structure* prototypeFunctionStructure, DatePrototype* datePrototype)
- : InternalFunction(&exec->globalData(), structure, Identifier(exec, datePrototype->classInfo()->className))
+ASSERT_CLASS_FITS_IN_CELL(DateConstructor);
+
+DateConstructor::DateConstructor(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, DatePrototype* datePrototype)
+ : InternalFunction(&exec->globalData(), globalObject, structure, Identifier(exec, datePrototype->classInfo()->className))
{
- putDirectWithoutTransition(exec->propertyNames().prototype, datePrototype, DontEnum|DontDelete|ReadOnly);
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().prototype, datePrototype, DontEnum | DontDelete | ReadOnly);
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(7), ReadOnly | DontEnum | DontDelete);
+}
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().parse, dateParse), DontEnum);
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 7, exec->propertyNames().UTC, dateUTC), DontEnum);
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 0, exec->propertyNames().now, dateNow), DontEnum);
+bool DateConstructor::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot &slot)
+{
+ return getStaticFunctionSlot<InternalFunction>(exec, ExecState::dateConstructorTable(exec), this, propertyName, slot);
+}
- putDirectWithoutTransition(exec->propertyNames().length, jsNumber(exec, 7), ReadOnly | DontEnum | DontDelete);
+bool DateConstructor::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ return getStaticFunctionDescriptor<InternalFunction>(exec, ExecState::dateConstructorTable(exec), this, propertyName, descriptor);
}
// ECMA 15.9.3
-JSObject* constructDate(ExecState* exec, const ArgList& args)
+JSObject* constructDate(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args)
{
int numArgs = args.size();
if (numArgs == 0) // new Date() ECMA 15.9.3.3
value = jsCurrentTime();
else if (numArgs == 1) {
- if (args.at(0).inherits(&DateInstance::info))
+ if (args.at(0).inherits(&DateInstance::s_info))
value = asDateInstance(args.at(0))->internalNumber();
else {
JSValue primitive = args.at(0).toPrimitive(exec);
value = primitive.toNumber(exec);
}
} else {
- if (isnan(args.at(0).toNumber(exec))
- || isnan(args.at(1).toNumber(exec))
- || (numArgs >= 3 && isnan(args.at(2).toNumber(exec)))
- || (numArgs >= 4 && isnan(args.at(3).toNumber(exec)))
- || (numArgs >= 5 && isnan(args.at(4).toNumber(exec)))
- || (numArgs >= 6 && isnan(args.at(5).toNumber(exec)))
- || (numArgs >= 7 && isnan(args.at(6).toNumber(exec))))
+ double doubleArguments[7] = {
+ args.at(0).toNumber(exec),
+ args.at(1).toNumber(exec),
+ args.at(2).toNumber(exec),
+ args.at(3).toNumber(exec),
+ args.at(4).toNumber(exec),
+ args.at(5).toNumber(exec),
+ args.at(6).toNumber(exec)
+ };
+ if (isnan(doubleArguments[0])
+ || isnan(doubleArguments[1])
+ || (numArgs >= 3 && isnan(doubleArguments[2]))
+ || (numArgs >= 4 && isnan(doubleArguments[3]))
+ || (numArgs >= 5 && isnan(doubleArguments[4]))
+ || (numArgs >= 6 && isnan(doubleArguments[5]))
+ || (numArgs >= 7 && isnan(doubleArguments[6])))
value = NaN;
else {
GregorianDateTime t;
- int year = args.at(0).toInt32(exec);
+ int year = JSC::toInt32(doubleArguments[0]);
t.year = (year >= 0 && year <= 99) ? year : year - 1900;
- t.month = args.at(1).toInt32(exec);
- t.monthDay = (numArgs >= 3) ? args.at(2).toInt32(exec) : 1;
- t.hour = args.at(3).toInt32(exec);
- t.minute = args.at(4).toInt32(exec);
- t.second = args.at(5).toInt32(exec);
+ t.month = JSC::toInt32(doubleArguments[1]);
+ t.monthDay = (numArgs >= 3) ? JSC::toInt32(doubleArguments[2]) : 1;
+ t.hour = JSC::toInt32(doubleArguments[3]);
+ t.minute = JSC::toInt32(doubleArguments[4]);
+ t.second = JSC::toInt32(doubleArguments[5]);
t.isDST = -1;
- double ms = (numArgs >= 7) ? args.at(6).toNumber(exec) : 0;
+ double ms = (numArgs >= 7) ? doubleArguments[6] : 0;
value = gregorianDateTimeToMS(exec, t, ms, false);
}
}
- return new (exec) DateInstance(exec, value);
+ return new (exec) DateInstance(exec, globalObject->dateStructure(), value);
}
-static JSObject* constructWithDateConstructor(ExecState* exec, JSObject*, const ArgList& args)
+static EncodedJSValue JSC_HOST_CALL constructWithDateConstructor(ExecState* exec)
{
- return constructDate(exec, args);
+ ArgList args(exec);
+ return JSValue::encode(constructDate(exec, asInternalFunction(exec->callee())->globalObject(), args));
}
ConstructType DateConstructor::getConstructData(ConstructData& constructData)
}
// ECMA 15.9.2
-static JSValue JSC_HOST_CALL callDate(ExecState* exec, JSObject*, JSValue, const ArgList&)
+static EncodedJSValue JSC_HOST_CALL callDate(ExecState* exec)
{
time_t localTime = time(0);
tm localTM;
DateConversionBuffer time;
formatDate(ts, date);
formatTime(ts, time);
- return jsMakeNontrivialString(exec, date, " ", time);
+ return JSValue::encode(jsMakeNontrivialString(exec, date, " ", time));
}
CallType DateConstructor::getCallData(CallData& callData)
return CallTypeHost;
}
-static JSValue JSC_HOST_CALL dateParse(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+static EncodedJSValue JSC_HOST_CALL dateParse(ExecState* exec)
{
- return jsNumber(exec, parseDate(exec, args.at(0).toString(exec)));
+ return JSValue::encode(jsNumber(parseDate(exec, exec->argument(0).toString(exec))));
}
-static JSValue JSC_HOST_CALL dateNow(ExecState* exec, JSObject*, JSValue, const ArgList&)
+static EncodedJSValue JSC_HOST_CALL dateNow(ExecState*)
{
- return jsNumber(exec, jsCurrentTime());
+ return JSValue::encode(jsNumber(jsCurrentTime()));
}
-static JSValue JSC_HOST_CALL dateUTC(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+static EncodedJSValue JSC_HOST_CALL dateUTC(ExecState* exec)
{
- int n = args.size();
- if (isnan(args.at(0).toNumber(exec))
- || isnan(args.at(1).toNumber(exec))
- || (n >= 3 && isnan(args.at(2).toNumber(exec)))
- || (n >= 4 && isnan(args.at(3).toNumber(exec)))
- || (n >= 5 && isnan(args.at(4).toNumber(exec)))
- || (n >= 6 && isnan(args.at(5).toNumber(exec)))
- || (n >= 7 && isnan(args.at(6).toNumber(exec))))
- return jsNaN(exec);
+ double doubleArguments[7] = {
+ exec->argument(0).toNumber(exec),
+ exec->argument(1).toNumber(exec),
+ exec->argument(2).toNumber(exec),
+ exec->argument(3).toNumber(exec),
+ exec->argument(4).toNumber(exec),
+ exec->argument(5).toNumber(exec),
+ exec->argument(6).toNumber(exec)
+ };
+ int n = exec->argumentCount();
+ if (isnan(doubleArguments[0])
+ || isnan(doubleArguments[1])
+ || (n >= 3 && isnan(doubleArguments[2]))
+ || (n >= 4 && isnan(doubleArguments[3]))
+ || (n >= 5 && isnan(doubleArguments[4]))
+ || (n >= 6 && isnan(doubleArguments[5]))
+ || (n >= 7 && isnan(doubleArguments[6])))
+ return JSValue::encode(jsNaN());
GregorianDateTime t;
- int year = args.at(0).toInt32(exec);
+ int year = JSC::toInt32(doubleArguments[0]);
t.year = (year >= 0 && year <= 99) ? year : year - 1900;
- t.month = args.at(1).toInt32(exec);
- t.monthDay = (n >= 3) ? args.at(2).toInt32(exec) : 1;
- t.hour = args.at(3).toInt32(exec);
- t.minute = args.at(4).toInt32(exec);
- t.second = args.at(5).toInt32(exec);
- double ms = (n >= 7) ? args.at(6).toNumber(exec) : 0;
- return jsNumber(exec, timeClip(gregorianDateTimeToMS(exec, t, ms, true)));
+ t.month = JSC::toInt32(doubleArguments[1]);
+ t.monthDay = (n >= 3) ? JSC::toInt32(doubleArguments[2]) : 1;
+ t.hour = JSC::toInt32(doubleArguments[3]);
+ t.minute = JSC::toInt32(doubleArguments[4]);
+ t.second = JSC::toInt32(doubleArguments[5]);
+ double ms = (n >= 7) ? doubleArguments[6] : 0;
+ return JSValue::encode(jsNumber(timeClip(gregorianDateTimeToMS(exec, t, ms, true))));
}
} // namespace JSC
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2011 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
class DateConstructor : public InternalFunction {
public:
- DateConstructor(ExecState*, NonNullPassRefPtr<Structure>, Structure* prototypeFunctionStructure, DatePrototype*);
+ DateConstructor(ExecState*, JSGlobalObject*, Structure*, DatePrototype*);
+
+ static const ClassInfo s_info;
+
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
+ {
+ return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
+ }
+
+ protected:
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InternalFunction::StructureFlags;
private:
virtual ConstructType getConstructData(ConstructData&);
virtual CallType getCallData(CallData&);
+
+ virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
+ virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
};
- JSObject* constructDate(ExecState*, const ArgList&);
+ JSObject* constructDate(ExecState*, JSGlobalObject*, const ArgList&);
} // namespace JSC
#include "DateConversion.h"
#include "CallFrame.h"
+#include "JSObject.h"
+#include "ScopeChain.h"
#include "UString.h"
#include <wtf/DateMath.h>
#include <wtf/StringExtras.h>
+#include <wtf/text/CString.h>
using namespace WTF;
{
if (date == exec->globalData().cachedDateString)
return exec->globalData().cachedDateStringValue;
- double value = parseDateFromNullTerminatedCharacters(exec, date.UTF8String().data());
+ double value = parseES5DateFromNullTerminatedCharacters(date.utf8().data());
+ if (isnan(value))
+ value = parseDateFromNullTerminatedCharacters(exec, date.utf8().data());
exec->globalData().cachedDateString = date;
exec->globalData().cachedDateStringValue = value;
return value;
namespace JSC {
-const ClassInfo DateInstance::info = {"Date", 0, 0, 0};
+const ClassInfo DateInstance::s_info = {"Date", &JSWrapperObject::s_info, 0, 0};
-DateInstance::DateInstance(ExecState* exec, NonNullPassRefPtr<Structure> structure)
- : JSWrapperObject(structure)
+DateInstance::DateInstance(ExecState* exec, Structure* structure)
+ : JSWrapperObject(exec->globalData(), structure)
{
- setInternalValue(jsNaN(exec));
+ ASSERT(inherits(&s_info));
+ setInternalValue(exec->globalData(), jsNaN());
}
-DateInstance::DateInstance(ExecState* exec, NonNullPassRefPtr<Structure> structure, double time)
- : JSWrapperObject(structure)
+DateInstance::DateInstance(ExecState* exec, Structure* structure, double time)
+ : JSWrapperObject(exec->globalData(), structure)
{
- setInternalValue(jsNumber(exec, timeClip(time)));
-}
-
-DateInstance::DateInstance(ExecState* exec, double time)
- : JSWrapperObject(exec->lexicalGlobalObject()->dateStructure())
-{
- setInternalValue(jsNumber(exec, timeClip(time)));
+ ASSERT(inherits(&s_info));
+ setInternalValue(exec->globalData(), jsNumber(timeClip(time)));
}
const GregorianDateTime* DateInstance::calculateGregorianDateTime(ExecState* exec) const
class DateInstance : public JSWrapperObject {
public:
- DateInstance(ExecState*, double);
- DateInstance(ExecState*, NonNullPassRefPtr<Structure>, double);
- explicit DateInstance(ExecState*, NonNullPassRefPtr<Structure>);
+ DateInstance(ExecState*, Structure*, double);
+ explicit DateInstance(ExecState*, Structure*);
double internalNumber() const { return internalValue().uncheckedGetNumber(); }
- static JS_EXPORTDATA const ClassInfo info;
+ static JS_EXPORTDATA const ClassInfo s_info;
const GregorianDateTime* gregorianDateTime(ExecState* exec) const
{
return calculateGregorianDateTimeUTC(exec);
}
- static PassRefPtr<Structure> createStructure(JSValue prototype)
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
+ return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
}
- protected:
- static const unsigned StructureFlags = OverridesMarkChildren | JSWrapperObject::StructureFlags;
-
private:
const GregorianDateTime* calculateGregorianDateTime(ExecState*) const;
const GregorianDateTime* calculateGregorianDateTimeUTC(ExecState*) const;
- virtual const ClassInfo* classInfo() const { return &info; }
mutable RefPtr<DateInstanceData> m_data;
};
inline DateInstance* asDateInstance(JSValue value)
{
- ASSERT(asObject(value)->inherits(&DateInstance::info));
+ ASSERT(asObject(value)->inherits(&DateInstance::s_info));
return static_cast<DateInstance*>(asObject(value));
}
CacheEntry& lookup(double d) { return m_cache[WTF::FloatHash<double>::hash(d) & (cacheSize - 1)]; }
- CacheEntry m_cache[cacheSize];
+ FixedArray<CacheEntry, cacheSize> m_cache;
};
} // namespace JSC
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
* Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
* Copyright (C) 2008, 2009 Torch Mobile, Inc. All rights reserved.
+ * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
#include <limits.h>
#include <locale.h>
#include <math.h>
+#include <stdlib.h>
#include <time.h>
#include <wtf/Assertions.h>
#include <wtf/DateMath.h>
ASSERT_CLASS_FITS_IN_CELL(DatePrototype);
-static JSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncSetDate(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncSetFullYear(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncSetHours(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncSetMilliSeconds(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncSetMinutes(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncSetMonth(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncSetSeconds(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncSetUTCDate(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncSetUTCHours(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncSetUTCMilliseconds(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncSetUTCMinutes(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncSetUTCMonth(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncSetUTCSeconds(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncToString(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState*, JSObject*, JSValue, const ArgList&);
-
-static JSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState*, JSObject*, JSValue, const ArgList&);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetDate(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetFullYear(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetHours(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMilliSeconds(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMinutes(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMonth(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetSeconds(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCDate(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCHours(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMilliseconds(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMinutes(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMonth(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCSeconds(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncToString(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState*);
}
// FIXME: Since this is superior to the strftime-based version, why limit this to PLATFORM(MAC)?
-// Instead we should consider using this whenever PLATFORM(CF) is true.
+// Instead we should consider using this whenever USE(CF) is true.
static CFDateFormatterStyle styleFromArgString(const UString& string, CFDateFormatterStyle defaultStyle)
{
return defaultStyle;
}
-static JSCell* formatLocaleDate(ExecState* exec, DateInstance*, double timeInMilliseconds, LocaleDateTimeFormat format, const ArgList& args)
+static JSCell* formatLocaleDate(ExecState* exec, DateInstance*, double timeInMilliseconds, LocaleDateTimeFormat format)
{
CFDateFormatterStyle dateStyle = (format != LocaleTime ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle);
CFDateFormatterStyle timeStyle = (format != LocaleDate ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle);
bool useCustomFormat = false;
UString customFormatString;
- UString arg0String = args.at(0).toString(exec);
- if (arg0String == "custom" && !args.at(1).isUndefined()) {
+ UString arg0String = exec->argument(0).toString(exec);
+ if (arg0String == "custom" && !exec->argument(1).isUndefined()) {
useCustomFormat = true;
- customFormatString = args.at(1).toString(exec);
- } else if (format == LocaleDateAndTime && !args.at(1).isUndefined()) {
+ customFormatString = exec->argument(1).toString(exec);
+ } else if (format == LocaleDateAndTime && !exec->argument(1).isUndefined()) {
dateStyle = styleFromArgString(arg0String, dateStyle);
- timeStyle = styleFromArgString(args.at(1).toString(exec), timeStyle);
- } else if (format != LocaleTime && !args.at(0).isUndefined())
+ timeStyle = styleFromArgString(exec->argument(1).toString(exec), timeStyle);
+ } else if (format != LocaleTime && !exec->argument(0).isUndefined())
dateStyle = styleFromArgString(arg0String, dateStyle);
- else if (format != LocaleDate && !args.at(0).isUndefined())
+ else if (format != LocaleDate && !exec->argument(0).isUndefined())
timeStyle = styleFromArgString(arg0String, timeStyle);
CFLocaleRef locale = CFLocaleCopyCurrent();
CFRelease(locale);
if (useCustomFormat) {
- CFStringRef customFormatCFString = CFStringCreateWithCharacters(0, customFormatString.data(), customFormatString.size());
+ CFStringRef customFormatCFString = CFStringCreateWithCharacters(0, customFormatString.characters(), customFormatString.length());
CFDateFormatterSetFormat(formatter, customFormatCFString);
CFRelease(customFormatCFString);
}
// We truncate the string returned from CFDateFormatter if it's absurdly long (> 200 characters).
// That's not great error handling, but it just won't happen so it doesn't matter.
UChar buffer[200];
- const size_t bufferLength = sizeof(buffer) / sizeof(buffer[0]);
+ const size_t bufferLength = WTF_ARRAY_LENGTH(buffer);
size_t length = CFStringGetLength(string);
ASSERT(length <= bufferLength);
if (length > bufferLength)
// ms (representing milliseconds) and t (representing the rest of the date structure) appropriately.
//
// Format of member function: f([hour,] [min,] [sec,] [ms])
-static bool fillStructuresUsingTimeArgs(ExecState* exec, const ArgList& args, int maxArgs, double* ms, GregorianDateTime* t)
+static bool fillStructuresUsingTimeArgs(ExecState* exec, int maxArgs, double* ms, GregorianDateTime* t)
{
double milliseconds = 0;
bool ok = true;
int idx = 0;
- int numArgs = args.size();
+ int numArgs = exec->argumentCount();
// JS allows extra trailing arguments -- ignore them
if (numArgs > maxArgs)
// hours
if (maxArgs >= 4 && idx < numArgs) {
t->hour = 0;
- milliseconds += args.at(idx++).toInt32(exec, ok) * msPerHour;
+ double hours = exec->argument(idx++).toIntegerPreserveNaN(exec);
+ ok = isfinite(hours);
+ milliseconds += hours * msPerHour;
}
// minutes
if (maxArgs >= 3 && idx < numArgs && ok) {
t->minute = 0;
- milliseconds += args.at(idx++).toInt32(exec, ok) * msPerMinute;
+ double minutes = exec->argument(idx++).toIntegerPreserveNaN(exec);
+ ok = isfinite(minutes);
+ milliseconds += minutes * msPerMinute;
}
// seconds
if (maxArgs >= 2 && idx < numArgs && ok) {
t->second = 0;
- milliseconds += args.at(idx++).toInt32(exec, ok) * msPerSecond;
+ double seconds = exec->argument(idx++).toIntegerPreserveNaN(exec);
+ ok = isfinite(seconds);
+ milliseconds += seconds * msPerSecond;
}
if (!ok)
// milliseconds
if (idx < numArgs) {
- double millis = args.at(idx).toNumber(exec);
+ double millis = exec->argument(idx).toIntegerPreserveNaN(exec);
ok = isfinite(millis);
milliseconds += millis;
} else
// ms (representing milliseconds) and t (representing the rest of the date structure) appropriately.
//
// Format of member function: f([years,] [months,] [days])
-static bool fillStructuresUsingDateArgs(ExecState *exec, const ArgList& args, int maxArgs, double *ms, GregorianDateTime *t)
+static bool fillStructuresUsingDateArgs(ExecState *exec, int maxArgs, double *ms, GregorianDateTime *t)
{
int idx = 0;
bool ok = true;
- int numArgs = args.size();
+ int numArgs = exec->argumentCount();
// JS allows extra trailing arguments -- ignore them
if (numArgs > maxArgs)
numArgs = maxArgs;
// years
- if (maxArgs >= 3 && idx < numArgs)
- t->year = args.at(idx++).toInt32(exec, ok) - 1900;
-
+ if (maxArgs >= 3 && idx < numArgs) {
+ double years = exec->argument(idx++).toIntegerPreserveNaN(exec);
+ ok = isfinite(years);
+ t->year = toInt32(years - 1900);
+ }
// months
- if (maxArgs >= 2 && idx < numArgs && ok)
- t->month = args.at(idx++).toInt32(exec, ok);
-
+ if (maxArgs >= 2 && idx < numArgs && ok) {
+ double months = exec->argument(idx++).toIntegerPreserveNaN(exec);
+ ok = isfinite(months);
+ t->month = toInt32(months);
+ }
// days
- if (idx < numArgs && ok) {
+ if (idx < numArgs && ok) {
+ double days = exec->argument(idx++).toIntegerPreserveNaN(exec);
+ ok = isfinite(days);
t->monthDay = 0;
- *ms += args.at(idx).toInt32(exec, ok) * msPerDay;
+ *ms += days * msPerDay;
}
return ok;
}
-const ClassInfo DatePrototype::info = {"Date", &DateInstance::info, 0, ExecState::dateTable};
+const ClassInfo DatePrototype::s_info = {"Date", &DateInstance::s_info, 0, ExecState::dateTable};
/* Source for DatePrototype.lut.h
@begin dateTable
setUTCFullYear dateProtoFuncSetUTCFullYear DontEnum|Function 3
setYear dateProtoFuncSetYear DontEnum|Function 1
getYear dateProtoFuncGetYear DontEnum|Function 0
- toJSON dateProtoFuncToJSON DontEnum|Function 0
+ toJSON dateProtoFuncToJSON DontEnum|Function 1
@end
*/
// ECMA 15.9.4
-DatePrototype::DatePrototype(ExecState* exec, NonNullPassRefPtr<Structure> structure)
+DatePrototype::DatePrototype(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
: DateInstance(exec, structure)
{
+ ASSERT(inherits(&s_info));
+
// The constructor will be added later, after DateConstructor has been built.
+ putAnonymousValue(exec->globalData(), 0, globalObject);
}
bool DatePrototype::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
// Functions
-JSValue JSC_HOST_CALL dateProtoFuncToString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToString(ExecState* exec)
{
- if (!thisValue.inherits(&DateInstance::info))
- return throwError(exec, TypeError);
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
if (!gregorianDateTime)
- return jsNontrivialString(exec, "Invalid Date");
+ return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
DateConversionBuffer date;
DateConversionBuffer time;
formatDate(*gregorianDateTime, date);
formatTime(*gregorianDateTime, time);
- return jsMakeNontrivialString(exec, date, " ", time);
+ return JSValue::encode(jsMakeNontrivialString(exec, date, " ", time));
}
-JSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState* exec)
{
- if (!thisValue.inherits(&DateInstance::info))
- return throwError(exec, TypeError);
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
if (!gregorianDateTime)
- return jsNontrivialString(exec, "Invalid Date");
+ return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
DateConversionBuffer date;
DateConversionBuffer time;
formatDateUTCVariant(*gregorianDateTime, date);
formatTimeUTC(*gregorianDateTime, time);
- return jsMakeNontrivialString(exec, date, " ", time);
+ return JSValue::encode(jsMakeNontrivialString(exec, date, " ", time));
}
-JSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState* exec)
{
- if (!thisValue.inherits(&DateInstance::info))
- return throwError(exec, TypeError);
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
if (!gregorianDateTime)
- return jsNontrivialString(exec, "Invalid Date");
+ return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
// Maximum amount of space we need in buffer: 6 (max. digits in year) + 2 * 5 (2 characters each for month, day, hour, minute, second) + 4 (. + 3 digits for milliseconds)
// 6 for formatting and one for null termination = 27. We add one extra character to allow us to force null termination.
char buffer[28];
snprintf(buffer, sizeof(buffer) - 1, "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", 1900 + gregorianDateTime->year, gregorianDateTime->month + 1, gregorianDateTime->monthDay, gregorianDateTime->hour, gregorianDateTime->minute, gregorianDateTime->second, static_cast<int>(fmod(thisDateObj->internalNumber(), 1000)));
buffer[sizeof(buffer) - 1] = 0;
- return jsNontrivialString(exec, buffer);
+ return JSValue::encode(jsNontrivialString(exec, buffer));
}
-JSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState* exec)
{
- if (!thisValue.inherits(&DateInstance::info))
- return throwError(exec, TypeError);
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
if (!gregorianDateTime)
- return jsNontrivialString(exec, "Invalid Date");
+ return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
DateConversionBuffer date;
formatDate(*gregorianDateTime, date);
- return jsNontrivialString(exec, date);
+ return JSValue::encode(jsNontrivialString(exec, date));
}
-JSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState* exec)
{
- if (!thisValue.inherits(&DateInstance::info))
- return throwError(exec, TypeError);
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
if (!gregorianDateTime)
- return jsNontrivialString(exec, "Invalid Date");
+ return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
DateConversionBuffer time;
formatTime(*gregorianDateTime, time);
- return jsNontrivialString(exec, time);
+ return JSValue::encode(jsNontrivialString(exec, time));
}
-JSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState* exec)
{
- if (!thisValue.inherits(&DateInstance::info))
- return throwError(exec, TypeError);
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
- return formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleDateAndTime, args);
+ return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleDateAndTime));
}
-JSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState* exec)
{
- if (!thisValue.inherits(&DateInstance::info))
- return throwError(exec, TypeError);
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
- return formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleDate, args);
+ return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleDate));
}
-JSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState* exec)
{
- if (!thisValue.inherits(&DateInstance::info))
- return throwError(exec, TypeError);
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
- return formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleTime, args);
+ return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleTime));
}
-JSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState* exec)
{
- if (!thisValue.inherits(&DateInstance::info))
- return throwError(exec, TypeError);
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
- return asDateInstance(thisValue)->internalValue();
+ return JSValue::encode(asDateInstance(thisValue)->internalValue());
}
-JSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState* exec)
{
- if (!thisValue.inherits(&DateInstance::info))
- return throwError(exec, TypeError);
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
if (!gregorianDateTime)
- return jsNaN(exec);
- return jsNumber(exec, 1900 + gregorianDateTime->year);
+ return JSValue::encode(jsNaN());
+ return JSValue::encode(jsNumber(1900 + gregorianDateTime->year));
}
-JSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState* exec)
{
- if (!thisValue.inherits(&DateInstance::info))
- return throwError(exec, TypeError);
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
if (!gregorianDateTime)
- return jsNaN(exec);
- return jsNumber(exec, 1900 + gregorianDateTime->year);
+ return JSValue::encode(jsNaN());
+ return JSValue::encode(jsNumber(1900 + gregorianDateTime->year));
}
-JSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState* exec)
{
- if (!thisValue.inherits(&DateInstance::info))
- return throwError(exec, TypeError);
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
if (!gregorianDateTime)
- return jsNontrivialString(exec, "Invalid Date");
+ return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
DateConversionBuffer date;
DateConversionBuffer time;
formatDateUTCVariant(*gregorianDateTime, date);
formatTimeUTC(*gregorianDateTime, time);
- return jsMakeNontrivialString(exec, date, " ", time);
+ return JSValue::encode(jsMakeNontrivialString(exec, date, " ", time));
}
-JSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState* exec)
{
- if (!thisValue.inherits(&DateInstance::info))
- return throwError(exec, TypeError);
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
if (!gregorianDateTime)
- return jsNaN(exec);
- return jsNumber(exec, gregorianDateTime->month);
+ return JSValue::encode(jsNaN());
+ return JSValue::encode(jsNumber(gregorianDateTime->month));
}
-JSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState* exec)
{
- if (!thisValue.inherits(&DateInstance::info))
- return throwError(exec, TypeError);
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
if (!gregorianDateTime)
- return jsNaN(exec);
- return jsNumber(exec, gregorianDateTime->month);
+ return JSValue::encode(jsNaN());
+ return JSValue::encode(jsNumber(gregorianDateTime->month));
}
-JSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState* exec)
{
- if (!thisValue.inherits(&DateInstance::info))
- return throwError(exec, TypeError);
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
if (!gregorianDateTime)
- return jsNaN(exec);
- return jsNumber(exec, gregorianDateTime->monthDay);
+ return JSValue::encode(jsNaN());
+ return JSValue::encode(jsNumber(gregorianDateTime->monthDay));
}
-JSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState* exec)
{
- if (!thisValue.inherits(&DateInstance::info))
- return throwError(exec, TypeError);
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
if (!gregorianDateTime)
- return jsNaN(exec);
- return jsNumber(exec, gregorianDateTime->monthDay);
+ return JSValue::encode(jsNaN());
+ return JSValue::encode(jsNumber(gregorianDateTime->monthDay));
}
-JSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState* exec)
{
- if (!thisValue.inherits(&DateInstance::info))
- return throwError(exec, TypeError);
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
if (!gregorianDateTime)
- return jsNaN(exec);
- return jsNumber(exec, gregorianDateTime->weekDay);
+ return JSValue::encode(jsNaN());
+ return JSValue::encode(jsNumber(gregorianDateTime->weekDay));
}
-JSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState* exec)
{
- if (!thisValue.inherits(&DateInstance::info))
- return throwError(exec, TypeError);
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
if (!gregorianDateTime)
- return jsNaN(exec);
- return jsNumber(exec, gregorianDateTime->weekDay);
+ return JSValue::encode(jsNaN());
+ return JSValue::encode(jsNumber(gregorianDateTime->weekDay));
}
-JSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState* exec)
{
- if (!thisValue.inherits(&DateInstance::info))
- return throwError(exec, TypeError);
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
if (!gregorianDateTime)
- return jsNaN(exec);
- return jsNumber(exec, gregorianDateTime->hour);
+ return JSValue::encode(jsNaN());
+ return JSValue::encode(jsNumber(gregorianDateTime->hour));
}
-JSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState* exec)
{
- if (!thisValue.inherits(&DateInstance::info))
- return throwError(exec, TypeError);
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
if (!gregorianDateTime)
- return jsNaN(exec);
- return jsNumber(exec, gregorianDateTime->hour);
+ return JSValue::encode(jsNaN());
+ return JSValue::encode(jsNumber(gregorianDateTime->hour));
}
-JSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState* exec)
{
- if (!thisValue.inherits(&DateInstance::info))
- return throwError(exec, TypeError);
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
if (!gregorianDateTime)
- return jsNaN(exec);
- return jsNumber(exec, gregorianDateTime->minute);
+ return JSValue::encode(jsNaN());
+ return JSValue::encode(jsNumber(gregorianDateTime->minute));
}
-JSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState* exec)
{
- if (!thisValue.inherits(&DateInstance::info))
- return throwError(exec, TypeError);
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
if (!gregorianDateTime)
- return jsNaN(exec);
- return jsNumber(exec, gregorianDateTime->minute);
+ return JSValue::encode(jsNaN());
+ return JSValue::encode(jsNumber(gregorianDateTime->minute));
}
-JSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState* exec)
{
- if (!thisValue.inherits(&DateInstance::info))
- return throwError(exec, TypeError);
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
if (!gregorianDateTime)
- return jsNaN(exec);
- return jsNumber(exec, gregorianDateTime->second);
+ return JSValue::encode(jsNaN());
+ return JSValue::encode(jsNumber(gregorianDateTime->second));
}
-JSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState* exec)
{
- if (!thisValue.inherits(&DateInstance::info))
- return throwError(exec, TypeError);
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
if (!gregorianDateTime)
- return jsNaN(exec);
- return jsNumber(exec, gregorianDateTime->second);
+ return JSValue::encode(jsNaN());
+ return JSValue::encode(jsNumber(gregorianDateTime->second));
}
-JSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState* exec)
{
- if (!thisValue.inherits(&DateInstance::info))
- return throwError(exec, TypeError);
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
double milli = thisDateObj->internalNumber();
if (isnan(milli))
- return jsNaN(exec);
+ return JSValue::encode(jsNaN());
double secs = floor(milli / msPerSecond);
double ms = milli - secs * msPerSecond;
- return jsNumber(exec, ms);
+ return JSValue::encode(jsNumber(ms));
}
-JSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState* exec)
{
- if (!thisValue.inherits(&DateInstance::info))
- return throwError(exec, TypeError);
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
double milli = thisDateObj->internalNumber();
if (isnan(milli))
- return jsNaN(exec);
+ return JSValue::encode(jsNaN());
double secs = floor(milli / msPerSecond);
double ms = milli - secs * msPerSecond;
- return jsNumber(exec, ms);
+ return JSValue::encode(jsNumber(ms));
}
-JSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState* exec)
{
- if (!thisValue.inherits(&DateInstance::info))
- return throwError(exec, TypeError);
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
if (!gregorianDateTime)
- return jsNaN(exec);
- return jsNumber(exec, -gregorianDateTime->utcOffset / minutesPerHour);
+ return JSValue::encode(jsNaN());
+ return JSValue::encode(jsNumber(-gregorianDateTime->utcOffset / minutesPerHour));
}
-JSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState* exec)
{
- if (!thisValue.inherits(&DateInstance::info))
- return throwError(exec, TypeError);
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
- double milli = timeClip(args.at(0).toNumber(exec));
- JSValue result = jsNumber(exec, milli);
- thisDateObj->setInternalValue(result);
- return result;
+ double milli = timeClip(exec->argument(0).toNumber(exec));
+ JSValue result = jsNumber(milli);
+ thisDateObj->setInternalValue(exec->globalData(), result);
+ return JSValue::encode(result);
}
-static JSValue setNewValueFromTimeArgs(ExecState* exec, JSValue thisValue, const ArgList& args, int numArgsToUse, bool inputIsUTC)
+static EncodedJSValue setNewValueFromTimeArgs(ExecState* exec, int numArgsToUse, bool inputIsUTC)
{
- if (!thisValue.inherits(&DateInstance::info))
- return throwError(exec, TypeError);
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
double milli = thisDateObj->internalNumber();
- if (args.isEmpty() || isnan(milli)) {
- JSValue result = jsNaN(exec);
- thisDateObj->setInternalValue(result);
- return result;
+ if (!exec->argumentCount() || isnan(milli)) {
+ JSValue result = jsNaN();
+ thisDateObj->setInternalValue(exec->globalData(), result);
+ return JSValue::encode(result);
}
double secs = floor(milli / msPerSecond);
? thisDateObj->gregorianDateTimeUTC(exec)
: thisDateObj->gregorianDateTime(exec);
if (!other)
- return jsNaN(exec);
+ return JSValue::encode(jsNaN());
GregorianDateTime gregorianDateTime;
gregorianDateTime.copyFrom(*other);
- if (!fillStructuresUsingTimeArgs(exec, args, numArgsToUse, &ms, &gregorianDateTime)) {
- JSValue result = jsNaN(exec);
- thisDateObj->setInternalValue(result);
- return result;
+ if (!fillStructuresUsingTimeArgs(exec, numArgsToUse, &ms, &gregorianDateTime)) {
+ JSValue result = jsNaN();
+ thisDateObj->setInternalValue(exec->globalData(), result);
+ return JSValue::encode(result);
}
- JSValue result = jsNumber(exec, gregorianDateTimeToMS(exec, gregorianDateTime, ms, inputIsUTC));
- thisDateObj->setInternalValue(result);
- return result;
+ JSValue result = jsNumber(gregorianDateTimeToMS(exec, gregorianDateTime, ms, inputIsUTC));
+ thisDateObj->setInternalValue(exec->globalData(), result);
+ return JSValue::encode(result);
}
-static JSValue setNewValueFromDateArgs(ExecState* exec, JSValue thisValue, const ArgList& args, int numArgsToUse, bool inputIsUTC)
+static EncodedJSValue setNewValueFromDateArgs(ExecState* exec, int numArgsToUse, bool inputIsUTC)
{
- if (!thisValue.inherits(&DateInstance::info))
- return throwError(exec, TypeError);
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
- if (args.isEmpty()) {
- JSValue result = jsNaN(exec);
- thisDateObj->setInternalValue(result);
- return result;
+ if (!exec->argumentCount()) {
+ JSValue result = jsNaN();
+ thisDateObj->setInternalValue(exec->globalData(), result);
+ return JSValue::encode(result);
}
double milli = thisDateObj->internalNumber();
? thisDateObj->gregorianDateTimeUTC(exec)
: thisDateObj->gregorianDateTime(exec);
if (!other)
- return jsNaN(exec);
+ return JSValue::encode(jsNaN());
gregorianDateTime.copyFrom(*other);
}
- if (!fillStructuresUsingDateArgs(exec, args, numArgsToUse, &ms, &gregorianDateTime)) {
- JSValue result = jsNaN(exec);
- thisDateObj->setInternalValue(result);
- return result;
+ if (!fillStructuresUsingDateArgs(exec, numArgsToUse, &ms, &gregorianDateTime)) {
+ JSValue result = jsNaN();
+ thisDateObj->setInternalValue(exec->globalData(), result);
+ return JSValue::encode(result);
}
- JSValue result = jsNumber(exec, gregorianDateTimeToMS(exec, gregorianDateTime, ms, inputIsUTC));
- thisDateObj->setInternalValue(result);
- return result;
+ JSValue result = jsNumber(gregorianDateTimeToMS(exec, gregorianDateTime, ms, inputIsUTC));
+ thisDateObj->setInternalValue(exec->globalData(), result);
+ return JSValue::encode(result);
}
-JSValue JSC_HOST_CALL dateProtoFuncSetMilliSeconds(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMilliSeconds(ExecState* exec)
{
const bool inputIsUTC = false;
- return setNewValueFromTimeArgs(exec, thisValue, args, 1, inputIsUTC);
+ return setNewValueFromTimeArgs(exec, 1, inputIsUTC);
}
-JSValue JSC_HOST_CALL dateProtoFuncSetUTCMilliseconds(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMilliseconds(ExecState* exec)
{
const bool inputIsUTC = true;
- return setNewValueFromTimeArgs(exec, thisValue, args, 1, inputIsUTC);
+ return setNewValueFromTimeArgs(exec, 1, inputIsUTC);
}
-JSValue JSC_HOST_CALL dateProtoFuncSetSeconds(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetSeconds(ExecState* exec)
{
const bool inputIsUTC = false;
- return setNewValueFromTimeArgs(exec, thisValue, args, 2, inputIsUTC);
+ return setNewValueFromTimeArgs(exec, 2, inputIsUTC);
}
-JSValue JSC_HOST_CALL dateProtoFuncSetUTCSeconds(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCSeconds(ExecState* exec)
{
const bool inputIsUTC = true;
- return setNewValueFromTimeArgs(exec, thisValue, args, 2, inputIsUTC);
+ return setNewValueFromTimeArgs(exec, 2, inputIsUTC);
}
-JSValue JSC_HOST_CALL dateProtoFuncSetMinutes(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMinutes(ExecState* exec)
{
const bool inputIsUTC = false;
- return setNewValueFromTimeArgs(exec, thisValue, args, 3, inputIsUTC);
+ return setNewValueFromTimeArgs(exec, 3, inputIsUTC);
}
-JSValue JSC_HOST_CALL dateProtoFuncSetUTCMinutes(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMinutes(ExecState* exec)
{
const bool inputIsUTC = true;
- return setNewValueFromTimeArgs(exec, thisValue, args, 3, inputIsUTC);
+ return setNewValueFromTimeArgs(exec, 3, inputIsUTC);
}
-JSValue JSC_HOST_CALL dateProtoFuncSetHours(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetHours(ExecState* exec)
{
const bool inputIsUTC = false;
- return setNewValueFromTimeArgs(exec, thisValue, args, 4, inputIsUTC);
+ return setNewValueFromTimeArgs(exec, 4, inputIsUTC);
}
-JSValue JSC_HOST_CALL dateProtoFuncSetUTCHours(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCHours(ExecState* exec)
{
const bool inputIsUTC = true;
- return setNewValueFromTimeArgs(exec, thisValue, args, 4, inputIsUTC);
+ return setNewValueFromTimeArgs(exec, 4, inputIsUTC);
}
-JSValue JSC_HOST_CALL dateProtoFuncSetDate(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetDate(ExecState* exec)
{
const bool inputIsUTC = false;
- return setNewValueFromDateArgs(exec, thisValue, args, 1, inputIsUTC);
+ return setNewValueFromDateArgs(exec, 1, inputIsUTC);
}
-JSValue JSC_HOST_CALL dateProtoFuncSetUTCDate(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCDate(ExecState* exec)
{
const bool inputIsUTC = true;
- return setNewValueFromDateArgs(exec, thisValue, args, 1, inputIsUTC);
+ return setNewValueFromDateArgs(exec, 1, inputIsUTC);
}
-JSValue JSC_HOST_CALL dateProtoFuncSetMonth(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMonth(ExecState* exec)
{
const bool inputIsUTC = false;
- return setNewValueFromDateArgs(exec, thisValue, args, 2, inputIsUTC);
+ return setNewValueFromDateArgs(exec, 2, inputIsUTC);
}
-JSValue JSC_HOST_CALL dateProtoFuncSetUTCMonth(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMonth(ExecState* exec)
{
const bool inputIsUTC = true;
- return setNewValueFromDateArgs(exec, thisValue, args, 2, inputIsUTC);
+ return setNewValueFromDateArgs(exec, 2, inputIsUTC);
}
-JSValue JSC_HOST_CALL dateProtoFuncSetFullYear(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetFullYear(ExecState* exec)
{
const bool inputIsUTC = false;
- return setNewValueFromDateArgs(exec, thisValue, args, 3, inputIsUTC);
+ return setNewValueFromDateArgs(exec, 3, inputIsUTC);
}
-JSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState* exec)
{
const bool inputIsUTC = true;
- return setNewValueFromDateArgs(exec, thisValue, args, 3, inputIsUTC);
+ return setNewValueFromDateArgs(exec, 3, inputIsUTC);
}
-JSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState* exec)
{
- if (!thisValue.inherits(&DateInstance::info))
- return throwError(exec, TypeError);
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
- if (args.isEmpty()) {
- JSValue result = jsNaN(exec);
- thisDateObj->setInternalValue(result);
- return result;
+ if (!exec->argumentCount()) {
+ JSValue result = jsNaN();
+ thisDateObj->setInternalValue(exec->globalData(), result);
+ return JSValue::encode(result);
}
double milli = thisDateObj->internalNumber();
gregorianDateTime.copyFrom(*other);
}
- bool ok = true;
- int32_t year = args.at(0).toInt32(exec, ok);
- if (!ok) {
- JSValue result = jsNaN(exec);
- thisDateObj->setInternalValue(result);
- return result;
+ double year = exec->argument(0).toIntegerPreserveNaN(exec);
+ if (!isfinite(year)) {
+ JSValue result = jsNaN();
+ thisDateObj->setInternalValue(exec->globalData(), result);
+ return JSValue::encode(result);
}
- gregorianDateTime.year = (year > 99 || year < 0) ? year - 1900 : year;
- JSValue result = jsNumber(exec, gregorianDateTimeToMS(exec, gregorianDateTime, ms, false));
- thisDateObj->setInternalValue(result);
- return result;
+ gregorianDateTime.year = toInt32((year > 99 || year < 0) ? year - 1900 : year);
+ JSValue result = jsNumber(gregorianDateTimeToMS(exec, gregorianDateTime, ms, false));
+ thisDateObj->setInternalValue(exec->globalData(), result);
+ return JSValue::encode(result);
}
-JSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState* exec)
{
- if (!thisValue.inherits(&DateInstance::info))
- return throwError(exec, TypeError);
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
if (!gregorianDateTime)
- return jsNaN(exec);
+ return JSValue::encode(jsNaN());
// NOTE: IE returns the full year even in getYear.
- return jsNumber(exec, gregorianDateTime->year);
+ return JSValue::encode(jsNumber(gregorianDateTime->year));
}
-JSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState* exec)
{
+ JSValue thisValue = exec->hostThisValue();
JSObject* object = thisValue.toThisObject(exec);
if (exec->hadException())
- return jsNull();
+ return JSValue::encode(jsNull());
JSValue toISOValue = object->get(exec, exec->globalData().propertyNames->toISOString);
if (exec->hadException())
- return jsNull();
+ return JSValue::encode(jsNull());
CallData callData;
- CallType callType = toISOValue.getCallData(callData);
+ CallType callType = getCallData(toISOValue, callData);
if (callType == CallTypeNone)
- return throwError(exec, TypeError, "toISOString is not a function");
+ return throwVMError(exec, createTypeError(exec, "toISOString is not a function"));
JSValue result = call(exec, asObject(toISOValue), callType, callData, object, exec->emptyList());
if (exec->hadException())
- return jsNull();
+ return JSValue::encode(jsNull());
if (result.isObject())
- return throwError(exec, TypeError, "toISOString did not return a primitive value");
- return result;
+ return throwVMError(exec, createTypeError(exec, "toISOString did not return a primitive value"));
+ return JSValue::encode(result);
}
} // namespace JSC
class DatePrototype : public DateInstance {
public:
- DatePrototype(ExecState*, NonNullPassRefPtr<Structure>);
+ DatePrototype(ExecState*, JSGlobalObject*, Structure*);
virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
- virtual const ClassInfo* classInfo() const { return &info; }
- static const ClassInfo info;
+ static const ClassInfo s_info;
- static PassRefPtr<Structure> createStructure(JSValue prototype)
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
+ return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
}
protected:
static const unsigned StructureFlags = OverridesGetOwnPropertySlot | DateInstance::StructureFlags;
+ COMPILE_ASSERT(!DateInstance::AnonymousSlotCount, DatePrototype_stomps_on_your_anonymous_slot);
+ static const unsigned AnonymousSlotCount = 1;
};
} // namespace JSC
#include "JSObject.h"
#include "JSString.h"
#include "NativeErrorConstructor.h"
+#include "SourceCode.h"
namespace JSC {
-const char* expressionBeginOffsetPropertyName = "expressionBeginOffset";
-const char* expressionCaretOffsetPropertyName = "expressionCaretOffset";
-const char* expressionEndOffsetPropertyName = "expressionEndOffset";
-
-JSObject* Error::create(ExecState* exec, ErrorType type, const UString& message, int lineNumber, intptr_t sourceID, const UString& sourceURL)
-{
- JSObject* constructor;
- const char* name;
- switch (type) {
- case EvalError:
- constructor = exec->lexicalGlobalObject()->evalErrorConstructor();
- name = "Evaluation error";
- break;
- case RangeError:
- constructor = exec->lexicalGlobalObject()->rangeErrorConstructor();
- name = "Range error";
- break;
- case ReferenceError:
- constructor = exec->lexicalGlobalObject()->referenceErrorConstructor();
- name = "Reference error";
- break;
- case SyntaxError:
- constructor = exec->lexicalGlobalObject()->syntaxErrorConstructor();
- name = "Syntax error";
- break;
- case TypeError:
- constructor = exec->lexicalGlobalObject()->typeErrorConstructor();
- name = "Type error";
- break;
- case URIError:
- constructor = exec->lexicalGlobalObject()->URIErrorConstructor();
- name = "URI error";
- break;
- default:
- constructor = exec->lexicalGlobalObject()->errorConstructor();
- name = "Error";
- break;
- }
+static const char* linePropertyName = "line";
+static const char* sourceIdPropertyName = "sourceId";
+static const char* sourceURLPropertyName = "sourceURL";
+
+JSObject* createError(JSGlobalObject* globalObject, const UString& message)
+{
+ ASSERT(!message.isEmpty());
+ return ErrorInstance::create(&globalObject->globalData(), globalObject->errorStructure(), message);
+}
+
+JSObject* createEvalError(JSGlobalObject* globalObject, const UString& message)
+{
+ ASSERT(!message.isEmpty());
+ return ErrorInstance::create(&globalObject->globalData(), globalObject->evalErrorConstructor()->errorStructure(), message);
+}
+
+JSObject* createRangeError(JSGlobalObject* globalObject, const UString& message)
+{
+ ASSERT(!message.isEmpty());
+ return ErrorInstance::create(&globalObject->globalData(), globalObject->rangeErrorConstructor()->errorStructure(), message);
+}
+
+JSObject* createReferenceError(JSGlobalObject* globalObject, const UString& message)
+{
+ ASSERT(!message.isEmpty());
+ return ErrorInstance::create(&globalObject->globalData(), globalObject->referenceErrorConstructor()->errorStructure(), message);
+}
+
+JSObject* createSyntaxError(JSGlobalObject* globalObject, const UString& message)
+{
+ ASSERT(!message.isEmpty());
+ return ErrorInstance::create(&globalObject->globalData(), globalObject->syntaxErrorConstructor()->errorStructure(), message);
+}
+
+JSObject* createTypeError(JSGlobalObject* globalObject, const UString& message)
+{
+ ASSERT(!message.isEmpty());
+ return ErrorInstance::create(&globalObject->globalData(), globalObject->typeErrorConstructor()->errorStructure(), message);
+}
+
+JSObject* createURIError(JSGlobalObject* globalObject, const UString& message)
+{
+ ASSERT(!message.isEmpty());
+ return ErrorInstance::create(&globalObject->globalData(), globalObject->URIErrorConstructor()->errorStructure(), message);
+}
+
+JSObject* createError(ExecState* exec, const UString& message)
+{
+ return createError(exec->lexicalGlobalObject(), message);
+}
+
+JSObject* createEvalError(ExecState* exec, const UString& message)
+{
+ return createEvalError(exec->lexicalGlobalObject(), message);
+}
+
+JSObject* createRangeError(ExecState* exec, const UString& message)
+{
+ return createRangeError(exec->lexicalGlobalObject(), message);
+}
- MarkedArgumentBuffer args;
- if (message.isEmpty())
- args.append(jsString(exec, name));
- else
- args.append(jsString(exec, message));
- ConstructData constructData;
- ConstructType constructType = constructor->getConstructData(constructData);
- JSObject* error = construct(exec, constructor, constructType, constructData, args);
-
- if (lineNumber != -1)
- error->putWithAttributes(exec, Identifier(exec, "line"), jsNumber(exec, lineNumber), ReadOnly | DontDelete);
+JSObject* createReferenceError(ExecState* exec, const UString& message)
+{
+ return createReferenceError(exec->lexicalGlobalObject(), message);
+}
+
+JSObject* createSyntaxError(ExecState* exec, const UString& message)
+{
+ return createSyntaxError(exec->lexicalGlobalObject(), message);
+}
+
+JSObject* createTypeError(ExecState* exec, const UString& message)
+{
+ return createTypeError(exec->lexicalGlobalObject(), message);
+}
+
+JSObject* createURIError(ExecState* exec, const UString& message)
+{
+ return createURIError(exec->lexicalGlobalObject(), message);
+}
+
+JSObject* addErrorInfo(JSGlobalData* globalData, JSObject* error, int line, const SourceCode& source)
+{
+ intptr_t sourceID = source.provider()->asID();
+ const UString& sourceURL = source.provider()->url();
+
+ if (line != -1)
+ error->putWithAttributes(globalData, Identifier(globalData, linePropertyName), jsNumber(line), ReadOnly | DontDelete);
if (sourceID != -1)
- error->putWithAttributes(exec, Identifier(exec, "sourceId"), jsNumber(exec, sourceID), ReadOnly | DontDelete);
+ error->putWithAttributes(globalData, Identifier(globalData, sourceIdPropertyName), jsNumber((double)sourceID), ReadOnly | DontDelete);
if (!sourceURL.isNull())
- error->putWithAttributes(exec, Identifier(exec, "sourceURL"), jsString(exec, sourceURL), ReadOnly | DontDelete);
+ error->putWithAttributes(globalData, Identifier(globalData, sourceURLPropertyName), jsString(globalData, sourceURL), ReadOnly | DontDelete);
return error;
}
-JSObject* Error::create(ExecState* exec, ErrorType type, const char* message)
+JSObject* addErrorInfo(ExecState* exec, JSObject* error, int line, const SourceCode& source)
{
- return create(exec, type, message, -1, -1, UString());
+ return addErrorInfo(&exec->globalData(), error, line, source);
}
-JSObject* throwError(ExecState* exec, JSObject* error)
+bool hasErrorInfo(ExecState* exec, JSObject* error)
{
- exec->setException(error);
- return error;
+ return error->hasProperty(exec, Identifier(exec, linePropertyName))
+ || error->hasProperty(exec, Identifier(exec, sourceIdPropertyName))
+ || error->hasProperty(exec, Identifier(exec, sourceURLPropertyName));
}
-JSObject* throwError(ExecState* exec, ErrorType type)
+JSValue throwError(ExecState* exec, JSValue error)
{
- JSObject* error = Error::create(exec, type, UString(), -1, -1, UString());
- exec->setException(error);
+ exec->globalData().exception = error;
return error;
}
-JSObject* throwError(ExecState* exec, ErrorType type, const UString& message)
+JSObject* throwError(ExecState* exec, JSObject* error)
{
- JSObject* error = Error::create(exec, type, message, -1, -1, UString());
- exec->setException(error);
+ exec->globalData().exception = error;
return error;
}
-JSObject* throwError(ExecState* exec, ErrorType type, const char* message)
+JSObject* throwTypeError(ExecState* exec)
{
- JSObject* error = Error::create(exec, type, message, -1, -1, UString());
- exec->setException(error);
- return error;
+ return throwError(exec, createTypeError(exec, "Type error"));
}
-JSObject* throwError(ExecState* exec, ErrorType type, const UString& message, int line, intptr_t sourceID, const UString& sourceURL)
+JSObject* throwSyntaxError(ExecState* exec)
{
- JSObject* error = Error::create(exec, type, message, line, sourceID, sourceURL);
- exec->setException(error);
- return error;
+ return throwError(exec, createSyntaxError(exec, "Syntax error"));
+}
+
+class StrictModeTypeErrorFunction : public InternalFunction {
+public:
+ StrictModeTypeErrorFunction(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, const UString& message)
+ : InternalFunction(&exec->globalData(), globalObject, structure, exec->globalData().propertyNames->emptyIdentifier)
+ , m_message(message)
+ {
+ }
+
+ static EncodedJSValue JSC_HOST_CALL constructThrowTypeError(ExecState* exec)
+ {
+ throwTypeError(exec, static_cast<StrictModeTypeErrorFunction*>(exec->callee())->m_message);
+ return JSValue::encode(jsNull());
+ }
+
+ ConstructType getConstructData(ConstructData& constructData)
+ {
+ constructData.native.function = constructThrowTypeError;
+ return ConstructTypeHost;
+ }
+
+ static EncodedJSValue JSC_HOST_CALL callThrowTypeError(ExecState* exec)
+ {
+ throwTypeError(exec, static_cast<StrictModeTypeErrorFunction*>(exec->callee())->m_message);
+ return JSValue::encode(jsNull());
+ }
+
+ CallType getCallData(CallData& callData)
+ {
+ callData.native.function = callThrowTypeError;
+ return CallTypeHost;
+ }
+
+private:
+ UString m_message;
+};
+
+ASSERT_CLASS_FITS_IN_CELL(StrictModeTypeErrorFunction);
+
+JSValue createTypeErrorFunction(ExecState* exec, const UString& message)
+{
+ return new (exec) StrictModeTypeErrorFunction(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->internalFunctionStructure(), message);
}
} // namespace JSC
#ifndef Error_h
#define Error_h
+#include "JSObject.h"
#include <stdint.h>
namespace JSC {
class ExecState;
+ class JSGlobalData;
+ class JSGlobalObject;
class JSObject;
+ class SourceCode;
+ class Structure;
class UString;
- /**
- * Types of Native Errors available. For custom errors, GeneralError
- * should be used.
- */
- enum ErrorType {
- GeneralError = 0,
- EvalError = 1,
- RangeError = 2,
- ReferenceError = 3,
- SyntaxError = 4,
- TypeError = 5,
- URIError = 6
- };
-
- extern const char* expressionBeginOffsetPropertyName;
- extern const char* expressionCaretOffsetPropertyName;
- extern const char* expressionEndOffsetPropertyName;
-
- class Error {
- public:
- static JSObject* create(ExecState*, ErrorType, const UString& message, int lineNumber, intptr_t sourceID, const UString& sourceURL);
- static JSObject* create(ExecState*, ErrorType, const char* message);
- };
+ // Methods to create a range of internal errors.
+ JSObject* createError(JSGlobalObject*, const UString&);
+ JSObject* createEvalError(JSGlobalObject*, const UString&);
+ JSObject* createRangeError(JSGlobalObject*, const UString&);
+ JSObject* createReferenceError(JSGlobalObject*, const UString&);
+ JSObject* createSyntaxError(JSGlobalObject*, const UString&);
+ JSObject* createTypeError(JSGlobalObject*, const UString&);
+ JSObject* createURIError(JSGlobalObject*, const UString&);
+ // ExecState wrappers.
+ JSObject* createError(ExecState*, const UString&);
+ JSObject* createEvalError(ExecState*, const UString&);
+ JSObject* createRangeError(ExecState*, const UString&);
+ JSObject* createReferenceError(ExecState*, const UString&);
+ JSObject* createSyntaxError(ExecState*, const UString&);
+ JSObject* createTypeError(ExecState*, const UString&);
+ JSObject* createURIError(ExecState*, const UString&);
+
+ // Methods to add
+ bool hasErrorInfo(ExecState*, JSObject* error);
+ JSObject* addErrorInfo(JSGlobalData*, JSObject* error, int line, const SourceCode&);
+ // ExecState wrappers.
+ JSObject* addErrorInfo(ExecState*, JSObject* error, int line, const SourceCode&);
- JSObject* throwError(ExecState*, ErrorType, const UString& message, int lineNumber, intptr_t sourceID, const UString& sourceURL);
- JSObject* throwError(ExecState*, ErrorType, const UString& message);
- JSObject* throwError(ExecState*, ErrorType, const char* message);
- JSObject* throwError(ExecState*, ErrorType);
+ // Methods to throw Errors.
+ JSValue throwError(ExecState*, JSValue);
JSObject* throwError(ExecState*, JSObject*);
+ // Convenience wrappers, create an throw an exception with a default message.
+ JSObject* throwTypeError(ExecState*);
+ JSObject* throwSyntaxError(ExecState*);
+
+ // Convenience wrappers, wrap result as an EncodedJSValue.
+ inline EncodedJSValue throwVMError(ExecState* exec, JSValue error) { return JSValue::encode(throwError(exec, error)); }
+ inline EncodedJSValue throwVMTypeError(ExecState* exec) { return JSValue::encode(throwTypeError(exec)); }
+
+ JSValue createTypeErrorFunction(ExecState* exec, const UString& message);
+
} // namespace JSC
#endif // Error_h
ASSERT_CLASS_FITS_IN_CELL(ErrorConstructor);
-ErrorConstructor::ErrorConstructor(ExecState* exec, NonNullPassRefPtr<Structure> structure, ErrorPrototype* errorPrototype)
- : InternalFunction(&exec->globalData(), structure, Identifier(exec, errorPrototype->classInfo()->className))
+ErrorConstructor::ErrorConstructor(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, ErrorPrototype* errorPrototype)
+ : InternalFunction(&exec->globalData(), globalObject, structure, Identifier(exec, errorPrototype->classInfo()->className))
{
// ECMA 15.11.3.1 Error.prototype
- putDirectWithoutTransition(exec->propertyNames().prototype, errorPrototype, DontEnum | DontDelete | ReadOnly);
- putDirectWithoutTransition(exec->propertyNames().length, jsNumber(exec, 1), DontDelete | ReadOnly | DontEnum);
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().prototype, errorPrototype, DontEnum | DontDelete | ReadOnly);
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(1), DontDelete | ReadOnly | DontEnum);
}
// ECMA 15.9.3
-ErrorInstance* constructError(ExecState* exec, const ArgList& args)
-{
- ErrorInstance* obj = new (exec) ErrorInstance(exec->lexicalGlobalObject()->errorStructure());
- if (!args.at(0).isUndefined())
- obj->putDirect(exec->propertyNames().message, jsString(exec, args.at(0).toString(exec)));
- return obj;
-}
-static JSObject* constructWithErrorConstructor(ExecState* exec, JSObject*, const ArgList& args)
+static EncodedJSValue JSC_HOST_CALL constructWithErrorConstructor(ExecState* exec)
{
- return constructError(exec, args);
+ JSValue message = exec->argumentCount() ? exec->argument(0) : jsUndefined();
+ Structure* errorStructure = asInternalFunction(exec->callee())->globalObject()->errorStructure();
+ return JSValue::encode(ErrorInstance::create(exec, errorStructure, message));
}
ConstructType ErrorConstructor::getConstructData(ConstructData& constructData)
return ConstructTypeHost;
}
-// ECMA 15.9.2
-static JSValue JSC_HOST_CALL callErrorConstructor(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+static EncodedJSValue JSC_HOST_CALL callErrorConstructor(ExecState* exec)
{
- // "Error()" gives the sames result as "new Error()"
- return constructError(exec, args);
+ JSValue message = exec->argumentCount() ? exec->argument(0) : jsUndefined();
+ Structure* errorStructure = asInternalFunction(exec->callee())->globalObject()->errorStructure();
+ return JSValue::encode(ErrorInstance::create(exec, errorStructure, message));
}
CallType ErrorConstructor::getCallData(CallData& callData)
class ErrorConstructor : public InternalFunction {
public:
- ErrorConstructor(ExecState*, NonNullPassRefPtr<Structure>, ErrorPrototype*);
+ ErrorConstructor(ExecState*, JSGlobalObject*, Structure*, ErrorPrototype*);
private:
virtual ConstructType getConstructData(ConstructData&);
virtual CallType getCallData(CallData&);
};
- ErrorInstance* constructError(ExecState*, const ArgList&);
-
} // namespace JSC
#endif // ErrorConstructor_h
namespace JSC {
-const ClassInfo ErrorInstance::info = { "Error", 0, 0, 0 };
+const ClassInfo ErrorInstance::s_info = { "Error", &JSNonFinalObject::s_info, 0, 0 };
-ErrorInstance::ErrorInstance(NonNullPassRefPtr<Structure> structure)
- : JSObject(structure)
+ErrorInstance::ErrorInstance(JSGlobalData* globalData, Structure* structure)
+ : JSNonFinalObject(*globalData, structure)
+ , m_appendSourceToMessage(false)
{
+ ASSERT(inherits(&s_info));
+ putDirect(*globalData, globalData->propertyNames->message, jsString(globalData, ""));
+}
+
+ErrorInstance::ErrorInstance(JSGlobalData* globalData, Structure* structure, const UString& message)
+ : JSNonFinalObject(*globalData, structure)
+ , m_appendSourceToMessage(false)
+{
+ ASSERT(inherits(&s_info));
+ putDirect(*globalData, globalData->propertyNames->message, jsString(globalData, message));
+}
+
+ErrorInstance* ErrorInstance::create(JSGlobalData* globalData, Structure* structure, const UString& message)
+{
+ return new (globalData) ErrorInstance(globalData, structure, message);
+}
+
+ErrorInstance* ErrorInstance::create(ExecState* exec, Structure* structure, JSValue message)
+{
+ if (message.isUndefined())
+ return new (exec) ErrorInstance(&exec->globalData(), structure);
+ return new (exec) ErrorInstance(&exec->globalData(), structure, message.toString(exec));
}
} // namespace JSC
namespace JSC {
- class ErrorInstance : public JSObject {
+ class ErrorInstance : public JSNonFinalObject {
public:
- explicit ErrorInstance(NonNullPassRefPtr<Structure>);
+ static const ClassInfo s_info;
- virtual const ClassInfo* classInfo() const { return &info; }
- static const ClassInfo info;
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
+ {
+ return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
+ }
+
+ static ErrorInstance* create(JSGlobalData*, Structure*, const UString&);
+ static ErrorInstance* create(ExecState*, Structure*, JSValue message);
+
+
+ bool appendSourceToMessage() { return m_appendSourceToMessage; }
+ void setAppendSourceToMessage() { m_appendSourceToMessage = true; }
+ void clearAppendSourceToMessage() { m_appendSourceToMessage = false; }
+
+ virtual bool isErrorInstance() const { return true; }
+
+ protected:
+ explicit ErrorInstance(JSGlobalData*, Structure*);
+ explicit ErrorInstance(JSGlobalData*, Structure*, const UString&);
+
+ bool m_appendSourceToMessage;
};
} // namespace JSC
#include "JSString.h"
#include "JSStringBuilder.h"
#include "ObjectPrototype.h"
-#include "PrototypeFunction.h"
+#include "StringRecursionChecker.h"
#include "UString.h"
namespace JSC {
ASSERT_CLASS_FITS_IN_CELL(ErrorPrototype);
-static JSValue JSC_HOST_CALL errorProtoFuncToString(ExecState*, JSObject*, JSValue, const ArgList&);
+static EncodedJSValue JSC_HOST_CALL errorProtoFuncToString(ExecState*);
-// ECMA 15.9.4
-ErrorPrototype::ErrorPrototype(ExecState* exec, NonNullPassRefPtr<Structure> structure, Structure* prototypeFunctionStructure)
- : ErrorInstance(structure)
+}
+
+#include "ErrorPrototype.lut.h"
+
+namespace JSC {
+
+const ClassInfo ErrorPrototype::s_info = { "Error", &ErrorInstance::s_info, 0, ExecState::errorPrototypeTable };
+
+/* Source for ErrorPrototype.lut.h
+@begin errorPrototypeTable
+ toString errorProtoFuncToString DontEnum|Function 0
+@end
+*/
+
+ASSERT_CLASS_FITS_IN_CELL(ErrorPrototype);
+
+ErrorPrototype::ErrorPrototype(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
+ : ErrorInstance(&exec->globalData(), structure)
{
- // The constructor will be added later in ErrorConstructor's constructor
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().name, jsNontrivialString(exec, "Error"), DontEnum);
- putDirectWithoutTransition(exec->propertyNames().name, jsNontrivialString(exec, "Error"), DontEnum);
- putDirectWithoutTransition(exec->propertyNames().message, jsNontrivialString(exec, "Unknown error"), DontEnum);
+ ASSERT(inherits(&s_info));
+ putAnonymousValue(globalObject->globalData(), 0, globalObject);
+}
+
+bool ErrorPrototype::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot &slot)
+{
+ return getStaticFunctionSlot<ErrorInstance>(exec, ExecState::errorPrototypeTable(exec), this, propertyName, slot);
+}
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 0, exec->propertyNames().toString, errorProtoFuncToString), DontEnum);
+bool ErrorPrototype::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ return getStaticFunctionDescriptor<ErrorInstance>(exec, ExecState::errorPrototypeTable(exec), this, propertyName, descriptor);
}
-JSValue JSC_HOST_CALL errorProtoFuncToString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+// ------------------------------ Functions ---------------------------
+
+EncodedJSValue JSC_HOST_CALL errorProtoFuncToString(ExecState* exec)
{
- JSObject* thisObj = thisValue.toThisObject(exec);
+ JSObject* thisObj = exec->hostThisValue().toThisObject(exec);
+
+ StringRecursionChecker checker(exec, thisObj);
+ if (EncodedJSValue earlyReturnValue = checker.earlyReturnValue())
+ return earlyReturnValue;
+
JSValue name = thisObj->get(exec, exec->propertyNames().name);
JSValue message = thisObj->get(exec, exec->propertyNames().message);
if (!name.isUndefined()) {
if (!message.isUndefined())
- return jsMakeNontrivialString(exec, name.toString(exec), ": ", message.toString(exec));
- return jsNontrivialString(exec, name.toString(exec));
+ return JSValue::encode(jsMakeNontrivialString(exec, name.toString(exec), ": ", message.toString(exec)));
+ return JSValue::encode(jsNontrivialString(exec, name.toString(exec)));
}
if (!message.isUndefined())
- return jsMakeNontrivialString(exec, "Error: ", message.toString(exec));
- return jsNontrivialString(exec, "Error");
+ return JSValue::encode(jsMakeNontrivialString(exec, "Error: ", message.toString(exec)));
+ return JSValue::encode(jsNontrivialString(exec, "Error"));
}
} // namespace JSC
class ErrorPrototype : public ErrorInstance {
public:
- ErrorPrototype(ExecState*, NonNullPassRefPtr<Structure>, Structure* prototypeFunctionStructure);
+ ErrorPrototype(ExecState*, JSGlobalObject*, Structure*);
+
+ static const ClassInfo s_info;
+
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
+ {
+ return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
+ }
+
+ protected:
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | ErrorInstance::StructureFlags;
+ static const unsigned AnonymousSlotCount = ErrorInstance::AnonymousSlotCount + 1;
+
+ private:
+ virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
+ virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
};
} // namespace JSC
#include "CodeBlock.h"
#include "CallFrame.h"
+#include "ErrorInstance.h"
#include "JSGlobalObjectFunctions.h"
#include "JSObject.h"
#include "JSNotAnObject.h"
#include "Interpreter.h"
#include "Nodes.h"
+#include "UStringConcatenate.h"
namespace JSC {
-class InterruptedExecutionError : public JSObject {
+class InterruptedExecutionError : public JSNonFinalObject {
public:
InterruptedExecutionError(JSGlobalData* globalData)
- : JSObject(globalData->interruptedExecutionErrorStructure)
+ : JSNonFinalObject(*globalData, globalData->interruptedExecutionErrorStructure.get())
{
}
virtual UString toString(ExecState*) const { return "JavaScript execution exceeded timeout."; }
};
-JSValue createInterruptedExecutionException(JSGlobalData* globalData)
+JSObject* createInterruptedExecutionException(JSGlobalData* globalData)
{
return new (globalData) InterruptedExecutionError(globalData);
}
-class TerminatedExecutionError : public JSObject {
+class TerminatedExecutionError : public JSNonFinalObject {
public:
TerminatedExecutionError(JSGlobalData* globalData)
- : JSObject(globalData->terminatedExecutionErrorStructure)
+ : JSNonFinalObject(*globalData, globalData->terminatedExecutionErrorStructure.get())
{
}
virtual UString toString(ExecState*) const { return "JavaScript execution terminated."; }
};
-JSValue createTerminatedExecutionException(JSGlobalData* globalData)
+JSObject* createTerminatedExecutionException(JSGlobalData* globalData)
{
return new (globalData) TerminatedExecutionError(globalData);
}
-static JSValue createError(ExecState* exec, ErrorType e, const char* msg)
+JSObject* createStackOverflowError(ExecState* exec)
{
- return Error::create(exec, e, msg, -1, -1, UString());
+ return createRangeError(exec, "Maximum call stack size exceeded.");
}
-JSValue createStackOverflowError(ExecState* exec)
+JSObject* createStackOverflowError(JSGlobalObject* globalObject)
{
- return createError(exec, RangeError, "Maximum call stack size exceeded.");
+ return createRangeError(globalObject, "Maximum call stack size exceeded.");
}
-JSValue createTypeError(ExecState* exec, const char* message)
+JSObject* createUndefinedVariableError(ExecState* exec, const Identifier& ident)
{
- return createError(exec, TypeError, message);
-}
-
-JSValue createUndefinedVariableError(ExecState* exec, const Identifier& ident, unsigned bytecodeOffset, CodeBlock* codeBlock)
-{
- int startOffset = 0;
- int endOffset = 0;
- int divotPoint = 0;
- int line = codeBlock->expressionRangeForBytecodeOffset(exec, bytecodeOffset, divotPoint, startOffset, endOffset);
- JSObject* exception = Error::create(exec, ReferenceError, makeString("Can't find variable: ", ident.ustring()), line, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->sourceURL());
- exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete);
- exception->putWithAttributes(exec, Identifier(exec, expressionCaretOffsetPropertyName), jsNumber(exec, divotPoint), ReadOnly | DontDelete);
- exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete);
- return exception;
+ UString message(makeUString("Can't find variable: ", ident.ustring()));
+ return createReferenceError(exec, message);
}
-static UString createErrorMessage(ExecState* exec, CodeBlock* codeBlock, int, int expressionStart, int expressionStop, JSValue value, UString error)
+JSObject* createInvalidParamError(ExecState* exec, const char* op, JSValue value)
{
- if (!expressionStop || expressionStart > codeBlock->source()->length())
- return makeString(value.toString(exec), " is ", error);
- if (expressionStart < expressionStop)
- return makeString("Result of expression '", codeBlock->source()->getRange(expressionStart, expressionStop), "' [", value.toString(exec), "] is ", error, ".");
-
- // No range information, so give a few characters of context
- const UChar* data = codeBlock->source()->data();
- int dataLength = codeBlock->source()->length();
- int start = expressionStart;
- int stop = expressionStart;
- // Get up to 20 characters of context to the left and right of the divot, clamping to the line.
- // then strip whitespace.
- while (start > 0 && (expressionStart - start < 20) && data[start - 1] != '\n')
- start--;
- while (start < (expressionStart - 1) && isStrWhiteSpace(data[start]))
- start++;
- while (stop < dataLength && (stop - expressionStart < 20) && data[stop] != '\n')
- stop++;
- while (stop > expressionStart && isStrWhiteSpace(data[stop]))
- stop--;
- return makeString("Result of expression near '...", codeBlock->source()->getRange(start, stop), "...' [", value.toString(exec), "] is ", error, ".");
+ UString errorMessage = makeUString("'", value.toString(exec), "' is not a valid argument for '", op, "'");
+ JSObject* exception = createTypeError(exec, errorMessage);
+ ASSERT(exception->isErrorInstance());
+ static_cast<ErrorInstance*>(exception)->setAppendSourceToMessage();
+ return exception;
}
-JSObject* createInvalidParamError(ExecState* exec, const char* op, JSValue value, unsigned bytecodeOffset, CodeBlock* codeBlock)
+JSObject* createNotAConstructorError(ExecState* exec, JSValue value)
{
- int startOffset = 0;
- int endOffset = 0;
- int divotPoint = 0;
- int line = codeBlock->expressionRangeForBytecodeOffset(exec, bytecodeOffset, divotPoint, startOffset, endOffset);
- UString errorMessage = createErrorMessage(exec, codeBlock, line, divotPoint, divotPoint + endOffset, value, makeString("not a valid argument for '", op, "'"));
- JSObject* exception = Error::create(exec, TypeError, errorMessage, line, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->sourceURL());
- exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete);
- exception->putWithAttributes(exec, Identifier(exec, expressionCaretOffsetPropertyName), jsNumber(exec, divotPoint), ReadOnly | DontDelete);
- exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete);
+ UString errorMessage = makeUString("'", value.toString(exec), "' is not a constructor");
+ JSObject* exception = createTypeError(exec, errorMessage);
+ ASSERT(exception->isErrorInstance());
+ static_cast<ErrorInstance*>(exception)->setAppendSourceToMessage();
return exception;
}
-JSObject* createNotAConstructorError(ExecState* exec, JSValue value, unsigned bytecodeOffset, CodeBlock* codeBlock)
+JSObject* createNotAFunctionError(ExecState* exec, JSValue value)
{
- int startOffset = 0;
- int endOffset = 0;
- int divotPoint = 0;
- int line = codeBlock->expressionRangeForBytecodeOffset(exec, bytecodeOffset, divotPoint, startOffset, endOffset);
-
- // We're in a "new" expression, so we need to skip over the "new.." part
- int startPoint = divotPoint - (startOffset ? startOffset - 4 : 0); // -4 for "new "
- const UChar* data = codeBlock->source()->data();
- while (startPoint < divotPoint && isStrWhiteSpace(data[startPoint]))
- startPoint++;
-
- UString errorMessage = createErrorMessage(exec, codeBlock, line, startPoint, divotPoint, value, "not a constructor");
- JSObject* exception = Error::create(exec, TypeError, errorMessage, line, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->sourceURL());
- exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete);
- exception->putWithAttributes(exec, Identifier(exec, expressionCaretOffsetPropertyName), jsNumber(exec, divotPoint), ReadOnly | DontDelete);
- exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete);
+ UString errorMessage = makeUString("'", value.toString(exec), "' is not a function");
+ JSObject* exception = createTypeError(exec, errorMessage);
+ ASSERT(exception->isErrorInstance());
+ static_cast<ErrorInstance*>(exception)->setAppendSourceToMessage();
return exception;
}
-JSValue createNotAFunctionError(ExecState* exec, JSValue value, unsigned bytecodeOffset, CodeBlock* codeBlock)
+JSObject* createNotAnObjectError(ExecState* exec, JSValue value)
{
- int startOffset = 0;
- int endOffset = 0;
- int divotPoint = 0;
- int line = codeBlock->expressionRangeForBytecodeOffset(exec, bytecodeOffset, divotPoint, startOffset, endOffset);
- UString errorMessage = createErrorMessage(exec, codeBlock, line, divotPoint - startOffset, divotPoint, value, "not a function");
- JSObject* exception = Error::create(exec, TypeError, errorMessage, line, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->sourceURL());
- exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete);
- exception->putWithAttributes(exec, Identifier(exec, expressionCaretOffsetPropertyName), jsNumber(exec, divotPoint), ReadOnly | DontDelete);
- exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete);
+ UString errorMessage = makeUString("'", value.toString(exec), "' is not an object");
+ JSObject* exception = createTypeError(exec, errorMessage);
+ ASSERT(exception->isErrorInstance());
+ static_cast<ErrorInstance*>(exception)->setAppendSourceToMessage();
return exception;
}
-JSNotAnObjectErrorStub* createNotAnObjectErrorStub(ExecState* exec, bool isNull)
+JSObject* createErrorForInvalidGlobalAssignment(ExecState* exec, const UString& propertyName)
{
- return new (exec) JSNotAnObjectErrorStub(exec, isNull);
+ return createReferenceError(exec, makeUString("Strict mode forbids implicit creation of global property '", propertyName, "'"));
}
-JSObject* createNotAnObjectError(ExecState* exec, JSNotAnObjectErrorStub* error, unsigned bytecodeOffset, CodeBlock* codeBlock)
+JSObject* createOutOfMemoryError(JSGlobalObject* globalObject)
{
- // Both op_construct and op_instanceof require a use of op_get_by_id to get
- // the prototype property from an object. The exception messages for exceptions
- // thrown by these instances op_get_by_id need to reflect this.
- OpcodeID followingOpcodeID;
- if (codeBlock->getByIdExceptionInfoForBytecodeOffset(exec, bytecodeOffset, followingOpcodeID)) {
- ASSERT(followingOpcodeID == op_construct || followingOpcodeID == op_instanceof);
- if (followingOpcodeID == op_construct)
- return createNotAConstructorError(exec, error->isNull() ? jsNull() : jsUndefined(), bytecodeOffset, codeBlock);
- return createInvalidParamError(exec, "instanceof", error->isNull() ? jsNull() : jsUndefined(), bytecodeOffset, codeBlock);
- }
+ return createError(globalObject, "Out of memory");
+}
- int startOffset = 0;
- int endOffset = 0;
- int divotPoint = 0;
- int line = codeBlock->expressionRangeForBytecodeOffset(exec, bytecodeOffset, divotPoint, startOffset, endOffset);
- UString errorMessage = createErrorMessage(exec, codeBlock, line, divotPoint - startOffset, divotPoint, error->isNull() ? jsNull() : jsUndefined(), "not an object");
- JSObject* exception = Error::create(exec, TypeError, errorMessage, line, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->sourceURL());
- exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete);
- exception->putWithAttributes(exec, Identifier(exec, expressionCaretOffsetPropertyName), jsNumber(exec, divotPoint), ReadOnly | DontDelete);
- exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete);
- return exception;
+JSObject* throwOutOfMemoryError(ExecState* exec)
+{
+ return throwError(exec, createOutOfMemoryError(exec->lexicalGlobalObject()));
}
-JSValue throwOutOfMemoryError(ExecState* exec)
+JSObject* throwStackOverflowError(ExecState* exec)
{
- return throwError(exec, GeneralError, "Out of memory");
+ return throwError(exec, createStackOverflowError(exec));
}
} // namespace JSC
#ifndef ExceptionHelpers_h
#define ExceptionHelpers_h
+#include "JSValue.h"
namespace JSC {
class ExecState;
class Identifier;
class JSGlobalData;
+ class JSGlobalObject;
class JSNotAnObjectErrorStub;
class JSObject;
- class JSValue;
class Node;
struct Instruction;
- JSValue createInterruptedExecutionException(JSGlobalData*);
- JSValue createTerminatedExecutionException(JSGlobalData*);
- JSValue createStackOverflowError(ExecState*);
- JSValue createTypeError(ExecState*, const char* message);
- JSValue createUndefinedVariableError(ExecState*, const Identifier&, unsigned bytecodeOffset, CodeBlock*);
- JSNotAnObjectErrorStub* createNotAnObjectErrorStub(ExecState*, bool isNull);
- JSObject* createInvalidParamError(ExecState*, const char* op, JSValue, unsigned bytecodeOffset, CodeBlock*);
- JSObject* createNotAConstructorError(ExecState*, JSValue, unsigned bytecodeOffset, CodeBlock*);
- JSValue createNotAFunctionError(ExecState*, JSValue, unsigned bytecodeOffset, CodeBlock*);
- JSObject* createNotAnObjectError(ExecState*, JSNotAnObjectErrorStub*, unsigned bytecodeOffset, CodeBlock*);
- JSValue throwOutOfMemoryError(ExecState*);
+ JSObject* createInterruptedExecutionException(JSGlobalData*);
+ JSObject* createTerminatedExecutionException(JSGlobalData*);
+ JSObject* createStackOverflowError(ExecState*);
+ JSObject* createStackOverflowError(JSGlobalObject*);
+ JSObject* createOutOfMemoryError(JSGlobalObject*);
+ JSObject* createUndefinedVariableError(ExecState*, const Identifier&);
+ JSObject* createNotAnObjectError(ExecState*, JSValue);
+ JSObject* createInvalidParamError(ExecState*, const char* op, JSValue);
+ JSObject* createNotAConstructorError(ExecState*, JSValue);
+ JSObject* createNotAFunctionError(ExecState*, JSValue);
+ JSObject* createErrorForInvalidGlobalAssignment(ExecState*, const UString&);
+
+ JSObject* throwOutOfMemoryError(ExecState*);
+ JSObject* throwStackOverflowError(ExecState*);
} // namespace JSC
/*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2009, 2010 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
#include "CodeBlock.h"
#include "JIT.h"
#include "Parser.h"
-#include "StringBuilder.h"
+#include "UStringBuilder.h"
#include "Vector.h"
+#if ENABLE(DFG_JIT)
+#include "DFGByteCodeParser.h"
+#include "DFGJITCompiler.h"
+#endif
+
namespace JSC {
+const ClassInfo ExecutableBase::s_info = { "Executable", 0, 0, 0 };
+
#if ENABLE(JIT)
-NativeExecutable::~NativeExecutable()
+class ExecutableFinalizer : public WeakHandleOwner {
+ virtual void finalize(Handle<Unknown> handle, void*)
+ {
+ Weak<ExecutableBase> executable(Weak<ExecutableBase>::Adopt, handle);
+ executable->clearExecutableCode();
+ }
+};
+
+WeakHandleOwner* ExecutableBase::executableFinalizer()
{
+ DEFINE_STATIC_LOCAL(ExecutableFinalizer, finalizer, ());
+ return &finalizer;
}
#endif
+
+const ClassInfo NativeExecutable::s_info = { "NativeExecutable", &ExecutableBase::s_info, 0, 0 };
-VPtrHackExecutable::~VPtrHackExecutable()
+NativeExecutable::~NativeExecutable()
+{
+}
+
+const ClassInfo ScriptExecutable::s_info = { "ScriptExecutable", &ExecutableBase::s_info, 0, 0 };
+
+const ClassInfo EvalExecutable::s_info = { "EvalExecutable", &ScriptExecutable::s_info, 0, 0 };
+
+EvalExecutable::EvalExecutable(ExecState* exec, const SourceCode& source, bool inStrictContext)
+ : ScriptExecutable(exec->globalData().evalExecutableStructure.get(), exec, source, inStrictContext)
{
}
EvalExecutable::~EvalExecutable()
{
- delete m_evalCodeBlock;
+}
+
+const ClassInfo ProgramExecutable::s_info = { "ProgramExecutable", &ScriptExecutable::s_info, 0, 0 };
+
+ProgramExecutable::ProgramExecutable(ExecState* exec, const SourceCode& source)
+ : ScriptExecutable(exec->globalData().programExecutableStructure.get(), exec, source, false)
+{
}
ProgramExecutable::~ProgramExecutable()
{
- delete m_programCodeBlock;
}
-FunctionExecutable::~FunctionExecutable()
+const ClassInfo FunctionExecutable::s_info = { "FunctionExecutable", &ScriptExecutable::s_info, 0, 0 };
+
+FunctionExecutable::FunctionExecutable(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool inStrictContext, int firstLine, int lastLine)
+ : ScriptExecutable(globalData->functionExecutableStructure.get(), globalData, source, inStrictContext)
+ , m_numCapturedVariables(0)
+ , m_forceUsesArguments(forceUsesArguments)
+ , m_parameters(parameters)
+ , m_name(name)
+ , m_symbolTable(0)
{
- delete m_codeBlock;
+ m_firstLine = firstLine;
+ m_lastLine = lastLine;
}
-JSObject* EvalExecutable::compile(ExecState* exec, ScopeChainNode* scopeChainNode)
+FunctionExecutable::FunctionExecutable(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool inStrictContext, int firstLine, int lastLine)
+ : ScriptExecutable(exec->globalData().functionExecutableStructure.get(), exec, source, inStrictContext)
+ , m_numCapturedVariables(0)
+ , m_forceUsesArguments(forceUsesArguments)
+ , m_parameters(parameters)
+ , m_name(name)
+ , m_symbolTable(0)
{
- int errLine;
- UString errMsg;
- RefPtr<EvalNode> evalNode = exec->globalData().parser->parse<EvalNode>(&exec->globalData(), exec->lexicalGlobalObject()->debugger(), exec, m_source, &errLine, &errMsg);
- if (!evalNode)
- return Error::create(exec, SyntaxError, errMsg, errLine, m_source.provider()->asID(), m_source.provider()->url());
- recordParse(evalNode->features(), evalNode->lineNo(), evalNode->lastLine());
+ m_firstLine = firstLine;
+ m_lastLine = lastLine;
+}
- ScopeChain scopeChain(scopeChainNode);
- JSGlobalObject* globalObject = scopeChain.globalObject();
+
+JSObject* EvalExecutable::compileInternal(ExecState* exec, ScopeChainNode* scopeChainNode)
+{
+ JSObject* exception = 0;
+ JSGlobalData* globalData = &exec->globalData();
+ JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
+ if (!lexicalGlobalObject->isEvalEnabled())
+ return throwError(exec, createEvalError(exec, "Eval is disabled"));
+ RefPtr<EvalNode> evalNode = globalData->parser->parse<EvalNode>(lexicalGlobalObject, lexicalGlobalObject->debugger(), exec, m_source, 0, isStrictMode() ? JSParseStrict : JSParseNormal, &exception);
+ if (!evalNode) {
+ ASSERT(exception);
+ return exception;
+ }
+ recordParse(evalNode->features(), evalNode->hasCapturedVariables(), evalNode->lineNo(), evalNode->lastLine());
+
+ JSGlobalObject* globalObject = scopeChainNode->globalObject.get();
ASSERT(!m_evalCodeBlock);
- m_evalCodeBlock = new EvalCodeBlock(this, globalObject, source().provider(), scopeChain.localDepth());
- OwnPtr<BytecodeGenerator> generator(new BytecodeGenerator(evalNode.get(), globalObject->debugger(), scopeChain, m_evalCodeBlock->symbolTable(), m_evalCodeBlock));
- generator->generate();
-
+ m_evalCodeBlock = adoptPtr(new EvalCodeBlock(this, globalObject, source().provider(), scopeChainNode->localDepth()));
+ OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(evalNode.get(), scopeChainNode, m_evalCodeBlock->symbolTable(), m_evalCodeBlock.get())));
+ if ((exception = generator->generate())) {
+ m_evalCodeBlock.clear();
+ evalNode->destroyData();
+ return exception;
+ }
+
evalNode->destroyData();
+
+#if ENABLE(JIT)
+ if (exec->globalData().canUseJIT()) {
+ m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, m_evalCodeBlock.get());
+#if !ENABLE(OPCODE_SAMPLING)
+ if (!BytecodeGenerator::dumpsGeneratedCode())
+ m_evalCodeBlock->discardBytecode();
+#endif
+ }
+#endif
+
+#if ENABLE(JIT)
+#if ENABLE(INTERPRETER)
+ if (!m_jitCodeForCall)
+ Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_evalCodeBlock));
+ else
+#endif
+ Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_evalCodeBlock) + m_jitCodeForCall.size());
+#else
+ Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_evalCodeBlock));
+#endif
+
return 0;
}
-JSObject* ProgramExecutable::checkSyntax(ExecState* exec)
+void EvalExecutable::visitChildren(SlotVisitor& visitor)
{
- int errLine;
- UString errMsg;
- RefPtr<ProgramNode> programNode = exec->globalData().parser->parse<ProgramNode>(&exec->globalData(), exec->lexicalGlobalObject()->debugger(), exec, m_source, &errLine, &errMsg);
- if (!programNode)
- return Error::create(exec, SyntaxError, errMsg, errLine, m_source.provider()->asID(), m_source.provider()->url());
- return 0;
+ ASSERT_GC_OBJECT_INHERITS(this, &s_info);
+ COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
+ ASSERT(structure()->typeInfo().overridesVisitChildren());
+ ScriptExecutable::visitChildren(visitor);
+ if (m_evalCodeBlock)
+ m_evalCodeBlock->visitAggregate(visitor);
}
-JSObject* ProgramExecutable::compile(ExecState* exec, ScopeChainNode* scopeChainNode)
+void EvalExecutable::unlinkCalls()
{
- int errLine;
- UString errMsg;
- RefPtr<ProgramNode> programNode = exec->globalData().parser->parse<ProgramNode>(&exec->globalData(), exec->lexicalGlobalObject()->debugger(), exec, m_source, &errLine, &errMsg);
- if (!programNode)
- return Error::create(exec, SyntaxError, errMsg, errLine, m_source.provider()->asID(), m_source.provider()->url());
- recordParse(programNode->features(), programNode->lineNo(), programNode->lastLine());
-
- ScopeChain scopeChain(scopeChainNode);
- JSGlobalObject* globalObject = scopeChain.globalObject();
-
- ASSERT(!m_programCodeBlock);
- m_programCodeBlock = new ProgramCodeBlock(this, GlobalCode, globalObject, source().provider());
- OwnPtr<BytecodeGenerator> generator(new BytecodeGenerator(programNode.get(), globalObject->debugger(), scopeChain, &globalObject->symbolTable(), m_programCodeBlock));
- generator->generate();
+#if ENABLE(JIT)
+ if (!m_jitCodeForCall)
+ return;
+ ASSERT(m_evalCodeBlock);
+ m_evalCodeBlock->unlinkCalls();
+#endif
+}
- programNode->destroyData();
- return 0;
+JSObject* ProgramExecutable::checkSyntax(ExecState* exec)
+{
+ JSObject* exception = 0;
+ JSGlobalData* globalData = &exec->globalData();
+ JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
+ RefPtr<ProgramNode> programNode = globalData->parser->parse<ProgramNode>(lexicalGlobalObject, lexicalGlobalObject->debugger(), exec, m_source, 0, JSParseNormal, &exception);
+ if (programNode)
+ return 0;
+ ASSERT(exception);
+ return exception;
}
-void FunctionExecutable::compile(ExecState*, ScopeChainNode* scopeChainNode)
+JSObject* ProgramExecutable::compileInternal(ExecState* exec, ScopeChainNode* scopeChainNode)
{
- JSGlobalData* globalData = scopeChainNode->globalData;
- RefPtr<FunctionBodyNode> body = globalData->parser->parse<FunctionBodyNode>(globalData, 0, 0, m_source);
- if (m_forceUsesArguments)
- body->setUsesArguments();
- body->finishParsing(m_parameters, m_name);
- recordParse(body->features(), body->lineNo(), body->lastLine());
+ ASSERT(!m_programCodeBlock);
- ScopeChain scopeChain(scopeChainNode);
- JSGlobalObject* globalObject = scopeChain.globalObject();
+ JSObject* exception = 0;
+ JSGlobalData* globalData = &exec->globalData();
+ JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
+ RefPtr<ProgramNode> programNode = globalData->parser->parse<ProgramNode>(lexicalGlobalObject, lexicalGlobalObject->debugger(), exec, m_source, 0, isStrictMode() ? JSParseStrict : JSParseNormal, &exception);
+ if (!programNode) {
+ ASSERT(exception);
+ return exception;
+ }
+ recordParse(programNode->features(), programNode->hasCapturedVariables(), programNode->lineNo(), programNode->lastLine());
- ASSERT(!m_codeBlock);
- m_codeBlock = new FunctionCodeBlock(this, FunctionCode, source().provider(), source().startOffset());
- OwnPtr<BytecodeGenerator> generator(new BytecodeGenerator(body.get(), globalObject->debugger(), scopeChain, m_codeBlock->symbolTable(), m_codeBlock));
- generator->generate();
- m_numParameters = m_codeBlock->m_numParameters;
- ASSERT(m_numParameters);
- m_numVariables = m_codeBlock->m_numVars;
+ JSGlobalObject* globalObject = scopeChainNode->globalObject.get();
+
+ m_programCodeBlock = adoptPtr(new ProgramCodeBlock(this, GlobalCode, globalObject, source().provider()));
+ OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(programNode.get(), scopeChainNode, &globalObject->symbolTable(), m_programCodeBlock.get())));
+ if ((exception = generator->generate())) {
+ m_programCodeBlock.clear();
+ programNode->destroyData();
+ return exception;
+ }
- body->destroyData();
-}
+ programNode->destroyData();
#if ENABLE(JIT)
+ if (exec->globalData().canUseJIT()) {
+ m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, m_programCodeBlock.get());
+#if !ENABLE(OPCODE_SAMPLING)
+ if (!BytecodeGenerator::dumpsGeneratedCode())
+ m_programCodeBlock->discardBytecode();
+#endif
+ }
+#endif
-void EvalExecutable::generateJITCode(ExecState* exec, ScopeChainNode* scopeChainNode)
-{
+#if ENABLE(JIT)
#if ENABLE(INTERPRETER)
- ASSERT(scopeChainNode->globalData->canUseJIT());
+ if (!m_jitCodeForCall)
+ Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_programCodeBlock));
+ else
#endif
- CodeBlock* codeBlock = &bytecode(exec, scopeChainNode);
- m_jitCode = JIT::compile(scopeChainNode->globalData, codeBlock);
-
-#if !ENABLE(OPCODE_SAMPLING)
- if (!BytecodeGenerator::dumpsGeneratedCode())
- codeBlock->discardBytecode();
+ Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_programCodeBlock) + m_jitCodeForCall.size());
+#else
+ Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_programCodeBlock));
#endif
+
+ return 0;
}
-void ProgramExecutable::generateJITCode(ExecState* exec, ScopeChainNode* scopeChainNode)
+void ProgramExecutable::unlinkCalls()
{
-#if ENABLE(INTERPRETER)
- ASSERT(scopeChainNode->globalData->canUseJIT());
-#endif
- CodeBlock* codeBlock = &bytecode(exec, scopeChainNode);
- m_jitCode = JIT::compile(scopeChainNode->globalData, codeBlock);
-
-#if !ENABLE(OPCODE_SAMPLING)
- if (!BytecodeGenerator::dumpsGeneratedCode())
- codeBlock->discardBytecode();
+#if ENABLE(JIT)
+ if (!m_jitCodeForCall)
+ return;
+ ASSERT(m_programCodeBlock);
+ m_programCodeBlock->unlinkCalls();
#endif
}
-void FunctionExecutable::generateJITCode(ExecState* exec, ScopeChainNode* scopeChainNode)
+#if ENABLE(JIT)
+static bool tryDFGCompile(JSGlobalData* globalData, CodeBlock* codeBlock, JITCode& jitCode, MacroAssemblerCodePtr& jitCodeWithArityCheck)
{
-#if ENABLE(INTERPRETER)
- ASSERT(scopeChainNode->globalData->canUseJIT());
+#if ENABLE(DFG_JIT)
+#if ENABLE(DFG_JIT_RESTRICTIONS)
+ // FIXME: No flow control yet supported, don't bother scanning the bytecode if there are any jump targets.
+ // FIXME: temporarily disable property accesses until we fix regressions.
+ if (codeBlock->numberOfJumpTargets() || codeBlock->numberOfStructureStubInfos())
+ return false;
#endif
- CodeBlock* codeBlock = &bytecode(exec, scopeChainNode);
- m_jitCode = JIT::compile(scopeChainNode->globalData, codeBlock);
-#if !ENABLE(OPCODE_SAMPLING)
- if (!BytecodeGenerator::dumpsGeneratedCode())
- codeBlock->discardBytecode();
+ DFG::Graph dfg(codeBlock->m_numParameters, codeBlock->m_numVars);
+ if (!parse(dfg, globalData, codeBlock))
+ return false;
+
+ DFG::JITCompiler dataFlowJIT(globalData, dfg, codeBlock);
+ dataFlowJIT.compileFunction(jitCode, jitCodeWithArityCheck);
+ return true;
+#else
+ UNUSED_PARAM(globalData);
+ UNUSED_PARAM(codeBlock);
+ UNUSED_PARAM(jitCode);
+ UNUSED_PARAM(jitCodeWithArityCheck);
+ return false;
#endif
}
-
#endif
-void FunctionExecutable::markAggregate(MarkStack& markStack)
+void ProgramExecutable::visitChildren(SlotVisitor& visitor)
{
- if (m_codeBlock)
- m_codeBlock->markAggregate(markStack);
+ ASSERT_GC_OBJECT_INHERITS(this, &s_info);
+ COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
+ ASSERT(structure()->typeInfo().overridesVisitChildren());
+ ScriptExecutable::visitChildren(visitor);
+ if (m_programCodeBlock)
+ m_programCodeBlock->visitAggregate(visitor);
}
-ExceptionInfo* FunctionExecutable::reparseExceptionInfo(JSGlobalData* globalData, ScopeChainNode* scopeChainNode, CodeBlock* codeBlock)
+JSObject* FunctionExecutable::compileForCallInternal(ExecState* exec, ScopeChainNode* scopeChainNode)
{
- RefPtr<FunctionBodyNode> newFunctionBody = globalData->parser->parse<FunctionBodyNode>(globalData, 0, 0, m_source);
+ JSObject* exception = 0;
+ JSGlobalData* globalData = scopeChainNode->globalData;
+ RefPtr<FunctionBodyNode> body = globalData->parser->parse<FunctionBodyNode>(exec->lexicalGlobalObject(), 0, 0, m_source, m_parameters.get(), isStrictMode() ? JSParseStrict : JSParseNormal, &exception);
+ if (!body) {
+ ASSERT(exception);
+ return exception;
+ }
if (m_forceUsesArguments)
- newFunctionBody->setUsesArguments();
- newFunctionBody->finishParsing(m_parameters, m_name);
+ body->setUsesArguments();
+ body->finishParsing(m_parameters, m_name);
+ recordParse(body->features(), body->hasCapturedVariables(), body->lineNo(), body->lastLine());
- ScopeChain scopeChain(scopeChainNode);
- JSGlobalObject* globalObject = scopeChain.globalObject();
+ JSGlobalObject* globalObject = scopeChainNode->globalObject.get();
- OwnPtr<CodeBlock> newCodeBlock(new FunctionCodeBlock(this, FunctionCode, source().provider(), source().startOffset()));
- globalData->functionCodeBlockBeingReparsed = newCodeBlock.get();
+ ASSERT(!m_codeBlockForCall);
+ m_codeBlockForCall = adoptPtr(new FunctionCodeBlock(this, FunctionCode, globalObject, source().provider(), source().startOffset(), false));
+ OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(body.get(), scopeChainNode, m_codeBlockForCall->symbolTable(), m_codeBlockForCall.get())));
+ if ((exception = generator->generate())) {
+ m_codeBlockForCall.clear();
+ body->destroyData();
+ return exception;
+ }
- OwnPtr<BytecodeGenerator> generator(new BytecodeGenerator(newFunctionBody.get(), globalObject->debugger(), scopeChain, newCodeBlock->symbolTable(), newCodeBlock.get()));
- generator->setRegeneratingForExceptionInfo(static_cast<FunctionCodeBlock*>(codeBlock));
- generator->generate();
+ m_numParametersForCall = m_codeBlockForCall->m_numParameters;
+ ASSERT(m_numParametersForCall);
+ m_numCapturedVariables = m_codeBlockForCall->m_numCapturedVars;
+ m_symbolTable = m_codeBlockForCall->sharedSymbolTable();
- ASSERT(newCodeBlock->instructionCount() == codeBlock->instructionCount());
+ body->destroyData();
#if ENABLE(JIT)
-#if ENABLE(INTERPRETER)
- if (globalData->canUseJIT())
+ if (exec->globalData().canUseJIT()) {
+ bool dfgCompiled = tryDFGCompile(&exec->globalData(), m_codeBlockForCall.get(), m_jitCodeForCall, m_jitCodeForCallWithArityCheck);
+ if (!dfgCompiled)
+ m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, m_codeBlockForCall.get(), &m_jitCodeForCallWithArityCheck);
+
+#if !ENABLE(OPCODE_SAMPLING)
+ if (!BytecodeGenerator::dumpsGeneratedCode())
+ m_codeBlockForCall->discardBytecode();
#endif
- {
- JITCode newJITCode = JIT::compile(globalData, newCodeBlock.get(), generatedJITCode().start());
- ASSERT(newJITCode.size() == generatedJITCode().size());
}
#endif
- globalData->functionCodeBlockBeingReparsed = 0;
+#if ENABLE(JIT)
+#if ENABLE(INTERPRETER)
+ if (!m_jitCodeForCall)
+ Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForCall));
+ else
+#endif
+ Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForCall) + m_jitCodeForCall.size());
+#else
+ Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForCall));
+#endif
- return newCodeBlock->extractExceptionInfo();
+ return 0;
}
-ExceptionInfo* EvalExecutable::reparseExceptionInfo(JSGlobalData* globalData, ScopeChainNode* scopeChainNode, CodeBlock* codeBlock)
+JSObject* FunctionExecutable::compileForConstructInternal(ExecState* exec, ScopeChainNode* scopeChainNode)
{
- RefPtr<EvalNode> newEvalBody = globalData->parser->parse<EvalNode>(globalData, 0, 0, m_source);
+ JSObject* exception = 0;
+ JSGlobalData* globalData = scopeChainNode->globalData;
+ RefPtr<FunctionBodyNode> body = globalData->parser->parse<FunctionBodyNode>(exec->lexicalGlobalObject(), 0, 0, m_source, m_parameters.get(), isStrictMode() ? JSParseStrict : JSParseNormal, &exception);
+ if (!body) {
+ ASSERT(exception);
+ return exception;
+ }
+ if (m_forceUsesArguments)
+ body->setUsesArguments();
+ body->finishParsing(m_parameters, m_name);
+ recordParse(body->features(), body->hasCapturedVariables(), body->lineNo(), body->lastLine());
- ScopeChain scopeChain(scopeChainNode);
- JSGlobalObject* globalObject = scopeChain.globalObject();
+ JSGlobalObject* globalObject = scopeChainNode->globalObject.get();
- OwnPtr<EvalCodeBlock> newCodeBlock(new EvalCodeBlock(this, globalObject, source().provider(), scopeChain.localDepth()));
+ ASSERT(!m_codeBlockForConstruct);
+ m_codeBlockForConstruct = adoptPtr(new FunctionCodeBlock(this, FunctionCode, globalObject, source().provider(), source().startOffset(), true));
+ OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(body.get(), scopeChainNode, m_codeBlockForConstruct->symbolTable(), m_codeBlockForConstruct.get())));
+ if ((exception = generator->generate())) {
+ m_codeBlockForConstruct.clear();
+ body->destroyData();
+ return exception;
+ }
- OwnPtr<BytecodeGenerator> generator(new BytecodeGenerator(newEvalBody.get(), globalObject->debugger(), scopeChain, newCodeBlock->symbolTable(), newCodeBlock.get()));
- generator->setRegeneratingForExceptionInfo(static_cast<EvalCodeBlock*>(codeBlock));
- generator->generate();
+ m_numParametersForConstruct = m_codeBlockForConstruct->m_numParameters;
+ ASSERT(m_numParametersForConstruct);
+ m_numCapturedVariables = m_codeBlockForConstruct->m_numCapturedVars;
+ m_symbolTable = m_codeBlockForConstruct->sharedSymbolTable();
- ASSERT(newCodeBlock->instructionCount() == codeBlock->instructionCount());
+ body->destroyData();
#if ENABLE(JIT)
-#if ENABLE(INTERPRETER)
- if (globalData->canUseJIT())
+ if (exec->globalData().canUseJIT()) {
+ m_jitCodeForConstruct = JIT::compile(scopeChainNode->globalData, m_codeBlockForConstruct.get(), &m_jitCodeForConstructWithArityCheck);
+#if !ENABLE(OPCODE_SAMPLING)
+ if (!BytecodeGenerator::dumpsGeneratedCode())
+ m_codeBlockForConstruct->discardBytecode();
#endif
- {
- JITCode newJITCode = JIT::compile(globalData, newCodeBlock.get(), generatedJITCode().start());
- ASSERT(newJITCode.size() == generatedJITCode().size());
}
#endif
- return newCodeBlock->extractExceptionInfo();
+#if ENABLE(JIT)
+#if ENABLE(INTERPRETER)
+ if (!m_jitCodeForConstruct)
+ Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForConstruct));
+ else
+#endif
+ Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForConstruct) + m_jitCodeForConstruct.size());
+#else
+ Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForConstruct));
+#endif
+
+ return 0;
+}
+
+void FunctionExecutable::visitChildren(SlotVisitor& visitor)
+{
+ ASSERT_GC_OBJECT_INHERITS(this, &s_info);
+ COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
+ ASSERT(structure()->typeInfo().overridesVisitChildren());
+ ScriptExecutable::visitChildren(visitor);
+ if (m_codeBlockForCall)
+ m_codeBlockForCall->visitAggregate(visitor);
+ if (m_codeBlockForConstruct)
+ m_codeBlockForConstruct->visitAggregate(visitor);
}
-void FunctionExecutable::recompile()
+void FunctionExecutable::discardCode()
{
- delete m_codeBlock;
- m_codeBlock = 0;
- m_numParameters = NUM_PARAMETERS_NOT_COMPILED;
#if ENABLE(JIT)
- m_jitCode = JITCode();
+ // These first two checks are to handle the rare case where
+ // we are trying to evict code for a function during its
+ // codegen.
+ if (!m_jitCodeForCall && m_codeBlockForCall)
+ return;
+ if (!m_jitCodeForConstruct && m_codeBlockForConstruct)
+ return;
+ m_jitCodeForCall = JITCode();
+ m_jitCodeForConstruct = JITCode();
+ m_jitCodeForCallWithArityCheck = MacroAssemblerCodePtr();
+ m_jitCodeForConstructWithArityCheck = MacroAssemblerCodePtr();
#endif
+ if (m_codeBlockForCall)
+ m_codeBlockForCall->clearEvalCache();
+ m_codeBlockForCall.clear();
+ if (m_codeBlockForConstruct)
+ m_codeBlockForConstruct->clearEvalCache();
+ m_codeBlockForConstruct.clear();
+ m_numParametersForCall = NUM_PARAMETERS_NOT_COMPILED;
+ m_numParametersForConstruct = NUM_PARAMETERS_NOT_COMPILED;
+
}
-PassRefPtr<FunctionExecutable> FunctionExecutable::fromGlobalCode(const Identifier& functionName, ExecState* exec, Debugger* debugger, const SourceCode& source, int* errLine, UString* errMsg)
+void FunctionExecutable::unlinkCalls()
{
- RefPtr<ProgramNode> program = exec->globalData().parser->parse<ProgramNode>(&exec->globalData(), debugger, exec, source, errLine, errMsg);
- if (!program)
+#if ENABLE(JIT)
+ if (!!m_jitCodeForCall) {
+ ASSERT(m_codeBlockForCall);
+ m_codeBlockForCall->unlinkCalls();
+ }
+ if (!!m_jitCodeForConstruct) {
+ ASSERT(m_codeBlockForConstruct);
+ m_codeBlockForConstruct->unlinkCalls();
+ }
+#endif
+}
+
+FunctionExecutable* FunctionExecutable::fromGlobalCode(const Identifier& functionName, ExecState* exec, Debugger* debugger, const SourceCode& source, JSObject** exception)
+{
+ JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
+ RefPtr<ProgramNode> program = exec->globalData().parser->parse<ProgramNode>(lexicalGlobalObject, debugger, exec, source, 0, JSParseNormal, exception);
+ if (!program) {
+ ASSERT(*exception);
return 0;
+ }
+ // Uses of this function that would not result in a single function expression are invalid.
StatementNode* exprStatement = program->singleStatement();
ASSERT(exprStatement);
ASSERT(exprStatement->isExprStatement());
- if (!exprStatement || !exprStatement->isExprStatement())
- return 0;
-
ExpressionNode* funcExpr = static_cast<ExprStatementNode*>(exprStatement)->expr();
ASSERT(funcExpr);
ASSERT(funcExpr->isFuncExprNode());
- if (!funcExpr || !funcExpr->isFuncExprNode())
- return 0;
-
FunctionBodyNode* body = static_cast<FuncExprNode*>(funcExpr)->body();
ASSERT(body);
- return FunctionExecutable::create(&exec->globalData(), functionName, body->source(), body->usesArguments(), body->parameters(), body->lineNo(), body->lastLine());
+
+ return FunctionExecutable::create(&exec->globalData(), functionName, body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine());
}
UString FunctionExecutable::paramString() const
{
FunctionParameters& parameters = *m_parameters;
- StringBuilder builder;
+ UStringBuilder builder;
for (size_t pos = 0; pos < parameters.size(); ++pos) {
if (!builder.isEmpty())
builder.append(", ");
builder.append(parameters[pos].ustring());
}
- return builder.build();
+ return builder.toUString();
}
-};
-
-
+}
/*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2009, 2010 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
#ifndef Executable_h
#define Executable_h
+#include "CallData.h"
#include "JSFunction.h"
#include "Interpreter.h"
#include "Nodes.h"
#include "SamplingTool.h"
+#include <wtf/PassOwnPtr.h>
namespace JSC {
class CodeBlock;
class Debugger;
class EvalCodeBlock;
+ class FunctionCodeBlock;
class ProgramCodeBlock;
class ScopeChainNode;
struct ExceptionInfo;
- class ExecutableBase : public RefCounted<ExecutableBase> {
+ class ExecutableBase : public JSCell {
friend class JIT;
protected:
static const int NUM_PARAMETERS_NOT_COMPILED = -1;
public:
- ExecutableBase(int numParameters)
- : m_numParameters(numParameters)
+ ExecutableBase(JSGlobalData& globalData, Structure* structure, int numParameters)
+ : JSCell(globalData, structure)
+ , m_numParametersForCall(numParameters)
+ , m_numParametersForConstruct(numParameters)
{
+#if ENABLE(JIT)
+ Weak<ExecutableBase> finalizer(globalData, this, executableFinalizer());
+ finalizer.leakHandle();
+#endif
}
- virtual ~ExecutableBase() {}
+ bool isHostFunction() const
+ {
+ ASSERT((m_numParametersForCall == NUM_PARAMETERS_IS_HOST) == (m_numParametersForConstruct == NUM_PARAMETERS_IS_HOST));
+ return m_numParametersForCall == NUM_PARAMETERS_IS_HOST;
+ }
- bool isHostFunction() const { return m_numParameters == NUM_PARAMETERS_IS_HOST; }
+ static Structure* createStructure(JSGlobalData& globalData, JSValue proto) { return Structure::create(globalData, proto, TypeInfo(CompoundType, StructureFlags), AnonymousSlotCount, &s_info); }
+
+ static const ClassInfo s_info;
protected:
- int m_numParameters;
+ static const unsigned StructureFlags = 0;
+ int m_numParametersForCall;
+ int m_numParametersForConstruct;
#if ENABLE(JIT)
public:
- JITCode& generatedJITCode()
+ JITCode& generatedJITCodeForCall()
{
- ASSERT(m_jitCode);
- return m_jitCode;
+ ASSERT(m_jitCodeForCall);
+ return m_jitCodeForCall;
}
- ExecutablePool* getExecutablePool()
+ JITCode& generatedJITCodeForConstruct()
{
- return m_jitCode.getExecutablePool();
+ ASSERT(m_jitCodeForConstruct);
+ return m_jitCodeForConstruct;
+ }
+
+ void clearExecutableCode()
+ {
+ m_jitCodeForCall.clear();
+ m_jitCodeForConstruct.clear();
}
protected:
- JITCode m_jitCode;
+ JITCode m_jitCodeForCall;
+ JITCode m_jitCodeForConstruct;
+ MacroAssemblerCodePtr m_jitCodeForCallWithArityCheck;
+ MacroAssemblerCodePtr m_jitCodeForConstructWithArityCheck;
+
+ private:
+ static WeakHandleOwner* executableFinalizer();
#endif
};
-#if ENABLE(JIT)
class NativeExecutable : public ExecutableBase {
+ friend class JIT;
public:
- NativeExecutable(JITCode thunk)
- : ExecutableBase(NUM_PARAMETERS_IS_HOST)
+#if ENABLE(JIT)
+ static NativeExecutable* create(JSGlobalData& globalData, MacroAssemblerCodePtr callThunk, NativeFunction function, MacroAssemblerCodePtr constructThunk, NativeFunction constructor)
{
- m_jitCode = thunk;
+ if (!callThunk)
+ return new (&globalData) NativeExecutable(globalData, JITCode(), function, JITCode(), constructor);
+ return new (&globalData) NativeExecutable(globalData, JITCode::HostFunction(callThunk), function, JITCode::HostFunction(constructThunk), constructor);
}
+#else
+ static NativeExecutable* create(JSGlobalData& globalData, NativeFunction function, NativeFunction constructor)
+ {
+ return new (&globalData) NativeExecutable(globalData, function, constructor);
+ }
+#endif
~NativeExecutable();
- };
-#endif
- class VPtrHackExecutable : public ExecutableBase {
- public:
- VPtrHackExecutable()
- : ExecutableBase(NUM_PARAMETERS_IS_HOST)
+ NativeFunction function() { return m_function; }
+
+ static Structure* createStructure(JSGlobalData& globalData, JSValue proto) { return Structure::create(globalData, proto, TypeInfo(LeafType, StructureFlags), AnonymousSlotCount, &s_info); }
+
+ static const ClassInfo s_info;
+
+ private:
+#if ENABLE(JIT)
+ NativeExecutable(JSGlobalData& globalData, JITCode callThunk, NativeFunction function, JITCode constructThunk, NativeFunction constructor)
+ : ExecutableBase(globalData, globalData.nativeExecutableStructure.get(), NUM_PARAMETERS_IS_HOST)
+ , m_function(function)
+ , m_constructor(constructor)
+ {
+ m_jitCodeForCall = callThunk;
+ m_jitCodeForConstruct = constructThunk;
+ m_jitCodeForCallWithArityCheck = callThunk.addressForCall();
+ m_jitCodeForConstructWithArityCheck = constructThunk.addressForCall();
+ }
+#else
+ NativeExecutable(JSGlobalData& globalData, NativeFunction function, NativeFunction constructor)
+ : ExecutableBase(globalData, globalData.nativeExecutableStructure.get(), NUM_PARAMETERS_IS_HOST)
+ , m_function(function)
+ , m_constructor(constructor)
{
}
+#endif
- ~VPtrHackExecutable();
+ NativeFunction m_function;
+ // Probably should be a NativeConstructor, but this will currently require rewriting the JIT
+ // trampoline. It may be easier to make NativeFunction be passed 'this' as a part of the ArgList.
+ NativeFunction m_constructor;
};
class ScriptExecutable : public ExecutableBase {
public:
- ScriptExecutable(JSGlobalData* globalData, const SourceCode& source)
- : ExecutableBase(NUM_PARAMETERS_NOT_COMPILED)
+ ScriptExecutable(Structure* structure, JSGlobalData* globalData, const SourceCode& source, bool isInStrictContext)
+ : ExecutableBase(*globalData, structure, NUM_PARAMETERS_NOT_COMPILED)
, m_source(source)
- , m_features(0)
+ , m_features(isInStrictContext ? StrictModeFeature : 0)
{
#if ENABLE(CODEBLOCK_SAMPLING)
+ relaxAdoptionRequirement();
if (SamplingTool* sampler = globalData->interpreter->sampler())
sampler->notifyOfScope(this);
#else
#endif
}
- ScriptExecutable(ExecState* exec, const SourceCode& source)
- : ExecutableBase(NUM_PARAMETERS_NOT_COMPILED)
+ ScriptExecutable(Structure* structure, ExecState* exec, const SourceCode& source, bool isInStrictContext)
+ : ExecutableBase(exec->globalData(), structure, NUM_PARAMETERS_NOT_COMPILED)
, m_source(source)
- , m_features(0)
+ , m_features(isInStrictContext ? StrictModeFeature : 0)
{
#if ENABLE(CODEBLOCK_SAMPLING)
+ relaxAdoptionRequirement();
if (SamplingTool* sampler = exec->globalData().interpreter->sampler())
sampler->notifyOfScope(this);
#else
bool usesEval() const { return m_features & EvalFeature; }
bool usesArguments() const { return m_features & ArgumentsFeature; }
- bool needsActivation() const { return m_features & (EvalFeature | ClosureFeature | WithFeature | CatchFeature); }
-
- virtual ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*) = 0;
+ bool needsActivation() const { return m_hasCapturedVariables || m_features & (EvalFeature | WithFeature | CatchFeature); }
+ bool isStrictMode() const { return m_features & StrictModeFeature; }
+ virtual void unlinkCalls() = 0;
+
+ static const ClassInfo s_info;
protected:
- void recordParse(CodeFeatures features, int firstLine, int lastLine)
+ void recordParse(CodeFeatures features, bool hasCapturedVariables, int firstLine, int lastLine)
{
m_features = features;
+ m_hasCapturedVariables = hasCapturedVariables;
m_firstLine = firstLine;
m_lastLine = lastLine;
}
SourceCode m_source;
CodeFeatures m_features;
+ bool m_hasCapturedVariables;
int m_firstLine;
int m_lastLine;
};
~EvalExecutable();
- EvalCodeBlock& bytecode(ExecState* exec, ScopeChainNode* scopeChainNode)
+ JSObject* compile(ExecState* exec, ScopeChainNode* scopeChainNode)
{
- if (!m_evalCodeBlock) {
- JSObject* error = compile(exec, scopeChainNode);
- ASSERT_UNUSED(!error, error);
- }
- return *m_evalCodeBlock;
+ ASSERT(exec->globalData().dynamicGlobalObject);
+ JSObject* error = 0;
+ if (!m_evalCodeBlock)
+ error = compileInternal(exec, scopeChainNode);
+ ASSERT(!error == !!m_evalCodeBlock);
+ return error;
}
- JSObject* compile(ExecState*, ScopeChainNode*);
-
- ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*);
- static PassRefPtr<EvalExecutable> create(ExecState* exec, const SourceCode& source) { return adoptRef(new EvalExecutable(exec, source)); }
-
- private:
- EvalExecutable(ExecState* exec, const SourceCode& source)
- : ScriptExecutable(exec, source)
- , m_evalCodeBlock(0)
+ EvalCodeBlock& generatedBytecode()
{
+ ASSERT(m_evalCodeBlock);
+ return *m_evalCodeBlock;
}
- EvalCodeBlock* m_evalCodeBlock;
+
+ static EvalExecutable* create(ExecState* exec, const SourceCode& source, bool isInStrictContext) { return new (exec) EvalExecutable(exec, source, isInStrictContext); }
#if ENABLE(JIT)
- public:
- JITCode& jitCode(ExecState* exec, ScopeChainNode* scopeChainNode)
+ JITCode& generatedJITCode()
{
- if (!m_jitCode)
- generateJITCode(exec, scopeChainNode);
- return m_jitCode;
+ return generatedJITCodeForCall();
}
-
- private:
- void generateJITCode(ExecState*, ScopeChainNode*);
#endif
+ static Structure* createStructure(JSGlobalData& globalData, JSValue proto)
+ {
+ return Structure::create(globalData, proto, TypeInfo(CompoundType, StructureFlags), AnonymousSlotCount, &s_info);
+ }
+
+ static const ClassInfo s_info;
+ private:
+ static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags;
+ EvalExecutable(ExecState*, const SourceCode&, bool);
+
+ JSObject* compileInternal(ExecState*, ScopeChainNode*);
+ virtual void visitChildren(SlotVisitor&);
+ void unlinkCalls();
+
+ OwnPtr<EvalCodeBlock> m_evalCodeBlock;
};
class ProgramExecutable : public ScriptExecutable {
public:
- static PassRefPtr<ProgramExecutable> create(ExecState* exec, const SourceCode& source)
+ static ProgramExecutable* create(ExecState* exec, const SourceCode& source)
{
- return adoptRef(new ProgramExecutable(exec, source));
+ return new (exec) ProgramExecutable(exec, source);
}
~ProgramExecutable();
- ProgramCodeBlock& bytecode(ExecState* exec, ScopeChainNode* scopeChainNode)
+ JSObject* compile(ExecState* exec, ScopeChainNode* scopeChainNode)
+ {
+ ASSERT(exec->globalData().dynamicGlobalObject);
+ JSObject* error = 0;
+ if (!m_programCodeBlock)
+ error = compileInternal(exec, scopeChainNode);
+ ASSERT(!error == !!m_programCodeBlock);
+ return error;
+ }
+
+ ProgramCodeBlock& generatedBytecode()
{
- if (!m_programCodeBlock) {
- JSObject* error = compile(exec, scopeChainNode);
- ASSERT_UNUSED(!error, error);
- }
+ ASSERT(m_programCodeBlock);
return *m_programCodeBlock;
}
JSObject* checkSyntax(ExecState*);
- JSObject* compile(ExecState*, ScopeChainNode*);
-
- // CodeBlocks for program code are transient and therefore do not gain from from throwing out there exception information.
- ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*) { ASSERT_NOT_REACHED(); return 0; }
- private:
- ProgramExecutable(ExecState* exec, const SourceCode& source)
- : ScriptExecutable(exec, source)
- , m_programCodeBlock(0)
+#if ENABLE(JIT)
+ JITCode& generatedJITCode()
{
+ return generatedJITCodeForCall();
}
- ProgramCodeBlock* m_programCodeBlock;
-
-#if ENABLE(JIT)
- public:
- JITCode& jitCode(ExecState* exec, ScopeChainNode* scopeChainNode)
+#endif
+
+ static Structure* createStructure(JSGlobalData& globalData, JSValue proto)
{
- if (!m_jitCode)
- generateJITCode(exec, scopeChainNode);
- return m_jitCode;
+ return Structure::create(globalData, proto, TypeInfo(CompoundType, StructureFlags), AnonymousSlotCount, &s_info);
}
+
+ static const ClassInfo s_info;
private:
- void generateJITCode(ExecState*, ScopeChainNode*);
-#endif
+ static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags;
+ ProgramExecutable(ExecState*, const SourceCode&);
+
+ JSObject* compileInternal(ExecState*, ScopeChainNode*);
+ virtual void visitChildren(SlotVisitor&);
+ void unlinkCalls();
+
+ OwnPtr<ProgramCodeBlock> m_programCodeBlock;
};
class FunctionExecutable : public ScriptExecutable {
friend class JIT;
public:
- static PassRefPtr<FunctionExecutable> create(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine)
+ static FunctionExecutable* create(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool isInStrictContext, int firstLine, int lastLine)
{
- return adoptRef(new FunctionExecutable(exec, name, source, forceUsesArguments, parameters, firstLine, lastLine));
+ return new (exec) FunctionExecutable(exec, name, source, forceUsesArguments, parameters, isInStrictContext, firstLine, lastLine);
}
- static PassRefPtr<FunctionExecutable> create(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine)
+ static FunctionExecutable* create(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool isInStrictContext, int firstLine, int lastLine)
{
- return adoptRef(new FunctionExecutable(globalData, name, source, forceUsesArguments, parameters, firstLine, lastLine));
+ return new (globalData) FunctionExecutable(globalData, name, source, forceUsesArguments, parameters, isInStrictContext, firstLine, lastLine);
}
- ~FunctionExecutable();
-
JSFunction* make(ExecState* exec, ScopeChainNode* scopeChain)
{
return new (exec) JSFunction(exec, this, scopeChain);
}
-
- CodeBlock& bytecode(ExecState* exec, ScopeChainNode* scopeChainNode)
+
+ // Returns either call or construct bytecode. This can be appropriate
+ // for answering questions that that don't vary between call and construct --
+ // for example, argumentsRegister().
+ FunctionCodeBlock& generatedBytecode()
{
- ASSERT(scopeChainNode);
- if (!m_codeBlock)
- compile(exec, scopeChainNode);
- return *m_codeBlock;
+ if (m_codeBlockForCall)
+ return *m_codeBlockForCall;
+ ASSERT(m_codeBlockForConstruct);
+ return *m_codeBlockForConstruct;
}
- bool isGenerated() const
+ JSObject* compileForCall(ExecState* exec, ScopeChainNode* scopeChainNode)
{
- return m_codeBlock;
+ ASSERT(exec->globalData().dynamicGlobalObject);
+ JSObject* error = 0;
+ if (!m_codeBlockForCall)
+ error = compileForCallInternal(exec, scopeChainNode);
+ ASSERT(!error == !!m_codeBlockForCall);
+ return error;
}
- CodeBlock& generatedBytecode()
+ bool isGeneratedForCall() const
{
- ASSERT(m_codeBlock);
- return *m_codeBlock;
+ return m_codeBlockForCall;
}
- const Identifier& name() { return m_name; }
- size_t parameterCount() const { return m_parameters->size(); }
- unsigned variableCount() const { return m_numVariables; }
- UString paramString() const;
+ FunctionCodeBlock& generatedBytecodeForCall()
+ {
+ ASSERT(m_codeBlockForCall);
+ return *m_codeBlockForCall;
+ }
- void recompile();
- ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*);
- void markAggregate(MarkStack& markStack);
- static PassRefPtr<FunctionExecutable> fromGlobalCode(const Identifier&, ExecState*, Debugger*, const SourceCode&, int* errLine = 0, UString* errMsg = 0);
+ JSObject* compileForConstruct(ExecState* exec, ScopeChainNode* scopeChainNode)
+ {
+ ASSERT(exec->globalData().dynamicGlobalObject);
+ JSObject* error = 0;
+ if (!m_codeBlockForConstruct)
+ error = compileForConstructInternal(exec, scopeChainNode);
+ ASSERT(!error == !!m_codeBlockForConstruct);
+ return error;
+ }
- private:
- FunctionExecutable(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine)
- : ScriptExecutable(globalData, source)
- , m_numVariables(0)
- , m_forceUsesArguments(forceUsesArguments)
- , m_parameters(parameters)
- , m_codeBlock(0)
- , m_name(name)
+ bool isGeneratedForConstruct() const
{
- m_firstLine = firstLine;
- m_lastLine = lastLine;
+ return m_codeBlockForConstruct;
}
- FunctionExecutable(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine)
- : ScriptExecutable(exec, source)
- , m_numVariables(0)
- , m_forceUsesArguments(forceUsesArguments)
- , m_parameters(parameters)
- , m_codeBlock(0)
- , m_name(name)
+ FunctionCodeBlock& generatedBytecodeForConstruct()
{
- m_firstLine = firstLine;
- m_lastLine = lastLine;
+ ASSERT(m_codeBlockForConstruct);
+ return *m_codeBlockForConstruct;
}
- void compile(ExecState*, ScopeChainNode*);
+ const Identifier& name() { return m_name; }
+ size_t parameterCount() const { return m_parameters->size(); }
+ unsigned capturedVariableCount() const { return m_numCapturedVariables; }
+ UString paramString() const;
+ SharedSymbolTable* symbolTable() const { return m_symbolTable; }
+
+ void discardCode();
+ void visitChildren(SlotVisitor&);
+ static FunctionExecutable* fromGlobalCode(const Identifier&, ExecState*, Debugger*, const SourceCode&, JSObject** exception);
+ static Structure* createStructure(JSGlobalData& globalData, JSValue proto)
+ {
+ return Structure::create(globalData, proto, TypeInfo(CompoundType, StructureFlags), AnonymousSlotCount, &s_info);
+ }
+
+ static const ClassInfo s_info;
- unsigned m_numVariables : 31;
+ private:
+ FunctionExecutable(JSGlobalData*, const Identifier& name, const SourceCode&, bool forceUsesArguments, FunctionParameters*, bool, int firstLine, int lastLine);
+ FunctionExecutable(ExecState*, const Identifier& name, const SourceCode&, bool forceUsesArguments, FunctionParameters*, bool, int firstLine, int lastLine);
+
+ JSObject* compileForCallInternal(ExecState*, ScopeChainNode*);
+ JSObject* compileForConstructInternal(ExecState*, ScopeChainNode*);
+
+ static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags;
+ unsigned m_numCapturedVariables : 31;
bool m_forceUsesArguments : 1;
+ void unlinkCalls();
RefPtr<FunctionParameters> m_parameters;
- CodeBlock* m_codeBlock;
+ OwnPtr<FunctionCodeBlock> m_codeBlockForCall;
+ OwnPtr<FunctionCodeBlock> m_codeBlockForConstruct;
Identifier m_name;
+ SharedSymbolTable* m_symbolTable;
#if ENABLE(JIT)
public:
- JITCode& jitCode(ExecState* exec, ScopeChainNode* scopeChainNode)
+ MacroAssemblerCodePtr generatedJITCodeForCallWithArityCheck()
{
- if (!m_jitCode)
- generateJITCode(exec, scopeChainNode);
- return m_jitCode;
+ ASSERT(m_jitCodeForCall);
+ ASSERT(m_jitCodeForCallWithArityCheck);
+ return m_jitCodeForCallWithArityCheck;
}
- private:
- void generateJITCode(ExecState*, ScopeChainNode*);
+ MacroAssemblerCodePtr generatedJITCodeForConstructWithArityCheck()
+ {
+ ASSERT(m_jitCodeForConstruct);
+ ASSERT(m_jitCodeForConstructWithArityCheck);
+ return m_jitCodeForConstructWithArityCheck;
+ }
#endif
};
return m_executable->isHostFunction();
}
+ inline NativeFunction JSFunction::nativeFunction()
+ {
+ ASSERT(isHostFunction());
+ return static_cast<NativeExecutable*>(m_executable.get())->function();
+ }
}
#endif
#include "FunctionConstructor.h"
#include "Debugger.h"
+#include "ExceptionHelpers.h"
#include "FunctionPrototype.h"
#include "JSFunction.h"
#include "JSGlobalObject.h"
#include "Lexer.h"
#include "Nodes.h"
#include "Parser.h"
-#include "StringBuilder.h"
+#include "UStringBuilder.h"
+#include "UStringConcatenate.h"
namespace JSC {
ASSERT_CLASS_FITS_IN_CELL(FunctionConstructor);
-FunctionConstructor::FunctionConstructor(ExecState* exec, NonNullPassRefPtr<Structure> structure, FunctionPrototype* functionPrototype)
- : InternalFunction(&exec->globalData(), structure, Identifier(exec, functionPrototype->classInfo()->className))
+FunctionConstructor::FunctionConstructor(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, FunctionPrototype* functionPrototype)
+ : InternalFunction(&exec->globalData(), globalObject, structure, Identifier(exec, functionPrototype->classInfo()->className))
{
- putDirectWithoutTransition(exec->propertyNames().prototype, functionPrototype, DontEnum | DontDelete | ReadOnly);
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().prototype, functionPrototype, DontEnum | DontDelete | ReadOnly);
// Number of arguments for constructor
- putDirectWithoutTransition(exec->propertyNames().length, jsNumber(exec, 1), ReadOnly | DontDelete | DontEnum);
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(1), ReadOnly | DontDelete | DontEnum);
}
-static JSObject* constructWithFunctionConstructor(ExecState* exec, JSObject*, const ArgList& args)
+static EncodedJSValue JSC_HOST_CALL constructWithFunctionConstructor(ExecState* exec)
{
- return constructFunction(exec, args);
+ ArgList args(exec);
+ return JSValue::encode(constructFunction(exec, asInternalFunction(exec->callee())->globalObject(), args));
}
ConstructType FunctionConstructor::getConstructData(ConstructData& constructData)
return ConstructTypeHost;
}
-static JSValue JSC_HOST_CALL callFunctionConstructor(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+static EncodedJSValue JSC_HOST_CALL callFunctionConstructor(ExecState* exec)
{
- return constructFunction(exec, args);
+ ArgList args(exec);
+ return JSValue::encode(constructFunction(exec, asInternalFunction(exec->callee())->globalObject(), args));
}
// ECMA 15.3.1 The Function Constructor Called as a Function
}
// ECMA 15.3.2 The Function Constructor
-JSObject* constructFunction(ExecState* exec, const ArgList& args, const Identifier& functionName, const UString& sourceURL, int lineNumber)
+JSObject* constructFunction(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args, const Identifier& functionName, const UString& sourceURL, int lineNumber)
+{
+ if (!globalObject->isEvalEnabled())
+ return throwError(exec, createEvalError(exec, "Function constructor is disabled"));
+ return constructFunctionSkippingEvalEnabledCheck(exec, globalObject, args, functionName, sourceURL, lineNumber);
+}
+
+JSObject* constructFunctionSkippingEvalEnabledCheck(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args, const Identifier& functionName, const UString& sourceURL, int lineNumber)
{
// Functions need to have a space following the opening { due to for web compatibility
// see https://bugs.webkit.org/show_bug.cgi?id=24350
if (args.isEmpty())
program = "(function() { \n})";
else if (args.size() == 1)
- program = makeString("(function() { ", args.at(0).toString(exec), "\n})");
+ program = makeUString("(function() { ", args.at(0).toString(exec), "\n})");
else {
- StringBuilder builder;
+ UStringBuilder builder;
builder.append("(function(");
builder.append(args.at(0).toString(exec));
for (size_t i = 1; i < args.size() - 1; i++) {
builder.append(") { ");
builder.append(args.at(args.size() - 1).toString(exec));
builder.append("\n})");
- program = builder.build();
+ program = builder.toUString();
}
- int errLine;
- UString errMsg;
+ JSGlobalData& globalData = globalObject->globalData();
SourceCode source = makeSource(program, sourceURL, lineNumber);
- RefPtr<FunctionExecutable> function = FunctionExecutable::fromGlobalCode(functionName, exec, exec->dynamicGlobalObject()->debugger(), source, &errLine, &errMsg);
- if (!function)
- return throwError(exec, SyntaxError, errMsg, errLine, source.provider()->asID(), source.provider()->url());
+ JSObject* exception = 0;
+ FunctionExecutable* function = FunctionExecutable::fromGlobalCode(functionName, exec, exec->dynamicGlobalObject()->debugger(), source, &exception);
+ if (!function) {
+ ASSERT(exception);
+ return throwError(exec, exception);
+ }
- JSGlobalObject* globalObject = exec->lexicalGlobalObject();
- ScopeChain scopeChain(globalObject, globalObject->globalData(), globalObject, exec->globalThisValue());
- return new (exec) JSFunction(exec, function, scopeChain.node());
+ ScopeChainNode* scopeChain = new (exec) ScopeChainNode(0, globalObject, &globalData, globalObject, exec->globalThisValue());
+ return new (exec) JSFunction(exec, function, scopeChain);
}
// ECMA 15.3.2 The Function Constructor
-JSObject* constructFunction(ExecState* exec, const ArgList& args)
+JSObject* constructFunction(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args)
{
- return constructFunction(exec, args, Identifier(exec, "anonymous"), UString(), 1);
+ return constructFunction(exec, globalObject, args, Identifier(exec, "anonymous"), UString(), 1);
}
} // namespace JSC
class FunctionConstructor : public InternalFunction {
public:
- FunctionConstructor(ExecState*, NonNullPassRefPtr<Structure>, FunctionPrototype*);
+ FunctionConstructor(ExecState*, JSGlobalObject*, Structure*, FunctionPrototype*);
private:
virtual ConstructType getConstructData(ConstructData&);
virtual CallType getCallData(CallData&);
};
- JSObject* constructFunction(ExecState*, const ArgList&, const Identifier& functionName, const UString& sourceURL, int lineNumber);
- JSObject* constructFunction(ExecState*, const ArgList&);
+ JSObject* constructFunction(ExecState*, JSGlobalObject*, const ArgList&, const Identifier& functionName, const UString& sourceURL, int lineNumber);
+ JSObject* constructFunction(ExecState*, JSGlobalObject*, const ArgList&);
+
+ JSObject* constructFunctionSkippingEvalEnabledCheck(ExecState*, JSGlobalObject*, const ArgList&, const Identifier&, const UString&, int lineNumber);
} // namespace JSC
#include "JSStringBuilder.h"
#include "Interpreter.h"
#include "Lexer.h"
-#include "PrototypeFunction.h"
namespace JSC {
ASSERT_CLASS_FITS_IN_CELL(FunctionPrototype);
-static JSValue JSC_HOST_CALL functionProtoFuncToString(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL functionProtoFuncApply(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL functionProtoFuncCall(ExecState*, JSObject*, JSValue, const ArgList&);
+static EncodedJSValue JSC_HOST_CALL functionProtoFuncToString(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionProtoFuncApply(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionProtoFuncCall(ExecState*);
-FunctionPrototype::FunctionPrototype(ExecState* exec, NonNullPassRefPtr<Structure> structure)
- : InternalFunction(&exec->globalData(), structure, exec->propertyNames().nullIdentifier)
+FunctionPrototype::FunctionPrototype(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
+ : InternalFunction(&exec->globalData(), globalObject, structure, exec->propertyNames().nullIdentifier)
{
- putDirectWithoutTransition(exec->propertyNames().length, jsNumber(exec, 0), DontDelete | ReadOnly | DontEnum);
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(0), DontDelete | ReadOnly | DontEnum);
}
-void FunctionPrototype::addFunctionProperties(ExecState* exec, Structure* prototypeFunctionStructure, NativeFunctionWrapper** callFunction, NativeFunctionWrapper** applyFunction)
+void FunctionPrototype::addFunctionProperties(ExecState* exec, JSGlobalObject* globalObject, Structure* functionStructure, JSFunction** callFunction, JSFunction** applyFunction)
{
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 0, exec->propertyNames().toString, functionProtoFuncToString), DontEnum);
- *applyFunction = new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 2, exec->propertyNames().apply, functionProtoFuncApply);
+ putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 0, exec->propertyNames().toString, functionProtoFuncToString), DontEnum);
+ *applyFunction = new (exec) JSFunction(exec, globalObject, functionStructure, 2, exec->propertyNames().apply, functionProtoFuncApply);
putDirectFunctionWithoutTransition(exec, *applyFunction, DontEnum);
- *callFunction = new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().call, functionProtoFuncCall);
+ *callFunction = new (exec) JSFunction(exec, globalObject, functionStructure, 1, exec->propertyNames().call, functionProtoFuncCall);
putDirectFunctionWithoutTransition(exec, *callFunction, DontEnum);
}
-static JSValue JSC_HOST_CALL callFunctionPrototype(ExecState*, JSObject*, JSValue, const ArgList&)
+static EncodedJSValue JSC_HOST_CALL callFunctionPrototype(ExecState*)
{
- return jsUndefined();
+ return JSValue::encode(jsUndefined());
}
// ECMA 15.3.4
static inline void insertSemicolonIfNeeded(UString& functionBody)
{
ASSERT(functionBody[0] == '{');
- ASSERT(functionBody[functionBody.size() - 1] == '}');
+ ASSERT(functionBody[functionBody.length() - 1] == '}');
- for (size_t i = functionBody.size() - 2; i > 0; --i) {
+ for (size_t i = functionBody.length() - 2; i > 0; --i) {
UChar ch = functionBody[i];
if (!Lexer::isWhiteSpace(ch) && !Lexer::isLineTerminator(ch)) {
if (ch != ';' && ch != '}')
- functionBody = makeString(functionBody.substr(0, i + 1), ";", functionBody.substr(i + 1, functionBody.size() - (i + 1)));
+ functionBody = makeUString(functionBody.substringSharingImpl(0, i + 1), ";", functionBody.substringSharingImpl(i + 1, functionBody.length() - (i + 1)));
return;
}
}
}
-JSValue JSC_HOST_CALL functionProtoFuncToString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL functionProtoFuncToString(ExecState* exec)
{
- if (thisValue.inherits(&JSFunction::info)) {
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.inherits(&JSFunction::s_info)) {
JSFunction* function = asFunction(thisValue);
- if (!function->isHostFunction()) {
- FunctionExecutable* executable = function->jsExecutable();
- UString sourceString = executable->source().toString();
- insertSemicolonIfNeeded(sourceString);
- return jsMakeNontrivialString(exec, "function ", function->name(exec), "(", executable->paramString(), ") ", sourceString);
- }
+ if (function->isHostFunction())
+ return JSValue::encode(jsMakeNontrivialString(exec, "function ", function->name(exec), "() {\n [native code]\n}"));
+ FunctionExecutable* executable = function->jsExecutable();
+ UString sourceString = executable->source().toString();
+ insertSemicolonIfNeeded(sourceString);
+ return JSValue::encode(jsMakeNontrivialString(exec, "function ", function->name(exec), "(", executable->paramString(), ") ", sourceString));
}
- if (thisValue.inherits(&InternalFunction::info)) {
+ if (thisValue.inherits(&InternalFunction::s_info)) {
InternalFunction* function = asInternalFunction(thisValue);
- return jsMakeNontrivialString(exec, "function ", function->name(exec), "() {\n [native code]\n}");
+ return JSValue::encode(jsMakeNontrivialString(exec, "function ", function->name(exec), "() {\n [native code]\n}"));
}
- return throwError(exec, TypeError);
+ return throwVMTypeError(exec);
}
-JSValue JSC_HOST_CALL functionProtoFuncApply(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL functionProtoFuncApply(ExecState* exec)
{
+ JSValue thisValue = exec->hostThisValue();
CallData callData;
- CallType callType = thisValue.getCallData(callData);
+ CallType callType = getCallData(thisValue, callData);
if (callType == CallTypeNone)
- return throwError(exec, TypeError);
+ return throwVMTypeError(exec);
- JSValue array = args.at(1);
+ JSValue array = exec->argument(1);
MarkedArgumentBuffer applyArgs;
if (!array.isUndefinedOrNull()) {
if (!array.isObject())
- return throwError(exec, TypeError);
- if (asObject(array)->classInfo() == &Arguments::info)
+ return throwVMTypeError(exec);
+ if (asObject(array)->classInfo() == &Arguments::s_info)
asArguments(array)->fillArgList(exec, applyArgs);
else if (isJSArray(&exec->globalData(), array))
asArray(array)->fillArgList(exec, applyArgs);
- else if (asObject(array)->inherits(&JSArray::info)) {
+ else if (asObject(array)->inherits(&JSArray::s_info)) {
unsigned length = asArray(array)->get(exec, exec->propertyNames().length).toUInt32(exec);
for (unsigned i = 0; i < length; ++i)
applyArgs.append(asArray(array)->get(exec, i));
} else
- return throwError(exec, TypeError);
+ return throwVMTypeError(exec);
}
- return call(exec, thisValue, callType, callData, args.at(0), applyArgs);
+ return JSValue::encode(call(exec, thisValue, callType, callData, exec->argument(0), applyArgs));
}
-JSValue JSC_HOST_CALL functionProtoFuncCall(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL functionProtoFuncCall(ExecState* exec)
{
+ JSValue thisValue = exec->hostThisValue();
CallData callData;
- CallType callType = thisValue.getCallData(callData);
+ CallType callType = getCallData(thisValue, callData);
if (callType == CallTypeNone)
- return throwError(exec, TypeError);
+ return throwVMTypeError(exec);
+ ArgList args(exec);
ArgList callArgs;
args.getSlice(1, callArgs);
- return call(exec, thisValue, callType, callData, args.at(0), callArgs);
+ return JSValue::encode(call(exec, thisValue, callType, callData, exec->argument(0), callArgs));
}
} // namespace JSC
namespace JSC {
- class PrototypeFunction;
-
class FunctionPrototype : public InternalFunction {
public:
- FunctionPrototype(ExecState*, NonNullPassRefPtr<Structure>);
- void addFunctionProperties(ExecState*, Structure* prototypeFunctionStructure, NativeFunctionWrapper** callFunction, NativeFunctionWrapper** applyFunction);
+ FunctionPrototype(ExecState*, JSGlobalObject*, Structure*);
+ void addFunctionProperties(ExecState*, JSGlobalObject*, Structure* functionStructure, JSFunction** callFunction, JSFunction** applyFunction);
- static PassRefPtr<Structure> createStructure(JSValue proto)
+ static Structure* createStructure(JSGlobalData& globalData, JSValue proto)
{
- return Structure::create(proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
+ return Structure::create(globalData, proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
}
private:
--- /dev/null
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "GCActivityCallback.h"
+
+namespace JSC {
+
+struct DefaultGCActivityCallbackPlatformData {
+};
+
+DefaultGCActivityCallback::DefaultGCActivityCallback(Heap*)
+{
+}
+
+DefaultGCActivityCallback::~DefaultGCActivityCallback()
+{
+}
+
+void DefaultGCActivityCallback::operator()()
+{
+}
+
+void DefaultGCActivityCallback::synchronize()
+{
+}
+
+}
+
--- /dev/null
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef GCActivityCallback_h
+#define GCActivityCallback_h
+
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+
+#if USE(CF)
+#include <CoreFoundation/CoreFoundation.h>
+#endif
+
+namespace JSC {
+
+class Heap;
+
+class GCActivityCallback {
+public:
+ virtual ~GCActivityCallback() {}
+ virtual void operator()() {}
+ virtual void synchronize() {}
+
+protected:
+ GCActivityCallback() {}
+};
+
+struct DefaultGCActivityCallbackPlatformData;
+
+class DefaultGCActivityCallback : public GCActivityCallback {
+public:
+ static PassOwnPtr<DefaultGCActivityCallback> create(Heap*);
+
+ DefaultGCActivityCallback(Heap*);
+ ~DefaultGCActivityCallback();
+
+ void operator()();
+ void synchronize();
+
+#if USE(CF)
+protected:
+ DefaultGCActivityCallback(Heap*, CFRunLoopRef);
+ void commonConstructor(Heap*, CFRunLoopRef);
+#endif
+
+private:
+ OwnPtr<DefaultGCActivityCallbackPlatformData> d;
+};
+
+inline PassOwnPtr<DefaultGCActivityCallback> DefaultGCActivityCallback::create(Heap* heap)
+{
+ return adoptPtr(new DefaultGCActivityCallback(heap));
+}
+
+}
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "GCActivityCallback.h"
+
+#include "APIShims.h"
+#include "Heap.h"
+#include "JSGlobalData.h"
+#include "JSLock.h"
+#include "JSObject.h"
+#include "ScopeChain.h"
+#include <wtf/RetainPtr.h>
+#include <wtf/WTFThreadData.h>
+
+#if !USE(CF)
+#error "This file should only be used on CF platforms."
+#endif
+
+namespace JSC {
+
+struct DefaultGCActivityCallbackPlatformData {
+ static void trigger(CFRunLoopTimerRef, void *info);
+
+ RetainPtr<CFRunLoopTimerRef> timer;
+ RetainPtr<CFRunLoopRef> runLoop;
+ CFRunLoopTimerContext context;
+};
+
+const CFTimeInterval decade = 60 * 60 * 24 * 365 * 10;
+const CFTimeInterval triggerInterval = 2; // seconds
+
+void DefaultGCActivityCallbackPlatformData::trigger(CFRunLoopTimerRef timer, void *info)
+{
+ Heap* heap = static_cast<Heap*>(info);
+ APIEntryShim shim(heap->globalData());
+ heap->collectAllGarbage();
+ CFRunLoopTimerSetNextFireDate(timer, CFAbsoluteTimeGetCurrent() + decade);
+}
+
+DefaultGCActivityCallback::DefaultGCActivityCallback(Heap* heap)
+{
+ commonConstructor(heap, CFRunLoopGetCurrent());
+}
+
+DefaultGCActivityCallback::DefaultGCActivityCallback(Heap* heap, CFRunLoopRef runLoop)
+{
+ commonConstructor(heap, runLoop);
+}
+
+DefaultGCActivityCallback::~DefaultGCActivityCallback()
+{
+ CFRunLoopRemoveTimer(d->runLoop.get(), d->timer.get(), kCFRunLoopCommonModes);
+ CFRunLoopTimerInvalidate(d->timer.get());
+ d->context.info = 0;
+ d->runLoop = 0;
+ d->timer = 0;
+}
+
+void DefaultGCActivityCallback::commonConstructor(Heap* heap, CFRunLoopRef runLoop)
+{
+ d = adoptPtr(new DefaultGCActivityCallbackPlatformData);
+
+ memset(&d->context, 0, sizeof(CFRunLoopTimerContext));
+ d->context.info = heap;
+ d->runLoop = runLoop;
+ d->timer.adoptCF(CFRunLoopTimerCreate(0, decade, decade, 0, 0, DefaultGCActivityCallbackPlatformData::trigger, &d->context));
+ CFRunLoopAddTimer(d->runLoop.get(), d->timer.get(), kCFRunLoopCommonModes);
+}
+
+void DefaultGCActivityCallback::operator()()
+{
+ CFRunLoopTimerSetNextFireDate(d->timer.get(), CFAbsoluteTimeGetCurrent() + triggerInterval);
+}
+
+void DefaultGCActivityCallback::synchronize()
+{
+ if (CFRunLoopGetCurrent() == d->runLoop.get())
+ return;
+ CFRunLoopRemoveTimer(d->runLoop.get(), d->timer.get(), kCFRunLoopCommonModes);
+ d->runLoop = CFRunLoopGetCurrent();
+ CFRunLoopAddTimer(d->runLoop.get(), d->timer.get(), kCFRunLoopCommonModes);
+}
+
+}
namespace JSC {
-void GetterSetter::markChildren(MarkStack& markStack)
+const ClassInfo GetterSetter::s_info = { "GetterSetter", 0, 0, 0 };
+
+void GetterSetter::visitChildren(SlotVisitor& visitor)
{
- JSCell::markChildren(markStack);
+ ASSERT_GC_OBJECT_INHERITS(this, &s_info);
+ ASSERT(structure()->typeInfo().overridesVisitChildren());
+ JSCell::visitChildren(visitor);
if (m_getter)
- markStack.append(m_getter);
+ visitor.append(&m_getter);
if (m_setter)
- markStack.append(m_setter);
+ visitor.append(&m_setter);
}
bool GetterSetter::isGetterSetter() const
#include "JSCell.h"
#include "CallFrame.h"
+#include "Structure.h"
namespace JSC {
friend class JIT;
public:
GetterSetter(ExecState* exec)
- : JSCell(exec->globalData().getterSetterStructure.get())
- , m_getter(0)
- , m_setter(0)
+ : JSCell(exec->globalData(), exec->globalData().getterSetterStructure.get())
{
}
- virtual void markChildren(MarkStack&);
+ virtual void visitChildren(SlotVisitor&);
- JSObject* getter() const { return m_getter; }
- void setGetter(JSObject* getter) { m_getter = getter; }
- JSObject* setter() const { return m_setter; }
- void setSetter(JSObject* setter) { m_setter = setter; }
- static PassRefPtr<Structure> createStructure(JSValue prototype)
+ JSObject* getter() const { return m_getter.get(); }
+ void setGetter(JSGlobalData& globalData, JSObject* getter) { m_getter.set(globalData, this, getter); }
+ JSObject* setter() const { return m_setter.get(); }
+ void setSetter(JSGlobalData& globalData, JSObject* setter) { m_setter.set(globalData, this, setter); }
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(GetterSetterType, OverridesMarkChildren), AnonymousSlotCount);
+ return Structure::create(globalData, prototype, TypeInfo(GetterSetterType, OverridesVisitChildren), AnonymousSlotCount, &s_info);
}
+
+ static const ClassInfo s_info;
+
private:
virtual bool isGetterSetter() const;
- JSObject* m_getter;
- JSObject* m_setter;
+ WriteBarrier<JSObject> m_getter;
+ WriteBarrier<JSObject> m_setter;
};
GetterSetter* asGetterSetter(JSValue);
inline GetterSetter* asGetterSetter(JSValue value)
{
- ASSERT(asCell(value)->isGetterSetter());
- return static_cast<GetterSetter*>(asCell(value));
+ ASSERT(value.asCell()->isGetterSetter());
+ return static_cast<GetterSetter*>(value.asCell());
}
+++ /dev/null
-/*
- * Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
- * Copyright (C) 2001 Peter Kelly (pmk@post.com)
- * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
- * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
- * Copyright (C) 2007 Maks Orlovich
- *
- * 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 "GlobalEvalFunction.h"
-
-#include "JSGlobalObject.h"
-#include <wtf/Assertions.h>
-
-namespace JSC {
-
-ASSERT_CLASS_FITS_IN_CELL(GlobalEvalFunction);
-
-GlobalEvalFunction::GlobalEvalFunction(ExecState* exec, NonNullPassRefPtr<Structure> structure, int len, const Identifier& name, NativeFunction function, JSGlobalObject* cachedGlobalObject)
- : PrototypeFunction(exec, structure, len, name, function)
- , m_cachedGlobalObject(cachedGlobalObject)
-{
- ASSERT_ARG(cachedGlobalObject, cachedGlobalObject);
-}
-
-void GlobalEvalFunction::markChildren(MarkStack& markStack)
-{
- PrototypeFunction::markChildren(markStack);
- markStack.append(m_cachedGlobalObject);
-}
-
-} // namespace JSC
+++ /dev/null
-/*
- * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
- * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
- * Copyright (C) 2007 Maks Orlovich
- *
- * 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.
- *
- */
-
-#ifndef GlobalEvalFunction_h
-#define GlobalEvalFunction_h
-
-#include "PrototypeFunction.h"
-
-namespace JSC {
-
- class JSGlobalObject;
-
- class GlobalEvalFunction : public PrototypeFunction {
- public:
- GlobalEvalFunction(ExecState*, NonNullPassRefPtr<Structure>, int len, const Identifier&, NativeFunction, JSGlobalObject* expectedThisObject);
- JSGlobalObject* cachedGlobalObject() const { return m_cachedGlobalObject; }
-
- static PassRefPtr<Structure> createStructure(JSValue prototype)
- {
- return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
- }
-
- protected:
- static const unsigned StructureFlags = ImplementsHasInstance | OverridesMarkChildren | OverridesGetPropertyNames | PrototypeFunction::StructureFlags;
-
- private:
- virtual void markChildren(MarkStack&);
-
- JSGlobalObject* m_cachedGlobalObject;
- };
-
-} // namespace JSC
-
-#endif // GlobalEvalFunction_h
#include "Identifier.h"
#include "CallFrame.h"
+#include "JSObject.h"
#include "NumericStrings.h"
+#include "ScopeChain.h"
#include <new> // for placement new
#include <string.h> // for strlen
#include <wtf/Assertions.h>
delete table;
}
-bool Identifier::equal(const UString::Rep* r, const char* s)
+bool Identifier::equal(const StringImpl* r, const char* s)
{
int length = r->length();
const UChar* d = r->characters();
return s[length] == 0;
}
-bool Identifier::equal(const UString::Rep* r, const UChar* s, unsigned length)
-{
- if (r->length() != length)
- return false;
- const UChar* d = r->characters();
- for (unsigned i = 0; i != length; ++i)
- if (d[i] != s[i])
- return false;
- return true;
-}
-
struct IdentifierCStringTranslator {
static unsigned hash(const char* c)
{
- return UString::Rep::computeHash(c);
+ return StringHasher::computeHash<char>(c);
}
- static bool equal(UString::Rep* r, const char* s)
+ static bool equal(StringImpl* r, const char* s)
{
return Identifier::equal(r, s);
}
- static void translate(UString::Rep*& location, const char* c, unsigned hash)
+ static void translate(StringImpl*& location, const char* c, unsigned hash)
{
size_t length = strlen(c);
UChar* d;
- UString::Rep* r = UString::Rep::createUninitialized(length, d).releaseRef();
+ StringImpl* r = StringImpl::createUninitialized(length, d).leakRef();
for (size_t i = 0; i != length; i++)
d[i] = static_cast<unsigned char>(c[i]); // use unsigned char to zero-extend instead of sign-extend
r->setHash(hash);
}
};
-PassRefPtr<UString::Rep> Identifier::add(JSGlobalData* globalData, const char* c)
+PassRefPtr<StringImpl> Identifier::add(JSGlobalData* globalData, const char* c)
{
if (!c)
- return UString::null().rep();
+ return 0;
if (!c[0])
- return UString::Rep::empty();
+ return StringImpl::empty();
if (!c[1])
return add(globalData, globalData->smallStrings.singleCharacterStringRep(static_cast<unsigned char>(c[0])));
if (iter != literalIdentifierTable.end())
return iter->second;
- pair<HashSet<UString::Rep*>::iterator, bool> addResult = identifierTable.add<const char*, IdentifierCStringTranslator>(c);
+ pair<HashSet<StringImpl*>::iterator, bool> addResult = identifierTable.add<const char*, IdentifierCStringTranslator>(c);
// If the string is newly-translated, then we need to adopt it.
// The boolean in the pair tells us if that is so.
- RefPtr<UString::Rep> addedString = addResult.second ? adoptRef(*addResult.first) : *addResult.first;
+ RefPtr<StringImpl> addedString = addResult.second ? adoptRef(*addResult.first) : *addResult.first;
literalIdentifierTable.add(c, addedString.get());
return addedString.release();
}
-PassRefPtr<UString::Rep> Identifier::add(ExecState* exec, const char* c)
+PassRefPtr<StringImpl> Identifier::add(ExecState* exec, const char* c)
{
return add(&exec->globalData(), c);
}
struct IdentifierUCharBufferTranslator {
static unsigned hash(const UCharBuffer& buf)
{
- return UString::Rep::computeHash(buf.s, buf.length);
+ return StringHasher::computeHash<UChar>(buf.s, buf.length);
}
- static bool equal(UString::Rep* str, const UCharBuffer& buf)
+ static bool equal(StringImpl* str, const UCharBuffer& buf)
{
return Identifier::equal(str, buf.s, buf.length);
}
- static void translate(UString::Rep*& location, const UCharBuffer& buf, unsigned hash)
+ static void translate(StringImpl*& location, const UCharBuffer& buf, unsigned hash)
{
UChar* d;
- UString::Rep* r = UString::Rep::createUninitialized(buf.length, d).releaseRef();
+ StringImpl* r = StringImpl::createUninitialized(buf.length, d).leakRef();
for (unsigned i = 0; i != buf.length; i++)
d[i] = buf.s[i];
r->setHash(hash);
}
};
-PassRefPtr<UString::Rep> Identifier::add(JSGlobalData* globalData, const UChar* s, int length)
+uint32_t Identifier::toUInt32(const UString& string, bool& ok)
+{
+ ok = false;
+
+ unsigned length = string.length();
+ const UChar* characters = string.characters();
+
+ // An empty string is not a number.
+ if (!length)
+ return 0;
+
+ // Get the first character, turning it into a digit.
+ uint32_t value = characters[0] - '0';
+ if (value > 9)
+ return 0;
+
+ // Check for leading zeros. If the first characher is 0, then the
+ // length of the string must be one - e.g. "042" is not equal to "42".
+ if (!value && length > 1)
+ return 0;
+
+ while (--length) {
+ // Multiply value by 10, checking for overflow out of 32 bits.
+ if (value > 0xFFFFFFFFU / 10)
+ return 0;
+ value *= 10;
+
+ // Get the next character, turning it into a digit.
+ uint32_t newValue = *(++characters) - '0';
+ if (newValue > 9)
+ return 0;
+
+ // Add in the old value, checking for overflow out of 32 bits.
+ newValue += value;
+ if (newValue < value)
+ return 0;
+ value = newValue;
+ }
+
+ ok = true;
+ return value;
+}
+
+PassRefPtr<StringImpl> Identifier::add(JSGlobalData* globalData, const UChar* s, int length)
{
if (length == 1) {
UChar c = s[0];
- if (c <= 0xFF)
+ if (c <= maxSingleCharacterString)
return add(globalData, globalData->smallStrings.singleCharacterStringRep(c));
}
if (!length)
- return UString::Rep::empty();
+ return StringImpl::empty();
UCharBuffer buf = {s, length};
- pair<HashSet<UString::Rep*>::iterator, bool> addResult = globalData->identifierTable->add<UCharBuffer, IdentifierUCharBufferTranslator>(buf);
+ pair<HashSet<StringImpl*>::iterator, bool> addResult = globalData->identifierTable->add<UCharBuffer, IdentifierUCharBufferTranslator>(buf);
// If the string is newly-translated, then we need to adopt it.
// The boolean in the pair tells us if that is so.
return addResult.second ? adoptRef(*addResult.first) : *addResult.first;
}
-PassRefPtr<UString::Rep> Identifier::add(ExecState* exec, const UChar* s, int length)
+PassRefPtr<StringImpl> Identifier::add(ExecState* exec, const UChar* s, int length)
{
return add(&exec->globalData(), s, length);
}
-PassRefPtr<UString::Rep> Identifier::addSlowCase(JSGlobalData* globalData, UString::Rep* r)
+PassRefPtr<StringImpl> Identifier::addSlowCase(JSGlobalData* globalData, StringImpl* r)
{
ASSERT(!r->isIdentifier());
// The empty & null strings are static singletons, and static strings are handled
if (r->length() == 1) {
UChar c = r->characters()[0];
- if (c <= 0xFF)
+ if (c <= maxSingleCharacterString)
r = globalData->smallStrings.singleCharacterStringRep(c);
if (r->isIdentifier())
return r;
return *globalData->identifierTable->add(r).first;
}
-PassRefPtr<UString::Rep> Identifier::addSlowCase(ExecState* exec, UString::Rep* r)
+PassRefPtr<StringImpl> Identifier::addSlowCase(ExecState* exec, StringImpl* r)
{
return addSlowCase(&exec->globalData(), r);
}
return Identifier(exec, exec->globalData().numericStrings.add(value));
}
+Identifier Identifier::from(JSGlobalData* globalData, unsigned value)
+{
+ return Identifier(globalData, globalData->numericStrings.add(value));
+}
+
+Identifier Identifier::from(JSGlobalData* globalData, int value)
+{
+ return Identifier(globalData, globalData->numericStrings.add(value));
+}
+
+Identifier Identifier::from(JSGlobalData* globalData, double value)
+{
+ return Identifier(globalData, globalData->numericStrings.add(value));
+}
+
#ifndef NDEBUG
void Identifier::checkCurrentIdentifierTable(JSGlobalData* globalData)
#include "JSGlobalData.h"
#include "ThreadSpecific.h"
#include "UString.h"
+#include <wtf/text/CString.h>
namespace JSC {
public:
Identifier() { }
- Identifier(ExecState* exec, const char* s) : _ustring(add(exec, s)) { } // Only to be used with string literals.
- Identifier(ExecState* exec, const UChar* s, int length) : _ustring(add(exec, s, length)) { }
- Identifier(ExecState* exec, UString::Rep* rep) : _ustring(add(exec, rep)) { }
- Identifier(ExecState* exec, const UString& s) : _ustring(add(exec, s.rep())) { }
+ Identifier(ExecState* exec, const char* s) : m_string(add(exec, s)) { } // Only to be used with string literals.
+ Identifier(ExecState* exec, const UChar* s, int length) : m_string(add(exec, s, length)) { }
+ Identifier(ExecState* exec, StringImpl* rep) : m_string(add(exec, rep)) { }
+ Identifier(ExecState* exec, const UString& s) : m_string(add(exec, s.impl())) { }
- Identifier(JSGlobalData* globalData, const char* s) : _ustring(add(globalData, s)) { } // Only to be used with string literals.
- Identifier(JSGlobalData* globalData, const UChar* s, int length) : _ustring(add(globalData, s, length)) { }
- Identifier(JSGlobalData* globalData, UString::Rep* rep) : _ustring(add(globalData, rep)) { }
- Identifier(JSGlobalData* globalData, const UString& s) : _ustring(add(globalData, s.rep())) { }
+ Identifier(JSGlobalData* globalData, const char* s) : m_string(add(globalData, s)) { } // Only to be used with string literals.
+ Identifier(JSGlobalData* globalData, const UChar* s, int length) : m_string(add(globalData, s, length)) { }
+ Identifier(JSGlobalData* globalData, StringImpl* rep) : m_string(add(globalData, rep)) { }
+ Identifier(JSGlobalData* globalData, const UString& s) : m_string(add(globalData, s.impl())) { }
- // Special constructor for cases where we overwrite an object in place.
- Identifier(PlacementNewAdoptType) : _ustring(PlacementNewAdopt) { }
+ const UString& ustring() const { return m_string; }
+ StringImpl* impl() const { return m_string.impl(); }
- const UString& ustring() const { return _ustring; }
+ const UChar* characters() const { return m_string.characters(); }
+ int length() const { return m_string.length(); }
- const UChar* data() const { return _ustring.data(); }
- int size() const { return _ustring.size(); }
-
- const char* ascii() const { return _ustring.ascii(); }
+ CString ascii() const { return m_string.ascii(); }
static Identifier from(ExecState* exec, unsigned y);
static Identifier from(ExecState* exec, int y);
static Identifier from(ExecState* exec, double y);
-
- bool isNull() const { return _ustring.isNull(); }
- bool isEmpty() const { return _ustring.isEmpty(); }
-
- uint32_t toUInt32(bool* ok) const { return _ustring.toUInt32(ok); }
- uint32_t toUInt32(bool* ok, bool tolerateEmptyString) const { return _ustring.toUInt32(ok, tolerateEmptyString); };
- uint32_t toStrictUInt32(bool* ok) const { return _ustring.toStrictUInt32(ok); }
- unsigned toArrayIndex(bool* ok) const { return _ustring.toArrayIndex(ok); }
- double toDouble() const { return _ustring.toDouble(); }
+ static Identifier from(JSGlobalData*, unsigned y);
+ static Identifier from(JSGlobalData*, int y);
+ static Identifier from(JSGlobalData*, double y);
+
+ static uint32_t toUInt32(const UString&, bool& ok);
+ uint32_t toUInt32(bool& ok) const { return toUInt32(m_string, ok); }
+ unsigned toArrayIndex(bool& ok) const;
+
+ bool isNull() const { return m_string.isNull(); }
+ bool isEmpty() const { return m_string.isEmpty(); }
friend bool operator==(const Identifier&, const Identifier&);
friend bool operator!=(const Identifier&, const Identifier&);
friend bool operator==(const Identifier&, const char*);
friend bool operator!=(const Identifier&, const char*);
- static bool equal(const UString::Rep*, const char*);
- static bool equal(const UString::Rep*, const UChar*, unsigned length);
- static bool equal(const UString::Rep* a, const UString::Rep* b) { return ::equal(a, b); }
+ static bool equal(const StringImpl*, const char*);
+ static bool equal(const StringImpl*, const UChar*, unsigned length);
+ static bool equal(const StringImpl* a, const StringImpl* b) { return ::equal(a, b); }
- static PassRefPtr<UString::Rep> add(ExecState*, const char*); // Only to be used with string literals.
- static PassRefPtr<UString::Rep> add(JSGlobalData*, const char*); // Only to be used with string literals.
+ static PassRefPtr<StringImpl> add(ExecState*, const char*); // Only to be used with string literals.
+ static PassRefPtr<StringImpl> add(JSGlobalData*, const char*); // Only to be used with string literals.
private:
- UString _ustring;
+ UString m_string;
- static bool equal(const Identifier& a, const Identifier& b) { return a._ustring.rep() == b._ustring.rep(); }
- static bool equal(const Identifier& a, const char* b) { return equal(a._ustring.rep(), b); }
+ static bool equal(const Identifier& a, const Identifier& b) { return a.m_string.impl() == b.m_string.impl(); }
+ static bool equal(const Identifier& a, const char* b) { return equal(a.m_string.impl(), b); }
- static PassRefPtr<UString::Rep> add(ExecState*, const UChar*, int length);
- static PassRefPtr<UString::Rep> add(JSGlobalData*, const UChar*, int length);
+ static PassRefPtr<StringImpl> add(ExecState*, const UChar*, int length);
+ static PassRefPtr<StringImpl> add(JSGlobalData*, const UChar*, int length);
- static PassRefPtr<UString::Rep> add(ExecState* exec, UString::Rep* r)
+ static PassRefPtr<StringImpl> add(ExecState* exec, StringImpl* r)
{
#ifndef NDEBUG
checkCurrentIdentifierTable(exec);
return r;
return addSlowCase(exec, r);
}
- static PassRefPtr<UString::Rep> add(JSGlobalData* globalData, UString::Rep* r)
+ static PassRefPtr<StringImpl> add(JSGlobalData* globalData, StringImpl* r)
{
#ifndef NDEBUG
checkCurrentIdentifierTable(globalData);
return addSlowCase(globalData, r);
}
- static PassRefPtr<UString::Rep> addSlowCase(ExecState*, UString::Rep* r);
- static PassRefPtr<UString::Rep> addSlowCase(JSGlobalData*, UString::Rep* r);
+ static PassRefPtr<StringImpl> addSlowCase(ExecState*, StringImpl* r);
+ static PassRefPtr<StringImpl> addSlowCase(JSGlobalData*, StringImpl* r);
static void checkCurrentIdentifierTable(ExecState*);
static void checkCurrentIdentifierTable(JSGlobalData*);
return !Identifier::equal(a, b);
}
+ inline bool Identifier::equal(const StringImpl* r, const UChar* s, unsigned length)
+ {
+ if (r->length() != length)
+ return false;
+ const UChar* d = r->characters();
+ for (unsigned i = 0; i != length; ++i)
+ if (d[i] != s[i])
+ return false;
+ return true;
+ }
+
IdentifierTable* createIdentifierTable();
void deleteIdentifierTable(IdentifierTable*);
+ struct IdentifierRepHash : PtrHash<RefPtr<StringImpl> > {
+ static unsigned hash(const RefPtr<StringImpl>& key) { return key->existingHash(); }
+ static unsigned hash(StringImpl* key) { return key->existingHash(); }
+ };
+
} // namespace JSC
#endif // Identifier_h
#include "config.h"
#include "InitializeThreading.h"
-#include "Collector.h"
+#include "Heap.h"
#include "dtoa.h"
#include "Identifier.h"
#include "JSGlobalObject.h"
static void initializeThreadingOnce()
{
+ // StringImpl::empty() does not construct its static string in a threadsafe fashion,
+ // so ensure it has been initialized from here.
+ StringImpl::empty();
+
WTF::initializeThreading();
wtfThreadData();
- initializeUString();
JSGlobalData::storeVPtrs();
#if ENABLE(JSC_MULTIPLE_THREADS)
s_dtoaP5Mutex = new Mutex;
initializeDates();
+ RegisterFile::initializeThreading();
#endif
}
#include "InternalFunction.h"
#include "FunctionPrototype.h"
+#include "JSGlobalObject.h"
#include "JSString.h"
namespace JSC {
+// Ensure the compiler generates a vtable for InternalFunction!
+void InternalFunction::vtableAnchor() {}
+
ASSERT_CLASS_FITS_IN_CELL(InternalFunction);
-const ClassInfo InternalFunction::info = { "Function", 0, 0, 0 };
+const ClassInfo InternalFunction::s_info = { "Function", &JSObjectWithGlobalObject::s_info, 0, 0 };
-const ClassInfo* InternalFunction::classInfo() const
+InternalFunction::InternalFunction(VPtrStealingHackType)
+ : JSObjectWithGlobalObject(VPtrStealingHack)
{
- return &info;
}
-InternalFunction::InternalFunction(JSGlobalData* globalData, NonNullPassRefPtr<Structure> structure, const Identifier& name)
- : JSObject(structure)
+InternalFunction::InternalFunction(JSGlobalData* globalData, JSGlobalObject* globalObject, Structure* structure, const Identifier& name)
+ : JSObjectWithGlobalObject(globalObject, structure)
{
- putDirect(globalData->propertyNames->name, jsString(globalData, name.isNull() ? "" : name.ustring()), DontDelete | ReadOnly | DontEnum);
+ ASSERT(inherits(&s_info));
+ putDirect(*globalData, globalData->propertyNames->name, jsString(globalData, name.isNull() ? "" : name.ustring()), DontDelete | ReadOnly | DontEnum);
}
const UString& InternalFunction::name(ExecState* exec)
{
- return asString(getDirect(exec->globalData().propertyNames->name))->tryGetValue();
+ return asString(getDirect(exec->globalData(), exec->globalData().propertyNames->name))->tryGetValue();
}
const UString InternalFunction::displayName(ExecState* exec)
{
- JSValue displayName = getDirect(exec->globalData().propertyNames->displayName);
+ JSValue displayName = getDirect(exec->globalData(), exec->globalData().propertyNames->displayName);
if (displayName && isJSString(&exec->globalData(), displayName))
return asString(displayName)->tryGetValue();
- return UString::null();
+ return UString();
}
const UString InternalFunction::calculatedDisplayName(ExecState* exec)
#ifndef InternalFunction_h
#define InternalFunction_h
-#include "JSObject.h"
+#include "JSObjectWithGlobalObject.h"
#include "Identifier.h"
namespace JSC {
class FunctionPrototype;
- class InternalFunction : public JSObject {
+ class InternalFunction : public JSObjectWithGlobalObject {
public:
- virtual const ClassInfo* classInfo() const;
- static JS_EXPORTDATA const ClassInfo info;
+ static JS_EXPORTDATA const ClassInfo s_info;
const UString& name(ExecState*);
const UString displayName(ExecState*);
const UString calculatedDisplayName(ExecState*);
- static PassRefPtr<Structure> createStructure(JSValue proto)
+ static Structure* createStructure(JSGlobalData& globalData, JSValue proto)
{
- return Structure::create(proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
+ return Structure::create(globalData, proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
}
protected:
static const unsigned StructureFlags = ImplementsHasInstance | JSObject::StructureFlags;
- InternalFunction(NonNullPassRefPtr<Structure> structure) : JSObject(structure) { }
- InternalFunction(JSGlobalData*, NonNullPassRefPtr<Structure>, const Identifier&);
+ // Only used to allow us to determine the JSFunction vptr
+ InternalFunction(VPtrStealingHackType);
+
+ InternalFunction(JSGlobalData*, JSGlobalObject*, Structure*, const Identifier&);
private:
virtual CallType getCallData(CallData&) = 0;
+
+ virtual void vtableAnchor();
};
InternalFunction* asInternalFunction(JSValue);
inline InternalFunction* asInternalFunction(JSValue value)
{
- ASSERT(asObject(value)->inherits(&InternalFunction::info));
+ ASSERT(asObject(value)->inherits(&InternalFunction::s_info));
return static_cast<InternalFunction*>(asObject(value));
}
namespace JSC {
+const ClassInfo JSAPIValueWrapper::s_info = { "API Wrapper", 0, 0, 0 };
+
} // namespace JSC
#include "JSCell.h"
#include "CallFrame.h"
+#include "Structure.h"
namespace JSC {
class JSAPIValueWrapper : public JSCell {
friend JSValue jsAPIValueWrapper(ExecState*, JSValue);
public:
- JSValue value() const { return m_value; }
+ JSValue value() const { return m_value.get(); }
virtual bool isAPIValueWrapper() const { return true; }
- static PassRefPtr<Structure> createStructure(JSValue prototype)
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(CompoundType, OverridesMarkChildren | OverridesGetPropertyNames), AnonymousSlotCount);
+ return Structure::create(globalData, prototype, TypeInfo(CompoundType, OverridesVisitChildren | OverridesGetPropertyNames), AnonymousSlotCount, &s_info);
}
-
+ static const ClassInfo s_info;
+
private:
JSAPIValueWrapper(ExecState* exec, JSValue value)
- : JSCell(exec->globalData().apiWrapperStructure.get())
- , m_value(value)
+ : JSCell(exec->globalData(), exec->globalData().apiWrapperStructure.get())
{
+ m_value.set(exec->globalData(), this, value);
ASSERT(!value.isCell());
}
- JSValue m_value;
+ WriteBarrier<Unknown> m_value;
};
inline JSValue jsAPIValueWrapper(ExecState* exec, JSValue value)
ASSERT_CLASS_FITS_IN_CELL(JSActivation);
-const ClassInfo JSActivation::info = { "JSActivation", 0, 0, 0 };
-
-JSActivation::JSActivation(CallFrame* callFrame, NonNullPassRefPtr<FunctionExecutable> functionExecutable)
- : Base(callFrame->globalData().activationStructure, new JSActivationData(functionExecutable, callFrame->registers()))
+const ClassInfo JSActivation::s_info = { "JSActivation", &Base::s_info, 0, 0 };
+
+JSActivation::JSActivation(CallFrame* callFrame, FunctionExecutable* functionExecutable)
+ : Base(callFrame->globalData(), callFrame->globalData().activationStructure.get(), functionExecutable->symbolTable(), callFrame->registers())
+ , m_numParametersMinusThis(static_cast<int>(functionExecutable->parameterCount()))
+ , m_numCapturedVars(functionExecutable->capturedVariableCount())
+ , m_requiresDynamicChecks(functionExecutable->usesEval())
+ , m_argumentsRegister(functionExecutable->generatedBytecode().argumentsRegister())
{
+ ASSERT(inherits(&s_info));
+
+ // We have to manually ref and deref the symbol table as JSVariableObject
+ // doesn't know about SharedSymbolTable
+ static_cast<SharedSymbolTable*>(m_symbolTable)->ref();
}
JSActivation::~JSActivation()
{
- delete d();
+ static_cast<SharedSymbolTable*>(m_symbolTable)->deref();
}
-void JSActivation::markChildren(MarkStack& markStack)
+void JSActivation::visitChildren(SlotVisitor& visitor)
{
- Base::markChildren(markStack);
+ ASSERT_GC_OBJECT_INHERITS(this, &s_info);
+ COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
+ ASSERT(structure()->typeInfo().overridesVisitChildren());
+ Base::visitChildren(visitor);
- Register* registerArray = d()->registerArray.get();
+ // No need to mark our registers if they're still in the RegisterFile.
+ WriteBarrier<Unknown>* registerArray = m_registerArray.get();
if (!registerArray)
return;
- size_t numParametersMinusThis = d()->functionExecutable->parameterCount();
+ visitor.appendValues(registerArray, m_numParametersMinusThis);
- size_t count = numParametersMinusThis;
- markStack.appendValues(registerArray, count);
+ // Skip the call frame, which sits between the parameters and vars.
+ visitor.appendValues(registerArray + m_numParametersMinusThis + RegisterFile::CallFrameHeaderSize, m_numCapturedVars, MayContainNullValues);
+}
- size_t numVars = d()->functionExecutable->variableCount();
+inline bool JSActivation::symbolTableGet(const Identifier& propertyName, PropertySlot& slot)
+{
+ SymbolTableEntry entry = symbolTable().inlineGet(propertyName.impl());
+ if (entry.isNull())
+ return false;
+ if (entry.getIndex() >= m_numCapturedVars)
+ return false;
- // Skip the call frame, which sits between the parameters and vars.
- markStack.appendValues(registerArray + count + RegisterFile::CallFrameHeaderSize, numVars, MayContainNullValues);
+ slot.setValue(registerAt(entry.getIndex()).get());
+ return true;
}
-bool JSActivation::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+inline bool JSActivation::symbolTablePut(JSGlobalData& globalData, const Identifier& propertyName, JSValue value)
{
- if (symbolTableGet(propertyName, slot))
+ ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
+
+ SymbolTableEntry entry = symbolTable().inlineGet(propertyName.impl());
+ if (entry.isNull())
+ return false;
+ if (entry.isReadOnly())
return true;
+ if (entry.getIndex() >= m_numCapturedVars)
+ return false;
- if (JSValue* location = getDirectLocation(propertyName)) {
- slot.setValueSlot(location);
- return true;
+ registerAt(entry.getIndex()).set(globalData, this, value);
+ return true;
+}
+
+void JSActivation::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
+{
+ SymbolTable::const_iterator end = symbolTable().end();
+ for (SymbolTable::const_iterator it = symbolTable().begin(); it != end; ++it) {
+ if (it->second.getAttributes() & DontEnum && mode != IncludeDontEnumProperties)
+ continue;
+ if (it->second.getIndex() >= m_numCapturedVars)
+ continue;
+ propertyNames.add(Identifier(exec, it->first.get()));
}
+ // Skip the JSVariableObject implementation of getOwnPropertyNames
+ JSObject::getOwnPropertyNames(exec, propertyNames, mode);
+}
+
+inline bool JSActivation::symbolTablePutWithAttributes(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
+{
+ ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
+
+ SymbolTable::iterator iter = symbolTable().find(propertyName.impl());
+ if (iter == symbolTable().end())
+ return false;
+ SymbolTableEntry& entry = iter->second;
+ ASSERT(!entry.isNull());
+ if (entry.getIndex() >= m_numCapturedVars)
+ return false;
+
+ entry.setAttributes(attributes);
+ registerAt(entry.getIndex()).set(globalData, this, value);
+ return true;
+}
- // Only return the built-in arguments object if it wasn't overridden above.
+bool JSActivation::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+{
if (propertyName == exec->propertyNames().arguments) {
slot.setCustom(this, getArgumentsGetter());
return true;
}
+ if (symbolTableGet(propertyName, slot))
+ return true;
+
+ if (WriteBarrierBase<Unknown>* location = getDirectLocation(exec->globalData(), propertyName)) {
+ slot.setValue(location->get());
+ return true;
+ }
+
// We don't call through to JSObject because there's no way to give an
// activation object getter properties or a prototype.
ASSERT(!hasGetterSetterProperties());
return false;
}
-void JSActivation::put(ExecState*, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
+void JSActivation::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
{
ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
- if (symbolTablePut(propertyName, value))
+ if (symbolTablePut(exec->globalData(), propertyName, value))
return;
// We don't call through to JSObject because __proto__ and getter/setter
// properties are non-standard extensions that other implementations do not
// expose in the activation object.
ASSERT(!hasGetterSetterProperties());
- putDirect(propertyName, value, 0, true, slot);
+ putDirect(exec->globalData(), propertyName, value, 0, true, slot);
}
// FIXME: Make this function honor ReadOnly (const) and DontEnum
{
ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
- if (symbolTablePutWithAttributes(propertyName, value, attributes))
+ if (symbolTablePutWithAttributes(exec->globalData(), propertyName, value, attributes))
return;
// We don't call through to JSObject because __proto__ and getter/setter
return exec->globalThisValue();
}
+JSValue JSActivation::toStrictThisObject(ExecState*) const
+{
+ return jsNull();
+}
+
bool JSActivation::isDynamicScope(bool& requiresDynamicChecks) const
{
- requiresDynamicChecks = d()->functionExecutable->usesEval();
+ requiresDynamicChecks = m_requiresDynamicChecks;
return false;
}
-JSValue JSActivation::argumentsGetter(ExecState* exec, JSValue slotBase, const Identifier&)
+JSValue JSActivation::argumentsGetter(ExecState*, JSValue slotBase, const Identifier&)
{
JSActivation* activation = asActivation(slotBase);
-
- if (activation->d()->functionExecutable->usesArguments()) {
- PropertySlot slot;
- activation->symbolTableGet(exec->propertyNames().arguments, slot);
- return slot.getValue(exec, exec->propertyNames().arguments);
- }
-
- CallFrame* callFrame = CallFrame::create(activation->d()->registers);
- Arguments* arguments = callFrame->optionalCalleeArguments();
- if (!arguments) {
- arguments = new (callFrame) Arguments(callFrame);
- arguments->copyRegisters();
- callFrame->setCalleeArguments(arguments);
- }
- ASSERT(arguments->inherits(&Arguments::info));
-
- return arguments;
+ CallFrame* callFrame = CallFrame::create(reinterpret_cast<Register*>(activation->m_registers));
+ int argumentsRegister = activation->m_argumentsRegister;
+ if (JSValue arguments = callFrame->uncheckedR(argumentsRegister).jsValue())
+ return arguments;
+ int realArgumentsRegister = unmodifiedArgumentsRegister(argumentsRegister);
+
+ JSValue arguments = JSValue(new (callFrame) Arguments(callFrame));
+ callFrame->uncheckedR(argumentsRegister) = arguments;
+ callFrame->uncheckedR(realArgumentsRegister) = arguments;
+
+ ASSERT(callFrame->uncheckedR(realArgumentsRegister).jsValue().inherits(&Arguments::s_info));
+ return callFrame->uncheckedR(realArgumentsRegister).jsValue();
}
// These two functions serve the purpose of isolating the common case from a
class JSActivation : public JSVariableObject {
typedef JSVariableObject Base;
public:
- JSActivation(CallFrame*, NonNullPassRefPtr<FunctionExecutable>);
+ JSActivation(CallFrame*, FunctionExecutable*);
virtual ~JSActivation();
- virtual void markChildren(MarkStack&);
+ virtual void visitChildren(SlotVisitor&);
virtual bool isDynamicScope(bool& requiresDynamicChecks) const;
virtual bool isActivationObject() const { return true; }
virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
+ virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode);
virtual void put(ExecState*, const Identifier&, JSValue, PutPropertySlot&);
virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
virtual JSObject* toThisObject(ExecState*) const;
+ virtual JSValue toStrictThisObject(ExecState*) const;
- void copyRegisters(Arguments* arguments);
+ void copyRegisters(JSGlobalData&);
- virtual const ClassInfo* classInfo() const { return &info; }
- static const ClassInfo info;
+ static const ClassInfo s_info;
- static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); }
+ static Structure* createStructure(JSGlobalData& globalData, JSValue proto) { return Structure::create(globalData, proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); }
protected:
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | NeedsThisConversion | OverridesMarkChildren | OverridesGetPropertyNames | JSVariableObject::StructureFlags;
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | NeedsThisConversion | OverridesVisitChildren | OverridesGetPropertyNames | JSVariableObject::StructureFlags;
private:
- struct JSActivationData : public JSVariableObjectData {
- JSActivationData(NonNullPassRefPtr<FunctionExecutable> _functionExecutable, Register* registers)
- : JSVariableObjectData(_functionExecutable->generatedBytecode().symbolTable(), registers)
- , functionExecutable(_functionExecutable)
- {
- // We have to manually ref and deref the symbol table as JSVariableObjectData
- // doesn't know about SharedSymbolTable
- functionExecutable->generatedBytecode().sharedSymbolTable()->ref();
- }
- ~JSActivationData()
- {
- static_cast<SharedSymbolTable*>(symbolTable)->deref();
- }
-
- RefPtr<FunctionExecutable> functionExecutable;
- };
-
+ bool symbolTableGet(const Identifier&, PropertySlot&);
+ bool symbolTableGet(const Identifier&, PropertyDescriptor&);
+ bool symbolTableGet(const Identifier&, PropertySlot&, bool& slotIsWriteable);
+ bool symbolTablePut(JSGlobalData&, const Identifier&, JSValue);
+ bool symbolTablePutWithAttributes(JSGlobalData&, const Identifier&, JSValue, unsigned attributes);
+
static JSValue argumentsGetter(ExecState*, JSValue, const Identifier&);
NEVER_INLINE PropertySlot::GetValueFunc getArgumentsGetter();
- JSActivationData* d() const { return static_cast<JSActivationData*>(JSVariableObject::d); }
+ int m_numParametersMinusThis;
+ int m_numCapturedVars : 31;
+ bool m_requiresDynamicChecks : 1;
+ int m_argumentsRegister;
};
JSActivation* asActivation(JSValue);
inline JSActivation* asActivation(JSValue value)
{
- ASSERT(asObject(value)->inherits(&JSActivation::info));
+ ASSERT(asObject(value)->inherits(&JSActivation::s_info));
return static_cast<JSActivation*>(asObject(value));
}
+
+ ALWAYS_INLINE JSActivation* Register::activation() const
+ {
+ return asActivation(jsValue());
+ }
} // namespace JSC
#include <wtf/OwnPtr.h>
#include <Operations.h>
-#define CHECK_ARRAY_CONSISTENCY 0
-
using namespace std;
using namespace WTF;
// 0xFFFFFFFF is a bit weird -- is not an array index even though it's an integer.
#define MAX_ARRAY_INDEX 0xFFFFFFFEU
+// The value BASE_VECTOR_LEN is the maximum number of vector elements we'll allocate
+// for an array that was created with a sepcified length (e.g. a = new Array(123))
+#define BASE_VECTOR_LEN 4U
+
+// The upper bound to the size we'll grow a zero length array when the first element
+// is added.
+#define FIRST_VECTOR_GROW 4U
+
// Our policy for when to use a vector and when to use a sparse map.
// For all array indices under MIN_SPARSE_ARRAY_INDEX, we always use a vector.
// When indices greater than MIN_SPARSE_ARRAY_INDEX are involved, we use a vector
// as long as it is 1/8 full. If more sparse than that, we use a map.
static const unsigned minDensityMultiplier = 8;
-const ClassInfo JSArray::info = {"Array", 0, 0, 0};
+const ClassInfo JSArray::s_info = {"Array", &JSNonFinalObject::s_info, 0, 0};
+
+// We keep track of the size of the last array after it was grown. We use this
+// as a simple heuristic for as the value to grow the next array from size 0.
+// This value is capped by the constant FIRST_VECTOR_GROW defined above.
+static unsigned lastArraySize = 0;
static inline size_t storageSize(unsigned vectorLength)
{
return size;
}
-static inline unsigned increasedVectorLength(unsigned newLength)
-{
- ASSERT(newLength <= MAX_STORAGE_VECTOR_LENGTH);
-
- // Mathematically equivalent to:
- // increasedLength = (newLength * 3 + 1) / 2;
- // or:
- // increasedLength = (unsigned)ceil(newLength * 1.5));
- // This form is not prone to internal overflow.
- unsigned increasedLength = newLength + (newLength >> 1) + (newLength & 1);
- ASSERT(increasedLength >= newLength);
-
- return min(increasedLength, MAX_STORAGE_VECTOR_LENGTH);
-}
-
static inline bool isDenseEnoughForVector(unsigned length, unsigned numValues)
{
return length / minDensityMultiplier <= numValues;
#endif
-JSArray::JSArray(NonNullPassRefPtr<Structure> structure)
- : JSObject(structure)
+JSArray::JSArray(VPtrStealingHackType)
+ : JSNonFinalObject(VPtrStealingHack)
{
+}
+
+JSArray::JSArray(JSGlobalData& globalData, Structure* structure)
+ : JSNonFinalObject(globalData, structure)
+{
+ ASSERT(inherits(&s_info));
+
unsigned initialCapacity = 0;
m_storage = static_cast<ArrayStorage*>(fastZeroedMalloc(storageSize(initialCapacity)));
+ m_storage->m_allocBase = m_storage;
+ m_indexBias = 0;
m_vectorLength = initialCapacity;
checkConsistency();
+
+ Heap::heap(this)->reportExtraMemoryCost(storageSize(0));
}
-JSArray::JSArray(NonNullPassRefPtr<Structure> structure, unsigned initialLength)
- : JSObject(structure)
+JSArray::JSArray(JSGlobalData& globalData, Structure* structure, unsigned initialLength, ArrayCreationMode creationMode)
+ : JSNonFinalObject(globalData, structure)
{
- unsigned initialCapacity = min(initialLength, MIN_SPARSE_ARRAY_INDEX);
+ ASSERT(inherits(&s_info));
+ unsigned initialCapacity;
+ if (creationMode == CreateCompact)
+ initialCapacity = initialLength;
+ else
+ initialCapacity = min(BASE_VECTOR_LEN, MIN_SPARSE_ARRAY_INDEX);
+
m_storage = static_cast<ArrayStorage*>(fastMalloc(storageSize(initialCapacity)));
+ m_storage->m_allocBase = m_storage;
m_storage->m_length = initialLength;
+ m_indexBias = 0;
m_vectorLength = initialCapacity;
- m_storage->m_numValuesInVector = 0;
m_storage->m_sparseValueMap = 0;
m_storage->subclassData = 0;
m_storage->reportedMapCapacity = 0;
- JSValue* vector = m_storage->m_vector;
- for (size_t i = 0; i < initialCapacity; ++i)
- vector[i] = JSValue();
+ if (creationMode == CreateCompact) {
+#if CHECK_ARRAY_CONSISTENCY
+ m_storage->m_inCompactInitialization = !!initialCapacity;
+#endif
+ m_storage->m_length = 0;
+ m_storage->m_numValuesInVector = initialCapacity;
+ } else {
+#if CHECK_ARRAY_CONSISTENCY
+ storage->m_inCompactInitialization = false;
+#endif
+ m_storage->m_length = initialLength;
+ m_storage->m_numValuesInVector = 0;
+ WriteBarrier<Unknown>* vector = m_storage->m_vector;
+ for (size_t i = 0; i < initialCapacity; ++i)
+ vector[i].clear();
+ }
checkConsistency();
-
- Heap::heap(this)->reportExtraMemoryCost(initialCapacity * sizeof(JSValue));
+
+ Heap::heap(this)->reportExtraMemoryCost(storageSize(initialCapacity));
}
-JSArray::JSArray(NonNullPassRefPtr<Structure> structure, const ArgList& list)
- : JSObject(structure)
+JSArray::JSArray(JSGlobalData& globalData, Structure* structure, const ArgList& list)
+ : JSNonFinalObject(globalData, structure)
{
- unsigned initialCapacity = list.size();
+ ASSERT(inherits(&s_info));
- m_storage = static_cast<ArrayStorage*>(fastMalloc(storageSize(initialCapacity)));
+ unsigned initialCapacity = list.size();
+ unsigned initialStorage;
+
+ // If the ArgList is empty, allocate space for 3 entries. This value empirically
+ // works well for benchmarks.
+ if (!initialCapacity)
+ initialStorage = 3;
+ else
+ initialStorage = initialCapacity;
+
+ m_storage = static_cast<ArrayStorage*>(fastMalloc(storageSize(initialStorage)));
+ m_storage->m_allocBase = m_storage;
+ m_indexBias = 0;
m_storage->m_length = initialCapacity;
- m_vectorLength = initialCapacity;
+ m_vectorLength = initialStorage;
m_storage->m_numValuesInVector = initialCapacity;
m_storage->m_sparseValueMap = 0;
m_storage->subclassData = 0;
m_storage->reportedMapCapacity = 0;
+#if CHECK_ARRAY_CONSISTENCY
+ m_storage->m_inCompactInitialization = false;
+#endif
size_t i = 0;
+ WriteBarrier<Unknown>* vector = m_storage->m_vector;
ArgList::const_iterator end = list.end();
for (ArgList::const_iterator it = list.begin(); it != end; ++it, ++i)
- m_storage->m_vector[i] = *it;
+ vector[i].set(globalData, this, *it);
+ for (; i < initialStorage; i++)
+ vector[i].clear();
checkConsistency();
- Heap::heap(this)->reportExtraMemoryCost(storageSize(initialCapacity));
+ Heap::heap(this)->reportExtraMemoryCost(storageSize(initialStorage));
}
JSArray::~JSArray()
checkConsistency(DestructorConsistencyCheck);
delete m_storage->m_sparseValueMap;
- fastFree(m_storage);
+ fastFree(m_storage->m_allocBase);
}
bool JSArray::getOwnPropertySlot(ExecState* exec, unsigned i, PropertySlot& slot)
{
ArrayStorage* storage = m_storage;
-
+
if (i >= storage->m_length) {
if (i > MAX_ARRAY_INDEX)
return getOwnPropertySlot(exec, Identifier::from(exec, i), slot);
}
if (i < m_vectorLength) {
- JSValue& valueSlot = storage->m_vector[i];
- if (valueSlot) {
- slot.setValueSlot(&valueSlot);
+ JSValue value = storage->m_vector[i].get();
+ if (value) {
+ slot.setValue(value);
return true;
}
} else if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
if (i >= MIN_SPARSE_ARRAY_INDEX) {
SparseArrayValueMap::iterator it = map->find(i);
if (it != map->end()) {
- slot.setValueSlot(&it->second);
+ slot.setValue(it->second.get());
return true;
}
}
bool JSArray::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
{
if (propertyName == exec->propertyNames().length) {
- slot.setValue(jsNumber(exec, length()));
+ slot.setValue(jsNumber(length()));
return true;
}
bool isArrayIndex;
- unsigned i = propertyName.toArrayIndex(&isArrayIndex);
+ unsigned i = propertyName.toArrayIndex(isArrayIndex);
if (isArrayIndex)
return JSArray::getOwnPropertySlot(exec, i, slot);
bool JSArray::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
{
if (propertyName == exec->propertyNames().length) {
- descriptor.setDescriptor(jsNumber(exec, length()), DontDelete | DontEnum);
+ descriptor.setDescriptor(jsNumber(length()), DontDelete | DontEnum);
return true;
}
+
+ ArrayStorage* storage = m_storage;
bool isArrayIndex;
- unsigned i = propertyName.toArrayIndex(&isArrayIndex);
+ unsigned i = propertyName.toArrayIndex(isArrayIndex);
if (isArrayIndex) {
- if (i >= m_storage->m_length)
+ if (i >= storage->m_length)
return false;
if (i < m_vectorLength) {
- JSValue& value = m_storage->m_vector[i];
+ WriteBarrier<Unknown>& value = storage->m_vector[i];
if (value) {
- descriptor.setDescriptor(value, 0);
+ descriptor.setDescriptor(value.get(), 0);
return true;
}
- } else if (SparseArrayValueMap* map = m_storage->m_sparseValueMap) {
+ } else if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
if (i >= MIN_SPARSE_ARRAY_INDEX) {
SparseArrayValueMap::iterator it = map->find(i);
if (it != map->end()) {
- descriptor.setDescriptor(it->second, 0);
+ descriptor.setDescriptor(it->second.get(), 0);
return true;
}
}
void JSArray::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
{
bool isArrayIndex;
- unsigned i = propertyName.toArrayIndex(&isArrayIndex);
+ unsigned i = propertyName.toArrayIndex(isArrayIndex);
if (isArrayIndex) {
put(exec, i, value);
return;
if (propertyName == exec->propertyNames().length) {
unsigned newLength = value.toUInt32(exec);
if (value.toNumber(exec) != static_cast<double>(newLength)) {
- throwError(exec, RangeError, "Invalid array length.");
+ throwError(exec, createRangeError(exec, "Invalid array length."));
return;
}
setLength(newLength);
{
checkConsistency();
- unsigned length = m_storage->m_length;
+ ArrayStorage* storage = m_storage;
+
+ unsigned length = storage->m_length;
if (i >= length && i <= MAX_ARRAY_INDEX) {
length = i + 1;
- m_storage->m_length = length;
+ storage->m_length = length;
}
if (i < m_vectorLength) {
- JSValue& valueSlot = m_storage->m_vector[i];
+ WriteBarrier<Unknown>& valueSlot = storage->m_vector[i];
if (valueSlot) {
- valueSlot = value;
+ valueSlot.set(exec->globalData(), this, value);
checkConsistency();
return;
}
- valueSlot = value;
- ++m_storage->m_numValuesInVector;
+ valueSlot.set(exec->globalData(), this, value);
+ ++storage->m_numValuesInVector;
checkConsistency();
return;
}
NEVER_INLINE void JSArray::putSlowCase(ExecState* exec, unsigned i, JSValue value)
{
ArrayStorage* storage = m_storage;
+
SparseArrayValueMap* map = storage->m_sparseValueMap;
if (i >= MIN_SPARSE_ARRAY_INDEX) {
storage->m_sparseValueMap = map;
}
- pair<SparseArrayValueMap::iterator, bool> result = map->add(i, value);
- if (!result.second) { // pre-existing entry
- result.first->second = value;
+ WriteBarrier<Unknown> temp;
+ pair<SparseArrayValueMap::iterator, bool> result = map->add(i, temp);
+ result.first->second.set(exec->globalData(), this, value);
+ if (!result.second) // pre-existing entry
return;
- }
size_t capacity = map->capacity();
if (capacity != storage->reportedMapCapacity) {
if (!map || map->isEmpty()) {
if (increaseVectorLength(i + 1)) {
storage = m_storage;
- storage->m_vector[i] = value;
+ storage->m_vector[i].set(exec->globalData(), this, value);
++storage->m_numValuesInVector;
checkConsistency();
} else
// Decide how many values it would be best to move from the map.
unsigned newNumValuesInVector = storage->m_numValuesInVector + 1;
- unsigned newVectorLength = increasedVectorLength(i + 1);
+ unsigned newVectorLength = getNewVectorLength(i + 1);
for (unsigned j = max(m_vectorLength, MIN_SPARSE_ARRAY_INDEX); j < newVectorLength; ++j)
newNumValuesInVector += map->contains(j);
if (i >= MIN_SPARSE_ARRAY_INDEX)
newNumValuesInVector -= map->contains(i);
if (isDenseEnoughForVector(newVectorLength, newNumValuesInVector)) {
+ unsigned needLength = max(i + 1, storage->m_length);
unsigned proposedNewNumValuesInVector = newNumValuesInVector;
// If newVectorLength is already the maximum - MAX_STORAGE_VECTOR_LENGTH - then do not attempt to grow any further.
- while (newVectorLength < MAX_STORAGE_VECTOR_LENGTH) {
- unsigned proposedNewVectorLength = increasedVectorLength(newVectorLength + 1);
+ while ((newVectorLength < needLength) && (newVectorLength < MAX_STORAGE_VECTOR_LENGTH)) {
+ unsigned proposedNewVectorLength = getNewVectorLength(newVectorLength + 1);
for (unsigned j = max(newVectorLength, MIN_SPARSE_ARRAY_INDEX); j < proposedNewVectorLength; ++j)
proposedNewNumValuesInVector += map->contains(j);
if (!isDenseEnoughForVector(proposedNewVectorLength, proposedNewNumValuesInVector))
}
}
- if (!tryFastRealloc(storage, storageSize(newVectorLength)).getValue(storage)) {
+ void* baseStorage = storage->m_allocBase;
+
+ if (!tryFastRealloc(baseStorage, storageSize(newVectorLength + m_indexBias)).getValue(baseStorage)) {
throwOutOfMemoryError(exec);
return;
}
+ m_storage = reinterpret_cast_ptr<ArrayStorage*>(static_cast<char*>(baseStorage) + m_indexBias * sizeof(JSValue));
+ m_storage->m_allocBase = baseStorage;
+ storage = m_storage;
+
unsigned vectorLength = m_vectorLength;
+ WriteBarrier<Unknown>* vector = storage->m_vector;
if (newNumValuesInVector == storage->m_numValuesInVector + 1) {
for (unsigned j = vectorLength; j < newVectorLength; ++j)
- storage->m_vector[j] = JSValue();
+ vector[j].clear();
if (i > MIN_SPARSE_ARRAY_INDEX)
map->remove(i);
} else {
for (unsigned j = vectorLength; j < max(vectorLength, MIN_SPARSE_ARRAY_INDEX); ++j)
- storage->m_vector[j] = JSValue();
+ vector[j].clear();
+ JSGlobalData& globalData = exec->globalData();
for (unsigned j = max(vectorLength, MIN_SPARSE_ARRAY_INDEX); j < newVectorLength; ++j)
- storage->m_vector[j] = map->take(j);
+ vector[j].set(globalData, this, map->take(j).get());
}
- storage->m_vector[i] = value;
+ ASSERT(i < newVectorLength);
m_vectorLength = newVectorLength;
storage->m_numValuesInVector = newNumValuesInVector;
- m_storage = storage;
+ storage->m_vector[i].set(exec->globalData(), this, value);
checkConsistency();
bool JSArray::deleteProperty(ExecState* exec, const Identifier& propertyName)
{
bool isArrayIndex;
- unsigned i = propertyName.toArrayIndex(&isArrayIndex);
+ unsigned i = propertyName.toArrayIndex(isArrayIndex);
if (isArrayIndex)
return deleteProperty(exec, i);
checkConsistency();
ArrayStorage* storage = m_storage;
-
+
if (i < m_vectorLength) {
- JSValue& valueSlot = storage->m_vector[i];
+ WriteBarrier<Unknown>& valueSlot = storage->m_vector[i];
if (!valueSlot) {
checkConsistency();
return false;
}
- valueSlot = JSValue();
+ valueSlot.clear();
--storage->m_numValuesInVector;
checkConsistency();
return true;
// which almost certainly means a different structure for PropertyNameArray.
ArrayStorage* storage = m_storage;
-
+
unsigned usedVectorLength = min(storage->m_length, m_vectorLength);
for (unsigned i = 0; i < usedVectorLength; ++i) {
if (storage->m_vector[i])
JSObject::getOwnPropertyNames(exec, propertyNames, mode);
}
+ALWAYS_INLINE unsigned JSArray::getNewVectorLength(unsigned desiredLength)
+{
+ ASSERT(desiredLength <= MAX_STORAGE_VECTOR_LENGTH);
+
+ unsigned increasedLength;
+ unsigned maxInitLength = min(m_storage->m_length, 100000U);
+
+ if (desiredLength < maxInitLength)
+ increasedLength = maxInitLength;
+ else if (!m_vectorLength)
+ increasedLength = max(desiredLength, lastArraySize);
+ else {
+ // Mathematically equivalent to:
+ // increasedLength = (newLength * 3 + 1) / 2;
+ // or:
+ // increasedLength = (unsigned)ceil(newLength * 1.5));
+ // This form is not prone to internal overflow.
+ increasedLength = desiredLength + (desiredLength >> 1) + (desiredLength & 1);
+ }
+
+ ASSERT(increasedLength >= desiredLength);
+
+ lastArraySize = min(increasedLength, FIRST_VECTOR_GROW);
+
+ return min(increasedLength, MAX_STORAGE_VECTOR_LENGTH);
+}
+
bool JSArray::increaseVectorLength(unsigned newLength)
{
// This function leaves the array in an internally inconsistent state, because it does not move any values from sparse value map
unsigned vectorLength = m_vectorLength;
ASSERT(newLength > vectorLength);
ASSERT(newLength <= MAX_STORAGE_VECTOR_INDEX);
- unsigned newVectorLength = increasedVectorLength(newLength);
+ unsigned newVectorLength = getNewVectorLength(newLength);
+ void* baseStorage = storage->m_allocBase;
- if (!tryFastRealloc(storage, storageSize(newVectorLength)).getValue(storage))
+ if (!tryFastRealloc(baseStorage, storageSize(newVectorLength + m_indexBias)).getValue(baseStorage))
return false;
- m_vectorLength = newVectorLength;
+ storage = m_storage = reinterpret_cast_ptr<ArrayStorage*>(static_cast<char*>(baseStorage) + m_indexBias * sizeof(JSValue));
+ m_storage->m_allocBase = baseStorage;
+ WriteBarrier<Unknown>* vector = storage->m_vector;
for (unsigned i = vectorLength; i < newVectorLength; ++i)
- storage->m_vector[i] = JSValue();
-
- m_storage = storage;
+ vector[i].clear();
+ m_vectorLength = newVectorLength;
+
Heap::heap(this)->reportExtraMemoryCost(storageSize(newVectorLength) - storageSize(vectorLength));
return true;
}
-void JSArray::setLength(unsigned newLength)
+bool JSArray::increaseVectorPrefixLength(unsigned newLength)
{
- checkConsistency();
+ // This function leaves the array in an internally inconsistent state, because it does not move any values from sparse value map
+ // to the vector. Callers have to account for that, because they can do it more efficiently.
+
+ ArrayStorage* storage = m_storage;
+
+ unsigned vectorLength = m_vectorLength;
+ ASSERT(newLength > vectorLength);
+ ASSERT(newLength <= MAX_STORAGE_VECTOR_INDEX);
+ unsigned newVectorLength = getNewVectorLength(newLength);
+ void* newBaseStorage = fastMalloc(storageSize(newVectorLength + m_indexBias));
+ if (!newBaseStorage)
+ return false;
+
+ m_indexBias += newVectorLength - newLength;
+
+ m_storage = reinterpret_cast_ptr<ArrayStorage*>(static_cast<char*>(newBaseStorage) + m_indexBias * sizeof(JSValue));
+
+ memcpy(m_storage, storage, storageSize(0));
+ memcpy(&m_storage->m_vector[newLength - m_vectorLength], &storage->m_vector[0], vectorLength * sizeof(JSValue));
+
+ m_storage->m_allocBase = newBaseStorage;
+ m_vectorLength = newLength;
+
+ fastFree(storage->m_allocBase);
+ ASSERT(newLength > vectorLength);
+ unsigned delta = newLength - vectorLength;
+ for (unsigned i = 0; i < delta; i++)
+ m_storage->m_vector[i].clear();
+ Heap::heap(this)->reportExtraMemoryCost(storageSize(newVectorLength) - storageSize(vectorLength));
+
+ return true;
+}
+
+
+void JSArray::setLength(unsigned newLength)
+{
ArrayStorage* storage = m_storage;
+
+#if CHECK_ARRAY_CONSISTENCY
+ if (!storage->m_inCompactInitialization)
+ checkConsistency();
+ else
+ storage->m_inCompactInitialization = false;
+#endif
- unsigned length = m_storage->m_length;
+ unsigned length = storage->m_length;
if (newLength < length) {
unsigned usedVectorLength = min(length, m_vectorLength);
for (unsigned i = newLength; i < usedVectorLength; ++i) {
- JSValue& valueSlot = storage->m_vector[i];
+ WriteBarrier<Unknown>& valueSlot = storage->m_vector[i];
bool hadValue = valueSlot;
- valueSlot = JSValue();
+ valueSlot.clear();
storage->m_numValuesInVector -= hadValue;
}
}
}
- m_storage->m_length = newLength;
+ storage->m_length = newLength;
checkConsistency();
}
{
checkConsistency();
- unsigned length = m_storage->m_length;
+ ArrayStorage* storage = m_storage;
+
+ unsigned length = storage->m_length;
if (!length)
return jsUndefined();
JSValue result;
if (length < m_vectorLength) {
- JSValue& valueSlot = m_storage->m_vector[length];
+ WriteBarrier<Unknown>& valueSlot = storage->m_vector[length];
if (valueSlot) {
- --m_storage->m_numValuesInVector;
- result = valueSlot;
- valueSlot = JSValue();
+ --storage->m_numValuesInVector;
+ result = valueSlot.get();
+ valueSlot.clear();
} else
result = jsUndefined();
} else {
result = jsUndefined();
- if (SparseArrayValueMap* map = m_storage->m_sparseValueMap) {
+ if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
SparseArrayValueMap::iterator it = map->find(length);
if (it != map->end()) {
- result = it->second;
+ result = it->second.get();
map->remove(it);
if (map->isEmpty()) {
delete map;
- m_storage->m_sparseValueMap = 0;
+ storage->m_sparseValueMap = 0;
}
}
}
}
- m_storage->m_length = length;
+ storage->m_length = length;
checkConsistency();
void JSArray::push(ExecState* exec, JSValue value)
{
checkConsistency();
+
+ ArrayStorage* storage = m_storage;
- if (m_storage->m_length < m_vectorLength) {
- m_storage->m_vector[m_storage->m_length] = value;
- ++m_storage->m_numValuesInVector;
- ++m_storage->m_length;
+ if (storage->m_length < m_vectorLength) {
+ storage->m_vector[storage->m_length].set(exec->globalData(), this, value);
+ ++storage->m_numValuesInVector;
+ ++storage->m_length;
checkConsistency();
return;
}
- if (m_storage->m_length < MIN_SPARSE_ARRAY_INDEX) {
- SparseArrayValueMap* map = m_storage->m_sparseValueMap;
+ if (storage->m_length < MIN_SPARSE_ARRAY_INDEX) {
+ SparseArrayValueMap* map = storage->m_sparseValueMap;
if (!map || map->isEmpty()) {
- if (increaseVectorLength(m_storage->m_length + 1)) {
- m_storage->m_vector[m_storage->m_length] = value;
- ++m_storage->m_numValuesInVector;
- ++m_storage->m_length;
+ if (increaseVectorLength(storage->m_length + 1)) {
+ storage = m_storage;
+ storage->m_vector[storage->m_length].set(exec->globalData(), this, value);
+ ++storage->m_numValuesInVector;
+ ++storage->m_length;
checkConsistency();
return;
}
}
}
- putSlowCase(exec, m_storage->m_length++, value);
+ putSlowCase(exec, storage->m_length++, value);
+}
+
+void JSArray::shiftCount(ExecState* exec, int count)
+{
+ ASSERT(count > 0);
+
+ ArrayStorage* storage = m_storage;
+
+ unsigned oldLength = storage->m_length;
+
+ if (!oldLength)
+ return;
+
+ if (oldLength != storage->m_numValuesInVector) {
+ // If m_length and m_numValuesInVector aren't the same, we have a sparse vector
+ // which means we need to go through each entry looking for the the "empty"
+ // slots and then fill them with possible properties. See ECMA spec.
+ // 15.4.4.9 steps 11 through 13.
+ for (unsigned i = count; i < oldLength; ++i) {
+ if ((i >= m_vectorLength) || (!m_storage->m_vector[i])) {
+ PropertySlot slot(this);
+ JSValue p = prototype();
+ if ((!p.isNull()) && (asObject(p)->getPropertySlot(exec, i, slot)))
+ put(exec, i, slot.getValue(exec, i));
+ }
+ }
+
+ storage = m_storage; // The put() above could have grown the vector and realloc'ed storage.
+
+ // Need to decrement numValuesInvector based on number of real entries
+ for (unsigned i = 0; i < (unsigned)count; ++i)
+ if ((i < m_vectorLength) && (storage->m_vector[i]))
+ --storage->m_numValuesInVector;
+ } else
+ storage->m_numValuesInVector -= count;
+
+ storage->m_length -= count;
+
+ if (m_vectorLength) {
+ count = min(m_vectorLength, (unsigned)count);
+
+ m_vectorLength -= count;
+
+ if (m_vectorLength) {
+ char* newBaseStorage = reinterpret_cast<char*>(storage) + count * sizeof(JSValue);
+ memmove(newBaseStorage, storage, storageSize(0));
+ m_storage = reinterpret_cast_ptr<ArrayStorage*>(newBaseStorage);
+
+ m_indexBias += count;
+ }
+ }
+}
+
+void JSArray::unshiftCount(ExecState* exec, int count)
+{
+ ArrayStorage* storage = m_storage;
+
+ ASSERT(m_indexBias >= 0);
+ ASSERT(count >= 0);
+
+ unsigned length = storage->m_length;
+
+ if (length != storage->m_numValuesInVector) {
+ // If m_length and m_numValuesInVector aren't the same, we have a sparse vector
+ // which means we need to go through each entry looking for the the "empty"
+ // slots and then fill them with possible properties. See ECMA spec.
+ // 15.4.4.13 steps 8 through 10.
+ for (unsigned i = 0; i < length; ++i) {
+ if ((i >= m_vectorLength) || (!m_storage->m_vector[i])) {
+ PropertySlot slot(this);
+ JSValue p = prototype();
+ if ((!p.isNull()) && (asObject(p)->getPropertySlot(exec, i, slot)))
+ put(exec, i, slot.getValue(exec, i));
+ }
+ }
+ }
+
+ storage = m_storage; // The put() above could have grown the vector and realloc'ed storage.
+
+ if (m_indexBias >= count) {
+ m_indexBias -= count;
+ char* newBaseStorage = reinterpret_cast<char*>(storage) - count * sizeof(JSValue);
+ memmove(newBaseStorage, storage, storageSize(0));
+ m_storage = reinterpret_cast_ptr<ArrayStorage*>(newBaseStorage);
+ m_vectorLength += count;
+ } else if (!increaseVectorPrefixLength(m_vectorLength + count)) {
+ throwOutOfMemoryError(exec);
+ return;
+ }
+
+ WriteBarrier<Unknown>* vector = m_storage->m_vector;
+ for (int i = 0; i < count; i++)
+ vector[i].clear();
}
-void JSArray::markChildren(MarkStack& markStack)
+void JSArray::visitChildren(SlotVisitor& visitor)
{
- markChildrenDirect(markStack);
+ ASSERT_GC_OBJECT_INHERITS(this, &s_info);
+ COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
+ ASSERT(structure()->typeInfo().overridesVisitChildren());
+ visitChildrenDirect(visitor);
}
static int compareNumbersForQSort(const void* a, const void* b)
{
const ValueStringPair* va = static_cast<const ValueStringPair*>(a);
const ValueStringPair* vb = static_cast<const ValueStringPair*>(b);
- return compare(va->second, vb->second);
+ return codePointCompare(va->second, vb->second);
}
void JSArray::sortNumeric(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData)
{
+ ArrayStorage* storage = m_storage;
+
unsigned lengthNotIncludingUndefined = compactForSorting();
- if (m_storage->m_sparseValueMap) {
+ if (storage->m_sparseValueMap) {
throwOutOfMemoryError(exec);
return;
}
return;
bool allValuesAreNumbers = true;
- size_t size = m_storage->m_numValuesInVector;
+ size_t size = storage->m_numValuesInVector;
for (size_t i = 0; i < size; ++i) {
- if (!m_storage->m_vector[i].isNumber()) {
+ if (!storage->m_vector[i].isNumber()) {
allValuesAreNumbers = false;
break;
}
// For numeric comparison, which is fast, qsort is faster than mergesort. We
// also don't require mergesort's stability, since there's no user visible
// side-effect from swapping the order of equal primitive values.
- qsort(m_storage->m_vector, size, sizeof(JSValue), compareNumbersForQSort);
+ qsort(storage->m_vector, size, sizeof(JSValue), compareNumbersForQSort);
checkConsistency(SortConsistencyCheck);
}
void JSArray::sort(ExecState* exec)
{
+ ArrayStorage* storage = m_storage;
+
unsigned lengthNotIncludingUndefined = compactForSorting();
- if (m_storage->m_sparseValueMap) {
+ if (storage->m_sparseValueMap) {
throwOutOfMemoryError(exec);
return;
}
Heap::heap(this)->pushTempSortVector(&values);
for (size_t i = 0; i < lengthNotIncludingUndefined; i++) {
- JSValue value = m_storage->m_vector[i];
+ JSValue value = storage->m_vector[i].get();
ASSERT(!value.isUndefined());
values[i].first = value;
}
// increase the length to handle the orignal number of actual values.
if (m_vectorLength < lengthNotIncludingUndefined)
increaseVectorLength(lengthNotIncludingUndefined);
- if (m_storage->m_length < lengthNotIncludingUndefined)
- m_storage->m_length = lengthNotIncludingUndefined;
-
+ if (storage->m_length < lengthNotIncludingUndefined)
+ storage->m_length = lengthNotIncludingUndefined;
+
+ JSGlobalData& globalData = exec->globalData();
for (size_t i = 0; i < lengthNotIncludingUndefined; i++)
- m_storage->m_vector[i] = values[i].first;
+ storage->m_vector[i].set(globalData, this, values[i].first);
Heap::heap(this)->popTempSortVector(&values);
{
checkConsistency();
+ ArrayStorage* storage = m_storage;
+
// FIXME: This ignores exceptions raised in the compare function or in toNumber.
// The maximum tree depth is compiled in - but the caller is clearly up to no good
// if a larger array is passed.
- ASSERT(m_storage->m_length <= static_cast<unsigned>(std::numeric_limits<int>::max()));
- if (m_storage->m_length > static_cast<unsigned>(std::numeric_limits<int>::max()))
+ ASSERT(storage->m_length <= static_cast<unsigned>(std::numeric_limits<int>::max()));
+ if (storage->m_length > static_cast<unsigned>(std::numeric_limits<int>::max()))
return;
- if (!m_storage->m_length)
- return;
+ unsigned usedVectorLength = min(storage->m_length, m_vectorLength);
+ unsigned nodeCount = usedVectorLength + (storage->m_sparseValueMap ? storage->m_sparseValueMap->size() : 0);
- unsigned usedVectorLength = min(m_storage->m_length, m_vectorLength);
+ if (!nodeCount)
+ return;
AVLTree<AVLTreeAbstractorForArrayCompare, 44> tree; // Depth 44 is enough for 2^31 items
tree.abstractor().m_exec = exec;
tree.abstractor().m_compareCallType = callType;
tree.abstractor().m_compareCallData = &callData;
tree.abstractor().m_globalThisValue = exec->globalThisValue();
- tree.abstractor().m_nodes.resize(usedVectorLength + (m_storage->m_sparseValueMap ? m_storage->m_sparseValueMap->size() : 0));
+ tree.abstractor().m_nodes.grow(nodeCount);
if (callType == CallTypeJS)
- tree.abstractor().m_cachedCall.set(new CachedCall(exec, asFunction(compareFunction), 2, exec->exceptionSlot()));
+ tree.abstractor().m_cachedCall = adoptPtr(new CachedCall(exec, asFunction(compareFunction), 2));
if (!tree.abstractor().m_nodes.begin()) {
throwOutOfMemoryError(exec);
// Iterate over the array, ignoring missing values, counting undefined ones, and inserting all other ones into the tree.
for (; numDefined < usedVectorLength; ++numDefined) {
- JSValue v = m_storage->m_vector[numDefined];
+ JSValue v = storage->m_vector[numDefined].get();
if (!v || v.isUndefined())
break;
tree.abstractor().m_nodes[numDefined].value = v;
tree.insert(numDefined);
}
for (unsigned i = numDefined; i < usedVectorLength; ++i) {
- JSValue v = m_storage->m_vector[i];
+ JSValue v = storage->m_vector[i].get();
if (v) {
if (v.isUndefined())
++numUndefined;
unsigned newUsedVectorLength = numDefined + numUndefined;
- if (SparseArrayValueMap* map = m_storage->m_sparseValueMap) {
+ if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
newUsedVectorLength += map->size();
if (newUsedVectorLength > m_vectorLength) {
// Check that it is possible to allocate an array large enough to hold all the entries.
return;
}
}
+
+ storage = m_storage;
SparseArrayValueMap::iterator end = map->end();
for (SparseArrayValueMap::iterator it = map->begin(); it != end; ++it) {
- tree.abstractor().m_nodes[numDefined].value = it->second;
+ tree.abstractor().m_nodes[numDefined].value = it->second.get();
tree.insert(numDefined);
++numDefined;
}
delete map;
- m_storage->m_sparseValueMap = 0;
+ storage->m_sparseValueMap = 0;
}
ASSERT(tree.abstractor().m_nodes.size() >= numDefined);
// Copy the values back into m_storage.
AVLTree<AVLTreeAbstractorForArrayCompare, 44>::Iterator iter;
iter.start_iter_least(tree);
+ JSGlobalData& globalData = exec->globalData();
for (unsigned i = 0; i < numDefined; ++i) {
- m_storage->m_vector[i] = tree.abstractor().m_nodes[*iter].value;
+ storage->m_vector[i].set(globalData, this, tree.abstractor().m_nodes[*iter].value);
++iter;
}
// Put undefined values back in.
for (unsigned i = numDefined; i < newUsedVectorLength; ++i)
- m_storage->m_vector[i] = jsUndefined();
+ storage->m_vector[i].setUndefined();
// Ensure that unused values in the vector are zeroed out.
for (unsigned i = newUsedVectorLength; i < usedVectorLength; ++i)
- m_storage->m_vector[i] = JSValue();
+ storage->m_vector[i].clear();
- m_storage->m_numValuesInVector = newUsedVectorLength;
+ storage->m_numValuesInVector = newUsedVectorLength;
checkConsistency(SortConsistencyCheck);
}
void JSArray::fillArgList(ExecState* exec, MarkedArgumentBuffer& args)
{
- JSValue* vector = m_storage->m_vector;
- unsigned vectorEnd = min(m_storage->m_length, m_vectorLength);
+ ArrayStorage* storage = m_storage;
+
+ WriteBarrier<Unknown>* vector = storage->m_vector;
+ unsigned vectorEnd = min(storage->m_length, m_vectorLength);
unsigned i = 0;
for (; i < vectorEnd; ++i) {
- JSValue& v = vector[i];
+ WriteBarrier<Unknown>& v = vector[i];
if (!v)
break;
- args.append(v);
+ args.append(v.get());
}
- for (; i < m_storage->m_length; ++i)
+ for (; i < storage->m_length; ++i)
args.append(get(exec, i));
}
{
ASSERT(m_storage->m_length >= maxSize);
UNUSED_PARAM(maxSize);
- JSValue* vector = m_storage->m_vector;
+ WriteBarrier<Unknown>* vector = m_storage->m_vector;
unsigned vectorEnd = min(maxSize, m_vectorLength);
unsigned i = 0;
for (; i < vectorEnd; ++i) {
- JSValue& v = vector[i];
+ WriteBarrier<Unknown>& v = vector[i];
if (!v)
break;
- buffer[i] = v;
+ buffer[i] = v.get();
}
for (; i < maxSize; ++i)
ArrayStorage* storage = m_storage;
- unsigned usedVectorLength = min(m_storage->m_length, m_vectorLength);
+ unsigned usedVectorLength = min(storage->m_length, m_vectorLength);
unsigned numDefined = 0;
unsigned numUndefined = 0;
for (; numDefined < usedVectorLength; ++numDefined) {
- JSValue v = storage->m_vector[numDefined];
+ JSValue v = storage->m_vector[numDefined].get();
if (!v || v.isUndefined())
break;
}
+
for (unsigned i = numDefined; i < usedVectorLength; ++i) {
- JSValue v = storage->m_vector[i];
+ JSValue v = storage->m_vector[i].get();
if (v) {
if (v.isUndefined())
++numUndefined;
else
- storage->m_vector[numDefined++] = v;
+ storage->m_vector[numDefined++].setWithoutWriteBarrier(v);
}
}
// exception is thrown by caller.
if ((newUsedVectorLength > MAX_STORAGE_VECTOR_LENGTH) || !increaseVectorLength(newUsedVectorLength))
return 0;
+
storage = m_storage;
}
SparseArrayValueMap::iterator end = map->end();
for (SparseArrayValueMap::iterator it = map->begin(); it != end; ++it)
- storage->m_vector[numDefined++] = it->second;
+ storage->m_vector[numDefined++].setWithoutWriteBarrier(it->second.get());
delete map;
storage->m_sparseValueMap = 0;
}
for (unsigned i = numDefined; i < newUsedVectorLength; ++i)
- storage->m_vector[i] = jsUndefined();
+ storage->m_vector[i].setUndefined();
for (unsigned i = newUsedVectorLength; i < usedVectorLength; ++i)
- storage->m_vector[i] = JSValue();
+ storage->m_vector[i].clear();
storage->m_numValuesInVector = newUsedVectorLength;
void JSArray::checkConsistency(ConsistencyCheckType type)
{
- ASSERT(m_storage);
+ ArrayStorage* storage = m_storage;
+
+ ASSERT(storage);
if (type == SortConsistencyCheck)
- ASSERT(!m_storage->m_sparseValueMap);
+ ASSERT(!storage->m_sparseValueMap);
unsigned numValuesInVector = 0;
for (unsigned i = 0; i < m_vectorLength; ++i) {
- if (JSValue value = m_storage->m_vector[i]) {
- ASSERT(i < m_storage->m_length);
+ if (JSValue value = storage->m_vector[i]) {
+ ASSERT(i < storage->m_length);
if (type != DestructorConsistencyCheck)
- value->type(); // Likely to crash if the object was deallocated.
+ value.isUndefined(); // Likely to crash if the object was deallocated.
++numValuesInVector;
} else {
if (type == SortConsistencyCheck)
- ASSERT(i >= m_storage->m_numValuesInVector);
+ ASSERT(i >= storage->m_numValuesInVector);
}
}
- ASSERT(numValuesInVector == m_storage->m_numValuesInVector);
- ASSERT(numValuesInVector <= m_storage->m_length);
+ ASSERT(numValuesInVector == storage->m_numValuesInVector);
+ ASSERT(numValuesInVector <= storage->m_length);
- if (m_storage->m_sparseValueMap) {
- SparseArrayValueMap::iterator end = m_storage->m_sparseValueMap->end();
- for (SparseArrayValueMap::iterator it = m_storage->m_sparseValueMap->begin(); it != end; ++it) {
+ if (storage->m_sparseValueMap) {
+ SparseArrayValueMap::iterator end = storage->m_sparseValueMap->end();
+ for (SparseArrayValueMap::iterator it = storage->m_sparseValueMap->begin(); it != end; ++it) {
unsigned index = it->first;
- ASSERT(index < m_storage->m_length);
- ASSERT(index >= m_vectorLength);
+ ASSERT(index < storage->m_length);
+ ASSERT(index >= storage->m_vectorLength);
ASSERT(index <= MAX_ARRAY_INDEX);
ASSERT(it->second);
if (type != DestructorConsistencyCheck)
- it->second->type(); // Likely to crash if the object was deallocated.
+ it->second.isUndefined(); // Likely to crash if the object was deallocated.
}
}
}
#include "JSObject.h"
+#define CHECK_ARRAY_CONSISTENCY 0
+
namespace JSC {
- typedef HashMap<unsigned, JSValue> SparseArrayValueMap;
+ typedef HashMap<unsigned, WriteBarrier<Unknown> > SparseArrayValueMap;
+ // This struct holds the actual data values of an array. A JSArray object points to it's contained ArrayStorage
+ // struct by pointing to m_vector. To access the contained ArrayStorage struct, use the getStorage() and
+ // setStorage() methods. It is important to note that there may be space before the ArrayStorage that
+ // is used to quick unshift / shift operation. The actual allocated pointer is available by using:
+ // getStorage() - m_indexBias * sizeof(JSValue)
struct ArrayStorage {
- unsigned m_length;
+ unsigned m_length; // The "length" property on the array
unsigned m_numValuesInVector;
SparseArrayValueMap* m_sparseValueMap;
void* subclassData; // A JSArray subclass can use this to fill the vector lazily.
+ void* m_allocBase; // Pointer to base address returned by malloc(). Keeping this pointer does eliminate false positives from the leak detector.
size_t reportedMapCapacity;
- JSValue m_vector[1];
+#if CHECK_ARRAY_CONSISTENCY
+ bool m_inCompactInitialization;
+#endif
+ WriteBarrier<Unknown> m_vector[1];
};
- class JSArray : public JSObject {
- friend class JIT;
+ // The CreateCompact creation mode is used for fast construction of arrays
+ // whose size and contents are known at time of creation.
+ //
+ // There are two obligations when using this mode:
+ //
+ // - uncheckedSetIndex() must be used when initializing the array.
+ // - setLength() must be called after initialization.
+
+ enum ArrayCreationMode { CreateCompact, CreateInitialized };
+
+ class JSArray : public JSNonFinalObject {
friend class Walker;
public:
- explicit JSArray(NonNullPassRefPtr<Structure>);
- JSArray(NonNullPassRefPtr<Structure>, unsigned initialLength);
- JSArray(NonNullPassRefPtr<Structure>, const ArgList& initialValues);
+ JSArray(VPtrStealingHackType);
+
+ explicit JSArray(JSGlobalData&, Structure*);
+ JSArray(JSGlobalData&, Structure*, unsigned initialLength, ArrayCreationMode);
+ JSArray(JSGlobalData&, Structure*, const ArgList& initialValues);
virtual ~JSArray();
virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
virtual void put(ExecState*, unsigned propertyName, JSValue); // FIXME: Make protected and add setItem.
- static JS_EXPORTDATA const ClassInfo info;
-
+ static JS_EXPORTDATA const ClassInfo s_info;
+
unsigned length() const { return m_storage->m_length; }
void setLength(unsigned); // OK to use on new arrays, but not if it might be a RegExpMatchArray.
void push(ExecState*, JSValue);
JSValue pop();
+ void shiftCount(ExecState*, int count);
+ void unshiftCount(ExecState*, int count);
+
bool canGetIndex(unsigned i) { return i < m_vectorLength && m_storage->m_vector[i]; }
JSValue getIndex(unsigned i)
{
ASSERT(canGetIndex(i));
- return m_storage->m_vector[i];
+ return m_storage->m_vector[i].get();
}
bool canSetIndex(unsigned i) { return i < m_vectorLength; }
- void setIndex(unsigned i, JSValue v)
+ void setIndex(JSGlobalData& globalData, unsigned i, JSValue v)
{
ASSERT(canSetIndex(i));
- JSValue& x = m_storage->m_vector[i];
+
+ WriteBarrier<Unknown>& x = m_storage->m_vector[i];
if (!x) {
- ++m_storage->m_numValuesInVector;
- if (i >= m_storage->m_length)
- m_storage->m_length = i + 1;
+ ArrayStorage *storage = m_storage;
+ ++storage->m_numValuesInVector;
+ if (i >= storage->m_length)
+ storage->m_length = i + 1;
}
- x = v;
+ x.set(globalData, this, v);
+ }
+
+ void uncheckedSetIndex(JSGlobalData& globalData, unsigned i, JSValue v)
+ {
+ ASSERT(canSetIndex(i));
+ ArrayStorage *storage = m_storage;
+#if CHECK_ARRAY_CONSISTENCY
+ ASSERT(storage->m_inCompactInitialization);
+#endif
+ storage->m_vector[i].set(globalData, this, v);
}
void fillArgList(ExecState*, MarkedArgumentBuffer&);
void copyToRegisters(ExecState*, Register*, uint32_t);
- static PassRefPtr<Structure> createStructure(JSValue prototype)
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
+ return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
}
- inline void markChildrenDirect(MarkStack& markStack);
+ inline void visitChildrenDirect(SlotVisitor&);
+
+ static ptrdiff_t storageOffset()
+ {
+ return OBJECT_OFFSETOF(JSArray, m_storage);
+ }
+
+ static ptrdiff_t vectorLengthOffset()
+ {
+ return OBJECT_OFFSETOF(JSArray, m_vectorLength);
+ }
protected:
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesMarkChildren | OverridesGetPropertyNames | JSObject::StructureFlags;
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | JSObject::StructureFlags;
virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
virtual bool deleteProperty(ExecState*, unsigned propertyName);
virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties);
- virtual void markChildren(MarkStack&);
+ virtual void visitChildren(SlotVisitor&);
void* subclassData() const;
void setSubclassData(void*);
private:
- virtual const ClassInfo* classInfo() const { return &info; }
-
bool getOwnPropertySlotSlowCase(ExecState*, unsigned propertyName, PropertySlot&);
void putSlowCase(ExecState*, unsigned propertyName, JSValue);
+ unsigned getNewVectorLength(unsigned desiredLength);
bool increaseVectorLength(unsigned newLength);
+ bool increaseVectorPrefixLength(unsigned newLength);
unsigned compactForSorting();
enum ConsistencyCheckType { NormalConsistencyCheck, DestructorConsistencyCheck, SortConsistencyCheck };
void checkConsistency(ConsistencyCheckType = NormalConsistencyCheck);
- unsigned m_vectorLength;
- ArrayStorage* m_storage;
+ unsigned m_vectorLength; // The valid length of m_vector
+ int m_indexBias; // The number of JSValue sized blocks before ArrayStorage.
+ ArrayStorage *m_storage;
};
JSArray* asArray(JSValue);
inline JSArray* asArray(JSCell* cell)
{
- ASSERT(cell->inherits(&JSArray::info));
+ ASSERT(cell->inherits(&JSArray::s_info));
return static_cast<JSArray*>(cell);
}
return asArray(value.asCell());
}
- inline bool isJSArray(JSGlobalData* globalData, JSValue v)
- {
- return v.isCell() && v.asCell()->vptr() == globalData->jsArrayVPtr;
- }
inline bool isJSArray(JSGlobalData* globalData, JSCell* cell) { return cell->vptr() == globalData->jsArrayVPtr; }
+ inline bool isJSArray(JSGlobalData* globalData, JSValue v) { return v.isCell() && isJSArray(globalData, v.asCell()); }
- inline void JSArray::markChildrenDirect(MarkStack& markStack)
+ inline void JSArray::visitChildrenDirect(SlotVisitor& visitor)
{
- JSObject::markChildrenDirect(markStack);
+ JSObject::visitChildrenDirect(visitor);
ArrayStorage* storage = m_storage;
unsigned usedVectorLength = std::min(storage->m_length, m_vectorLength);
- markStack.appendValues(storage->m_vector, usedVectorLength, MayContainNullValues);
+ visitor.appendValues(storage->m_vector, usedVectorLength, MayContainNullValues);
if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
SparseArrayValueMap::iterator end = map->end();
for (SparseArrayValueMap::iterator it = map->begin(); it != end; ++it)
- markStack.append(it->second);
+ visitor.append(&it->second);
}
}
- inline void MarkStack::markChildren(JSCell* cell)
+ // Rule from ECMA 15.2 about what an array index is.
+ // Must exactly match string form of an unsigned integer, and be less than 2^32 - 1.
+ inline unsigned Identifier::toArrayIndex(bool& ok) const
{
- ASSERT(Heap::isCellMarked(cell));
- if (!cell->structure()->typeInfo().overridesMarkChildren()) {
-#ifdef NDEBUG
- asObject(cell)->markChildrenDirect(*this);
-#else
- ASSERT(!m_isCheckingForDefaultMarkViolation);
- m_isCheckingForDefaultMarkViolation = true;
- cell->markChildren(*this);
- ASSERT(m_isCheckingForDefaultMarkViolation);
- m_isCheckingForDefaultMarkViolation = false;
-#endif
- return;
- }
- if (cell->vptr() == m_jsArrayVPtr) {
- asArray(cell)->markChildrenDirect(*this);
- return;
- }
- cell->markChildren(*this);
+ unsigned i = toUInt32(ok);
+ if (ok && i >= 0xFFFFFFFFU)
+ ok = false;
+ return i;
}
- inline void MarkStack::drain()
- {
- while (!m_markSets.isEmpty() || !m_values.isEmpty()) {
- while (!m_markSets.isEmpty() && m_values.size() < 50) {
- ASSERT(!m_markSets.isEmpty());
- MarkSet& current = m_markSets.last();
- ASSERT(current.m_values);
- JSValue* end = current.m_end;
- ASSERT(current.m_values);
- ASSERT(current.m_values != end);
- findNextUnmarkedNullValue:
- ASSERT(current.m_values != end);
- JSValue value = *current.m_values;
- current.m_values++;
-
- JSCell* cell;
- if (!value || !value.isCell() || Heap::isCellMarked(cell = value.asCell())) {
- if (current.m_values == end) {
- m_markSets.removeLast();
- continue;
- }
- goto findNextUnmarkedNullValue;
- }
-
- Heap::markCell(cell);
- if (cell->structure()->typeInfo().type() < CompoundType) {
- if (current.m_values == end) {
- m_markSets.removeLast();
- continue;
- }
- goto findNextUnmarkedNullValue;
- }
-
- if (current.m_values == end)
- m_markSets.removeLast();
-
- markChildren(cell);
- }
- while (!m_values.isEmpty())
- markChildren(m_values.removeLast());
- }
- }
-
} // namespace JSC
#endif // JSArray_h
namespace JSC {
-const ClassInfo JSByteArray::s_defaultInfo = { "ByteArray", 0, 0, 0 };
+const ClassInfo JSByteArray::s_defaultInfo = { "ByteArray", &Base::s_info, 0, 0 };
-JSByteArray::JSByteArray(ExecState* exec, NonNullPassRefPtr<Structure> structure, ByteArray* storage, const JSC::ClassInfo* classInfo)
- : JSObject(structure)
+JSByteArray::JSByteArray(ExecState* exec, Structure* structure, ByteArray* storage)
+ : JSNonFinalObject(exec->globalData(), structure)
, m_storage(storage)
- , m_classInfo(classInfo)
{
- putDirect(exec->globalData().propertyNames->length, jsNumber(exec, m_storage->length()), ReadOnly | DontDelete);
+ putDirect(exec->globalData(), exec->globalData().propertyNames->length, jsNumber(m_storage->length()), ReadOnly | DontDelete);
}
#if !ASSERT_DISABLED
#endif
-PassRefPtr<Structure> JSByteArray::createStructure(JSValue prototype)
+Structure* JSByteArray::createStructure(JSGlobalData& globalData, JSValue prototype, const JSC::ClassInfo* classInfo)
{
- PassRefPtr<Structure> result = Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
- return result;
+ return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, classInfo);
}
bool JSByteArray::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
{
bool ok;
- unsigned index = propertyName.toUInt32(&ok, false);
+ unsigned index = propertyName.toUInt32(ok);
if (ok && canAccessIndex(index)) {
slot.setValue(getIndex(exec, index));
return true;
bool JSByteArray::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
{
bool ok;
- unsigned index = propertyName.toUInt32(&ok, false);
+ unsigned index = propertyName.toUInt32(ok);
if (ok && canAccessIndex(index)) {
descriptor.setDescriptor(getIndex(exec, index), DontDelete);
return true;
void JSByteArray::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
{
bool ok;
- unsigned index = propertyName.toUInt32(&ok, false);
+ unsigned index = propertyName.toUInt32(ok);
if (ok) {
setIndex(exec, index, value);
return;
namespace JSC {
- class JSByteArray : public JSObject {
+ class JSByteArray : public JSNonFinalObject {
friend class JSGlobalData;
public:
+ typedef JSNonFinalObject Base;
+
bool canAccessIndex(unsigned i) { return i < m_storage->length(); }
- JSValue getIndex(ExecState* exec, unsigned i)
+ JSValue getIndex(ExecState*, unsigned i)
{
ASSERT(canAccessIndex(i));
- return jsNumber(exec, m_storage->data()[i]);
+ return jsNumber(m_storage->data()[i]);
}
void setIndex(unsigned i, int value)
setIndex(i, byteValue);
}
- JSByteArray(ExecState* exec, NonNullPassRefPtr<Structure>, WTF::ByteArray* storage, const JSC::ClassInfo* = &s_defaultInfo);
- static PassRefPtr<Structure> createStructure(JSValue prototype);
-
+ JSByteArray(ExecState*, Structure*, WTF::ByteArray* storage);
+ static Structure* createStructure(JSGlobalData&, JSValue prototype, const JSC::ClassInfo* = &s_defaultInfo);
+
virtual bool getOwnPropertySlot(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::PropertySlot&);
virtual bool getOwnPropertySlot(JSC::ExecState*, unsigned propertyName, JSC::PropertySlot&);
virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
virtual void getOwnPropertyNames(JSC::ExecState*, JSC::PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties);
- virtual const ClassInfo* classInfo() const { return m_classInfo; }
static const ClassInfo s_defaultInfo;
size_t length() const { return m_storage->length(); }
static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesGetPropertyNames | JSObject::StructureFlags;
private:
- enum VPtrStealingHackType { VPtrStealingHack };
- JSByteArray(VPtrStealingHackType)
- : JSObject(createStructure(jsNull()))
- , m_classInfo(0)
+ JSByteArray(VPtrStealingHackType)
+ : JSNonFinalObject(VPtrStealingHack)
{
}
RefPtr<WTF::ByteArray> m_storage;
- const ClassInfo* m_classInfo;
};
JSByteArray* asByteArray(JSValue value);
inline JSByteArray* asByteArray(JSValue value)
{
- return static_cast<JSByteArray*>(asCell(value));
+ return static_cast<JSByteArray*>(value.asCell());
}
inline bool isJSByteArray(JSGlobalData* globalData, JSValue v) { return v.isCell() && v.asCell()->vptr() == globalData->jsByteArrayVPtr; }
#endif // !(defined NAN && defined INFINITY)
+const ClassInfo JSCell::s_dummyCellInfo = { "DummyCell", 0, 0, 0 };
+
bool JSCell::getUInt32(uint32_t&) const
{
return false;
// This is not a general purpose implementation of getOwnPropertySlot.
// It should only be called by JSValue::get.
// It calls getPropertySlot, not getOwnPropertySlot.
- JSObject* object = toObject(exec);
+ JSObject* object = toObject(exec, exec->lexicalGlobalObject());
slot.setBase(object);
if (!object->getPropertySlot(exec, identifier, slot))
slot.setUndefined();
// This is not a general purpose implementation of getOwnPropertySlot.
// It should only be called by JSValue::get.
// It calls getPropertySlot, not getOwnPropertySlot.
- JSObject* object = toObject(exec);
+ JSObject* object = toObject(exec, exec->lexicalGlobalObject());
slot.setBase(object);
if (!object->getPropertySlot(exec, identifier, slot))
slot.setUndefined();
void JSCell::put(ExecState* exec, const Identifier& identifier, JSValue value, PutPropertySlot& slot)
{
- toObject(exec)->put(exec, identifier, value, slot);
+ toObject(exec, exec->lexicalGlobalObject())->put(exec, identifier, value, slot);
}
void JSCell::put(ExecState* exec, unsigned identifier, JSValue value)
{
- toObject(exec)->put(exec, identifier, value);
+ toObject(exec, exec->lexicalGlobalObject())->put(exec, identifier, value);
}
bool JSCell::deleteProperty(ExecState* exec, const Identifier& identifier)
{
- return toObject(exec)->deleteProperty(exec, identifier);
+ return toObject(exec, exec->lexicalGlobalObject())->deleteProperty(exec, identifier);
}
bool JSCell::deleteProperty(ExecState* exec, unsigned identifier)
{
- return toObject(exec)->deleteProperty(exec, identifier);
+ return toObject(exec, exec->lexicalGlobalObject())->deleteProperty(exec, identifier);
}
JSObject* JSCell::toThisObject(ExecState* exec) const
{
- return toObject(exec);
-}
-
-const ClassInfo* JSCell::classInfo() const
-{
- return 0;
+ return toObject(exec, exec->lexicalGlobalObject());
}
JSValue JSCell::getJSNumber()
return UString();
}
-JSObject* JSCell::toObject(ExecState*) const
+JSObject* JSCell::toObject(ExecState*, JSGlobalObject*) const
{
ASSERT_NOT_REACHED();
return 0;
}
+bool isZombie(const JSCell* cell)
+{
+#if ENABLE(JSC_ZOMBIES)
+ return cell && cell->isZombie();
+#else
+ UNUSED_PARAM(cell);
+ return false;
+#endif
+}
+
+void slowValidateCell(JSCell* cell)
+{
+ ASSERT_GC_OBJECT_LOOKS_VALID(cell);
+}
+
} // namespace JSC
#ifndef JSCell_h
#define JSCell_h
-#include "Collector.h"
-#include "JSImmediate.h"
-#include "JSValue.h"
+#include "CallData.h"
+#include "CallFrame.h"
+#include "ConstructData.h"
+#include "Heap.h"
+#include "JSLock.h"
+#include "JSValueInlineMethods.h"
#include "MarkStack.h"
-#include "Structure.h"
+#include "WriteBarrier.h"
#include <wtf/Noncopyable.h>
namespace JSC {
- class JSCell : public NoncopyableCustomAllocated {
+ class JSGlobalObject;
+ class Structure;
+
+#if COMPILER(MSVC)
+ // If WTF_MAKE_NONCOPYABLE is applied to JSCell we end up with a bunch of
+ // undefined references to the JSCell copy constructor and assignment operator
+ // when linking JavaScriptCore.
+ class MSVCBugWorkaround {
+ WTF_MAKE_NONCOPYABLE(MSVCBugWorkaround);
+
+ protected:
+ MSVCBugWorkaround() { }
+ ~MSVCBugWorkaround() { }
+ };
+
+ class JSCell : MSVCBugWorkaround {
+#else
+ class JSCell {
+ WTF_MAKE_NONCOPYABLE(JSCell);
+#endif
+
+ friend class ExecutableBase;
friend class GetterSetter;
friend class Heap;
- friend class JIT;
- friend class JSNumberCell;
friend class JSObject;
friend class JSPropertyNameIterator;
friend class JSString;
friend class JSAPIValueWrapper;
friend class JSZombie;
friend class JSGlobalData;
+ friend class MarkedSpace;
+ friend class MarkedBlock;
+ friend class ScopeChainNode;
+ friend class Structure;
+ friend class StructureChain;
+ friend class RegExp;
+ enum CreatingEarlyCellTag { CreatingEarlyCell };
+
+ protected:
+ enum VPtrStealingHackType { VPtrStealingHack };
private:
- explicit JSCell(Structure*);
+ explicit JSCell(VPtrStealingHackType) { }
+ JSCell(JSGlobalData&, Structure*);
+ JSCell(JSGlobalData&, Structure*, CreatingEarlyCellTag);
virtual ~JSCell();
+ static const ClassInfo s_dummyCellInfo;
public:
- static PassRefPtr<Structure> createDummyStructure()
- {
- return Structure::create(jsNull(), TypeInfo(UnspecifiedType), AnonymousSlotCount);
- }
+ static Structure* createDummyStructure(JSGlobalData&);
// Querying the type.
-#if USE(JSVALUE32)
- bool isNumber() const;
-#endif
bool isString() const;
bool isObject() const;
virtual bool isGetterSetter() const;
virtual bool toBoolean(ExecState*) const;
virtual double toNumber(ExecState*) const;
virtual UString toString(ExecState*) const;
- virtual JSObject* toObject(ExecState*) const;
+ virtual JSObject* toObject(ExecState*, JSGlobalObject*) const;
// Garbage collection.
void* operator new(size_t, ExecState*);
void* operator new(size_t, JSGlobalData*);
void* operator new(size_t, void* placementNewDestination) { return placementNewDestination; }
- virtual void markChildren(MarkStack&);
+ virtual void visitChildren(SlotVisitor&);
#if ENABLE(JSC_ZOMBIES)
virtual bool isZombie() const { return false; }
#endif
// Object operations, with the toObject operation included.
- virtual const ClassInfo* classInfo() const;
+ const ClassInfo* classInfo() const;
virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
virtual void put(ExecState*, unsigned propertyName, JSValue);
virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
// property names, we want a similar interface with appropriate optimizations.)
bool fastGetOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
+ static ptrdiff_t structureOffset()
+ {
+ return OBJECT_OFFSETOF(JSCell, m_structure);
+ }
+
+#if ENABLE(GC_VALIDATION)
+ Structure* unvalidatedStructure() { return m_structure.unvalidatedGet(); }
+#endif
+
protected:
static const unsigned AnonymousSlotCount = 0;
virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
- Structure* m_structure;
+ WriteBarrier<Structure> m_structure;
};
- inline JSCell::JSCell(Structure* structure)
- : m_structure(structure)
- {
- }
-
- inline JSCell::~JSCell()
+ inline JSCell::JSCell(JSGlobalData& globalData, Structure* structure)
+ : m_structure(globalData, this, structure)
{
+ ASSERT(m_structure);
}
-#if USE(JSVALUE32)
- inline bool JSCell::isNumber() const
+ inline JSCell::JSCell(JSGlobalData& globalData, Structure* structure, CreatingEarlyCellTag)
{
- return m_structure->typeInfo().type() == NumberType;
- }
+#if ENABLE(GC_VALIDATION)
+ if (structure)
#endif
-
- inline bool JSCell::isObject() const
- {
- return m_structure->typeInfo().type() == ObjectType;
+ m_structure.setEarlyValue(globalData, this, structure);
+ // Very first set of allocations won't have a real structure.
+ ASSERT(m_structure || !globalData.dummyMarkableCellStructure);
}
- inline bool JSCell::isString() const
+ inline JSCell::~JSCell()
{
- return m_structure->typeInfo().type() == StringType;
+#if ENABLE(GC_VALIDATION)
+ m_structure.clear();
+#endif
}
inline Structure* JSCell::structure() const
{
- return m_structure;
+ return m_structure.get();
}
- inline void JSCell::markChildren(MarkStack&)
+ inline void JSCell::visitChildren(SlotVisitor& visitor)
{
- }
-
- inline void* JSCell::operator new(size_t size, JSGlobalData* globalData)
- {
- return globalData->heap.allocate(size);
- }
-
- inline void* JSCell::operator new(size_t size, ExecState* exec)
- {
- return exec->heap()->allocate(size);
+ visitor.append(&m_structure);
}
// --- JSValue inlines ----------------------------
return isCell() ? asCell()->getString(exec) : UString();
}
+ template <typename Base> UString HandleConverter<Base, Unknown>::getString(ExecState* exec) const
+ {
+ return jsValue().getString(exec);
+ }
+
inline JSObject* JSValue::getObject() const
{
return isCell() ? asCell()->getObject() : 0;
}
- inline CallType JSValue::getCallData(CallData& callData)
+ inline CallType getCallData(JSValue value, CallData& callData)
{
- return isCell() ? asCell()->getCallData(callData) : CallTypeNone;
+ CallType result = value.isCell() ? value.asCell()->getCallData(callData) : CallTypeNone;
+ ASSERT(result == CallTypeNone || value.isValidCallee());
+ return result;
}
- inline ConstructType JSValue::getConstructData(ConstructData& constructData)
+ inline ConstructType getConstructData(JSValue value, ConstructData& constructData)
{
- return isCell() ? asCell()->getConstructData(constructData) : ConstructTypeNone;
+ ConstructType result = value.isCell() ? value.asCell()->getConstructData(constructData) : ConstructTypeNone;
+ ASSERT(result == ConstructTypeNone || value.isValidCallee());
+ return result;
}
ALWAYS_INLINE bool JSValue::getUInt32(uint32_t& v) const
return false;
}
-#if !USE(JSVALUE32_64)
- ALWAYS_INLINE JSCell* JSValue::asCell() const
- {
- ASSERT(isCell());
- return m_ptr;
- }
-#endif // !USE(JSVALUE32_64)
-
inline JSValue JSValue::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const
{
return isCell() ? asCell()->toPrimitive(exec, preferredType) : asValue();
return isUndefined() ? nonInlineNaN() : 0; // null and false both convert to 0.
}
- inline bool JSValue::needsThisConversion() const
- {
- if (UNLIKELY(!isCell()))
- return true;
- return asCell()->structure()->typeInfo().needsThisConversion();
- }
-
inline JSValue JSValue::getJSNumber()
{
if (isInt32() || isDouble())
inline JSObject* JSValue::toObject(ExecState* exec) const
{
- return isCell() ? asCell()->toObject(exec) : toObjectSlowCase(exec);
+ return isCell() ? asCell()->toObject(exec, exec->lexicalGlobalObject()) : toObjectSlowCase(exec, exec->lexicalGlobalObject());
}
- inline JSObject* JSValue::toThisObject(ExecState* exec) const
+ inline JSObject* JSValue::toObject(ExecState* exec, JSGlobalObject* globalObject) const
{
- return isCell() ? asCell()->toThisObject(exec) : toThisObjectSlowCase(exec);
+ return isCell() ? asCell()->toObject(exec, globalObject) : toObjectSlowCase(exec, globalObject);
}
- ALWAYS_INLINE void MarkStack::append(JSCell* cell)
- {
- ASSERT(!m_isCheckingForDefaultMarkViolation);
- ASSERT(cell);
- if (Heap::isCellMarked(cell))
- return;
- Heap::markCell(cell);
- if (cell->structure()->typeInfo().type() >= CompoundType)
- m_values.append(cell);
- }
-
- ALWAYS_INLINE void MarkStack::append(JSValue value)
+ inline JSObject* JSValue::toThisObject(ExecState* exec) const
{
- ASSERT(value);
- if (value.isCell())
- append(value.asCell());
+ return isCell() ? asCell()->toThisObject(exec) : toThisObjectSlowCase(exec);
}
inline Heap* Heap::heap(JSValue v)
inline Heap* Heap::heap(JSCell* c)
{
- return cellBlock(c)->heap;
+ return MarkedSpace::heap(c);
}
#if ENABLE(JSC_ZOMBIES)
inline bool JSValue::isZombie() const
{
- return isCell() && asCell() && asCell()->isZombie();
+ return isCell() && asCell() > (JSCell*)0x1ffffffffL && asCell()->isZombie();
}
#endif
+
+ inline void* MarkedBlock::allocate()
+ {
+ while (m_nextAtom < m_endAtom) {
+ if (!m_marks.testAndSet(m_nextAtom)) {
+ JSCell* cell = reinterpret_cast<JSCell*>(&atoms()[m_nextAtom]);
+ m_nextAtom += m_atomsPerCell;
+ cell->~JSCell();
+ return cell;
+ }
+ m_nextAtom += m_atomsPerCell;
+ }
+
+ return 0;
+ }
+
+ inline MarkedSpace::SizeClass& MarkedSpace::sizeClassFor(size_t bytes)
+ {
+ ASSERT(bytes && bytes < maxCellSize);
+ if (bytes < preciseCutoff)
+ return m_preciseSizeClasses[(bytes - 1) / preciseStep];
+ return m_impreciseSizeClasses[(bytes - 1) / impreciseStep];
+ }
+
+ inline void* MarkedSpace::allocate(size_t bytes)
+ {
+ SizeClass& sizeClass = sizeClassFor(bytes);
+ return allocateFromSizeClass(sizeClass);
+ }
+
+ inline void* Heap::allocate(size_t bytes)
+ {
+ ASSERT(globalData()->identifierTable == wtfThreadData().currentIdentifierTable());
+ ASSERT(JSLock::lockCount() > 0);
+ ASSERT(JSLock::currentThreadIsHoldingLock());
+ ASSERT(bytes <= MarkedSpace::maxCellSize);
+ ASSERT(m_operationInProgress == NoOperation);
+
+ m_operationInProgress = Allocation;
+ void* result = m_markedSpace.allocate(bytes);
+ m_operationInProgress = NoOperation;
+ if (result)
+ return result;
+
+ return allocateSlowCase(bytes);
+ }
+
+ inline void* JSCell::operator new(size_t size, JSGlobalData* globalData)
+ {
+ JSCell* result = static_cast<JSCell*>(globalData->heap.allocate(size));
+ result->m_structure.clear();
+ return result;
+ }
+
+ inline void* JSCell::operator new(size_t size, ExecState* exec)
+ {
+ JSCell* result = static_cast<JSCell*>(exec->heap()->allocate(size));
+ result->m_structure.clear();
+ return result;
+ }
+
} // namespace JSC
#endif // JSCell_h
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "JSChunk.h"
+
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef JSChunk_h
+#define JSChunk_h
+
+
+
+#endif // JSChunk_h
#include "CodeBlock.h"
#include "CommonIdentifiers.h"
#include "CallFrame.h"
+#include "ExceptionHelpers.h"
#include "FunctionPrototype.h"
#include "JSGlobalObject.h"
+#include "JSNotAnObject.h"
#include "Interpreter.h"
#include "ObjectPrototype.h"
#include "Parser.h"
using namespace Unicode;
namespace JSC {
+EncodedJSValue JSC_HOST_CALL callHostFunctionAsConstructor(ExecState* exec)
+{
+ return throwVMError(exec, createNotAConstructorError(exec, exec->callee()));
+}
ASSERT_CLASS_FITS_IN_CELL(JSFunction);
-const ClassInfo JSFunction::info = { "Function", &InternalFunction::info, 0, 0 };
+const ClassInfo JSFunction::s_info = { "Function", &Base::s_info, 0, 0 };
bool JSFunction::isHostFunctionNonInline() const
{
return isHostFunction();
}
-JSFunction::JSFunction(NonNullPassRefPtr<Structure> structure)
- : Base(structure)
- , m_executable(adoptRef(new VPtrHackExecutable()))
+JSFunction::JSFunction(VPtrStealingHackType)
+ : Base(VPtrStealingHack)
{
}
-JSFunction::JSFunction(ExecState* exec, NonNullPassRefPtr<Structure> structure, int length, const Identifier& name, NativeExecutable* thunk, NativeFunction func)
- : Base(&exec->globalData(), structure, name)
-#if ENABLE(JIT)
- , m_executable(thunk)
-#endif
+JSFunction::JSFunction(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, int length, const Identifier& name, NativeExecutable* thunk)
+ : Base(globalObject, structure)
+ , m_executable(exec->globalData(), this, thunk)
+ , m_scopeChain(exec->globalData(), this, globalObject->globalScopeChain())
{
-#if ENABLE(JIT)
- setNativeFunction(func);
- putDirect(exec->propertyNames().length, jsNumber(exec, length), DontDelete | ReadOnly | DontEnum);
-#else
- UNUSED_PARAM(thunk);
- UNUSED_PARAM(length);
- UNUSED_PARAM(func);
- ASSERT_NOT_REACHED();
-#endif
+ ASSERT(inherits(&s_info));
+ putDirect(exec->globalData(), exec->globalData().propertyNames->name, jsString(exec, name.isNull() ? "" : name.ustring()), DontDelete | ReadOnly | DontEnum);
+ putDirect(exec->globalData(), exec->propertyNames().length, jsNumber(length), DontDelete | ReadOnly | DontEnum);
}
-JSFunction::JSFunction(ExecState* exec, NonNullPassRefPtr<Structure> structure, int length, const Identifier& name, NativeFunction func)
- : Base(&exec->globalData(), structure, name)
-#if ENABLE(JIT)
- , m_executable(exec->globalData().jitStubs->ctiNativeCallThunk())
-#endif
+JSFunction::JSFunction(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, int length, const Identifier& name, NativeFunction func)
+ : Base(globalObject, structure)
+ , m_scopeChain(exec->globalData(), this, globalObject->globalScopeChain())
{
-#if ENABLE(JIT)
- setNativeFunction(func);
- putDirect(exec->propertyNames().length, jsNumber(exec, length), DontDelete | ReadOnly | DontEnum);
-#else
- UNUSED_PARAM(length);
- UNUSED_PARAM(func);
- ASSERT_NOT_REACHED();
-#endif
+ ASSERT(inherits(&s_info));
+
+ // Can't do this during initialization because getHostFunction might do a GC allocation.
+ m_executable.set(exec->globalData(), this, exec->globalData().getHostFunction(func));
+
+ putDirect(exec->globalData(), exec->globalData().propertyNames->name, jsString(exec, name.isNull() ? "" : name.ustring()), DontDelete | ReadOnly | DontEnum);
+ putDirect(exec->globalData(), exec->propertyNames().length, jsNumber(length), DontDelete | ReadOnly | DontEnum);
}
-JSFunction::JSFunction(ExecState* exec, NonNullPassRefPtr<FunctionExecutable> executable, ScopeChainNode* scopeChainNode)
- : Base(&exec->globalData(), exec->lexicalGlobalObject()->functionStructure(), executable->name())
- , m_executable(executable)
+JSFunction::JSFunction(ExecState* exec, FunctionExecutable* executable, ScopeChainNode* scopeChainNode)
+ : Base(scopeChainNode->globalObject.get(), scopeChainNode->globalObject->functionStructure())
+ , m_executable(exec->globalData(), this, executable)
+ , m_scopeChain(exec->globalData(), this, scopeChainNode)
{
- setScopeChain(scopeChainNode);
+ ASSERT(inherits(&s_info));
+ const Identifier& name = static_cast<FunctionExecutable*>(m_executable.get())->name();
+ putDirect(exec->globalData(), exec->globalData().propertyNames->name, jsString(exec, name.isNull() ? "" : name.ustring()), DontDelete | ReadOnly | DontEnum);
}
JSFunction::~JSFunction()
{
ASSERT(vptr() == JSGlobalData::jsFunctionVPtr);
+}
- // JIT code for other functions may have had calls linked directly to the code for this function; these links
- // are based on a check for the this pointer value for this JSFunction - which will no longer be valid once
- // this memory is freed and may be reused (potentially for another, different JSFunction).
- if (!isHostFunction()) {
-#if ENABLE(JIT_OPTIMIZE_CALL)
- ASSERT(m_executable);
- if (jsExecutable()->isGenerated())
- jsExecutable()->generatedBytecode().unlinkCallers();
-#endif
- scopeChain().~ScopeChain(); // FIXME: Don't we need to do this in the interpreter too?
- }
+static const char* StrictModeCallerAccessError = "Cannot access caller property of a strict mode function";
+static const char* StrictModeArgumentsAccessError = "Cannot access arguments property of a strict mode function";
+
+static void createDescriptorForThrowingProperty(ExecState* exec, PropertyDescriptor& descriptor, const char* message)
+{
+ JSValue thrower = createTypeErrorFunction(exec, message);
+ descriptor.setAccessorDescriptor(thrower, thrower, DontEnum | DontDelete | Getter | Setter);
}
-void JSFunction::markChildren(MarkStack& markStack)
+const UString& JSFunction::name(ExecState* exec)
{
- Base::markChildren(markStack);
- if (!isHostFunction()) {
- jsExecutable()->markAggregate(markStack);
- scopeChain().markAggregate(markStack);
- }
+ return asString(getDirect(exec->globalData(), exec->globalData().propertyNames->name))->tryGetValue();
+}
+
+const UString JSFunction::displayName(ExecState* exec)
+{
+ JSValue displayName = getDirect(exec->globalData(), exec->globalData().propertyNames->displayName);
+
+ if (displayName && isJSString(&exec->globalData(), displayName))
+ return asString(displayName)->tryGetValue();
+
+ return UString();
+}
+
+const UString JSFunction::calculatedDisplayName(ExecState* exec)
+{
+ const UString explicitName = displayName(exec);
+
+ if (!explicitName.isEmpty())
+ return explicitName;
+
+ return name(exec);
+}
+
+void JSFunction::visitChildren(SlotVisitor& visitor)
+{
+ ASSERT_GC_OBJECT_INHERITS(this, &s_info);
+ COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
+ ASSERT(structure()->typeInfo().overridesVisitChildren());
+ Base::visitChildren(visitor);
+
+ visitor.append(&m_scopeChain);
+ if (m_executable)
+ visitor.append(&m_executable);
}
CallType JSFunction::getCallData(CallData& callData)
return CallTypeHost;
}
callData.js.functionExecutable = jsExecutable();
- callData.js.scopeChain = scopeChain().node();
+ callData.js.scopeChain = scope();
return CallTypeJS;
}
-JSValue JSFunction::call(ExecState* exec, JSValue thisValue, const ArgList& args)
-{
- ASSERT(!isHostFunction());
- return exec->interpreter()->execute(jsExecutable(), exec, this, thisValue.toThisObject(exec), args, scopeChain().node(), exec->exceptionSlot());
-}
-
JSValue JSFunction::argumentsGetter(ExecState* exec, JSValue slotBase, const Identifier&)
{
JSFunction* thisObj = asFunction(slotBase);
return exec->interpreter()->retrieveCaller(exec, thisObj);
}
-JSValue JSFunction::lengthGetter(ExecState* exec, JSValue slotBase, const Identifier&)
+JSValue JSFunction::lengthGetter(ExecState*, JSValue slotBase, const Identifier&)
{
JSFunction* thisObj = asFunction(slotBase);
ASSERT(!thisObj->isHostFunction());
- return jsNumber(exec, thisObj->jsExecutable()->parameterCount());
+ return jsNumber(thisObj->jsExecutable()->parameterCount());
+}
+
+static inline WriteBarrierBase<Unknown>* createPrototypeProperty(JSGlobalData& globalData, JSGlobalObject* globalObject, JSFunction* function)
+{
+ ASSERT(!function->isHostFunction());
+
+ ExecState* exec = globalObject->globalExec();
+ if (WriteBarrierBase<Unknown>* location = function->getDirectLocation(globalData, exec->propertyNames().prototype))
+ return location;
+ JSObject* prototype = constructEmptyObject(exec, globalObject->emptyObjectStructure());
+ prototype->putDirect(globalData, exec->propertyNames().constructor, function, DontEnum);
+ function->putDirect(globalData, exec->propertyNames().prototype, prototype, DontDelete | DontEnum);
+ return function->getDirectLocation(exec->globalData(), exec->propertyNames().prototype);
+}
+
+void JSFunction::preventExtensions(JSGlobalData& globalData)
+{
+ if (!isHostFunction())
+ createPrototypeProperty(globalData, scope()->globalObject.get(), this);
+ JSObject::preventExtensions(globalData);
}
bool JSFunction::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
return Base::getOwnPropertySlot(exec, propertyName, slot);
if (propertyName == exec->propertyNames().prototype) {
- JSValue* location = getDirectLocation(propertyName);
+ WriteBarrierBase<Unknown>* location = getDirectLocation(exec->globalData(), propertyName);
- if (!location) {
- JSObject* prototype = new (exec) JSObject(scopeChain().globalObject()->emptyObjectStructure());
- prototype->putDirect(exec->propertyNames().constructor, this, DontEnum);
- putDirect(exec->propertyNames().prototype, prototype, DontDelete);
- location = getDirectLocation(propertyName);
- }
+ if (!location)
+ location = createPrototypeProperty(exec->globalData(), scope()->globalObject.get(), this);
- slot.setValueSlot(this, location, offsetForLocation(location));
+ slot.setValue(this, location->get(), offsetForLocation(location));
}
if (propertyName == exec->propertyNames().arguments) {
+ if (jsExecutable()->isStrictMode()) {
+ throwTypeError(exec, "Can't access arguments object of a strict mode function");
+ slot.setValue(jsNull());
+ return true;
+ }
+
slot.setCacheableCustom(this, argumentsGetter);
return true;
}
}
if (propertyName == exec->propertyNames().caller) {
+ if (jsExecutable()->isStrictMode()) {
+ throwTypeError(exec, StrictModeCallerAccessError);
+ slot.setValue(jsNull());
+ return true;
+ }
slot.setCacheableCustom(this, callerGetter);
return true;
}
return Base::getOwnPropertySlot(exec, propertyName, slot);
}
- bool JSFunction::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
- {
- if (isHostFunction())
- return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor);
-
- if (propertyName == exec->propertyNames().prototype) {
- PropertySlot slot;
- getOwnPropertySlot(exec, propertyName, slot);
- return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor);
- }
-
- if (propertyName == exec->propertyNames().arguments) {
+bool JSFunction::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ if (isHostFunction())
+ return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor);
+
+ if (propertyName == exec->propertyNames().prototype) {
+ PropertySlot slot;
+ getOwnPropertySlot(exec, propertyName, slot);
+ return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor);
+ }
+
+ if (propertyName == exec->propertyNames().arguments) {
+ if (jsExecutable()->isStrictMode())
+ createDescriptorForThrowingProperty(exec, descriptor, StrictModeArgumentsAccessError);
+ else
descriptor.setDescriptor(exec->interpreter()->retrieveArguments(exec, this), ReadOnly | DontEnum | DontDelete);
- return true;
- }
-
- if (propertyName == exec->propertyNames().length) {
- descriptor.setDescriptor(jsNumber(exec, jsExecutable()->parameterCount()), ReadOnly | DontEnum | DontDelete);
- return true;
- }
-
- if (propertyName == exec->propertyNames().caller) {
+ return true;
+ }
+
+ if (propertyName == exec->propertyNames().length) {
+ descriptor.setDescriptor(jsNumber(jsExecutable()->parameterCount()), ReadOnly | DontEnum | DontDelete);
+ return true;
+ }
+
+ if (propertyName == exec->propertyNames().caller) {
+ if (jsExecutable()->isStrictMode())
+ createDescriptorForThrowingProperty(exec, descriptor, StrictModeCallerAccessError);
+ else
descriptor.setDescriptor(exec->interpreter()->retrieveCaller(exec, this), ReadOnly | DontEnum | DontDelete);
- return true;
- }
-
- return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor);
+ return true;
}
+ return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor);
+}
+
void JSFunction::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
{
if (!isHostFunction() && (mode == IncludeDontEnumProperties)) {
+ // Make sure prototype has been reified.
+ PropertySlot slot;
+ getOwnPropertySlot(exec, exec->propertyNames().prototype, slot);
+
propertyNames.add(exec->propertyNames().arguments);
propertyNames.add(exec->propertyNames().callee);
propertyNames.add(exec->propertyNames().caller);
Base::put(exec, propertyName, value, slot);
return;
}
+ if (propertyName == exec->propertyNames().prototype) {
+ // Make sure prototype has been reified, such that it can only be overwritten
+ // following the rules set out in ECMA-262 8.12.9.
+ PropertySlot slot;
+ getOwnPropertySlot(exec, propertyName, slot);
+ }
+ if (jsExecutable()->isStrictMode()) {
+ if (propertyName == exec->propertyNames().arguments) {
+ throwTypeError(exec, StrictModeArgumentsAccessError);
+ return;
+ }
+ if (propertyName == exec->propertyNames().caller) {
+ throwTypeError(exec, StrictModeCallerAccessError);
+ return;
+ }
+ }
if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length)
return;
Base::put(exec, propertyName, value, slot);
if (isHostFunction())
return ConstructTypeNone;
constructData.js.functionExecutable = jsExecutable();
- constructData.js.scopeChain = scopeChain().node();
+ constructData.js.scopeChain = scope();
return ConstructTypeJS;
}
-JSObject* JSFunction::construct(ExecState* exec, const ArgList& args)
-{
- ASSERT(!isHostFunction());
- Structure* structure;
- JSValue prototype = get(exec, exec->propertyNames().prototype);
- if (prototype.isObject())
- structure = asObject(prototype)->inheritorID();
- else
- structure = exec->lexicalGlobalObject()->emptyObjectStructure();
- JSObject* thisObj = new (exec) JSObject(structure);
-
- JSValue result = exec->interpreter()->execute(jsExecutable(), exec, this, thisObj, args, scopeChain().node(), exec->exceptionSlot());
- if (exec->hadException() || !result.isObject())
- return thisObj;
- return asObject(result);
-}
-
} // namespace JSC
#ifndef JSFunction_h
#define JSFunction_h
-#include "InternalFunction.h"
+#include "JSObjectWithGlobalObject.h"
namespace JSC {
class JSActivation;
class JSGlobalObject;
class NativeExecutable;
+ class VPtrHackExecutable;
- class JSFunction : public InternalFunction {
+ EncodedJSValue JSC_HOST_CALL callHostFunctionAsConstructor(ExecState*);
+
+ class JSFunction : public JSObjectWithGlobalObject {
friend class JIT;
friend class JSGlobalData;
- typedef InternalFunction Base;
+ typedef JSObjectWithGlobalObject Base;
public:
- JSFunction(ExecState*, NonNullPassRefPtr<Structure>, int length, const Identifier&, NativeFunction);
- JSFunction(ExecState*, NonNullPassRefPtr<Structure>, int length, const Identifier&, NativeExecutable*, NativeFunction);
- JSFunction(ExecState*, NonNullPassRefPtr<FunctionExecutable>, ScopeChainNode*);
+ JSFunction(ExecState*, JSGlobalObject*, Structure*, int length, const Identifier&, NativeFunction);
+ JSFunction(ExecState*, JSGlobalObject*, Structure*, int length, const Identifier&, NativeExecutable*);
+ JSFunction(ExecState*, FunctionExecutable*, ScopeChainNode*);
virtual ~JSFunction();
- JSObject* construct(ExecState*, const ArgList&);
- JSValue call(ExecState*, JSValue thisValue, const ArgList&);
+ const UString& name(ExecState*);
+ const UString displayName(ExecState*);
+ const UString calculatedDisplayName(ExecState*);
- void setScope(const ScopeChain& scopeChain) { setScopeChain(scopeChain); }
- ScopeChain& scope() { return scopeChain(); }
+ ScopeChainNode* scope()
+ {
+ ASSERT(!isHostFunctionNonInline());
+ return m_scopeChain.get();
+ }
+ void setScope(JSGlobalData& globalData, ScopeChainNode* scopeChain)
+ {
+ ASSERT(!isHostFunctionNonInline());
+ m_scopeChain.set(globalData, this, scopeChain);
+ }
ExecutableBase* executable() const { return m_executable.get(); }
inline bool isHostFunction() const;
FunctionExecutable* jsExecutable() const;
- static JS_EXPORTDATA const ClassInfo info;
+ static JS_EXPORTDATA const ClassInfo s_info;
- static PassRefPtr<Structure> createStructure(JSValue prototype)
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
+ return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
}
- NativeFunction nativeFunction()
- {
- return *WTF::bitwise_cast<NativeFunction*>(m_data);
- }
+ NativeFunction nativeFunction();
virtual ConstructType getConstructData(ConstructData&);
virtual CallType getCallData(CallData&);
protected:
- const static unsigned StructureFlags = OverridesGetOwnPropertySlot | ImplementsHasInstance | OverridesMarkChildren | OverridesGetPropertyNames | InternalFunction::StructureFlags;
+ const static unsigned StructureFlags = OverridesGetOwnPropertySlot | ImplementsHasInstance | OverridesVisitChildren | OverridesGetPropertyNames | JSObject::StructureFlags;
private:
- JSFunction(NonNullPassRefPtr<Structure>);
+ explicit JSFunction(VPtrStealingHackType);
bool isHostFunctionNonInline() const;
+ virtual void preventExtensions(JSGlobalData&);
virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties);
virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
- virtual void markChildren(MarkStack&);
-
- virtual const ClassInfo* classInfo() const { return &info; }
+ virtual void visitChildren(SlotVisitor&);
static JSValue argumentsGetter(ExecState*, JSValue, const Identifier&);
static JSValue callerGetter(ExecState*, JSValue, const Identifier&);
static JSValue lengthGetter(ExecState*, JSValue, const Identifier&);
- RefPtr<ExecutableBase> m_executable;
- ScopeChain& scopeChain()
- {
- ASSERT(!isHostFunctionNonInline());
- return *WTF::bitwise_cast<ScopeChain*>(m_data);
- }
- void clearScopeChain()
- {
- ASSERT(!isHostFunctionNonInline());
- new (m_data) ScopeChain(NoScopeChain());
- }
- void setScopeChain(ScopeChainNode* sc)
- {
- ASSERT(!isHostFunctionNonInline());
- new (m_data) ScopeChain(sc);
- }
- void setScopeChain(const ScopeChain& sc)
- {
- ASSERT(!isHostFunctionNonInline());
- *WTF::bitwise_cast<ScopeChain*>(m_data) = sc;
- }
- void setNativeFunction(NativeFunction func)
- {
- *WTF::bitwise_cast<NativeFunction*>(m_data) = func;
- }
- unsigned char m_data[sizeof(void*)];
+ WriteBarrier<ExecutableBase> m_executable;
+ WriteBarrier<ScopeChainNode> m_scopeChain;
};
JSFunction* asFunction(JSValue);
inline JSFunction* asFunction(JSValue value)
{
- ASSERT(asObject(value)->inherits(&JSFunction::info));
+ ASSERT(asObject(value)->inherits(&JSFunction::s_info));
return static_cast<JSFunction*>(asObject(value));
}
/*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2011 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
#include "JSGlobalData.h"
#include "ArgList.h"
-#include "Collector.h"
-#include "CollectorHeapIterator.h"
+#include "Heap.h"
#include "CommonIdentifiers.h"
+#include "DebuggerActivation.h"
#include "FunctionConstructor.h"
#include "GetterSetter.h"
#include "Interpreter.h"
#include "JSNotAnObject.h"
#include "JSPropertyNameIterator.h"
#include "JSStaticScopeObject.h"
+#include "JSZombie.h"
#include "Lexer.h"
#include "Lookup.h"
#include "Nodes.h"
#include "Parser.h"
#include "RegExpCache.h"
+#include "RegExpObject.h"
+#include "StrictEvalActivation.h"
#include <wtf/WTFThreadData.h>
+#if ENABLE(REGEXP_TRACING)
+#include "RegExp.h"
+#endif
+
#if ENABLE(JSC_MULTIPLE_THREADS)
#include <wtf/Threading.h>
using namespace WTF;
+namespace {
+
+using namespace JSC;
+
+class Recompiler {
+public:
+ void operator()(JSCell*);
+};
+
+inline void Recompiler::operator()(JSCell* cell)
+{
+ if (!cell->inherits(&JSFunction::s_info))
+ return;
+ JSFunction* function = asFunction(cell);
+ if (function->executable()->isHostFunction())
+ return;
+ function->jsExecutable()->discardCode();
+}
+
+} // namespace
+
namespace JSC {
-extern JSC_CONST_HASHTABLE HashTable arrayTable;
+extern JSC_CONST_HASHTABLE HashTable arrayConstructorTable;
+extern JSC_CONST_HASHTABLE HashTable arrayPrototypeTable;
+extern JSC_CONST_HASHTABLE HashTable booleanPrototypeTable;
extern JSC_CONST_HASHTABLE HashTable jsonTable;
extern JSC_CONST_HASHTABLE HashTable dateTable;
+extern JSC_CONST_HASHTABLE HashTable dateConstructorTable;
+extern JSC_CONST_HASHTABLE HashTable errorPrototypeTable;
+extern JSC_CONST_HASHTABLE HashTable globalObjectTable;
extern JSC_CONST_HASHTABLE HashTable mathTable;
-extern JSC_CONST_HASHTABLE HashTable numberTable;
+extern JSC_CONST_HASHTABLE HashTable numberConstructorTable;
+extern JSC_CONST_HASHTABLE HashTable numberPrototypeTable;
+extern JSC_CONST_HASHTABLE HashTable objectConstructorTable;
+extern JSC_CONST_HASHTABLE HashTable objectPrototypeTable;
extern JSC_CONST_HASHTABLE HashTable regExpTable;
extern JSC_CONST_HASHTABLE HashTable regExpConstructorTable;
+extern JSC_CONST_HASHTABLE HashTable regExpPrototypeTable;
extern JSC_CONST_HASHTABLE HashTable stringTable;
+extern JSC_CONST_HASHTABLE HashTable stringConstructorTable;
void* JSGlobalData::jsArrayVPtr;
void* JSGlobalData::jsByteArrayVPtr;
void* JSGlobalData::jsStringVPtr;
void* JSGlobalData::jsFunctionVPtr;
+#if COMPILER(GCC)
+// Work around for gcc trying to coalesce our reads of the various cell vptrs
+#define CLOBBER_MEMORY() do { \
+ asm volatile ("" : : : "memory"); \
+} while (false)
+#else
+#define CLOBBER_MEMORY() do { } while (false)
+#endif
+
void JSGlobalData::storeVPtrs()
{
- CollectorCell cell;
- void* storage = &cell;
+ // Enough storage to fit a JSArray, JSByteArray, JSString, or JSFunction.
+ // COMPILE_ASSERTS below check that this is true.
+ char storage[64];
- COMPILE_ASSERT(sizeof(JSArray) <= sizeof(CollectorCell), sizeof_JSArray_must_be_less_than_CollectorCell);
- JSCell* jsArray = new (storage) JSArray(JSArray::createStructure(jsNull()));
+ COMPILE_ASSERT(sizeof(JSArray) <= sizeof(storage), sizeof_JSArray_must_be_less_than_storage);
+ JSCell* jsArray = new (storage) JSArray(JSArray::VPtrStealingHack);
+ CLOBBER_MEMORY();
JSGlobalData::jsArrayVPtr = jsArray->vptr();
- jsArray->~JSCell();
- COMPILE_ASSERT(sizeof(JSByteArray) <= sizeof(CollectorCell), sizeof_JSByteArray_must_be_less_than_CollectorCell);
+ COMPILE_ASSERT(sizeof(JSByteArray) <= sizeof(storage), sizeof_JSByteArray_must_be_less_than_storage);
JSCell* jsByteArray = new (storage) JSByteArray(JSByteArray::VPtrStealingHack);
+ CLOBBER_MEMORY();
JSGlobalData::jsByteArrayVPtr = jsByteArray->vptr();
- jsByteArray->~JSCell();
- COMPILE_ASSERT(sizeof(JSString) <= sizeof(CollectorCell), sizeof_JSString_must_be_less_than_CollectorCell);
+ COMPILE_ASSERT(sizeof(JSString) <= sizeof(storage), sizeof_JSString_must_be_less_than_storage);
JSCell* jsString = new (storage) JSString(JSString::VPtrStealingHack);
+ CLOBBER_MEMORY();
JSGlobalData::jsStringVPtr = jsString->vptr();
- jsString->~JSCell();
- COMPILE_ASSERT(sizeof(JSFunction) <= sizeof(CollectorCell), sizeof_JSFunction_must_be_less_than_CollectorCell);
- JSCell* jsFunction = new (storage) JSFunction(JSFunction::createStructure(jsNull()));
+ COMPILE_ASSERT(sizeof(JSFunction) <= sizeof(storage), sizeof_JSFunction_must_be_less_than_storage);
+ JSCell* jsFunction = new (storage) JSFunction(JSCell::VPtrStealingHack);
+ CLOBBER_MEMORY();
JSGlobalData::jsFunctionVPtr = jsFunction->vptr();
- jsFunction->~JSCell();
}
JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType threadStackType)
: globalDataType(globalDataType)
, clientData(0)
- , arrayTable(fastNew<HashTable>(JSC::arrayTable))
+ , arrayConstructorTable(fastNew<HashTable>(JSC::arrayConstructorTable))
+ , arrayPrototypeTable(fastNew<HashTable>(JSC::arrayPrototypeTable))
+ , booleanPrototypeTable(fastNew<HashTable>(JSC::booleanPrototypeTable))
, dateTable(fastNew<HashTable>(JSC::dateTable))
+ , dateConstructorTable(fastNew<HashTable>(JSC::dateConstructorTable))
+ , errorPrototypeTable(fastNew<HashTable>(JSC::errorPrototypeTable))
+ , globalObjectTable(fastNew<HashTable>(JSC::globalObjectTable))
, jsonTable(fastNew<HashTable>(JSC::jsonTable))
, mathTable(fastNew<HashTable>(JSC::mathTable))
- , numberTable(fastNew<HashTable>(JSC::numberTable))
+ , numberConstructorTable(fastNew<HashTable>(JSC::numberConstructorTable))
+ , numberPrototypeTable(fastNew<HashTable>(JSC::numberPrototypeTable))
+ , objectConstructorTable(fastNew<HashTable>(JSC::objectConstructorTable))
+ , objectPrototypeTable(fastNew<HashTable>(JSC::objectPrototypeTable))
, regExpTable(fastNew<HashTable>(JSC::regExpTable))
, regExpConstructorTable(fastNew<HashTable>(JSC::regExpConstructorTable))
+ , regExpPrototypeTable(fastNew<HashTable>(JSC::regExpPrototypeTable))
, stringTable(fastNew<HashTable>(JSC::stringTable))
- , activationStructure(JSActivation::createStructure(jsNull()))
- , interruptedExecutionErrorStructure(JSObject::createStructure(jsNull()))
- , terminatedExecutionErrorStructure(JSObject::createStructure(jsNull()))
- , staticScopeStructure(JSStaticScopeObject::createStructure(jsNull()))
- , stringStructure(JSString::createStructure(jsNull()))
- , notAnObjectErrorStubStructure(JSNotAnObjectErrorStub::createStructure(jsNull()))
- , notAnObjectStructure(JSNotAnObject::createStructure(jsNull()))
- , propertyNameIteratorStructure(JSPropertyNameIterator::createStructure(jsNull()))
- , getterSetterStructure(GetterSetter::createStructure(jsNull()))
- , apiWrapperStructure(JSAPIValueWrapper::createStructure(jsNull()))
- , dummyMarkableCellStructure(JSCell::createDummyStructure())
-#if USE(JSVALUE32)
- , numberStructure(JSNumberCell::createStructure(jsNull()))
-#endif
+ , stringConstructorTable(fastNew<HashTable>(JSC::stringConstructorTable))
, identifierTable(globalDataType == Default ? wtfThreadData().currentIdentifierTable() : createIdentifierTable())
, propertyNames(new CommonIdentifiers(this))
, emptyList(new MarkedArgumentBuffer)
+#if ENABLE(ASSEMBLER)
+ , executableAllocator(*this)
+ , regexAllocator(*this)
+#endif
, lexer(new Lexer(this))
, parser(new Parser)
- , interpreter(new Interpreter)
+ , interpreter(0)
, heap(this)
- , initializingLazyNumericCompareFunction(false)
- , head(0)
+ , globalObjectCount(0)
, dynamicGlobalObject(0)
- , functionCodeBlockBeingReparsed(0)
- , firstStringifierToMark(0)
- , markStack(jsArrayVPtr)
, cachedUTCOffset(NaN)
, maxReentryDepth(threadStackType == ThreadStackTypeSmall ? MaxSmallThreadReentryDepth : MaxLargeThreadReentryDepth)
, m_regExpCache(new RegExpCache(this))
+#if ENABLE(REGEXP_TRACING)
+ , m_rtTraceList(new RTTraceList())
+#endif
#ifndef NDEBUG
, exclusiveThread(0)
#endif
{
+ interpreter = new Interpreter(*this);
+ if (globalDataType == Default)
+ m_stack = wtfThreadData().stack();
+
+ // Need to be careful to keep everything consistent here
+ IdentifierTable* existingEntryIdentifierTable = wtfThreadData().setCurrentIdentifierTable(identifierTable);
+ JSLock lock(SilenceAssertionsOnly);
+ structureStructure.set(*this, Structure::createStructure(*this));
+ debuggerActivationStructure.set(*this, DebuggerActivation::createStructure(*this, jsNull()));
+ activationStructure.set(*this, JSActivation::createStructure(*this, jsNull()));
+ interruptedExecutionErrorStructure.set(*this, JSNonFinalObject::createStructure(*this, jsNull()));
+ terminatedExecutionErrorStructure.set(*this, JSNonFinalObject::createStructure(*this, jsNull()));
+ staticScopeStructure.set(*this, JSStaticScopeObject::createStructure(*this, jsNull()));
+ strictEvalActivationStructure.set(*this, StrictEvalActivation::createStructure(*this, jsNull()));
+ stringStructure.set(*this, JSString::createStructure(*this, jsNull()));
+ notAnObjectStructure.set(*this, JSNotAnObject::createStructure(*this, jsNull()));
+ propertyNameIteratorStructure.set(*this, JSPropertyNameIterator::createStructure(*this, jsNull()));
+ getterSetterStructure.set(*this, GetterSetter::createStructure(*this, jsNull()));
+ apiWrapperStructure.set(*this, JSAPIValueWrapper::createStructure(*this, jsNull()));
+ scopeChainNodeStructure.set(*this, ScopeChainNode::createStructure(*this, jsNull()));
+ executableStructure.set(*this, ExecutableBase::createStructure(*this, jsNull()));
+ nativeExecutableStructure.set(*this, NativeExecutable::createStructure(*this, jsNull()));
+ evalExecutableStructure.set(*this, EvalExecutable::createStructure(*this, jsNull()));
+ programExecutableStructure.set(*this, ProgramExecutable::createStructure(*this, jsNull()));
+ functionExecutableStructure.set(*this, FunctionExecutable::createStructure(*this, jsNull()));
+ dummyMarkableCellStructure.set(*this, JSCell::createDummyStructure(*this));
+ regExpStructure.set(*this, RegExp::createStructure(*this, jsNull()));
+ structureChainStructure.set(*this, StructureChain::createStructure(*this, jsNull()));
+
+#if ENABLE(JSC_ZOMBIES)
+ zombieStructure.set(*this, JSZombie::createStructure(*this, jsNull()));
+#endif
+
+ wtfThreadData().setCurrentIdentifierTable(existingEntryIdentifierTable);
+
#if PLATFORM(MAC)
startProfilerServerIfNeeded();
#endif
#if ENABLE(JIT) && ENABLE(INTERPRETER)
-#if PLATFORM(CF)
+#if USE(CF)
CFStringRef canUseJITKey = CFStringCreateWithCString(0 , "JavaScriptCoreUseJIT", kCFStringEncodingMacRoman);
CFBooleanRef canUseJIT = (CFBooleanRef)CFPreferencesCopyAppValue(canUseJITKey, kCFPreferencesCurrentApplication);
if (canUseJIT) {
m_canUseJIT = kCFBooleanTrue == canUseJIT;
CFRelease(canUseJIT);
- } else
- m_canUseJIT = !getenv("JavaScriptCoreUseJIT");
+ } else {
+ char* canUseJITString = getenv("JavaScriptCoreUseJIT");
+ m_canUseJIT = !canUseJITString || atoi(canUseJITString);
+ }
CFRelease(canUseJITKey);
#elif OS(UNIX)
- m_canUseJIT = !getenv("JavaScriptCoreUseJIT");
+ char* canUseJITString = getenv("JavaScriptCoreUseJIT");
+ m_canUseJIT = !canUseJITString || atoi(canUseJITString);
#else
m_canUseJIT = true;
#endif
if (m_canUseJIT)
m_canUseJIT = executableAllocator.isValid();
#endif
- jitStubs.set(new JITThunks(this));
+ jitStubs = adoptPtr(new JITThunks(this));
+#endif
+}
+
+void JSGlobalData::clearBuiltinStructures()
+{
+ structureStructure.clear();
+ debuggerActivationStructure.clear();
+ activationStructure.clear();
+ interruptedExecutionErrorStructure.clear();
+ terminatedExecutionErrorStructure.clear();
+ staticScopeStructure.clear();
+ strictEvalActivationStructure.clear();
+ stringStructure.clear();
+ notAnObjectStructure.clear();
+ propertyNameIteratorStructure.clear();
+ getterSetterStructure.clear();
+ apiWrapperStructure.clear();
+ scopeChainNodeStructure.clear();
+ executableStructure.clear();
+ nativeExecutableStructure.clear();
+ evalExecutableStructure.clear();
+ programExecutableStructure.clear();
+ functionExecutableStructure.clear();
+ dummyMarkableCellStructure.clear();
+ regExpStructure.clear();
+ structureChainStructure.clear();
+
+#if ENABLE(JSC_ZOMBIES)
+ zombieStructure.clear();
#endif
}
interpreter = 0;
#endif
- arrayTable->deleteTable();
+ arrayPrototypeTable->deleteTable();
+ arrayConstructorTable->deleteTable();
+ booleanPrototypeTable->deleteTable();
dateTable->deleteTable();
+ dateConstructorTable->deleteTable();
+ errorPrototypeTable->deleteTable();
+ globalObjectTable->deleteTable();
jsonTable->deleteTable();
mathTable->deleteTable();
- numberTable->deleteTable();
+ numberConstructorTable->deleteTable();
+ numberPrototypeTable->deleteTable();
+ objectConstructorTable->deleteTable();
+ objectPrototypeTable->deleteTable();
regExpTable->deleteTable();
regExpConstructorTable->deleteTable();
+ regExpPrototypeTable->deleteTable();
stringTable->deleteTable();
+ stringConstructorTable->deleteTable();
- fastDelete(const_cast<HashTable*>(arrayTable));
+ fastDelete(const_cast<HashTable*>(arrayConstructorTable));
+ fastDelete(const_cast<HashTable*>(arrayPrototypeTable));
+ fastDelete(const_cast<HashTable*>(booleanPrototypeTable));
fastDelete(const_cast<HashTable*>(dateTable));
+ fastDelete(const_cast<HashTable*>(dateConstructorTable));
+ fastDelete(const_cast<HashTable*>(errorPrototypeTable));
+ fastDelete(const_cast<HashTable*>(globalObjectTable));
fastDelete(const_cast<HashTable*>(jsonTable));
fastDelete(const_cast<HashTable*>(mathTable));
- fastDelete(const_cast<HashTable*>(numberTable));
+ fastDelete(const_cast<HashTable*>(numberConstructorTable));
+ fastDelete(const_cast<HashTable*>(numberPrototypeTable));
+ fastDelete(const_cast<HashTable*>(objectConstructorTable));
+ fastDelete(const_cast<HashTable*>(objectPrototypeTable));
fastDelete(const_cast<HashTable*>(regExpTable));
fastDelete(const_cast<HashTable*>(regExpConstructorTable));
+ fastDelete(const_cast<HashTable*>(regExpPrototypeTable));
fastDelete(const_cast<HashTable*>(stringTable));
+ fastDelete(const_cast<HashTable*>(stringConstructorTable));
delete parser;
delete lexer;
delete clientData;
delete m_regExpCache;
+#if ENABLE(REGEXP_TRACING)
+ delete m_rtTraceList;
+#endif
}
PassRefPtr<JSGlobalData> JSGlobalData::createContextGroup(ThreadStackType type)
PassRefPtr<JSGlobalData> JSGlobalData::createLeaked(ThreadStackType type)
{
- Structure::startIgnoringLeaks();
- RefPtr<JSGlobalData> data = create(type);
- Structure::stopIgnoringLeaks();
- return data.release();
+ return create(type);
}
bool JSGlobalData::sharedInstanceExists()
{
JSGlobalData*& instance = sharedInstanceInternal();
if (!instance) {
- instance = new JSGlobalData(APIShared, ThreadStackTypeSmall);
+ instance = adoptRef(new JSGlobalData(APIShared, ThreadStackTypeSmall)).leakRef();
#if ENABLE(JSC_MULTIPLE_THREADS)
instance->makeUsableFromMultipleThreads();
#endif
return sharedInstance;
}
-// FIXME: We can also detect forms like v1 < v2 ? -1 : 0, reverse comparison, etc.
-const Vector<Instruction>& JSGlobalData::numericCompareFunction(ExecState* exec)
+#if ENABLE(JIT)
+NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function)
{
- if (!lazyNumericCompareFunction.size() && !initializingLazyNumericCompareFunction) {
- initializingLazyNumericCompareFunction = true;
- RefPtr<FunctionExecutable> function = FunctionExecutable::fromGlobalCode(Identifier(exec, "numericCompare"), exec, 0, makeSource(UString("(function (v1, v2) { return v1 - v2; })")), 0, 0);
- lazyNumericCompareFunction = function->bytecode(exec, exec->scopeChain()).instructions();
- initializingLazyNumericCompareFunction = false;
- }
-
- return lazyNumericCompareFunction;
+ return jitStubs->hostFunctionStub(this, function);
+}
+NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function, ThunkGenerator generator)
+{
+ return jitStubs->hostFunctionStub(this, function, generator);
}
+#else
+NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function)
+{
+ return NativeExecutable::create(*this, function, callHostFunctionAsConstructor);
+}
+#endif
JSGlobalData::ClientData::~ClientData()
{
cachedUTCOffset = NaN;
dstOffsetCache.reset();
cachedDateString = UString();
+ cachedDateStringValue = NaN;
dateInstanceCache.reset();
}
// If JavaScript is running, it's not safe to recompile, since we'll end
// up throwing away code that is live on the stack.
ASSERT(!dynamicGlobalObject);
+
+ Recompiler recompiler;
+ heap.forEach(recompiler);
+}
+
+struct StackPreservingRecompiler {
+ HashSet<FunctionExecutable*> currentlyExecutingFunctions;
+ void operator()(JSCell* cell)
+ {
+ if (!cell->inherits(&FunctionExecutable::s_info))
+ return;
+ FunctionExecutable* executable = static_cast<FunctionExecutable*>(cell);
+ if (currentlyExecutingFunctions.contains(executable))
+ return;
+ executable->discardCode();
+ }
+};
- LiveObjectIterator it = heap.primaryHeapBegin();
- LiveObjectIterator heapEnd = heap.primaryHeapEnd();
- for ( ; it != heapEnd; ++it) {
- if ((*it)->inherits(&JSFunction::info)) {
- JSFunction* function = asFunction(*it);
- if (!function->executable()->isHostFunction())
- function->jsExecutable()->recompile();
+void JSGlobalData::releaseExecutableMemory()
+{
+ if (dynamicGlobalObject) {
+ StackPreservingRecompiler recompiler;
+ HashSet<JSCell*> roots;
+ heap.getConservativeRegisterRoots(roots);
+ HashSet<JSCell*>::iterator end = roots.end();
+ for (HashSet<JSCell*>::iterator ptr = roots.begin(); ptr != end; ++ptr) {
+ ScriptExecutable* executable = 0;
+ JSCell* cell = *ptr;
+ if (cell->inherits(&ScriptExecutable::s_info))
+ executable = static_cast<ScriptExecutable*>(*ptr);
+ else if (cell->inherits(&JSFunction::s_info)) {
+ JSFunction* function = asFunction(*ptr);
+ if (function->isHostFunction())
+ continue;
+ executable = function->jsExecutable();
+ } else
+ continue;
+ ASSERT(executable->inherits(&ScriptExecutable::s_info));
+ executable->unlinkCalls();
+ if (executable->inherits(&FunctionExecutable::s_info))
+ recompiler.currentlyExecutingFunctions.add(static_cast<FunctionExecutable*>(executable));
+
}
+ heap.forEach(recompiler);
+ } else
+ recompileAllJSFunctions();
+
+ m_regExpCache->invalidateCode();
+ heap.collectAllGarbage();
+}
+
+#if ENABLE(ASSEMBLER)
+void releaseExecutableMemory(JSGlobalData& globalData)
+{
+ globalData.releaseExecutableMemory();
+}
+#endif
+
+#if ENABLE(REGEXP_TRACING)
+void JSGlobalData::addRegExpToTrace(RegExp* regExp)
+{
+ m_rtTraceList->add(regExp);
+}
+
+void JSGlobalData::dumpRegExpTrace()
+{
+ // The first RegExp object is ignored. It is create by the RegExpPrototype ctor and not used.
+ RTTraceList::iterator iter = ++m_rtTraceList->begin();
+
+ if (iter != m_rtTraceList->end()) {
+ printf("\nRegExp Tracing\n");
+ printf(" match() matches\n");
+ printf("Regular Expression JIT Address calls found\n");
+ printf("----------------------------------------+----------------+----------+----------\n");
+
+ unsigned reCount = 0;
+
+ for (; iter != m_rtTraceList->end(); ++iter, ++reCount)
+ (*iter)->printTraceData();
+
+ printf("%d Regular Expressions\n", reCount);
}
+
+ m_rtTraceList->clear();
+}
+#else
+void JSGlobalData::dumpRegExpTrace()
+{
}
+#endif
} // namespace JSC
#define JSGlobalData_h
#include "CachedTranscendentalFunction.h"
-#include "Collector.h"
+#include "Heap.h"
#include "DateInstanceCache.h"
#include "ExecutableAllocator.h"
+#include "Strong.h"
#include "JITStubs.h"
#include "JSValue.h"
-#include "MarkStack.h"
#include "NumericStrings.h"
#include "SmallStrings.h"
#include "Terminator.h"
#include "TimeoutChecker.h"
#include "WeakRandom.h"
+#include <wtf/BumpPointerAllocator.h>
#include <wtf/Forward.h>
#include <wtf/HashMap.h>
#include <wtf/RefCounted.h>
+#include <wtf/ThreadSpecific.h>
+#include <wtf/WTFThreadData.h>
+#if ENABLE(REGEXP_TRACING)
+#include <wtf/ListHashSet.h>
+#endif
struct OpaqueJSClass;
struct OpaqueJSClassContextData;
class CodeBlock;
class CommonIdentifiers;
+ class HandleStack;
class IdentifierTable;
class Interpreter;
class JSGlobalObject;
class JSObject;
class Lexer;
+ class NativeExecutable;
class Parser;
class RegExpCache;
class Stringifier;
class Structure;
class UString;
+#if ENABLE(REGEXP_TRACING)
+ class RegExp;
+#endif
struct HashTable;
- struct Instruction;
+ struct Instruction;
struct DSTOffsetCache {
DSTOffsetCache()
};
bool isSharedInstance() { return globalDataType == APIShared; }
+ bool usingAPI() { return globalDataType != Default; }
static bool sharedInstanceExists();
static JSGlobalData& sharedInstance();
#if ENABLE(JSC_MULTIPLE_THREADS)
// Will start tracking threads that use the heap, which is resource-heavy.
- void makeUsableFromMultipleThreads() { heap.makeUsableFromMultipleThreads(); }
+ void makeUsableFromMultipleThreads() { heap.machineThreads().makeUsableFromMultipleThreads(); }
#endif
GlobalDataType globalDataType;
ClientData* clientData;
- const HashTable* arrayTable;
+ const HashTable* arrayConstructorTable;
+ const HashTable* arrayPrototypeTable;
+ const HashTable* booleanPrototypeTable;
const HashTable* dateTable;
+ const HashTable* dateConstructorTable;
+ const HashTable* errorPrototypeTable;
+ const HashTable* globalObjectTable;
const HashTable* jsonTable;
const HashTable* mathTable;
- const HashTable* numberTable;
+ const HashTable* numberConstructorTable;
+ const HashTable* numberPrototypeTable;
+ const HashTable* objectConstructorTable;
+ const HashTable* objectPrototypeTable;
const HashTable* regExpTable;
const HashTable* regExpConstructorTable;
+ const HashTable* regExpPrototypeTable;
const HashTable* stringTable;
+ const HashTable* stringConstructorTable;
- RefPtr<Structure> activationStructure;
- RefPtr<Structure> interruptedExecutionErrorStructure;
- RefPtr<Structure> terminatedExecutionErrorStructure;
- RefPtr<Structure> staticScopeStructure;
- RefPtr<Structure> stringStructure;
- RefPtr<Structure> notAnObjectErrorStubStructure;
- RefPtr<Structure> notAnObjectStructure;
- RefPtr<Structure> propertyNameIteratorStructure;
- RefPtr<Structure> getterSetterStructure;
- RefPtr<Structure> apiWrapperStructure;
- RefPtr<Structure> dummyMarkableCellStructure;
-
-#if USE(JSVALUE32)
- RefPtr<Structure> numberStructure;
+ Strong<Structure> structureStructure;
+ Strong<Structure> debuggerActivationStructure;
+ Strong<Structure> activationStructure;
+ Strong<Structure> interruptedExecutionErrorStructure;
+ Strong<Structure> terminatedExecutionErrorStructure;
+ Strong<Structure> staticScopeStructure;
+ Strong<Structure> strictEvalActivationStructure;
+ Strong<Structure> stringStructure;
+ Strong<Structure> notAnObjectStructure;
+ Strong<Structure> propertyNameIteratorStructure;
+ Strong<Structure> getterSetterStructure;
+ Strong<Structure> apiWrapperStructure;
+ Strong<Structure> scopeChainNodeStructure;
+ Strong<Structure> executableStructure;
+ Strong<Structure> nativeExecutableStructure;
+ Strong<Structure> evalExecutableStructure;
+ Strong<Structure> programExecutableStructure;
+ Strong<Structure> functionExecutableStructure;
+ Strong<Structure> dummyMarkableCellStructure;
+ Strong<Structure> regExpStructure;
+ Strong<Structure> structureChainStructure;
+
+#if ENABLE(JSC_ZOMBIES)
+ Strong<Structure> zombieStructure;
#endif
static void storeVPtrs();
ExecutableAllocator regexAllocator;
#endif
-#if ENABLE(JIT)
-#if ENABLE(INTERPRETER)
- bool canUseJIT() { return m_canUseJIT; }
-#endif
+#if !ENABLE(JIT)
+ bool canUseJIT() { return false; } // interpreter only
+#elif !ENABLE(INTERPRETER)
+ bool canUseJIT() { return true; } // jit only
#else
- bool canUseJIT() { return false; }
+ bool canUseJIT() { return m_canUseJIT; }
#endif
+
+ const StackBounds& stack()
+ {
+ return wtfThreadData().stack();
+ }
+
Lexer* lexer;
Parser* parser;
Interpreter* interpreter;
#if ENABLE(JIT)
OwnPtr<JITThunks> jitStubs;
- NativeExecutable* getThunk(ThunkGenerator generator)
+ MacroAssemblerCodePtr getCTIStub(ThunkGenerator generator)
{
- return jitStubs->specializedThunk(this, generator);
+ return jitStubs->ctiStub(this, generator);
}
+ NativeExecutable* getHostFunction(NativeFunction, ThunkGenerator);
#endif
+ NativeExecutable* getHostFunction(NativeFunction);
+
TimeoutChecker timeoutChecker;
Terminator terminator;
Heap heap;
ReturnAddressPtr exceptionLocation;
#endif
- const Vector<Instruction>& numericCompareFunction(ExecState*);
- Vector<Instruction> lazyNumericCompareFunction;
- bool initializingLazyNumericCompareFunction;
-
HashMap<OpaqueJSClass*, OpaqueJSClassContextData*> opaqueJSClassData;
- JSGlobalObject* head;
+ unsigned globalObjectCount;
JSGlobalObject* dynamicGlobalObject;
- HashSet<JSObject*> arrayVisitedElements;
-
- CodeBlock* functionCodeBlockBeingReparsed;
- Stringifier* firstStringifierToMark;
-
- MarkStack markStack;
+ HashSet<JSObject*> stringRecursionCheckVisitedObjects;
double cachedUTCOffset;
DSTOffsetCache dstOffsetCache;
int maxReentryDepth;
RegExpCache* m_regExpCache;
+ BumpPointerAllocator m_regExpAllocator;
+
+#if ENABLE(REGEXP_TRACING)
+ typedef ListHashSet<RefPtr<RegExp> > RTTraceList;
+ RTTraceList* m_rtTraceList;
+#endif
#ifndef NDEBUG
ThreadIdentifier exclusiveThread;
void dumpSampleData(ExecState* exec);
void recompileAllJSFunctions();
RegExpCache* regExpCache() { return m_regExpCache; }
+#if ENABLE(REGEXP_TRACING)
+ void addRegExpToTrace(PassRefPtr<RegExp> regExp);
+#endif
+ void dumpRegExpTrace();
+ HandleSlot allocateGlobalHandle() { return heap.allocateGlobalHandle(); }
+ HandleSlot allocateLocalHandle() { return heap.allocateLocalHandle(); }
+ void clearBuiltinStructures();
+
+ bool isCollectorBusy() { return heap.isBusy(); }
+ void releaseExecutableMemory();
+
private:
JSGlobalData(GlobalDataType, ThreadStackType);
static JSGlobalData*& sharedInstanceInternal();
#if ENABLE(JIT) && ENABLE(INTERPRETER)
bool m_canUseJIT;
#endif
+ StackBounds m_stack;
};
+ inline HandleSlot allocateGlobalHandle(JSGlobalData& globalData)
+ {
+ return globalData.allocateGlobalHandle();
+ }
+
} // namespace JSC
#endif // JSGlobalData_h
#include "ErrorPrototype.h"
#include "FunctionConstructor.h"
#include "FunctionPrototype.h"
-#include "GlobalEvalFunction.h"
#include "JSFunction.h"
#include "JSGlobalObjectFunctions.h"
#include "JSLock.h"
#include "JSONObject.h"
#include "Interpreter.h"
+#include "Lookup.h"
#include "MathObject.h"
#include "NativeErrorConstructor.h"
#include "NativeErrorPrototype.h"
#include "ObjectConstructor.h"
#include "ObjectPrototype.h"
#include "Profiler.h"
-#include "PrototypeFunction.h"
#include "RegExpConstructor.h"
#include "RegExpMatchesArray.h"
#include "RegExpObject.h"
#include "StringPrototype.h"
#include "Debugger.h"
+#include "JSGlobalObject.lut.h"
+
namespace JSC {
+const ClassInfo JSGlobalObject::s_info = { "GlobalObject", &JSVariableObject::s_info, 0, ExecState::globalObjectTable };
+
+/* Source for JSGlobalObject.lut.h
+@begin globalObjectTable
+ parseInt globalFuncParseInt DontEnum|Function 2
+ parseFloat globalFuncParseFloat DontEnum|Function 1
+ isNaN globalFuncIsNaN DontEnum|Function 1
+ isFinite globalFuncIsFinite DontEnum|Function 1
+ escape globalFuncEscape DontEnum|Function 1
+ unescape globalFuncUnescape DontEnum|Function 1
+ decodeURI globalFuncDecodeURI DontEnum|Function 1
+ decodeURIComponent globalFuncDecodeURIComponent DontEnum|Function 1
+ encodeURI globalFuncEncodeURI DontEnum|Function 1
+ encodeURIComponent globalFuncEncodeURIComponent DontEnum|Function 1
+@end
+*/
+
ASSERT_CLASS_FITS_IN_CELL(JSGlobalObject);
// Default number of ticks before a timeout check should be done.
// Preferred number of milliseconds between each timeout check
static const int preferredScriptCheckTimeInterval = 1000;
-static inline void markIfNeeded(MarkStack& markStack, JSValue v)
+template <typename T> static inline void visitIfNeeded(SlotVisitor& visitor, WriteBarrier<T>* v)
{
- if (v)
- markStack.append(v);
-}
-
-static inline void markIfNeeded(MarkStack& markStack, const RefPtr<Structure>& s)
-{
- if (s)
- markIfNeeded(markStack, s->storedPrototype());
+ if (*v)
+ visitor.append(v);
}
JSGlobalObject::~JSGlobalObject()
{
ASSERT(JSLock::currentThreadIsHoldingLock());
- if (d()->debugger)
- d()->debugger->detach(this);
+ if (m_debugger)
+ m_debugger->detach(this);
Profiler** profiler = Profiler::enabledProfilerReference();
if (UNLIKELY(*profiler != 0)) {
- (*profiler)->stopProfiling(globalExec(), UString());
+ (*profiler)->stopProfiling(this);
}
-
- d()->next->d()->prev = d()->prev;
- d()->prev->d()->next = d()->next;
- JSGlobalObject*& headObject = head();
- if (headObject == this)
- headObject = d()->next;
- if (headObject == this)
- headObject = 0;
-
- HashSet<GlobalCodeBlock*>::const_iterator end = codeBlocks().end();
- for (HashSet<GlobalCodeBlock*>::const_iterator it = codeBlocks().begin(); it != end; ++it)
- (*it)->clearGlobalObject();
-
- RegisterFile& registerFile = globalData()->interpreter->registerFile();
- if (registerFile.clearGlobalObject(this))
- registerFile.setNumGlobals(0);
- d()->destructor(d());
}
void JSGlobalObject::init(JSObject* thisValue)
{
ASSERT(JSLock::currentThreadIsHoldingLock());
-
+
structure()->disableSpecificFunctionTracking();
- d()->globalData = Heap::heap(this)->globalData();
- d()->globalScopeChain = ScopeChain(this, d()->globalData.get(), this, thisValue);
-
- JSGlobalObject::globalExec()->init(0, 0, d()->globalScopeChain.node(), CallFrame::noCaller(), 0, 0, 0);
+ m_globalData = Heap::heap(this)->globalData();
+ m_globalScopeChain.set(*m_globalData, this, new (m_globalData.get()) ScopeChainNode(0, this, m_globalData.get(), this, thisValue));
- if (JSGlobalObject*& headObject = head()) {
- d()->prev = headObject;
- d()->next = headObject->d()->next;
- headObject->d()->next->d()->prev = this;
- headObject->d()->next = this;
- } else
- headObject = d()->next = d()->prev = this;
+ JSGlobalObject::globalExec()->init(0, 0, m_globalScopeChain.get(), CallFrame::noCaller(), 0, 0);
- d()->recursion = 0;
- d()->debugger = 0;
+ m_debugger = 0;
- d()->profileGroup = 0;
+ m_profileGroup = 0;
reset(prototype());
}
{
ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
- if (symbolTablePut(propertyName, value))
+ if (symbolTablePut(exec->globalData(), propertyName, value))
return;
JSVariableObject::put(exec, propertyName, value, slot);
}
{
ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
- if (symbolTablePutWithAttributes(propertyName, value, attributes))
+ if (symbolTablePutWithAttributes(exec->globalData(), propertyName, value, attributes))
return;
- JSValue valueBefore = getDirect(propertyName);
+ JSValue valueBefore = getDirect(exec->globalData(), propertyName);
PutPropertySlot slot;
JSVariableObject::put(exec, propertyName, value, slot);
if (!valueBefore) {
- JSValue valueAfter = getDirect(propertyName);
+ JSValue valueAfter = getDirect(exec->globalData(), propertyName);
if (valueAfter)
JSObject::putWithAttributes(exec, propertyName, valueAfter, attributes);
}
{
ExecState* exec = JSGlobalObject::globalExec();
- // Prototypes
-
- d()->functionPrototype = new (exec) FunctionPrototype(exec, FunctionPrototype::createStructure(jsNull())); // The real prototype will be set once ObjectPrototype is created.
- d()->prototypeFunctionStructure = PrototypeFunction::createStructure(d()->functionPrototype);
- NativeFunctionWrapper* callFunction = 0;
- NativeFunctionWrapper* applyFunction = 0;
- d()->functionPrototype->addFunctionProperties(exec, d()->prototypeFunctionStructure.get(), &callFunction, &applyFunction);
- d()->callFunction = callFunction;
- d()->applyFunction = applyFunction;
- d()->objectPrototype = new (exec) ObjectPrototype(exec, ObjectPrototype::createStructure(jsNull()), d()->prototypeFunctionStructure.get());
- d()->functionPrototype->structure()->setPrototypeWithoutTransition(d()->objectPrototype);
+ m_functionPrototype.set(exec->globalData(), this, new (exec) FunctionPrototype(exec, this, FunctionPrototype::createStructure(exec->globalData(), jsNull()))); // The real prototype will be set once ObjectPrototype is created.
+ m_functionStructure.set(exec->globalData(), this, JSFunction::createStructure(exec->globalData(), m_functionPrototype.get()));
+ m_internalFunctionStructure.set(exec->globalData(), this, InternalFunction::createStructure(exec->globalData(), m_functionPrototype.get()));
+ JSFunction* callFunction = 0;
+ JSFunction* applyFunction = 0;
+ m_functionPrototype->addFunctionProperties(exec, this, m_functionStructure.get(), &callFunction, &applyFunction);
+ m_callFunction.set(exec->globalData(), this, callFunction);
+ m_applyFunction.set(exec->globalData(), this, applyFunction);
+ m_objectPrototype.set(exec->globalData(), this, new (exec) ObjectPrototype(exec, this, ObjectPrototype::createStructure(exec->globalData(), jsNull())));
+ m_functionPrototype->structure()->setPrototypeWithoutTransition(exec->globalData(), m_objectPrototype.get());
- d()->emptyObjectStructure = d()->objectPrototype->inheritorID();
+ m_emptyObjectStructure.set(exec->globalData(), this, m_objectPrototype->inheritorID(exec->globalData()));
+ m_nullPrototypeObjectStructure.set(exec->globalData(), this, createEmptyObjectStructure(exec->globalData(), jsNull()));
- d()->functionStructure = JSFunction::createStructure(d()->functionPrototype);
- d()->callbackFunctionStructure = JSCallbackFunction::createStructure(d()->functionPrototype);
- d()->argumentsStructure = Arguments::createStructure(d()->objectPrototype);
- d()->callbackConstructorStructure = JSCallbackConstructor::createStructure(d()->objectPrototype);
- d()->callbackObjectStructure = JSCallbackObject<JSObject>::createStructure(d()->objectPrototype);
+ m_callbackFunctionStructure.set(exec->globalData(), this, JSCallbackFunction::createStructure(exec->globalData(), m_functionPrototype.get()));
+ m_argumentsStructure.set(exec->globalData(), this, Arguments::createStructure(exec->globalData(), m_objectPrototype.get()));
+ m_callbackConstructorStructure.set(exec->globalData(), this, JSCallbackConstructor::createStructure(exec->globalData(), m_objectPrototype.get()));
+ m_callbackObjectStructure.set(exec->globalData(), this, JSCallbackObject<JSObjectWithGlobalObject>::createStructure(exec->globalData(), m_objectPrototype.get()));
- d()->arrayPrototype = new (exec) ArrayPrototype(ArrayPrototype::createStructure(d()->objectPrototype));
- d()->arrayStructure = JSArray::createStructure(d()->arrayPrototype);
- d()->regExpMatchesArrayStructure = RegExpMatchesArray::createStructure(d()->arrayPrototype);
+ m_arrayPrototype.set(exec->globalData(), this, new (exec) ArrayPrototype(this, ArrayPrototype::createStructure(exec->globalData(), m_objectPrototype.get())));
+ m_arrayStructure.set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), m_arrayPrototype.get()));
+ m_regExpMatchesArrayStructure.set(exec->globalData(), this, RegExpMatchesArray::createStructure(exec->globalData(), m_arrayPrototype.get()));
- d()->stringPrototype = new (exec) StringPrototype(exec, StringPrototype::createStructure(d()->objectPrototype));
- d()->stringObjectStructure = StringObject::createStructure(d()->stringPrototype);
+ m_stringPrototype.set(exec->globalData(), this, new (exec) StringPrototype(exec, this, StringPrototype::createStructure(exec->globalData(), m_objectPrototype.get())));
+ m_stringObjectStructure.set(exec->globalData(), this, StringObject::createStructure(exec->globalData(), m_stringPrototype.get()));
- d()->booleanPrototype = new (exec) BooleanPrototype(exec, BooleanPrototype::createStructure(d()->objectPrototype), d()->prototypeFunctionStructure.get());
- d()->booleanObjectStructure = BooleanObject::createStructure(d()->booleanPrototype);
+ m_booleanPrototype.set(exec->globalData(), this, new (exec) BooleanPrototype(exec, this, BooleanPrototype::createStructure(exec->globalData(), m_objectPrototype.get())));
+ m_booleanObjectStructure.set(exec->globalData(), this, BooleanObject::createStructure(exec->globalData(), m_booleanPrototype.get()));
- d()->numberPrototype = new (exec) NumberPrototype(exec, NumberPrototype::createStructure(d()->objectPrototype), d()->prototypeFunctionStructure.get());
- d()->numberObjectStructure = NumberObject::createStructure(d()->numberPrototype);
+ m_numberPrototype.set(exec->globalData(), this, new (exec) NumberPrototype(exec, this, NumberPrototype::createStructure(exec->globalData(), m_objectPrototype.get())));
+ m_numberObjectStructure.set(exec->globalData(), this, NumberObject::createStructure(exec->globalData(), m_numberPrototype.get()));
- d()->datePrototype = new (exec) DatePrototype(exec, DatePrototype::createStructure(d()->objectPrototype));
- d()->dateStructure = DateInstance::createStructure(d()->datePrototype);
+ m_datePrototype.set(exec->globalData(), this, new (exec) DatePrototype(exec, this, DatePrototype::createStructure(exec->globalData(), m_objectPrototype.get())));
+ m_dateStructure.set(exec->globalData(), this, DateInstance::createStructure(exec->globalData(), m_datePrototype.get()));
- d()->regExpPrototype = new (exec) RegExpPrototype(exec, RegExpPrototype::createStructure(d()->objectPrototype), d()->prototypeFunctionStructure.get());
- d()->regExpStructure = RegExpObject::createStructure(d()->regExpPrototype);
+ RegExp* emptyRegex = RegExp::create(&exec->globalData(), "", NoFlags);
+
+ m_regExpPrototype.set(exec->globalData(), this, new (exec) RegExpPrototype(exec, this, RegExpPrototype::createStructure(exec->globalData(), m_objectPrototype.get()), emptyRegex));
+ m_regExpStructure.set(exec->globalData(), this, RegExpObject::createStructure(exec->globalData(), m_regExpPrototype.get()));
- d()->methodCallDummy = constructEmptyObject(exec);
+ m_methodCallDummy.set(exec->globalData(), this, constructEmptyObject(exec));
- ErrorPrototype* errorPrototype = new (exec) ErrorPrototype(exec, ErrorPrototype::createStructure(d()->objectPrototype), d()->prototypeFunctionStructure.get());
- d()->errorStructure = ErrorInstance::createStructure(errorPrototype);
+ ErrorPrototype* errorPrototype = new (exec) ErrorPrototype(exec, this, ErrorPrototype::createStructure(exec->globalData(), m_objectPrototype.get()));
+ m_errorStructure.set(exec->globalData(), this, ErrorInstance::createStructure(exec->globalData(), errorPrototype));
// Constructors
- JSCell* objectConstructor = new (exec) ObjectConstructor(exec, ObjectConstructor::createStructure(d()->functionPrototype), d()->objectPrototype, d()->prototypeFunctionStructure.get());
- JSCell* functionConstructor = new (exec) FunctionConstructor(exec, FunctionConstructor::createStructure(d()->functionPrototype), d()->functionPrototype);
- JSCell* arrayConstructor = new (exec) ArrayConstructor(exec, ArrayConstructor::createStructure(d()->functionPrototype), d()->arrayPrototype, d()->prototypeFunctionStructure.get());
- JSCell* stringConstructor = new (exec) StringConstructor(exec, StringConstructor::createStructure(d()->functionPrototype), d()->prototypeFunctionStructure.get(), d()->stringPrototype);
- JSCell* booleanConstructor = new (exec) BooleanConstructor(exec, BooleanConstructor::createStructure(d()->functionPrototype), d()->booleanPrototype);
- JSCell* numberConstructor = new (exec) NumberConstructor(exec, NumberConstructor::createStructure(d()->functionPrototype), d()->numberPrototype);
- JSCell* dateConstructor = new (exec) DateConstructor(exec, DateConstructor::createStructure(d()->functionPrototype), d()->prototypeFunctionStructure.get(), d()->datePrototype);
-
- d()->regExpConstructor = new (exec) RegExpConstructor(exec, RegExpConstructor::createStructure(d()->functionPrototype), d()->regExpPrototype);
-
- d()->errorConstructor = new (exec) ErrorConstructor(exec, ErrorConstructor::createStructure(d()->functionPrototype), errorPrototype);
-
- RefPtr<Structure> nativeErrorPrototypeStructure = NativeErrorPrototype::createStructure(errorPrototype);
- RefPtr<Structure> nativeErrorStructure = NativeErrorConstructor::createStructure(d()->functionPrototype);
-
- d()->evalErrorConstructor = new (exec) NativeErrorConstructor(exec, nativeErrorStructure, nativeErrorPrototypeStructure, "EvalError");
- d()->rangeErrorConstructor = new (exec) NativeErrorConstructor(exec, nativeErrorStructure, nativeErrorPrototypeStructure, "RangeError");
- d()->referenceErrorConstructor = new (exec) NativeErrorConstructor(exec, nativeErrorStructure, nativeErrorPrototypeStructure, "ReferenceError");
- d()->syntaxErrorConstructor = new (exec) NativeErrorConstructor(exec, nativeErrorStructure, nativeErrorPrototypeStructure, "SyntaxError");
- d()->typeErrorConstructor = new (exec) NativeErrorConstructor(exec, nativeErrorStructure, nativeErrorPrototypeStructure, "TypeError");
- d()->URIErrorConstructor = new (exec) NativeErrorConstructor(exec, nativeErrorStructure, nativeErrorPrototypeStructure, "URIError");
-
- d()->objectPrototype->putDirectFunctionWithoutTransition(exec->propertyNames().constructor, objectConstructor, DontEnum);
- d()->functionPrototype->putDirectFunctionWithoutTransition(exec->propertyNames().constructor, functionConstructor, DontEnum);
- d()->arrayPrototype->putDirectFunctionWithoutTransition(exec->propertyNames().constructor, arrayConstructor, DontEnum);
- d()->booleanPrototype->putDirectFunctionWithoutTransition(exec->propertyNames().constructor, booleanConstructor, DontEnum);
- d()->stringPrototype->putDirectFunctionWithoutTransition(exec->propertyNames().constructor, stringConstructor, DontEnum);
- d()->numberPrototype->putDirectFunctionWithoutTransition(exec->propertyNames().constructor, numberConstructor, DontEnum);
- d()->datePrototype->putDirectFunctionWithoutTransition(exec->propertyNames().constructor, dateConstructor, DontEnum);
- d()->regExpPrototype->putDirectFunctionWithoutTransition(exec->propertyNames().constructor, d()->regExpConstructor, DontEnum);
- errorPrototype->putDirectFunctionWithoutTransition(exec->propertyNames().constructor, d()->errorConstructor, DontEnum);
-
- // Set global constructors
-
- // FIXME: These properties could be handled by a static hash table.
-
- putDirectFunctionWithoutTransition(Identifier(exec, "Object"), objectConstructor, DontEnum);
- putDirectFunctionWithoutTransition(Identifier(exec, "Function"), functionConstructor, DontEnum);
- putDirectFunctionWithoutTransition(Identifier(exec, "Array"), arrayConstructor, DontEnum);
- putDirectFunctionWithoutTransition(Identifier(exec, "Boolean"), booleanConstructor, DontEnum);
- putDirectFunctionWithoutTransition(Identifier(exec, "String"), stringConstructor, DontEnum);
- putDirectFunctionWithoutTransition(Identifier(exec, "Number"), numberConstructor, DontEnum);
- putDirectFunctionWithoutTransition(Identifier(exec, "Date"), dateConstructor, DontEnum);
- putDirectFunctionWithoutTransition(Identifier(exec, "RegExp"), d()->regExpConstructor, DontEnum);
- putDirectFunctionWithoutTransition(Identifier(exec, "Error"), d()->errorConstructor, DontEnum);
- putDirectFunctionWithoutTransition(Identifier(exec, "EvalError"), d()->evalErrorConstructor);
- putDirectFunctionWithoutTransition(Identifier(exec, "RangeError"), d()->rangeErrorConstructor);
- putDirectFunctionWithoutTransition(Identifier(exec, "ReferenceError"), d()->referenceErrorConstructor);
- putDirectFunctionWithoutTransition(Identifier(exec, "SyntaxError"), d()->syntaxErrorConstructor);
- putDirectFunctionWithoutTransition(Identifier(exec, "TypeError"), d()->typeErrorConstructor);
- putDirectFunctionWithoutTransition(Identifier(exec, "URIError"), d()->URIErrorConstructor);
-
- // Set global values.
+ JSCell* objectConstructor = new (exec) ObjectConstructor(exec, this, ObjectConstructor::createStructure(exec->globalData(), m_functionPrototype.get()), m_objectPrototype.get());
+ JSCell* functionConstructor = new (exec) FunctionConstructor(exec, this, FunctionConstructor::createStructure(exec->globalData(), m_functionPrototype.get()), m_functionPrototype.get());
+ JSCell* arrayConstructor = new (exec) ArrayConstructor(exec, this, ArrayConstructor::createStructure(exec->globalData(), m_functionPrototype.get()), m_arrayPrototype.get());
+ JSCell* stringConstructor = new (exec) StringConstructor(exec, this, StringConstructor::createStructure(exec->globalData(), m_functionPrototype.get()), m_stringPrototype.get());
+ JSCell* booleanConstructor = new (exec) BooleanConstructor(exec, this, BooleanConstructor::createStructure(exec->globalData(), m_functionPrototype.get()), m_booleanPrototype.get());
+ JSCell* numberConstructor = new (exec) NumberConstructor(exec, this, NumberConstructor::createStructure(exec->globalData(), m_functionPrototype.get()), m_numberPrototype.get());
+ JSCell* dateConstructor = new (exec) DateConstructor(exec, this, DateConstructor::createStructure(exec->globalData(), m_functionPrototype.get()), m_datePrototype.get());
+
+ m_regExpConstructor.set(exec->globalData(), this, new (exec) RegExpConstructor(exec, this, RegExpConstructor::createStructure(exec->globalData(), m_functionPrototype.get()), m_regExpPrototype.get()));
+
+ m_errorConstructor.set(exec->globalData(), this, new (exec) ErrorConstructor(exec, this, ErrorConstructor::createStructure(exec->globalData(), m_functionPrototype.get()), errorPrototype));
+
+ Structure* nativeErrorPrototypeStructure = NativeErrorPrototype::createStructure(exec->globalData(), errorPrototype);
+ Structure* nativeErrorStructure = NativeErrorConstructor::createStructure(exec->globalData(), m_functionPrototype.get());
+ m_evalErrorConstructor.set(exec->globalData(), this, new (exec) NativeErrorConstructor(exec, this, nativeErrorStructure, nativeErrorPrototypeStructure, "EvalError"));
+ m_rangeErrorConstructor.set(exec->globalData(), this, new (exec) NativeErrorConstructor(exec, this, nativeErrorStructure, nativeErrorPrototypeStructure, "RangeError"));
+ m_referenceErrorConstructor.set(exec->globalData(), this, new (exec) NativeErrorConstructor(exec, this, nativeErrorStructure, nativeErrorPrototypeStructure, "ReferenceError"));
+ m_syntaxErrorConstructor.set(exec->globalData(), this, new (exec) NativeErrorConstructor(exec, this, nativeErrorStructure, nativeErrorPrototypeStructure, "SyntaxError"));
+ m_typeErrorConstructor.set(exec->globalData(), this, new (exec) NativeErrorConstructor(exec, this, nativeErrorStructure, nativeErrorPrototypeStructure, "TypeError"));
+ m_URIErrorConstructor.set(exec->globalData(), this, new (exec) NativeErrorConstructor(exec, this, nativeErrorStructure, nativeErrorPrototypeStructure, "URIError"));
+
+ m_objectPrototype->putDirectFunctionWithoutTransition(exec->globalData(), exec->propertyNames().constructor, objectConstructor, DontEnum);
+ m_functionPrototype->putDirectFunctionWithoutTransition(exec->globalData(), exec->propertyNames().constructor, functionConstructor, DontEnum);
+ m_arrayPrototype->putDirectFunctionWithoutTransition(exec->globalData(), exec->propertyNames().constructor, arrayConstructor, DontEnum);
+ m_booleanPrototype->putDirectFunctionWithoutTransition(exec->globalData(), exec->propertyNames().constructor, booleanConstructor, DontEnum);
+ m_stringPrototype->putDirectFunctionWithoutTransition(exec->globalData(), exec->propertyNames().constructor, stringConstructor, DontEnum);
+ m_numberPrototype->putDirectFunctionWithoutTransition(exec->globalData(), exec->propertyNames().constructor, numberConstructor, DontEnum);
+ m_datePrototype->putDirectFunctionWithoutTransition(exec->globalData(), exec->propertyNames().constructor, dateConstructor, DontEnum);
+ m_regExpPrototype->putDirectFunctionWithoutTransition(exec->globalData(), exec->propertyNames().constructor, m_regExpConstructor.get(), DontEnum);
+ errorPrototype->putDirectFunctionWithoutTransition(exec->globalData(), exec->propertyNames().constructor, m_errorConstructor.get(), DontEnum);
+
+ putDirectFunctionWithoutTransition(exec->globalData(), Identifier(exec, "Object"), objectConstructor, DontEnum);
+ putDirectFunctionWithoutTransition(exec->globalData(), Identifier(exec, "Function"), functionConstructor, DontEnum);
+ putDirectFunctionWithoutTransition(exec->globalData(), Identifier(exec, "Array"), arrayConstructor, DontEnum);
+ putDirectFunctionWithoutTransition(exec->globalData(), Identifier(exec, "Boolean"), booleanConstructor, DontEnum);
+ putDirectFunctionWithoutTransition(exec->globalData(), Identifier(exec, "String"), stringConstructor, DontEnum);
+ putDirectFunctionWithoutTransition(exec->globalData(), Identifier(exec, "Number"), numberConstructor, DontEnum);
+ putDirectFunctionWithoutTransition(exec->globalData(), Identifier(exec, "Date"), dateConstructor, DontEnum);
+ putDirectFunctionWithoutTransition(exec->globalData(), Identifier(exec, "RegExp"), m_regExpConstructor.get(), DontEnum);
+ putDirectFunctionWithoutTransition(exec->globalData(), Identifier(exec, "Error"), m_errorConstructor.get(), DontEnum);
+ putDirectFunctionWithoutTransition(exec->globalData(), Identifier(exec, "EvalError"), m_evalErrorConstructor.get(), DontEnum);
+ putDirectFunctionWithoutTransition(exec->globalData(), Identifier(exec, "RangeError"), m_rangeErrorConstructor.get(), DontEnum);
+ putDirectFunctionWithoutTransition(exec->globalData(), Identifier(exec, "ReferenceError"), m_referenceErrorConstructor.get(), DontEnum);
+ putDirectFunctionWithoutTransition(exec->globalData(), Identifier(exec, "SyntaxError"), m_syntaxErrorConstructor.get(), DontEnum);
+ putDirectFunctionWithoutTransition(exec->globalData(), Identifier(exec, "TypeError"), m_typeErrorConstructor.get(), DontEnum);
+ putDirectFunctionWithoutTransition(exec->globalData(), Identifier(exec, "URIError"), m_URIErrorConstructor.get(), DontEnum);
+
+ m_evalFunction.set(exec->globalData(), this, new (exec) JSFunction(exec, this, m_functionStructure.get(), 1, exec->propertyNames().eval, globalFuncEval));
+ putDirectFunctionWithoutTransition(exec, m_evalFunction.get(), DontEnum);
+
GlobalPropertyInfo staticGlobals[] = {
- GlobalPropertyInfo(Identifier(exec, "Math"), new (exec) MathObject(exec, MathObject::createStructure(d()->objectPrototype)), DontEnum | DontDelete),
- GlobalPropertyInfo(Identifier(exec, "NaN"), jsNaN(exec), DontEnum | DontDelete | ReadOnly),
- GlobalPropertyInfo(Identifier(exec, "Infinity"), jsNumber(exec, Inf), DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(Identifier(exec, "Math"), new (exec) MathObject(exec, this, MathObject::createStructure(exec->globalData(), m_objectPrototype.get())), DontEnum | DontDelete),
+ GlobalPropertyInfo(Identifier(exec, "NaN"), jsNaN(), DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(Identifier(exec, "Infinity"), jsNumber(Inf), DontEnum | DontDelete | ReadOnly),
GlobalPropertyInfo(Identifier(exec, "undefined"), jsUndefined(), DontEnum | DontDelete | ReadOnly),
- GlobalPropertyInfo(Identifier(exec, "JSON"), new (exec) JSONObject(JSONObject::createStructure(d()->objectPrototype)), DontEnum | DontDelete)
+ GlobalPropertyInfo(Identifier(exec, "JSON"), new (exec) JSONObject(this, JSONObject::createStructure(exec->globalData(), m_objectPrototype.get())), DontEnum | DontDelete)
};
+ addStaticGlobals(staticGlobals, WTF_ARRAY_LENGTH(staticGlobals));
- addStaticGlobals(staticGlobals, sizeof(staticGlobals) / sizeof(GlobalPropertyInfo));
-
- // Set global functions.
-
- d()->evalFunction = new (exec) GlobalEvalFunction(exec, GlobalEvalFunction::createStructure(d()->functionPrototype), 1, exec->propertyNames().eval, globalFuncEval, this);
- putDirectFunctionWithoutTransition(exec, d()->evalFunction, DontEnum);
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, d()->prototypeFunctionStructure.get(), 2, Identifier(exec, "parseInt"), globalFuncParseInt), DontEnum);
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "parseFloat"), globalFuncParseFloat), DontEnum);
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "isNaN"), globalFuncIsNaN), DontEnum);
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "isFinite"), globalFuncIsFinite), DontEnum);
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "escape"), globalFuncEscape), DontEnum);
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "unescape"), globalFuncUnescape), DontEnum);
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "decodeURI"), globalFuncDecodeURI), DontEnum);
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "decodeURIComponent"), globalFuncDecodeURIComponent), DontEnum);
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "encodeURI"), globalFuncEncodeURI), DontEnum);
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "encodeURIComponent"), globalFuncEncodeURIComponent), DontEnum);
-#ifndef NDEBUG
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "jscprint"), globalFuncJSCPrint), DontEnum);
-#endif
-
- resetPrototype(prototype);
+ resetPrototype(exec->globalData(), prototype);
}
// Set prototype, and also insert the object prototype at the end of the chain.
-void JSGlobalObject::resetPrototype(JSValue prototype)
+void JSGlobalObject::resetPrototype(JSGlobalData& globalData, JSValue prototype)
{
- setPrototype(prototype);
+ setPrototype(globalData, prototype);
JSObject* oldLastInPrototypeChain = lastInPrototypeChain(this);
- JSObject* objectPrototype = d()->objectPrototype;
+ JSObject* objectPrototype = m_objectPrototype.get();
if (oldLastInPrototypeChain != objectPrototype)
- oldLastInPrototypeChain->setPrototype(objectPrototype);
+ oldLastInPrototypeChain->setPrototype(globalData, objectPrototype);
}
-void JSGlobalObject::markChildren(MarkStack& markStack)
+void JSGlobalObject::visitChildren(SlotVisitor& visitor)
{
- JSVariableObject::markChildren(markStack);
-
- HashSet<GlobalCodeBlock*>::const_iterator end = codeBlocks().end();
- for (HashSet<GlobalCodeBlock*>::const_iterator it = codeBlocks().begin(); it != end; ++it)
- (*it)->markAggregate(markStack);
-
- RegisterFile& registerFile = globalData()->interpreter->registerFile();
- if (registerFile.globalObject() == this)
- registerFile.markGlobals(markStack, &globalData()->heap);
-
- markIfNeeded(markStack, d()->regExpConstructor);
- markIfNeeded(markStack, d()->errorConstructor);
- markIfNeeded(markStack, d()->evalErrorConstructor);
- markIfNeeded(markStack, d()->rangeErrorConstructor);
- markIfNeeded(markStack, d()->referenceErrorConstructor);
- markIfNeeded(markStack, d()->syntaxErrorConstructor);
- markIfNeeded(markStack, d()->typeErrorConstructor);
- markIfNeeded(markStack, d()->URIErrorConstructor);
-
- markIfNeeded(markStack, d()->evalFunction);
- markIfNeeded(markStack, d()->callFunction);
- markIfNeeded(markStack, d()->applyFunction);
-
- markIfNeeded(markStack, d()->objectPrototype);
- markIfNeeded(markStack, d()->functionPrototype);
- markIfNeeded(markStack, d()->arrayPrototype);
- markIfNeeded(markStack, d()->booleanPrototype);
- markIfNeeded(markStack, d()->stringPrototype);
- markIfNeeded(markStack, d()->numberPrototype);
- markIfNeeded(markStack, d()->datePrototype);
- markIfNeeded(markStack, d()->regExpPrototype);
-
- markIfNeeded(markStack, d()->methodCallDummy);
-
- markIfNeeded(markStack, d()->errorStructure);
- markIfNeeded(markStack, d()->argumentsStructure);
- markIfNeeded(markStack, d()->arrayStructure);
- markIfNeeded(markStack, d()->booleanObjectStructure);
- markIfNeeded(markStack, d()->callbackConstructorStructure);
- markIfNeeded(markStack, d()->callbackFunctionStructure);
- markIfNeeded(markStack, d()->callbackObjectStructure);
- markIfNeeded(markStack, d()->dateStructure);
- markIfNeeded(markStack, d()->emptyObjectStructure);
- markIfNeeded(markStack, d()->errorStructure);
- markIfNeeded(markStack, d()->functionStructure);
- markIfNeeded(markStack, d()->numberObjectStructure);
- markIfNeeded(markStack, d()->prototypeFunctionStructure);
- markIfNeeded(markStack, d()->regExpMatchesArrayStructure);
- markIfNeeded(markStack, d()->regExpStructure);
- markIfNeeded(markStack, d()->stringObjectStructure);
-
- // No need to mark the other structures, because their prototypes are all
- // guaranteed to be referenced elsewhere.
-
- Register* registerArray = d()->registerArray.get();
- if (!registerArray)
- return;
-
- size_t size = d()->registerArraySize;
- markStack.appendValues(reinterpret_cast<JSValue*>(registerArray), size);
+ ASSERT_GC_OBJECT_INHERITS(this, &s_info);
+ COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
+ ASSERT(structure()->typeInfo().overridesVisitChildren());
+ JSVariableObject::visitChildren(visitor);
+
+ visitIfNeeded(visitor, &m_globalScopeChain);
+ visitIfNeeded(visitor, &m_methodCallDummy);
+
+ visitIfNeeded(visitor, &m_regExpConstructor);
+ visitIfNeeded(visitor, &m_errorConstructor);
+ visitIfNeeded(visitor, &m_evalErrorConstructor);
+ visitIfNeeded(visitor, &m_rangeErrorConstructor);
+ visitIfNeeded(visitor, &m_referenceErrorConstructor);
+ visitIfNeeded(visitor, &m_syntaxErrorConstructor);
+ visitIfNeeded(visitor, &m_typeErrorConstructor);
+ visitIfNeeded(visitor, &m_URIErrorConstructor);
+
+ visitIfNeeded(visitor, &m_evalFunction);
+ visitIfNeeded(visitor, &m_callFunction);
+ visitIfNeeded(visitor, &m_applyFunction);
+
+ visitIfNeeded(visitor, &m_objectPrototype);
+ visitIfNeeded(visitor, &m_functionPrototype);
+ visitIfNeeded(visitor, &m_arrayPrototype);
+ visitIfNeeded(visitor, &m_booleanPrototype);
+ visitIfNeeded(visitor, &m_stringPrototype);
+ visitIfNeeded(visitor, &m_numberPrototype);
+ visitIfNeeded(visitor, &m_datePrototype);
+ visitIfNeeded(visitor, &m_regExpPrototype);
+
+ visitIfNeeded(visitor, &m_argumentsStructure);
+ visitIfNeeded(visitor, &m_arrayStructure);
+ visitIfNeeded(visitor, &m_booleanObjectStructure);
+ visitIfNeeded(visitor, &m_callbackConstructorStructure);
+ visitIfNeeded(visitor, &m_callbackFunctionStructure);
+ visitIfNeeded(visitor, &m_callbackObjectStructure);
+ visitIfNeeded(visitor, &m_dateStructure);
+ visitIfNeeded(visitor, &m_emptyObjectStructure);
+ visitIfNeeded(visitor, &m_nullPrototypeObjectStructure);
+ visitIfNeeded(visitor, &m_errorStructure);
+ visitIfNeeded(visitor, &m_functionStructure);
+ visitIfNeeded(visitor, &m_numberObjectStructure);
+ visitIfNeeded(visitor, &m_regExpMatchesArrayStructure);
+ visitIfNeeded(visitor, &m_regExpStructure);
+ visitIfNeeded(visitor, &m_stringObjectStructure);
+ visitIfNeeded(visitor, &m_internalFunctionStructure);
+
+ if (m_registerArray) {
+ // Outside the execution of global code, when our variables are torn off,
+ // we can mark the torn-off array.
+ visitor.appendValues(m_registerArray.get(), m_registerArraySize);
+ } else if (m_registers) {
+ // During execution of global code, when our variables are in the register file,
+ // the symbol table tells us how many variables there are, and registers
+ // points to where they end, and the registers used for execution begin.
+ visitor.appendValues(m_registers - symbolTable().size(), symbolTable().size());
+ }
}
ExecState* JSGlobalObject::globalExec()
{
- return CallFrame::create(d()->globalCallFrame + RegisterFile::CallFrameHeaderSize);
+ return CallFrame::create(m_globalCallFrame + RegisterFile::CallFrameHeaderSize);
}
bool JSGlobalObject::isDynamicScope(bool&) const
return true;
}
+void JSGlobalObject::disableEval()
+{
+ ASSERT(m_isEvalEnabled);
+ m_isEvalEnabled = false;
+}
+
void JSGlobalObject::copyGlobalsFrom(RegisterFile& registerFile)
{
- ASSERT(!d()->registerArray);
- ASSERT(!d()->registerArraySize);
+ ASSERT(!m_registerArray);
+ ASSERT(!m_registerArraySize);
int numGlobals = registerFile.numGlobals();
if (!numGlobals) {
- d()->registers = 0;
+ m_registers = 0;
return;
}
-
- Register* registerArray = copyRegisterArray(registerFile.lastGlobal(), numGlobals);
- setRegisters(registerArray + numGlobals, registerArray, numGlobals);
+
+ OwnArrayPtr<WriteBarrier<Unknown> > registerArray = copyRegisterArray(globalData(), reinterpret_cast<WriteBarrier<Unknown>*>(registerFile.lastGlobal()), numGlobals, numGlobals);
+ WriteBarrier<Unknown>* registers = registerArray.get() + numGlobals;
+ setRegisters(registers, registerArray.release(), numGlobals);
}
void JSGlobalObject::copyGlobalsTo(RegisterFile& registerFile)
registerFile.setGlobalObject(this);
registerFile.setNumGlobals(symbolTable().size());
- if (d()->registerArray) {
- memcpy(registerFile.start() - d()->registerArraySize, d()->registerArray.get(), d()->registerArraySize * sizeof(Register));
- setRegisters(registerFile.start(), 0, 0);
+ if (m_registerArray) {
+ // The register file is always a gc root so no barrier is needed here
+ memcpy(registerFile.start() - m_registerArraySize, m_registerArray.get(), m_registerArraySize * sizeof(WriteBarrier<Unknown>));
+ setRegisters(reinterpret_cast<WriteBarrier<Unknown>*>(registerFile.start()), nullptr, 0);
}
}
+void JSGlobalObject::resizeRegisters(int oldSize, int newSize)
+{
+ ASSERT(oldSize <= newSize);
+ if (newSize == oldSize)
+ return;
+ ASSERT(newSize && newSize > oldSize);
+ if (m_registerArray || !m_registers) {
+ ASSERT(static_cast<size_t>(oldSize) == m_registerArraySize);
+ OwnArrayPtr<WriteBarrier<Unknown> > registerArray = adoptArrayPtr(new WriteBarrier<Unknown>[newSize]);
+ for (int i = 0; i < oldSize; i++)
+ registerArray[newSize - oldSize + i].set(globalData(), this, m_registerArray[i].get());
+ WriteBarrier<Unknown>* registers = registerArray.get() + newSize;
+ setRegisters(registers, registerArray.release(), newSize);
+ } else {
+ ASSERT(static_cast<size_t>(newSize) < globalData().interpreter->registerFile().maxGlobals());
+ globalData().interpreter->registerFile().setNumGlobals(newSize);
+ }
+
+ for (int i = -newSize; i < -oldSize; ++i)
+ m_registers[i].setUndefined();
+}
+
void* JSGlobalObject::operator new(size_t size, JSGlobalData* globalData)
{
return globalData->heap.allocate(size);
}
-void JSGlobalObject::destroyJSGlobalObjectData(void* jsGlobalObjectData)
+void JSGlobalObject::addStaticGlobals(GlobalPropertyInfo* globals, int count)
+{
+ size_t oldSize = m_registerArraySize;
+ size_t newSize = oldSize + count;
+ OwnArrayPtr<WriteBarrier<Unknown> > registerArray = adoptArrayPtr(new WriteBarrier<Unknown>[newSize]);
+ if (m_registerArray) {
+ // memcpy is safe here as we're copying barriers we already own from the existing array
+ memcpy(registerArray.get() + count, m_registerArray.get(), oldSize * sizeof(Register));
+ }
+
+ WriteBarrier<Unknown>* registers = registerArray.get() + newSize;
+ setRegisters(registers, registerArray.release(), newSize);
+
+ for (int i = 0, index = -static_cast<int>(oldSize) - 1; i < count; ++i, --index) {
+ GlobalPropertyInfo& global = globals[i];
+ ASSERT(global.attributes & DontDelete);
+ SymbolTableEntry newEntry(index, global.attributes);
+ symbolTable().add(global.identifier.impl(), newEntry);
+ registerAt(index).set(globalData(), this, global.value);
+ }
+}
+
+bool JSGlobalObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+{
+ if (getStaticFunctionSlot<JSVariableObject>(exec, ExecState::globalObjectTable(exec), this, propertyName, slot))
+ return true;
+ return symbolTableGet(propertyName, slot);
+}
+
+bool JSGlobalObject::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ if (getStaticFunctionDescriptor<JSVariableObject>(exec, ExecState::globalObjectTable(exec), this, propertyName, descriptor))
+ return true;
+ return symbolTableGet(propertyName, descriptor);
+}
+
+void JSGlobalObject::WeakMapsFinalizer::finalize(Handle<Unknown> handle, void*)
+{
+ JSGlobalObject* globalObject = asGlobalObject(handle.get());
+ globalObject->m_weakMaps.clear();
+}
+
+JSGlobalObject::WeakMapsFinalizer* JSGlobalObject::weakMapsFinalizer()
{
- delete static_cast<JSGlobalObjectData*>(jsGlobalObjectData);
+ static WeakMapsFinalizer* finalizer = new WeakMapsFinalizer();
+ return finalizer;
}
-DynamicGlobalObjectScope::DynamicGlobalObjectScope(CallFrame* callFrame, JSGlobalObject* dynamicGlobalObject)
- : m_dynamicGlobalObjectSlot(callFrame->globalData().dynamicGlobalObject)
+DynamicGlobalObjectScope::DynamicGlobalObjectScope(JSGlobalData& globalData, JSGlobalObject* dynamicGlobalObject)
+ : m_dynamicGlobalObjectSlot(globalData.dynamicGlobalObject)
, m_savedDynamicGlobalObject(m_dynamicGlobalObjectSlot)
{
if (!m_dynamicGlobalObjectSlot) {
-#if ENABLE(JIT)
- if (ExecutablePool::underMemoryPressure())
- callFrame->globalData().recompileAllJSFunctions();
+#if ENABLE(ASSEMBLER)
+ if (ExecutableAllocator::underMemoryPressure())
+ globalData.recompileAllJSFunctions();
#endif
+
m_dynamicGlobalObjectSlot = dynamicGlobalObject;
// Reset the date cache between JS invocations to force the VM
// to observe time zone changes.
- callFrame->globalData().resetDateCache();
+ globalData.resetDateCache();
}
}
+void slowValidateCell(JSGlobalObject* globalObject)
+{
+ if (!globalObject->isGlobalObject())
+ CRASH();
+ ASSERT_GC_OBJECT_INHERITS(globalObject, &JSGlobalObject::s_info);
+}
+
} // namespace JSC
#include "JSGlobalData.h"
#include "JSVariableObject.h"
#include "JSWeakObjectMapRefInternal.h"
-#include "NativeFunctionWrapper.h"
#include "NumberPrototype.h"
#include "StringPrototype.h"
+#include "StructureChain.h"
#include <wtf/HashSet.h>
#include <wtf/OwnPtr.h>
#include <wtf/RandomNumber.h>
class ErrorConstructor;
class FunctionPrototype;
class GlobalCodeBlock;
- class GlobalEvalFunction;
class NativeErrorConstructor;
class ProgramCodeBlock;
- class PrototypeFunction;
class RegExpConstructor;
class RegExpPrototype;
class RegisterFile;
class JSGlobalObject : public JSVariableObject {
protected:
- using JSVariableObject::JSVariableObjectData;
typedef HashSet<RefPtr<OpaqueJSWeakObjectMap> > WeakMapSet;
- struct JSGlobalObjectData : public JSVariableObjectData {
- // We use an explicit destructor function pointer instead of a
- // virtual destructor because we want to avoid adding a vtable
- // pointer to this struct. Adding a vtable pointer would force the
- // compiler to emit costly pointer fixup code when casting from
- // JSVariableObjectData* to JSGlobalObjectData*.
- typedef void (*Destructor)(void*);
-
- JSGlobalObjectData(Destructor destructor)
- : JSVariableObjectData(&symbolTable, 0)
- , destructor(destructor)
- , registerArraySize(0)
- , globalScopeChain(NoScopeChain())
- , regExpConstructor(0)
- , errorConstructor(0)
- , evalErrorConstructor(0)
- , rangeErrorConstructor(0)
- , referenceErrorConstructor(0)
- , syntaxErrorConstructor(0)
- , typeErrorConstructor(0)
- , URIErrorConstructor(0)
- , evalFunction(0)
- , callFunction(0)
- , applyFunction(0)
- , objectPrototype(0)
- , functionPrototype(0)
- , arrayPrototype(0)
- , booleanPrototype(0)
- , stringPrototype(0)
- , numberPrototype(0)
- , datePrototype(0)
- , regExpPrototype(0)
- , methodCallDummy(0)
- , weakRandom(static_cast<unsigned>(randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0)))
- {
- }
-
- Destructor destructor;
-
- size_t registerArraySize;
-
- JSGlobalObject* next;
- JSGlobalObject* prev;
-
- Debugger* debugger;
-
- ScopeChain globalScopeChain;
- Register globalCallFrame[RegisterFile::CallFrameHeaderSize];
-
- int recursion;
-
- RegExpConstructor* regExpConstructor;
- ErrorConstructor* errorConstructor;
- NativeErrorConstructor* evalErrorConstructor;
- NativeErrorConstructor* rangeErrorConstructor;
- NativeErrorConstructor* referenceErrorConstructor;
- NativeErrorConstructor* syntaxErrorConstructor;
- NativeErrorConstructor* typeErrorConstructor;
- NativeErrorConstructor* URIErrorConstructor;
-
- GlobalEvalFunction* evalFunction;
- NativeFunctionWrapper* callFunction;
- NativeFunctionWrapper* applyFunction;
-
- ObjectPrototype* objectPrototype;
- FunctionPrototype* functionPrototype;
- ArrayPrototype* arrayPrototype;
- BooleanPrototype* booleanPrototype;
- StringPrototype* stringPrototype;
- NumberPrototype* numberPrototype;
- DatePrototype* datePrototype;
- RegExpPrototype* regExpPrototype;
-
- JSObject* methodCallDummy;
-
- RefPtr<Structure> argumentsStructure;
- RefPtr<Structure> arrayStructure;
- RefPtr<Structure> booleanObjectStructure;
- RefPtr<Structure> callbackConstructorStructure;
- RefPtr<Structure> callbackFunctionStructure;
- RefPtr<Structure> callbackObjectStructure;
- RefPtr<Structure> dateStructure;
- RefPtr<Structure> emptyObjectStructure;
- RefPtr<Structure> errorStructure;
- RefPtr<Structure> functionStructure;
- RefPtr<Structure> numberObjectStructure;
- RefPtr<Structure> prototypeFunctionStructure;
- RefPtr<Structure> regExpMatchesArrayStructure;
- RefPtr<Structure> regExpStructure;
- RefPtr<Structure> stringObjectStructure;
-
- SymbolTable symbolTable;
- unsigned profileGroup;
-
- RefPtr<JSGlobalData> globalData;
-
- HashSet<GlobalCodeBlock*> codeBlocks;
- WeakMapSet weakMaps;
- WeakRandom weakRandom;
+ RefPtr<JSGlobalData> m_globalData;
+
+ size_t m_registerArraySize;
+ Register m_globalCallFrame[RegisterFile::CallFrameHeaderSize];
+
+ WriteBarrier<ScopeChainNode> m_globalScopeChain;
+ WriteBarrier<JSObject> m_methodCallDummy;
+
+ WriteBarrier<RegExpConstructor> m_regExpConstructor;
+ WriteBarrier<ErrorConstructor> m_errorConstructor;
+ WriteBarrier<NativeErrorConstructor> m_evalErrorConstructor;
+ WriteBarrier<NativeErrorConstructor> m_rangeErrorConstructor;
+ WriteBarrier<NativeErrorConstructor> m_referenceErrorConstructor;
+ WriteBarrier<NativeErrorConstructor> m_syntaxErrorConstructor;
+ WriteBarrier<NativeErrorConstructor> m_typeErrorConstructor;
+ WriteBarrier<NativeErrorConstructor> m_URIErrorConstructor;
+
+ WriteBarrier<JSFunction> m_evalFunction;
+ WriteBarrier<JSFunction> m_callFunction;
+ WriteBarrier<JSFunction> m_applyFunction;
+
+ WriteBarrier<ObjectPrototype> m_objectPrototype;
+ WriteBarrier<FunctionPrototype> m_functionPrototype;
+ WriteBarrier<ArrayPrototype> m_arrayPrototype;
+ WriteBarrier<BooleanPrototype> m_booleanPrototype;
+ WriteBarrier<StringPrototype> m_stringPrototype;
+ WriteBarrier<NumberPrototype> m_numberPrototype;
+ WriteBarrier<DatePrototype> m_datePrototype;
+ WriteBarrier<RegExpPrototype> m_regExpPrototype;
+
+ WriteBarrier<Structure> m_argumentsStructure;
+ WriteBarrier<Structure> m_arrayStructure;
+ WriteBarrier<Structure> m_booleanObjectStructure;
+ WriteBarrier<Structure> m_callbackConstructorStructure;
+ WriteBarrier<Structure> m_callbackFunctionStructure;
+ WriteBarrier<Structure> m_callbackObjectStructure;
+ WriteBarrier<Structure> m_dateStructure;
+ WriteBarrier<Structure> m_emptyObjectStructure;
+ WriteBarrier<Structure> m_nullPrototypeObjectStructure;
+ WriteBarrier<Structure> m_errorStructure;
+ WriteBarrier<Structure> m_functionStructure;
+ WriteBarrier<Structure> m_numberObjectStructure;
+ WriteBarrier<Structure> m_regExpMatchesArrayStructure;
+ WriteBarrier<Structure> m_regExpStructure;
+ WriteBarrier<Structure> m_stringObjectStructure;
+ WriteBarrier<Structure> m_internalFunctionStructure;
+
+ unsigned m_profileGroup;
+ Debugger* m_debugger;
+
+ WeakMapSet m_weakMaps;
+ Weak<JSGlobalObject> m_weakMapsFinalizer;
+ class WeakMapsFinalizer : public WeakHandleOwner {
+ public:
+ virtual void finalize(Handle<Unknown>, void* context);
};
+ static WeakMapsFinalizer* weakMapsFinalizer();
+
+ WeakRandom m_weakRandom;
+
+ SymbolTable m_symbolTable;
+
+ bool m_isEvalEnabled;
public:
void* operator new(size_t, JSGlobalData*);
- explicit JSGlobalObject()
- : JSVariableObject(JSGlobalObject::createStructure(jsNull()), new JSGlobalObjectData(destroyJSGlobalObjectData))
+ explicit JSGlobalObject(JSGlobalData& globalData, Structure* structure)
+ : JSVariableObject(globalData, structure, &m_symbolTable, 0)
+ , m_registerArraySize(0)
+ , m_globalScopeChain()
+ , m_weakRandom(static_cast<unsigned>(randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0)))
+ , m_isEvalEnabled(true)
{
+ COMPILE_ASSERT(JSGlobalObject::AnonymousSlotCount == 1, JSGlobalObject_has_only_a_single_slot);
+ putThisToAnonymousValue(0);
init(this);
}
+ static JS_EXPORTDATA const ClassInfo s_info;
+
protected:
- JSGlobalObject(NonNullPassRefPtr<Structure> structure, JSGlobalObjectData* data, JSObject* thisValue)
- : JSVariableObject(structure, data)
+ JSGlobalObject(JSGlobalData& globalData, Structure* structure, JSObject* thisValue)
+ : JSVariableObject(globalData, structure, &m_symbolTable, 0)
+ , m_registerArraySize(0)
+ , m_globalScopeChain()
+ , m_weakRandom(static_cast<unsigned>(randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0)))
+ , m_isEvalEnabled(true)
{
+ COMPILE_ASSERT(JSGlobalObject::AnonymousSlotCount == 1, JSGlobalObject_has_only_a_single_slot);
+ putThisToAnonymousValue(0);
init(thisValue);
}
public:
virtual ~JSGlobalObject();
- virtual void markChildren(MarkStack&);
+ virtual void visitChildren(SlotVisitor&);
virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
virtual void defineGetter(ExecState*, const Identifier& propertyName, JSObject* getterFunc, unsigned attributes);
virtual void defineSetter(ExecState*, const Identifier& propertyName, JSObject* setterFunc, unsigned attributes);
- // Linked list of all global objects that use the same JSGlobalData.
- JSGlobalObject*& head() { return d()->globalData->head; }
- JSGlobalObject* next() { return d()->next; }
+ // We use this in the code generator as we perform symbol table
+ // lookups prior to initializing the properties
+ bool symbolTableHasProperty(const Identifier& propertyName);
// The following accessors return pristine values, even if a script
// replaces the global object's associated property.
- RegExpConstructor* regExpConstructor() const { return d()->regExpConstructor; }
-
- ErrorConstructor* errorConstructor() const { return d()->errorConstructor; }
- NativeErrorConstructor* evalErrorConstructor() const { return d()->evalErrorConstructor; }
- NativeErrorConstructor* rangeErrorConstructor() const { return d()->rangeErrorConstructor; }
- NativeErrorConstructor* referenceErrorConstructor() const { return d()->referenceErrorConstructor; }
- NativeErrorConstructor* syntaxErrorConstructor() const { return d()->syntaxErrorConstructor; }
- NativeErrorConstructor* typeErrorConstructor() const { return d()->typeErrorConstructor; }
- NativeErrorConstructor* URIErrorConstructor() const { return d()->URIErrorConstructor; }
-
- GlobalEvalFunction* evalFunction() const { return d()->evalFunction; }
-
- ObjectPrototype* objectPrototype() const { return d()->objectPrototype; }
- FunctionPrototype* functionPrototype() const { return d()->functionPrototype; }
- ArrayPrototype* arrayPrototype() const { return d()->arrayPrototype; }
- BooleanPrototype* booleanPrototype() const { return d()->booleanPrototype; }
- StringPrototype* stringPrototype() const { return d()->stringPrototype; }
- NumberPrototype* numberPrototype() const { return d()->numberPrototype; }
- DatePrototype* datePrototype() const { return d()->datePrototype; }
- RegExpPrototype* regExpPrototype() const { return d()->regExpPrototype; }
-
- JSObject* methodCallDummy() const { return d()->methodCallDummy; }
-
- Structure* argumentsStructure() const { return d()->argumentsStructure.get(); }
- Structure* arrayStructure() const { return d()->arrayStructure.get(); }
- Structure* booleanObjectStructure() const { return d()->booleanObjectStructure.get(); }
- Structure* callbackConstructorStructure() const { return d()->callbackConstructorStructure.get(); }
- Structure* callbackFunctionStructure() const { return d()->callbackFunctionStructure.get(); }
- Structure* callbackObjectStructure() const { return d()->callbackObjectStructure.get(); }
- Structure* dateStructure() const { return d()->dateStructure.get(); }
- Structure* emptyObjectStructure() const { return d()->emptyObjectStructure.get(); }
- Structure* errorStructure() const { return d()->errorStructure.get(); }
- Structure* functionStructure() const { return d()->functionStructure.get(); }
- Structure* numberObjectStructure() const { return d()->numberObjectStructure.get(); }
- Structure* prototypeFunctionStructure() const { return d()->prototypeFunctionStructure.get(); }
- Structure* regExpMatchesArrayStructure() const { return d()->regExpMatchesArrayStructure.get(); }
- Structure* regExpStructure() const { return d()->regExpStructure.get(); }
- Structure* stringObjectStructure() const { return d()->stringObjectStructure.get(); }
-
- void setProfileGroup(unsigned value) { d()->profileGroup = value; }
- unsigned profileGroup() const { return d()->profileGroup; }
-
- Debugger* debugger() const { return d()->debugger; }
- void setDebugger(Debugger* debugger) { d()->debugger = debugger; }
-
+ RegExpConstructor* regExpConstructor() const { return m_regExpConstructor.get(); }
+
+ ErrorConstructor* errorConstructor() const { return m_errorConstructor.get(); }
+ NativeErrorConstructor* evalErrorConstructor() const { return m_evalErrorConstructor.get(); }
+ NativeErrorConstructor* rangeErrorConstructor() const { return m_rangeErrorConstructor.get(); }
+ NativeErrorConstructor* referenceErrorConstructor() const { return m_referenceErrorConstructor.get(); }
+ NativeErrorConstructor* syntaxErrorConstructor() const { return m_syntaxErrorConstructor.get(); }
+ NativeErrorConstructor* typeErrorConstructor() const { return m_typeErrorConstructor.get(); }
+ NativeErrorConstructor* URIErrorConstructor() const { return m_URIErrorConstructor.get(); }
+
+ JSFunction* evalFunction() const { return m_evalFunction.get(); }
+ JSFunction* callFunction() const { return m_callFunction.get(); }
+ JSFunction* applyFunction() const { return m_applyFunction.get(); }
+
+ ObjectPrototype* objectPrototype() const { return m_objectPrototype.get(); }
+ FunctionPrototype* functionPrototype() const { return m_functionPrototype.get(); }
+ ArrayPrototype* arrayPrototype() const { return m_arrayPrototype.get(); }
+ BooleanPrototype* booleanPrototype() const { return m_booleanPrototype.get(); }
+ StringPrototype* stringPrototype() const { return m_stringPrototype.get(); }
+ NumberPrototype* numberPrototype() const { return m_numberPrototype.get(); }
+ DatePrototype* datePrototype() const { return m_datePrototype.get(); }
+ RegExpPrototype* regExpPrototype() const { return m_regExpPrototype.get(); }
+
+ JSObject* methodCallDummy() const { return m_methodCallDummy.get(); }
+
+ Structure* argumentsStructure() const { return m_argumentsStructure.get(); }
+ Structure* arrayStructure() const { return m_arrayStructure.get(); }
+ Structure* booleanObjectStructure() const { return m_booleanObjectStructure.get(); }
+ Structure* callbackConstructorStructure() const { return m_callbackConstructorStructure.get(); }
+ Structure* callbackFunctionStructure() const { return m_callbackFunctionStructure.get(); }
+ Structure* callbackObjectStructure() const { return m_callbackObjectStructure.get(); }
+ Structure* dateStructure() const { return m_dateStructure.get(); }
+ Structure* emptyObjectStructure() const { return m_emptyObjectStructure.get(); }
+ Structure* nullPrototypeObjectStructure() const { return m_nullPrototypeObjectStructure.get(); }
+ Structure* errorStructure() const { return m_errorStructure.get(); }
+ Structure* functionStructure() const { return m_functionStructure.get(); }
+ Structure* numberObjectStructure() const { return m_numberObjectStructure.get(); }
+ Structure* internalFunctionStructure() const { return m_internalFunctionStructure.get(); }
+ Structure* regExpMatchesArrayStructure() const { return m_regExpMatchesArrayStructure.get(); }
+ Structure* regExpStructure() const { return m_regExpStructure.get(); }
+ Structure* stringObjectStructure() const { return m_stringObjectStructure.get(); }
+
+ void setProfileGroup(unsigned value) { m_profileGroup = value; }
+ unsigned profileGroup() const { return m_profileGroup; }
+
+ Debugger* debugger() const { return m_debugger; }
+ void setDebugger(Debugger* debugger) { m_debugger = debugger; }
+
virtual bool supportsProfiling() const { return false; }
-
- int recursion() { return d()->recursion; }
- void incRecursion() { ++d()->recursion; }
- void decRecursion() { --d()->recursion; }
-
- ScopeChain& globalScopeChain() { return d()->globalScopeChain; }
+ virtual bool supportsRichSourceInfo() const { return true; }
+
+ ScopeChainNode* globalScopeChain() { return m_globalScopeChain.get(); }
virtual bool isGlobalObject() const { return true; }
virtual bool isDynamicScope(bool& requiresDynamicChecks) const;
- HashSet<GlobalCodeBlock*>& codeBlocks() { return d()->codeBlocks; }
+ void disableEval();
+ bool isEvalEnabled() { return m_isEvalEnabled; }
void copyGlobalsFrom(RegisterFile&);
void copyGlobalsTo(RegisterFile&);
-
- void resetPrototype(JSValue prototype);
+ void resizeRegisters(int oldSize, int newSize);
+
+ void resetPrototype(JSGlobalData&, JSValue prototype);
- JSGlobalData* globalData() { return d()->globalData.get(); }
- JSGlobalObjectData* d() const { return static_cast<JSGlobalObjectData*>(JSVariableObject::d); }
+ JSGlobalData& globalData() const { return *m_globalData.get(); }
- static PassRefPtr<Structure> createStructure(JSValue prototype)
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
+ return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
}
void registerWeakMap(OpaqueJSWeakObjectMap* map)
{
- d()->weakMaps.add(map);
+ if (!m_weakMapsFinalizer)
+ m_weakMapsFinalizer.set(globalData(), this, weakMapsFinalizer());
+ m_weakMaps.add(map);
}
void deregisterWeakMap(OpaqueJSWeakObjectMap* map)
{
- d()->weakMaps.remove(map);
+ m_weakMaps.remove(map);
}
- double weakRandomNumber() { return d()->weakRandom.get(); }
+ double weakRandomNumber() { return m_weakRandom.get(); }
protected:
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesMarkChildren | OverridesGetPropertyNames | JSVariableObject::StructureFlags;
+ static const unsigned AnonymousSlotCount = JSVariableObject::AnonymousSlotCount + 1;
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | JSVariableObject::StructureFlags;
struct GlobalPropertyInfo {
GlobalPropertyInfo(const Identifier& i, JSValue v, unsigned a)
void addStaticGlobals(GlobalPropertyInfo*, int count);
private:
- static void destroyJSGlobalObjectData(void*);
-
// FIXME: Fold reset into init.
void init(JSObject* thisValue);
void reset(JSValue prototype);
- void setRegisters(Register* registers, Register* registerArray, size_t count);
+ void setRegisters(WriteBarrier<Unknown>* registers, PassOwnArrayPtr<WriteBarrier<Unknown> > registerArray, size_t count);
void* operator new(size_t); // can only be allocated with JSGlobalData
};
return static_cast<JSGlobalObject*>(asObject(value));
}
- inline void JSGlobalObject::setRegisters(Register* registers, Register* registerArray, size_t count)
+ inline void JSGlobalObject::setRegisters(WriteBarrier<Unknown>* registers, PassOwnArrayPtr<WriteBarrier<Unknown> > registerArray, size_t count)
{
JSVariableObject::setRegisters(registers, registerArray);
- d()->registerArraySize = count;
- }
-
- inline void JSGlobalObject::addStaticGlobals(GlobalPropertyInfo* globals, int count)
- {
- size_t oldSize = d()->registerArraySize;
- size_t newSize = oldSize + count;
- Register* registerArray = new Register[newSize];
- if (d()->registerArray)
- memcpy(registerArray + count, d()->registerArray.get(), oldSize * sizeof(Register));
- setRegisters(registerArray + newSize, registerArray, newSize);
-
- for (int i = 0, index = -static_cast<int>(oldSize) - 1; i < count; ++i, --index) {
- GlobalPropertyInfo& global = globals[i];
- ASSERT(global.attributes & DontDelete);
- SymbolTableEntry newEntry(index, global.attributes);
- symbolTable().add(global.identifier.ustring().rep(), newEntry);
- registerAt(index) = global.value;
- }
- }
-
- inline bool JSGlobalObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
- {
- if (JSVariableObject::getOwnPropertySlot(exec, propertyName, slot))
- return true;
- return symbolTableGet(propertyName, slot);
- }
-
- inline bool JSGlobalObject::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
- {
- if (symbolTableGet(propertyName, descriptor))
- return true;
- return JSVariableObject::getOwnPropertyDescriptor(exec, propertyName, descriptor);
+ m_registerArraySize = count;
}
inline bool JSGlobalObject::hasOwnPropertyForWrite(ExecState* exec, const Identifier& propertyName)
return symbolTableGet(propertyName, slot, slotIsWriteable);
}
+ inline bool JSGlobalObject::symbolTableHasProperty(const Identifier& propertyName)
+ {
+ SymbolTableEntry entry = symbolTable().inlineGet(propertyName.impl());
+ return !entry.isNull();
+ }
+
inline JSValue Structure::prototypeForLookup(ExecState* exec) const
{
if (typeInfo().type() == ObjectType)
- return m_prototype;
-
-#if USE(JSVALUE32)
- if (typeInfo().type() == StringType)
- return exec->lexicalGlobalObject()->stringPrototype();
+ return m_prototype.get();
- ASSERT(typeInfo().type() == NumberType);
- return exec->lexicalGlobalObject()->numberPrototype();
-#else
ASSERT(typeInfo().type() == StringType);
return exec->lexicalGlobalObject()->stringPrototype();
-#endif
}
inline StructureChain* Structure::prototypeChain(ExecState* exec) const
// We cache our prototype chain so our clients can share it.
if (!isValid(exec, m_cachedPrototypeChain.get())) {
JSValue prototype = prototypeForLookup(exec);
- m_cachedPrototypeChain = StructureChain::create(prototype.isNull() ? 0 : asObject(prototype)->structure());
+ m_cachedPrototypeChain.set(exec->globalData(), this, StructureChain::create(exec->globalData(), prototype.isNull() ? 0 : asObject(prototype)->structure()));
}
return m_cachedPrototypeChain.get();
}
return false;
JSValue prototype = prototypeForLookup(exec);
- RefPtr<Structure>* cachedStructure = cachedPrototypeChain->head();
+ WriteBarrier<Structure>* cachedStructure = cachedPrototypeChain->head();
while(*cachedStructure && !prototype.isNull()) {
- if (asObject(prototype)->structure() != *cachedStructure)
+ if (asObject(prototype)->structure() != cachedStructure->get())
return false;
++cachedStructure;
prototype = asObject(prototype)->prototype();
return globalData().dynamicGlobalObject;
}
- inline JSObject* constructEmptyObject(ExecState* exec)
+ inline JSObject* constructEmptyObject(ExecState* exec, JSGlobalObject* globalObject)
{
- return new (exec) JSObject(exec->lexicalGlobalObject()->emptyObjectStructure());
+ return constructEmptyObject(exec, globalObject->emptyObjectStructure());
}
-
- inline JSObject* constructEmptyObject(ExecState* exec, JSGlobalObject* globalObject)
+
+ inline JSObject* constructEmptyObject(ExecState* exec)
{
- return new (exec) JSObject(globalObject->emptyObjectStructure());
+ return constructEmptyObject(exec, exec->lexicalGlobalObject());
}
- inline JSArray* constructEmptyArray(ExecState* exec)
+ inline JSArray* constructEmptyArray(ExecState* exec, JSGlobalObject* globalObject)
{
- return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure());
+ return new (exec) JSArray(exec->globalData(), globalObject->arrayStructure());
}
- inline JSArray* constructEmptyArray(ExecState* exec, JSGlobalObject* globalObject)
+ inline JSArray* constructEmptyArray(ExecState* exec)
+ {
+ return constructEmptyArray(exec, exec->lexicalGlobalObject());
+ }
+
+ inline JSArray* constructEmptyArray(ExecState* exec, JSGlobalObject* globalObject, unsigned initialLength)
{
- return new (exec) JSArray(globalObject->arrayStructure());
+ return new (exec) JSArray(exec->globalData(), globalObject->arrayStructure(), initialLength, CreateInitialized);
}
inline JSArray* constructEmptyArray(ExecState* exec, unsigned initialLength)
{
- return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), initialLength);
+ return constructEmptyArray(exec, exec->lexicalGlobalObject(), initialLength);
}
- inline JSArray* constructArray(ExecState* exec, JSValue singleItemValue)
+ inline JSArray* constructArray(ExecState* exec, JSGlobalObject* globalObject, JSValue singleItemValue)
{
MarkedArgumentBuffer values;
values.append(singleItemValue);
- return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), values);
+ return new (exec) JSArray(exec->globalData(), globalObject->arrayStructure(), values);
+ }
+
+ inline JSArray* constructArray(ExecState* exec, JSValue singleItemValue)
+ {
+ return constructArray(exec, exec->lexicalGlobalObject(), singleItemValue);
+ }
+
+ inline JSArray* constructArray(ExecState* exec, JSGlobalObject* globalObject, const ArgList& values)
+ {
+ return new (exec) JSArray(exec->globalData(), globalObject->arrayStructure(), values);
}
inline JSArray* constructArray(ExecState* exec, const ArgList& values)
{
- return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), values);
+ return constructArray(exec, exec->lexicalGlobalObject(), values);
}
- class DynamicGlobalObjectScope : public Noncopyable {
+ class DynamicGlobalObjectScope {
+ WTF_MAKE_NONCOPYABLE(DynamicGlobalObjectScope);
public:
- DynamicGlobalObjectScope(CallFrame* callFrame, JSGlobalObject* dynamicGlobalObject);
+ DynamicGlobalObjectScope(JSGlobalData&, JSGlobalObject*);
~DynamicGlobalObjectScope()
{
#include "JSGlobalObjectFunctions.h"
#include "CallFrame.h"
-#include "GlobalEvalFunction.h"
#include "Interpreter.h"
#include "JSGlobalObject.h"
#include "JSString.h"
#include "LiteralParser.h"
#include "Nodes.h"
#include "Parser.h"
-#include "StringBuilder.h"
-#include "StringExtras.h"
+#include "UStringBuilder.h"
#include "dtoa.h"
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
#include <wtf/ASCIICType.h>
#include <wtf/Assertions.h>
#include <wtf/MathExtras.h>
+#include <wtf/StringExtras.h>
#include <wtf/unicode/UTF8.h>
using namespace WTF;
namespace JSC {
-static JSValue encode(ExecState* exec, const ArgList& args, const char* doNotEscape)
+static JSValue encode(ExecState* exec, const char* doNotEscape)
{
- UString str = args.at(0).toString(exec);
- CString cstr = str.UTF8String(true);
+ UString str = exec->argument(0).toString(exec);
+ CString cstr = str.utf8(true);
if (!cstr.data())
- return throwError(exec, URIError, "String contained an illegal UTF-16 sequence.");
+ return throwError(exec, createURIError(exec, "String contained an illegal UTF-16 sequence."));
JSStringBuilder builder;
const char* p = cstr.data();
return builder.build(exec);
}
-static JSValue decode(ExecState* exec, const ArgList& args, const char* doNotUnescape, bool strict)
+static JSValue decode(ExecState* exec, const char* doNotUnescape, bool strict)
{
JSStringBuilder builder;
- UString str = args.at(0).toString(exec);
+ UString str = exec->argument(0).toString(exec);
int k = 0;
- int len = str.size();
- const UChar* d = str.data();
+ int len = str.length();
+ const UChar* d = str.characters();
UChar u = 0;
while (k < len) {
const UChar* p = d + k;
}
if (charLen == 0) {
if (strict)
- return throwError(exec, URIError);
+ return throwError(exec, createURIError(exec, "URI error"));
// The only case where we don't use "strict" mode is the "unescape" function.
// For that, it's good to support the wonky "%u" syntax for compatibility with WinIE.
if (k <= len - 6 && p[1] == 'u'
bool isStrWhiteSpace(UChar c)
{
switch (c) {
+ // ECMA-262-5th 7.2 & 7.3
case 0x0009:
case 0x000A:
case 0x000B:
case 0x00A0:
case 0x2028:
case 0x2029:
+ case 0xFEFF:
return true;
default:
return c > 0xff && isSeparatorSpace(c);
return number;
}
+double parseIntOverflow(const UChar* s, int length, int radix)
+{
+ double number = 0.0;
+ double radixMultiplier = 1.0;
+
+ for (const UChar* p = s + length - 1; p >= s; p--) {
+ if (radixMultiplier == Inf) {
+ if (*p != '0') {
+ number = Inf;
+ break;
+ }
+ } else {
+ int digit = parseDigit(*p, radix);
+ number += digit * radixMultiplier;
+ }
+
+ radixMultiplier *= radix;
+ }
+
+ return number;
+}
+
static double parseInt(const UString& s, int radix)
{
- int length = s.size();
- const UChar* data = s.data();
+ int length = s.length();
+ const UChar* data = s.characters();
int p = 0;
while (p < length && isStrWhiteSpace(data[p]))
}
if (number >= mantissaOverflowLowerBound) {
- // FIXME: It is incorrect to use UString::ascii() here because it's not thread-safe.
if (radix == 10)
- number = WTF::strtod(s.substr(firstDigitPosition, p - firstDigitPosition).ascii(), 0);
+ number = WTF::strtod(s.substringSharingImpl(firstDigitPosition, p - firstDigitPosition).utf8().data(), 0);
else if (radix == 2 || radix == 4 || radix == 8 || radix == 16 || radix == 32)
- number = parseIntOverflow(s.substr(firstDigitPosition, p - firstDigitPosition).ascii(), p - firstDigitPosition, radix);
+ number = parseIntOverflow(s.substringSharingImpl(firstDigitPosition, p - firstDigitPosition).utf8().data(), p - firstDigitPosition, radix);
}
if (!sawDigit)
return sign * number;
}
+static const int SizeOfInfinity = 8;
+
+static bool isInfinity(const UChar* data, const UChar* end)
+{
+ return (end - data) >= SizeOfInfinity
+ && data[0] == 'I'
+ && data[1] == 'n'
+ && data[2] == 'f'
+ && data[3] == 'i'
+ && data[4] == 'n'
+ && data[5] == 'i'
+ && data[6] == 't'
+ && data[7] == 'y';
+}
+
+// See ecma-262 9.3.1
+static double jsHexIntegerLiteral(const UChar*& data, const UChar* end)
+{
+ // Hex number.
+ data += 2;
+ const UChar* firstDigitPosition = data;
+ double number = 0;
+ while (true) {
+ number = number * 16 + toASCIIHexValue(*data);
+ ++data;
+ if (data == end)
+ break;
+ if (!isASCIIHexDigit(*data))
+ break;
+ }
+ if (number >= mantissaOverflowLowerBound)
+ number = parseIntOverflow(firstDigitPosition, data - firstDigitPosition, 16);
+
+ return number;
+}
+
+// See ecma-262 9.3.1
+static double jsStrDecimalLiteral(const UChar*& data, const UChar* end)
+{
+ ASSERT(data < end);
+
+ // Copy the sting into a null-terminated byte buffer, and call strtod.
+ Vector<char, 32> byteBuffer;
+ for (const UChar* characters = data; characters < end; ++characters) {
+ UChar character = *characters;
+ byteBuffer.append(isASCII(character) ? character : 0);
+ }
+ byteBuffer.append(0);
+ char* endOfNumber;
+ double number = WTF::strtod(byteBuffer.data(), &endOfNumber);
+
+ // Check if strtod found a number; if so return it.
+ ptrdiff_t consumed = endOfNumber - byteBuffer.data();
+ if (consumed) {
+ data += consumed;
+ return number;
+ }
+
+ // Check for [+-]?Infinity
+ switch (*data) {
+ case 'I':
+ if (isInfinity(data, end)) {
+ data += SizeOfInfinity;
+ return Inf;
+ }
+ break;
+
+ case '+':
+ if (isInfinity(data + 1, end)) {
+ data += SizeOfInfinity + 1;
+ return Inf;
+ }
+ break;
+
+ case '-':
+ if (isInfinity(data + 1, end)) {
+ data += SizeOfInfinity + 1;
+ return -Inf;
+ }
+ break;
+ }
+
+ // Not a number.
+ return NaN;
+}
+
+// See ecma-262 9.3.1
+double jsToNumber(const UString& s)
+{
+ unsigned size = s.length();
+
+ if (size == 1) {
+ UChar c = s.characters()[0];
+ if (isASCIIDigit(c))
+ return c - '0';
+ if (isStrWhiteSpace(c))
+ return 0;
+ return NaN;
+ }
+
+ const UChar* data = s.characters();
+ const UChar* end = data + size;
+
+ // Skip leading white space.
+ for (; data < end; ++data) {
+ if (!isStrWhiteSpace(*data))
+ break;
+ }
+
+ // Empty string.
+ if (data == end)
+ return 0.0;
+
+ double number;
+ if (data[0] == '0' && data + 2 < end && (data[1] | 0x20) == 'x' && isASCIIHexDigit(data[2]))
+ number = jsHexIntegerLiteral(data, end);
+ else
+ number = jsStrDecimalLiteral(data, end);
+
+ // Allow trailing white space.
+ for (; data < end; ++data) {
+ if (!isStrWhiteSpace(*data))
+ break;
+ }
+ if (data != end)
+ return NaN;
+
+ return number;
+}
+
static double parseFloat(const UString& s)
{
- // Check for 0x prefix here, because toDouble allows it, but we must treat it as 0.
- // Need to skip any whitespace and then one + or - sign.
- int length = s.size();
- const UChar* data = s.data();
- int p = 0;
- while (p < length && isStrWhiteSpace(data[p]))
- ++p;
+ unsigned size = s.length();
- if (p < length && (data[p] == '+' || data[p] == '-'))
- ++p;
+ if (size == 1) {
+ UChar c = s.characters()[0];
+ if (isASCIIDigit(c))
+ return c - '0';
+ return NaN;
+ }
- if (length - p >= 2 && data[p] == '0' && (data[p + 1] == 'x' || data[p + 1] == 'X'))
- return 0;
+ const UChar* data = s.characters();
+ const UChar* end = data + size;
- // FIXME: UString::toDouble will ignore leading ASCII spaces, but we need to ignore
- // other StrWhiteSpaceChar values as well.
- return s.toDouble(true /*tolerant*/, false /* NaN for empty string */);
+ // Skip leading white space.
+ for (; data < end; ++data) {
+ if (!isStrWhiteSpace(*data))
+ break;
+ }
+
+ // Empty string.
+ if (data == end)
+ return NaN;
+
+ return jsStrDecimalLiteral(data, end);
}
-JSValue JSC_HOST_CALL globalFuncEval(ExecState* exec, JSObject* function, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL globalFuncEval(ExecState* exec)
{
- JSObject* thisObject = thisValue.toThisObject(exec);
+ JSObject* thisObject = exec->hostThisValue().toThisObject(exec);
JSObject* unwrappedObject = thisObject->unwrappedObject();
- if (!unwrappedObject->isGlobalObject() || static_cast<JSGlobalObject*>(unwrappedObject)->evalFunction() != function)
- return throwError(exec, EvalError, "The \"this\" value passed to eval must be the global object from which eval originated");
+ if (!unwrappedObject->isGlobalObject() || static_cast<JSGlobalObject*>(unwrappedObject)->evalFunction() != exec->callee())
+ return throwVMError(exec, createEvalError(exec, "The \"this\" value passed to eval must be the global object from which eval originated"));
- JSValue x = args.at(0);
+ JSValue x = exec->argument(0);
if (!x.isString())
- return x;
+ return JSValue::encode(x);
UString s = x.toString(exec);
- LiteralParser preparser(exec, s, LiteralParser::NonStrictJSON);
+ LiteralParser preparser(exec, s.characters(), s.length(), LiteralParser::NonStrictJSON);
if (JSValue parsedObject = preparser.tryLiteralParse())
- return parsedObject;
+ return JSValue::encode(parsedObject);
- RefPtr<EvalExecutable> eval = EvalExecutable::create(exec, makeSource(s));
- JSObject* error = eval->compile(exec, static_cast<JSGlobalObject*>(unwrappedObject)->globalScopeChain().node());
+ EvalExecutable* eval = EvalExecutable::create(exec, makeSource(s), false);
+ JSObject* error = eval->compile(exec, static_cast<JSGlobalObject*>(unwrappedObject)->globalScopeChain());
if (error)
- return throwError(exec, error);
+ return throwVMError(exec, error);
- return exec->interpreter()->execute(eval.get(), exec, thisObject, static_cast<JSGlobalObject*>(unwrappedObject)->globalScopeChain().node(), exec->exceptionSlot());
+ return JSValue::encode(exec->interpreter()->execute(eval, exec, thisObject, static_cast<JSGlobalObject*>(unwrappedObject)->globalScopeChain()));
}
-JSValue JSC_HOST_CALL globalFuncParseInt(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL globalFuncParseInt(ExecState* exec)
{
- JSValue value = args.at(0);
- int32_t radix = args.at(1).toInt32(exec);
+ JSValue value = exec->argument(0);
+ int32_t radix = exec->argument(1).toInt32(exec);
if (radix != 0 && radix != 10)
- return jsNumber(exec, parseInt(value.toString(exec), radix));
+ return JSValue::encode(jsNumber(parseInt(value.toString(exec), radix)));
if (value.isInt32())
- return value;
+ return JSValue::encode(value);
if (value.isDouble()) {
double d = value.asDouble();
if (isfinite(d))
- return jsNumber(exec, (d > 0) ? floor(d) : ceil(d));
+ return JSValue::encode(jsNumber((d > 0) ? floor(d) : ceil(d)));
if (isnan(d) || isinf(d))
- return jsNaN(exec);
- return jsNumber(exec, 0);
+ return JSValue::encode(jsNaN());
+ return JSValue::encode(jsNumber(0));
}
- return jsNumber(exec, parseInt(value.toString(exec), radix));
+ return JSValue::encode(jsNumber(parseInt(value.toString(exec), radix)));
}
-JSValue JSC_HOST_CALL globalFuncParseFloat(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL globalFuncParseFloat(ExecState* exec)
{
- return jsNumber(exec, parseFloat(args.at(0).toString(exec)));
+ return JSValue::encode(jsNumber(parseFloat(exec->argument(0).toString(exec))));
}
-JSValue JSC_HOST_CALL globalFuncIsNaN(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL globalFuncIsNaN(ExecState* exec)
{
- return jsBoolean(isnan(args.at(0).toNumber(exec)));
+ return JSValue::encode(jsBoolean(isnan(exec->argument(0).toNumber(exec))));
}
-JSValue JSC_HOST_CALL globalFuncIsFinite(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL globalFuncIsFinite(ExecState* exec)
{
- double n = args.at(0).toNumber(exec);
- return jsBoolean(!isnan(n) && !isinf(n));
+ double n = exec->argument(0).toNumber(exec);
+ return JSValue::encode(jsBoolean(!isnan(n) && !isinf(n)));
}
-JSValue JSC_HOST_CALL globalFuncDecodeURI(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL globalFuncDecodeURI(ExecState* exec)
{
static const char do_not_unescape_when_decoding_URI[] =
"#$&+,/:;=?@";
- return decode(exec, args, do_not_unescape_when_decoding_URI, true);
+ return JSValue::encode(decode(exec, do_not_unescape_when_decoding_URI, true));
}
-JSValue JSC_HOST_CALL globalFuncDecodeURIComponent(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL globalFuncDecodeURIComponent(ExecState* exec)
{
- return decode(exec, args, "", true);
+ return JSValue::encode(decode(exec, "", true));
}
-JSValue JSC_HOST_CALL globalFuncEncodeURI(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL globalFuncEncodeURI(ExecState* exec)
{
static const char do_not_escape_when_encoding_URI[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789"
"!#$&'()*+,-./:;=?@_~";
- return encode(exec, args, do_not_escape_when_encoding_URI);
+ return JSValue::encode(encode(exec, do_not_escape_when_encoding_URI));
}
-JSValue JSC_HOST_CALL globalFuncEncodeURIComponent(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL globalFuncEncodeURIComponent(ExecState* exec)
{
static const char do_not_escape_when_encoding_URI_component[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789"
"!'()*-._~";
- return encode(exec, args, do_not_escape_when_encoding_URI_component);
+ return JSValue::encode(encode(exec, do_not_escape_when_encoding_URI_component));
}
-JSValue JSC_HOST_CALL globalFuncEscape(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL globalFuncEscape(ExecState* exec)
{
static const char do_not_escape[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"*+-./@_";
JSStringBuilder builder;
- UString str = args.at(0).toString(exec);
- const UChar* c = str.data();
- for (unsigned k = 0; k < str.size(); k++, c++) {
+ UString str = exec->argument(0).toString(exec);
+ const UChar* c = str.characters();
+ for (unsigned k = 0; k < str.length(); k++, c++) {
int u = c[0];
if (u > 255) {
char tmp[7];
}
}
- return builder.build(exec);
+ return JSValue::encode(builder.build(exec));
}
-JSValue JSC_HOST_CALL globalFuncUnescape(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL globalFuncUnescape(ExecState* exec)
{
- StringBuilder builder;
- UString str = args.at(0).toString(exec);
+ UStringBuilder builder;
+ UString str = exec->argument(0).toString(exec);
int k = 0;
- int len = str.size();
+ int len = str.length();
while (k < len) {
- const UChar* c = str.data() + k;
+ const UChar* c = str.characters() + k;
UChar u;
if (c[0] == '%' && k <= len - 6 && c[1] == 'u') {
if (isASCIIHexDigit(c[2]) && isASCIIHexDigit(c[3]) && isASCIIHexDigit(c[4]) && isASCIIHexDigit(c[5])) {
builder.append(*c);
}
- return jsString(exec, builder.build());
-}
-
-#ifndef NDEBUG
-JSValue JSC_HOST_CALL globalFuncJSCPrint(ExecState* exec, JSObject*, JSValue, const ArgList& args)
-{
- CString string = args.at(0).toString(exec).UTF8String();
- puts(string.data());
- return jsUndefined();
+ return JSValue::encode(jsString(exec, builder.toUString()));
}
-#endif
} // namespace JSC
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
* Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
* Copyright (C) 2007 Maks Orlovich
*
#ifndef JSGlobalObjectFunctions_h
#define JSGlobalObjectFunctions_h
+#include "JSValue.h"
#include <wtf/unicode/Unicode.h>
namespace JSC {
class ArgList;
class ExecState;
class JSObject;
- class JSValue;
// FIXME: These functions should really be in JSGlobalObject.cpp, but putting them there
// is a 0.5% reduction.
- JSValue JSC_HOST_CALL globalFuncEval(ExecState*, JSObject*, JSValue, const ArgList&);
- JSValue JSC_HOST_CALL globalFuncParseInt(ExecState*, JSObject*, JSValue, const ArgList&);
- JSValue JSC_HOST_CALL globalFuncParseFloat(ExecState*, JSObject*, JSValue, const ArgList&);
- JSValue JSC_HOST_CALL globalFuncIsNaN(ExecState*, JSObject*, JSValue, const ArgList&);
- JSValue JSC_HOST_CALL globalFuncIsFinite(ExecState*, JSObject*, JSValue, const ArgList&);
- JSValue JSC_HOST_CALL globalFuncDecodeURI(ExecState*, JSObject*, JSValue, const ArgList&);
- JSValue JSC_HOST_CALL globalFuncDecodeURIComponent(ExecState*, JSObject*, JSValue, const ArgList&);
- JSValue JSC_HOST_CALL globalFuncEncodeURI(ExecState*, JSObject*, JSValue, const ArgList&);
- JSValue JSC_HOST_CALL globalFuncEncodeURIComponent(ExecState*, JSObject*, JSValue, const ArgList&);
- JSValue JSC_HOST_CALL globalFuncEscape(ExecState*, JSObject*, JSValue, const ArgList&);
- JSValue JSC_HOST_CALL globalFuncUnescape(ExecState*, JSObject*, JSValue, const ArgList&);
-#ifndef NDEBUG
- JSValue JSC_HOST_CALL globalFuncJSCPrint(ExecState*, JSObject*, JSValue, const ArgList&);
-#endif
+ EncodedJSValue JSC_HOST_CALL globalFuncEval(ExecState*);
+ EncodedJSValue JSC_HOST_CALL globalFuncParseInt(ExecState*);
+ EncodedJSValue JSC_HOST_CALL globalFuncParseFloat(ExecState*);
+ EncodedJSValue JSC_HOST_CALL globalFuncIsNaN(ExecState*);
+ EncodedJSValue JSC_HOST_CALL globalFuncIsFinite(ExecState*);
+ EncodedJSValue JSC_HOST_CALL globalFuncDecodeURI(ExecState*);
+ EncodedJSValue JSC_HOST_CALL globalFuncDecodeURIComponent(ExecState*);
+ EncodedJSValue JSC_HOST_CALL globalFuncEncodeURI(ExecState*);
+ EncodedJSValue JSC_HOST_CALL globalFuncEncodeURIComponent(ExecState*);
+ EncodedJSValue JSC_HOST_CALL globalFuncEscape(ExecState*);
+ EncodedJSValue JSC_HOST_CALL globalFuncUnescape(ExecState*);
static const double mantissaOverflowLowerBound = 9007199254740992.0;
double parseIntOverflow(const char*, int length, int radix);
+ double parseIntOverflow(const UChar*, int length, int radix);
bool isStrWhiteSpace(UChar);
+ double jsToNumber(const UString& s);
} // namespace JSC
+++ /dev/null
-/*
- * Copyright (C) 2003-2006, 2008 Apple Inc. All rights reserved.
- *
- * 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 "JSImmediate.h"
-
-namespace JSC {
-
-} // namespace JSC
+++ /dev/null
-/*
- * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
- * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
- *
- * 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.
- *
- */
-
-#ifndef JSImmediate_h
-#define JSImmediate_h
-
-#if !USE(JSVALUE32_64)
-
-#include <wtf/Assertions.h>
-#include <wtf/AlwaysInline.h>
-#include <wtf/MathExtras.h>
-#include <wtf/StdLibExtras.h>
-#include "JSValue.h"
-#include <limits>
-#include <limits.h>
-#include <stdarg.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-namespace JSC {
-
- class ExecState;
- class JSCell;
- class JSFastMath;
- class JSGlobalData;
- class JSObject;
- class UString;
-
-#if USE(JSVALUE64)
- inline intptr_t reinterpretDoubleToIntptr(double value)
- {
- return WTF::bitwise_cast<intptr_t>(value);
- }
-
- inline double reinterpretIntptrToDouble(intptr_t value)
- {
- return WTF::bitwise_cast<double>(value);
- }
-#endif
-
- /*
- * A JSValue* is either a pointer to a cell (a heap-allocated object) or an immediate (a type-tagged
- * value masquerading as a pointer). The low two bits in a JSValue* are available for type tagging
- * because allocator alignment guarantees they will be 00 in cell pointers.
- *
- * For example, on a 32 bit system:
- *
- * JSCell*: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 00
- * [ high 30 bits: pointer address ] [ low 2 bits -- always 0 ]
- * JSImmediate: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX TT
- * [ high 30 bits: 'payload' ] [ low 2 bits -- tag ]
- *
- * Where the bottom two bits are non-zero they either indicate that the immediate is a 31 bit signed
- * integer, or they mark the value as being an immediate of a type other than integer, with a secondary
- * tag used to indicate the exact type.
- *
- * Where the lowest bit is set (TT is equal to 01 or 11) the high 31 bits form a 31 bit signed int value.
- * Where TT is equal to 10 this indicates this is a type of immediate other than an integer, and the next
- * two bits will form an extended tag.
- *
- * 31 bit signed int: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX X1
- * [ high 30 bits of the value ] [ high bit part of value ]
- * Other: YYYYYYYYYYYYYYYYYYYYYYYYYYYY ZZ 10
- * [ extended 'payload' ] [ extended tag ] [ tag 'other' ]
- *
- * Where the first bit of the extended tag is set this flags the value as being a boolean, and the following
- * bit would flag the value as undefined. If neither bits are set, the value is null.
- *
- * Other: YYYYYYYYYYYYYYYYYYYYYYYYYYYY UB 10
- * [ extended 'payload' ] [ undefined | bool ] [ tag 'other' ]
- *
- * For boolean value the lowest bit in the payload holds the value of the bool, all remaining bits are zero.
- * For undefined or null immediates the payload is zero.
- *
- * Boolean: 000000000000000000000000000V 01 10
- * [ boolean value ] [ bool ] [ tag 'other' ]
- * Undefined: 0000000000000000000000000000 10 10
- * [ zero ] [ undefined ] [ tag 'other' ]
- * Null: 0000000000000000000000000000 00 10
- * [ zero ] [ zero ] [ tag 'other' ]
- */
-
- /*
- * On 64-bit platforms, we support an alternative encoding form for immediates, if
- * USE(JSVALUE64) is defined. When this format is used, double precision
- * floating point values may also be encoded as JSImmediates.
- *
- * The encoding makes use of unused NaN space in the IEEE754 representation. Any value
- * with the top 13 bits set represents a QNaN (with the sign bit set). QNaN values
- * can encode a 51-bit payload. Hardware produced and C-library payloads typically
- * have a payload of zero. We assume that non-zero payloads are available to encode
- * pointer and integer values. Since any 64-bit bit pattern where the top 15 bits are
- * all set represents a NaN with a non-zero payload, we can use this space in the NaN
- * ranges to encode other values (however there are also other ranges of NaN space that
- * could have been selected). This range of NaN space is represented by 64-bit numbers
- * begining with the 16-bit hex patterns 0xFFFE and 0xFFFF - we rely on the fact that no
- * valid double-precision numbers will begin fall in these ranges.
- *
- * The scheme we have implemented encodes double precision values by adding 2^48 to the
- * 64-bit integer representation of the number. After this manipulation, no encoded
- * double-precision value will begin with the pattern 0x0000 or 0xFFFF.
- *
- * The top 16-bits denote the type of the encoded JSImmediate:
- *
- * Pointer: 0000:PPPP:PPPP:PPPP
- * 0001:****:****:****
- * Double:{ ...
- * FFFE:****:****:****
- * Integer: FFFF:0000:IIII:IIII
- *
- * 32-bit signed integers are marked with the 16-bit tag 0xFFFF. The tag 0x0000
- * denotes a pointer, or another form of tagged immediate. Boolean, null and undefined
- * values are encoded in the same manner as the default format.
- */
-
- class JSImmediate {
- private:
- friend class JIT;
- friend class JSValue;
- friend class JSFastMath;
- friend class JSInterfaceJIT;
- friend class SpecializedThunkJIT;
- friend JSValue jsNumber(ExecState* exec, double d);
- friend JSValue jsNumber(ExecState*, char i);
- friend JSValue jsNumber(ExecState*, unsigned char i);
- friend JSValue jsNumber(ExecState*, short i);
- friend JSValue jsNumber(ExecState*, unsigned short i);
- friend JSValue jsNumber(ExecState* exec, int i);
- friend JSValue jsNumber(ExecState* exec, unsigned i);
- friend JSValue jsNumber(ExecState* exec, long i);
- friend JSValue jsNumber(ExecState* exec, unsigned long i);
- friend JSValue jsNumber(ExecState* exec, long long i);
- friend JSValue jsNumber(ExecState* exec, unsigned long long i);
- friend JSValue jsNumber(JSGlobalData* globalData, double d);
- friend JSValue jsNumber(JSGlobalData* globalData, short i);
- friend JSValue jsNumber(JSGlobalData* globalData, unsigned short i);
- friend JSValue jsNumber(JSGlobalData* globalData, int i);
- friend JSValue jsNumber(JSGlobalData* globalData, unsigned i);
- friend JSValue jsNumber(JSGlobalData* globalData, long i);
- friend JSValue jsNumber(JSGlobalData* globalData, unsigned long i);
- friend JSValue jsNumber(JSGlobalData* globalData, long long i);
- friend JSValue jsNumber(JSGlobalData* globalData, unsigned long long i);
-
-#if USE(JSVALUE64)
- // If all bits in the mask are set, this indicates an integer number,
- // if any but not all are set this value is a double precision number.
- static const intptr_t TagTypeNumber = 0xffff000000000000ll;
- // This value is 2^48, used to encode doubles such that the encoded value will begin
- // with a 16-bit pattern within the range 0x0001..0xFFFE.
- static const intptr_t DoubleEncodeOffset = 0x1000000000000ll;
-#elif USE(JSVALUE32)
- static const intptr_t TagTypeNumber = 0x1; // bottom bit set indicates integer, this dominates the following bit
-#endif
- static const intptr_t TagBitTypeOther = 0x2; // second bit set indicates immediate other than an integer
- static const intptr_t TagMask = TagTypeNumber | TagBitTypeOther;
-
- static const intptr_t ExtendedTagMask = 0xC; // extended tag holds a further two bits
- static const intptr_t ExtendedTagBitBool = 0x4;
- static const intptr_t ExtendedTagBitUndefined = 0x8;
-
- static const intptr_t FullTagTypeMask = TagMask | ExtendedTagMask;
- static const intptr_t FullTagTypeBool = TagBitTypeOther | ExtendedTagBitBool;
- static const intptr_t FullTagTypeUndefined = TagBitTypeOther | ExtendedTagBitUndefined;
- static const intptr_t FullTagTypeNull = TagBitTypeOther;
-
-#if USE(JSVALUE64)
- static const int32_t IntegerPayloadShift = 0;
-#else
- static const int32_t IntegerPayloadShift = 1;
-#endif
- static const int32_t ExtendedPayloadShift = 4;
-
- static const intptr_t ExtendedPayloadBitBoolValue = 1 << ExtendedPayloadShift;
-
- static const int32_t signBit = 0x80000000;
-
- static ALWAYS_INLINE bool isImmediate(JSValue v)
- {
- return rawValue(v) & TagMask;
- }
-
- static ALWAYS_INLINE bool isNumber(JSValue v)
- {
- return rawValue(v) & TagTypeNumber;
- }
-
- static ALWAYS_INLINE bool isIntegerNumber(JSValue v)
- {
-#if USE(JSVALUE64)
- return (rawValue(v) & TagTypeNumber) == TagTypeNumber;
-#else
- return isNumber(v);
-#endif
- }
-
-#if USE(JSVALUE64)
- static ALWAYS_INLINE bool isDouble(JSValue v)
- {
- return isNumber(v) && !isIntegerNumber(v);
- }
-#endif
-
- static ALWAYS_INLINE bool isPositiveIntegerNumber(JSValue v)
- {
- // A single mask to check for the sign bit and the number tag all at once.
- return (rawValue(v) & (signBit | TagTypeNumber)) == TagTypeNumber;
- }
-
- static ALWAYS_INLINE bool isBoolean(JSValue v)
- {
- return (rawValue(v) & FullTagTypeMask) == FullTagTypeBool;
- }
-
- static ALWAYS_INLINE bool isUndefinedOrNull(JSValue v)
- {
- // Undefined and null share the same value, bar the 'undefined' bit in the extended tag.
- return (rawValue(v) & ~ExtendedTagBitUndefined) == FullTagTypeNull;
- }
-
- static JSValue from(char);
- static JSValue from(signed char);
- static JSValue from(unsigned char);
- static JSValue from(short);
- static JSValue from(unsigned short);
- static JSValue from(int);
- static JSValue from(unsigned);
- static JSValue from(long);
- static JSValue from(unsigned long);
- static JSValue from(long long);
- static JSValue from(unsigned long long);
- static JSValue from(double);
-
- static ALWAYS_INLINE bool isEitherImmediate(JSValue v1, JSValue v2)
- {
- return (rawValue(v1) | rawValue(v2)) & TagMask;
- }
-
- static ALWAYS_INLINE bool areBothImmediate(JSValue v1, JSValue v2)
- {
- return isImmediate(v1) & isImmediate(v2);
- }
-
- static ALWAYS_INLINE bool areBothImmediateIntegerNumbers(JSValue v1, JSValue v2)
- {
-#if USE(JSVALUE64)
- return (rawValue(v1) & rawValue(v2) & TagTypeNumber) == TagTypeNumber;
-#else
- return rawValue(v1) & rawValue(v2) & TagTypeNumber;
-#endif
- }
-
- static double toDouble(JSValue);
- static bool toBoolean(JSValue);
-
- static bool getUInt32(JSValue, uint32_t&);
- static bool getTruncatedInt32(JSValue, int32_t&);
- static bool getTruncatedUInt32(JSValue, uint32_t&);
-
- static int32_t getTruncatedInt32(JSValue);
- static uint32_t getTruncatedUInt32(JSValue);
-
- static JSValue trueImmediate();
- static JSValue falseImmediate();
- static JSValue undefinedImmediate();
- static JSValue nullImmediate();
- static JSValue zeroImmediate();
- static JSValue oneImmediate();
-
- private:
-#if USE(JSVALUE64)
- static const int minImmediateInt = ((-INT_MAX) - 1);
- static const int maxImmediateInt = INT_MAX;
-#else
- static const int minImmediateInt = ((-INT_MAX) - 1) >> IntegerPayloadShift;
- static const int maxImmediateInt = INT_MAX >> IntegerPayloadShift;
-#endif
- static const unsigned maxImmediateUInt = maxImmediateInt;
-
- static ALWAYS_INLINE JSValue makeValue(intptr_t integer)
- {
- return JSValue::makeImmediate(integer);
- }
-
- // With USE(JSVALUE64) we want the argument to be zero extended, so the
- // integer doesn't interfere with the tag bits in the upper word. In the default encoding,
- // if intptr_t id larger then int32_t we sign extend the value through the upper word.
-#if USE(JSVALUE64)
- static ALWAYS_INLINE JSValue makeInt(uint32_t value)
-#else
- static ALWAYS_INLINE JSValue makeInt(int32_t value)
-#endif
- {
- return makeValue((static_cast<intptr_t>(value) << IntegerPayloadShift) | TagTypeNumber);
- }
-
-#if USE(JSVALUE64)
- static ALWAYS_INLINE JSValue makeDouble(double value)
- {
- return makeValue(reinterpretDoubleToIntptr(value) + DoubleEncodeOffset);
- }
-#endif
-
- static ALWAYS_INLINE JSValue makeBool(bool b)
- {
- return makeValue((static_cast<intptr_t>(b) << ExtendedPayloadShift) | FullTagTypeBool);
- }
-
- static ALWAYS_INLINE JSValue makeUndefined()
- {
- return makeValue(FullTagTypeUndefined);
- }
-
- static ALWAYS_INLINE JSValue makeNull()
- {
- return makeValue(FullTagTypeNull);
- }
-
- template<typename T>
- static JSValue fromNumberOutsideIntegerRange(T);
-
-#if USE(JSVALUE64)
- static ALWAYS_INLINE double doubleValue(JSValue v)
- {
- return reinterpretIntptrToDouble(rawValue(v) - DoubleEncodeOffset);
- }
-#endif
-
- static ALWAYS_INLINE int32_t intValue(JSValue v)
- {
- return static_cast<int32_t>(rawValue(v) >> IntegerPayloadShift);
- }
-
- static ALWAYS_INLINE uint32_t uintValue(JSValue v)
- {
- return static_cast<uint32_t>(rawValue(v) >> IntegerPayloadShift);
- }
-
- static ALWAYS_INLINE bool boolValue(JSValue v)
- {
- return rawValue(v) & ExtendedPayloadBitBoolValue;
- }
-
- static ALWAYS_INLINE intptr_t rawValue(JSValue v)
- {
- return v.immediateValue();
- }
- };
-
- ALWAYS_INLINE JSValue JSImmediate::trueImmediate() { return makeBool(true); }
- ALWAYS_INLINE JSValue JSImmediate::falseImmediate() { return makeBool(false); }
- ALWAYS_INLINE JSValue JSImmediate::undefinedImmediate() { return makeUndefined(); }
- ALWAYS_INLINE JSValue JSImmediate::nullImmediate() { return makeNull(); }
- ALWAYS_INLINE JSValue JSImmediate::zeroImmediate() { return makeInt(0); }
- ALWAYS_INLINE JSValue JSImmediate::oneImmediate() { return makeInt(1); }
-
-#if USE(JSVALUE64)
- inline bool doubleToBoolean(double value)
- {
- return value < 0.0 || value > 0.0;
- }
-
- ALWAYS_INLINE bool JSImmediate::toBoolean(JSValue v)
- {
- ASSERT(isImmediate(v));
- return isNumber(v) ? isIntegerNumber(v) ? v != zeroImmediate()
- : doubleToBoolean(doubleValue(v)) : v == trueImmediate();
- }
-#else
- ALWAYS_INLINE bool JSImmediate::toBoolean(JSValue v)
- {
- ASSERT(isImmediate(v));
- return isIntegerNumber(v) ? v != zeroImmediate() : v == trueImmediate();
- }
-#endif
-
- ALWAYS_INLINE uint32_t JSImmediate::getTruncatedUInt32(JSValue v)
- {
- // FIXME: should probably be asserting isPositiveIntegerNumber here.
- ASSERT(isIntegerNumber(v));
- return intValue(v);
- }
-
-#if USE(JSVALUE64)
- template<typename T>
- inline JSValue JSImmediate::fromNumberOutsideIntegerRange(T value)
- {
- return makeDouble(static_cast<double>(value));
- }
-#else
- template<typename T>
- inline JSValue JSImmediate::fromNumberOutsideIntegerRange(T)
- {
- return JSValue();
- }
-#endif
-
- ALWAYS_INLINE JSValue JSImmediate::from(char i)
- {
- return makeInt(i);
- }
-
- ALWAYS_INLINE JSValue JSImmediate::from(signed char i)
- {
- return makeInt(i);
- }
-
- ALWAYS_INLINE JSValue JSImmediate::from(unsigned char i)
- {
- return makeInt(i);
- }
-
- ALWAYS_INLINE JSValue JSImmediate::from(short i)
- {
- return makeInt(i);
- }
-
- ALWAYS_INLINE JSValue JSImmediate::from(unsigned short i)
- {
- return makeInt(i);
- }
-
- ALWAYS_INLINE JSValue JSImmediate::from(int i)
- {
-#if !USE(JSVALUE64)
- if ((i < minImmediateInt) | (i > maxImmediateInt))
- return fromNumberOutsideIntegerRange(i);
-#endif
- return makeInt(i);
- }
-
- ALWAYS_INLINE JSValue JSImmediate::from(unsigned i)
- {
- if (i > maxImmediateUInt)
- return fromNumberOutsideIntegerRange(i);
- return makeInt(i);
- }
-
- ALWAYS_INLINE JSValue JSImmediate::from(long i)
- {
- if ((i < minImmediateInt) | (i > maxImmediateInt))
- return fromNumberOutsideIntegerRange(i);
- return makeInt(i);
- }
-
- ALWAYS_INLINE JSValue JSImmediate::from(unsigned long i)
- {
- if (i > maxImmediateUInt)
- return fromNumberOutsideIntegerRange(i);
- return makeInt(i);
- }
-
- ALWAYS_INLINE JSValue JSImmediate::from(long long i)
- {
- if ((i < minImmediateInt) | (i > maxImmediateInt))
- return JSValue();
- return makeInt(static_cast<intptr_t>(i));
- }
-
- ALWAYS_INLINE JSValue JSImmediate::from(unsigned long long i)
- {
- if (i > maxImmediateUInt)
- return fromNumberOutsideIntegerRange(i);
- return makeInt(static_cast<intptr_t>(i));
- }
-
- ALWAYS_INLINE JSValue JSImmediate::from(double d)
- {
- const int intVal = static_cast<int>(d);
-
- // Check for data loss from conversion to int.
- if (intVal != d || (!intVal && signbit(d)))
- return fromNumberOutsideIntegerRange(d);
-
- return from(intVal);
- }
-
- ALWAYS_INLINE int32_t JSImmediate::getTruncatedInt32(JSValue v)
- {
- ASSERT(isIntegerNumber(v));
- return intValue(v);
- }
-
- ALWAYS_INLINE double JSImmediate::toDouble(JSValue v)
- {
- ASSERT(isImmediate(v));
-
- if (isIntegerNumber(v))
- return intValue(v);
-
-#if USE(JSVALUE64)
- if (isNumber(v)) {
- ASSERT(isDouble(v));
- return doubleValue(v);
- }
-#else
- ASSERT(!isNumber(v));
-#endif
-
- if (rawValue(v) == FullTagTypeUndefined)
- return nonInlineNaN();
-
- ASSERT(JSImmediate::isBoolean(v) || (v == JSImmediate::nullImmediate()));
- return rawValue(v) >> ExtendedPayloadShift;
- }
-
- ALWAYS_INLINE bool JSImmediate::getUInt32(JSValue v, uint32_t& i)
- {
- i = uintValue(v);
- return isPositiveIntegerNumber(v);
- }
-
- ALWAYS_INLINE bool JSImmediate::getTruncatedInt32(JSValue v, int32_t& i)
- {
- i = intValue(v);
- return isIntegerNumber(v);
- }
-
- ALWAYS_INLINE bool JSImmediate::getTruncatedUInt32(JSValue v, uint32_t& i)
- {
- return getUInt32(v, i);
- }
-
- inline JSValue::JSValue(JSNullTag)
- {
- *this = JSImmediate::nullImmediate();
- }
-
- inline JSValue::JSValue(JSUndefinedTag)
- {
- *this = JSImmediate::undefinedImmediate();
- }
-
- inline JSValue::JSValue(JSTrueTag)
- {
- *this = JSImmediate::trueImmediate();
- }
-
- inline JSValue::JSValue(JSFalseTag)
- {
- *this = JSImmediate::falseImmediate();
- }
-
- inline bool JSValue::isUndefinedOrNull() const
- {
- return JSImmediate::isUndefinedOrNull(asValue());
- }
-
- inline bool JSValue::isBoolean() const
- {
- return JSImmediate::isBoolean(asValue());
- }
-
- inline bool JSValue::isTrue() const
- {
- return asValue() == JSImmediate::trueImmediate();
- }
-
- inline bool JSValue::isFalse() const
- {
- return asValue() == JSImmediate::falseImmediate();
- }
-
- inline bool JSValue::getBoolean(bool& v) const
- {
- if (JSImmediate::isBoolean(asValue())) {
- v = JSImmediate::toBoolean(asValue());
- return true;
- }
-
- return false;
- }
-
- inline bool JSValue::getBoolean() const
- {
- return asValue() == jsBoolean(true);
- }
-
- inline bool JSValue::isCell() const
- {
- return !JSImmediate::isImmediate(asValue());
- }
-
- inline bool JSValue::isInt32() const
- {
- return JSImmediate::isIntegerNumber(asValue());
- }
-
- inline int32_t JSValue::asInt32() const
- {
- ASSERT(isInt32());
- return JSImmediate::getTruncatedInt32(asValue());
- }
-
- inline bool JSValue::isUInt32() const
- {
- return JSImmediate::isPositiveIntegerNumber(asValue());
- }
-
- inline uint32_t JSValue::asUInt32() const
- {
- ASSERT(isUInt32());
- return JSImmediate::getTruncatedUInt32(asValue());
- }
-
- class JSFastMath {
- public:
- static ALWAYS_INLINE bool canDoFastBitwiseOperations(JSValue v1, JSValue v2)
- {
- return JSImmediate::areBothImmediateIntegerNumbers(v1, v2);
- }
-
- static ALWAYS_INLINE JSValue equal(JSValue v1, JSValue v2)
- {
- ASSERT(canDoFastBitwiseOperations(v1, v2));
- return jsBoolean(v1 == v2);
- }
-
- static ALWAYS_INLINE JSValue notEqual(JSValue v1, JSValue v2)
- {
- ASSERT(canDoFastBitwiseOperations(v1, v2));
- return jsBoolean(v1 != v2);
- }
-
- static ALWAYS_INLINE JSValue andImmediateNumbers(JSValue v1, JSValue v2)
- {
- ASSERT(canDoFastBitwiseOperations(v1, v2));
- return JSImmediate::makeValue(JSImmediate::rawValue(v1) & JSImmediate::rawValue(v2));
- }
-
- static ALWAYS_INLINE JSValue xorImmediateNumbers(JSValue v1, JSValue v2)
- {
- ASSERT(canDoFastBitwiseOperations(v1, v2));
- return JSImmediate::makeValue((JSImmediate::rawValue(v1) ^ JSImmediate::rawValue(v2)) | JSImmediate::TagTypeNumber);
- }
-
- static ALWAYS_INLINE JSValue orImmediateNumbers(JSValue v1, JSValue v2)
- {
- ASSERT(canDoFastBitwiseOperations(v1, v2));
- return JSImmediate::makeValue(JSImmediate::rawValue(v1) | JSImmediate::rawValue(v2));
- }
-
- static ALWAYS_INLINE bool canDoFastRshift(JSValue v1, JSValue v2)
- {
- return JSImmediate::areBothImmediateIntegerNumbers(v1, v2);
- }
-
- static ALWAYS_INLINE bool canDoFastUrshift(JSValue v1, JSValue v2)
- {
- return JSImmediate::areBothImmediateIntegerNumbers(v1, v2) && !(JSImmediate::rawValue(v1) & JSImmediate::signBit);
- }
-
- static ALWAYS_INLINE JSValue rightShiftImmediateNumbers(JSValue val, JSValue shift)
- {
- ASSERT(canDoFastRshift(val, shift) || canDoFastUrshift(val, shift));
-#if USE(JSVALUE64)
- return JSImmediate::makeValue(static_cast<intptr_t>(static_cast<uint32_t>(static_cast<int32_t>(JSImmediate::rawValue(val)) >> ((JSImmediate::rawValue(shift) >> JSImmediate::IntegerPayloadShift) & 0x1f))) | JSImmediate::TagTypeNumber);
-#else
- return JSImmediate::makeValue((JSImmediate::rawValue(val) >> ((JSImmediate::rawValue(shift) >> JSImmediate::IntegerPayloadShift) & 0x1f)) | JSImmediate::TagTypeNumber);
-#endif
- }
-
- static ALWAYS_INLINE bool canDoFastAdditiveOperations(JSValue v)
- {
- // Number is non-negative and an operation involving two of these can't overflow.
- // Checking for allowed negative numbers takes more time than it's worth on SunSpider.
- return (JSImmediate::rawValue(v) & (JSImmediate::TagTypeNumber + (JSImmediate::signBit | (JSImmediate::signBit >> 1)))) == JSImmediate::TagTypeNumber;
- }
-
- static ALWAYS_INLINE bool canDoFastAdditiveOperations(JSValue v1, JSValue v2)
- {
- // Number is non-negative and an operation involving two of these can't overflow.
- // Checking for allowed negative numbers takes more time than it's worth on SunSpider.
- return canDoFastAdditiveOperations(v1) && canDoFastAdditiveOperations(v2);
- }
-
- static ALWAYS_INLINE JSValue addImmediateNumbers(JSValue v1, JSValue v2)
- {
- ASSERT(canDoFastAdditiveOperations(v1, v2));
- return JSImmediate::makeValue(JSImmediate::rawValue(v1) + JSImmediate::rawValue(v2) - JSImmediate::TagTypeNumber);
- }
-
- static ALWAYS_INLINE JSValue subImmediateNumbers(JSValue v1, JSValue v2)
- {
- ASSERT(canDoFastAdditiveOperations(v1, v2));
- return JSImmediate::makeValue(JSImmediate::rawValue(v1) - JSImmediate::rawValue(v2) + JSImmediate::TagTypeNumber);
- }
-
- static ALWAYS_INLINE JSValue incImmediateNumber(JSValue v)
- {
- ASSERT(canDoFastAdditiveOperations(v));
- return JSImmediate::makeValue(JSImmediate::rawValue(v) + (1 << JSImmediate::IntegerPayloadShift));
- }
-
- static ALWAYS_INLINE JSValue decImmediateNumber(JSValue v)
- {
- ASSERT(canDoFastAdditiveOperations(v));
- return JSImmediate::makeValue(JSImmediate::rawValue(v) - (1 << JSImmediate::IntegerPayloadShift));
- }
- };
-
-} // namespace JSC
-
-#endif // !USE(JSVALUE32_64)
-
-#endif // JSImmediate_h
#include "config.h"
#include "JSLock.h"
-#include "Collector.h"
+#include "Heap.h"
#include "CallFrame.h"
+#include "JSObject.h"
+#include "ScopeChain.h"
-#if ENABLE(JSC_MULTIPLE_THREADS)
+#if USE(PTHREADS)
#include <pthread.h>
#endif
namespace JSC {
-#if ENABLE(JSC_MULTIPLE_THREADS)
+// JSLock is only needed to support an obsolete execution model where JavaScriptCore
+// automatically protected against concurrent access from multiple threads.
+// So it's safe to disable it on non-mac platforms where we don't have native pthreads.
+#if ENABLE(JSC_MULTIPLE_THREADS) && (OS(DARWIN) || USE(PTHREADS))
// Acquire this mutex before accessing lock-related data.
static pthread_mutex_t JSMutex = PTHREAD_MUTEX_INITIALIZER;
lock(m_lockBehavior);
}
+JSLock::JSLock(JSGlobalData* globalData)
+ : m_lockBehavior(globalData->isSharedInstance() ? LockForReal : SilenceAssertionsOnly)
+{
+ lock(m_lockBehavior);
+}
+
void JSLock::lock(JSLockBehavior lockBehavior)
{
#ifdef NDEBUG
--lockDropDepth;
}
-#else
+#else // ENABLE(JSC_MULTIPLE_THREADS) && (OS(DARWIN) || USE(PTHREADS))
JSLock::JSLock(ExecState*)
: m_lockBehavior(SilenceAssertionsOnly)
{
}
-#endif // USE(MULTIPLE_THREADS)
+#endif // ENABLE(JSC_MULTIPLE_THREADS) && (OS(DARWIN) || USE(PTHREADS))
} // namespace JSC
// assertions working, so that clients that use the shared context don't break.
class ExecState;
+ class JSGlobalData;
enum JSLockBehavior { SilenceAssertionsOnly, LockForReal };
- class JSLock : public Noncopyable {
+ class JSLock {
+ WTF_MAKE_NONCOPYABLE(JSLock);
public:
JSLock(ExecState*);
+ JSLock(JSGlobalData*);
JSLock(JSLockBehavior lockBehavior)
: m_lockBehavior(lockBehavior)
JSLockBehavior m_lockBehavior;
- class DropAllLocks : public Noncopyable {
+ class DropAllLocks {
+ WTF_MAKE_NONCOPYABLE(DropAllLocks);
public:
DropAllLocks(ExecState* exec);
DropAllLocks(JSLockBehavior);
// JSValue methods
JSValue JSNotAnObject::toPrimitive(ExecState* exec, PreferredPrimitiveType) const
{
- ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception);
- return m_exception;
+ ASSERT_UNUSED(exec, exec->hadException());
+ return jsNumber(0);
}
bool JSNotAnObject::getPrimitiveNumber(ExecState* exec, double&, JSValue&)
{
- ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception);
+ ASSERT_UNUSED(exec, exec->hadException());
return false;
}
bool JSNotAnObject::toBoolean(ExecState* exec) const
{
- ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception);
+ ASSERT_UNUSED(exec, exec->hadException());
return false;
}
double JSNotAnObject::toNumber(ExecState* exec) const
{
- ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception);
+ ASSERT_UNUSED(exec, exec->hadException());
return NaN;
}
UString JSNotAnObject::toString(ExecState* exec) const
{
- ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception);
+ ASSERT_UNUSED(exec, exec->hadException());
return "";
}
-JSObject* JSNotAnObject::toObject(ExecState* exec) const
+JSObject* JSNotAnObject::toObject(ExecState* exec, JSGlobalObject*) const
{
- ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception);
- return m_exception;
-}
-
-// Marking
-void JSNotAnObject::markChildren(MarkStack& markStack)
-{
- JSObject::markChildren(markStack);
- markStack.append(m_exception);
+ ASSERT_UNUSED(exec, exec->hadException());
+ return const_cast<JSNotAnObject*>(this);
}
// JSObject methods
bool JSNotAnObject::getOwnPropertySlot(ExecState* exec, const Identifier&, PropertySlot&)
{
- ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception);
+ ASSERT_UNUSED(exec, exec->hadException());
return false;
}
bool JSNotAnObject::getOwnPropertySlot(ExecState* exec, unsigned, PropertySlot&)
{
- ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception);
+ ASSERT_UNUSED(exec, exec->hadException());
return false;
}
bool JSNotAnObject::getOwnPropertyDescriptor(ExecState* exec, const Identifier&, PropertyDescriptor&)
{
- ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception);
+ ASSERT_UNUSED(exec, exec->hadException());
return false;
}
void JSNotAnObject::put(ExecState* exec, const Identifier& , JSValue, PutPropertySlot&)
{
- ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception);
+ ASSERT_UNUSED(exec, exec->hadException());
}
void JSNotAnObject::put(ExecState* exec, unsigned, JSValue)
{
- ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception);
+ ASSERT_UNUSED(exec, exec->hadException());
}
bool JSNotAnObject::deleteProperty(ExecState* exec, const Identifier&)
{
- ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception);
+ ASSERT_UNUSED(exec, exec->hadException());
return false;
}
bool JSNotAnObject::deleteProperty(ExecState* exec, unsigned)
{
- ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception);
+ ASSERT_UNUSED(exec, exec->hadException());
return false;
}
void JSNotAnObject::getOwnPropertyNames(ExecState* exec, PropertyNameArray&, EnumerationMode)
{
- ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception);
+ ASSERT_UNUSED(exec, exec->hadException());
}
} // namespace JSC
namespace JSC {
- class JSNotAnObjectErrorStub : public JSObject {
- public:
- JSNotAnObjectErrorStub(ExecState* exec, bool isNull)
- : JSObject(exec->globalData().notAnObjectErrorStubStructure)
- , m_isNull(isNull)
- {
- }
-
- bool isNull() const { return m_isNull; }
-
- private:
- virtual bool isNotAnObjectErrorStub() const { return true; }
-
- bool m_isNull;
- };
-
// This unholy class is used to allow us to avoid multiple exception checks
// in certain SquirrelFish bytecodes -- effectively it just silently consumes
// any operations performed on the result of a failed toObject call.
- class JSNotAnObject : public JSObject {
+ class JSNotAnObject : public JSNonFinalObject {
public:
- JSNotAnObject(ExecState* exec, JSNotAnObjectErrorStub* exception)
- : JSObject(exec->globalData().notAnObjectStructure)
- , m_exception(exception)
+ JSNotAnObject(ExecState* exec)
+ : JSNonFinalObject(exec->globalData(), exec->globalData().notAnObjectStructure.get())
{
}
- static PassRefPtr<Structure> createStructure(JSValue prototype)
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
+ return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
}
private:
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesMarkChildren | OverridesGetPropertyNames | JSObject::StructureFlags;
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesGetPropertyNames | JSObject::StructureFlags;
// JSValue methods
virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const;
virtual bool toBoolean(ExecState*) const;
virtual double toNumber(ExecState*) const;
virtual UString toString(ExecState*) const;
- virtual JSObject* toObject(ExecState*) const;
-
- // Marking
- virtual void markChildren(MarkStack&);
+ virtual JSObject* toObject(ExecState*, JSGlobalObject*) const;
// JSObject methods
virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
virtual bool deleteProperty(ExecState*, unsigned propertyName);
virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties);
-
- JSNotAnObjectErrorStub* m_exception;
};
} // namespace JSC
+++ /dev/null
-/*
- * Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
- * Copyright (C) 2001 Peter Kelly (pmk@post.com)
- * Copyright (C) 2004, 2007, 2008 Apple Inc. All rights reserved.
- *
- * 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 "JSNumberCell.h"
-
-#if USE(JSVALUE32)
-
-#include "NumberObject.h"
-#include "UString.h"
-
-namespace JSC {
-
-JSValue JSNumberCell::toPrimitive(ExecState*, PreferredPrimitiveType) const
-{
- return const_cast<JSNumberCell*>(this);
-}
-
-bool JSNumberCell::getPrimitiveNumber(ExecState*, double& number, JSValue& value)
-{
- number = m_value;
- value = this;
- return true;
-}
-
-bool JSNumberCell::toBoolean(ExecState*) const
-{
- return m_value < 0.0 || m_value > 0.0; // false for NaN
-}
-
-double JSNumberCell::toNumber(ExecState*) const
-{
- return m_value;
-}
-
-UString JSNumberCell::toString(ExecState*) const
-{
- return UString::from(m_value);
-}
-
-JSObject* JSNumberCell::toObject(ExecState* exec) const
-{
- return constructNumber(exec, const_cast<JSNumberCell*>(this));
-}
-
-JSObject* JSNumberCell::toThisObject(ExecState* exec) const
-{
- return constructNumber(exec, const_cast<JSNumberCell*>(this));
-}
-
-bool JSNumberCell::getUInt32(uint32_t& uint32) const
-{
- uint32 = static_cast<uint32_t>(m_value);
- return uint32 == m_value;
-}
-
-JSValue JSNumberCell::getJSNumber()
-{
- return this;
-}
-
-JSValue jsNumberCell(ExecState* exec, double d)
-{
- return new (exec) JSNumberCell(exec, d);
-}
-
-JSValue jsNumberCell(JSGlobalData* globalData, double d)
-{
- return new (globalData) JSNumberCell(globalData, d);
-}
-
-} // namespace JSC
-
-#else // USE(JSVALUE32)
-
-// Keep our exported symbols lists happy.
-namespace JSC {
-
-JSValue jsNumberCell(ExecState*, double);
-
-JSValue jsNumberCell(ExecState*, double)
-{
- ASSERT_NOT_REACHED();
- return JSValue();
-}
-
-} // namespace JSC
-
-#endif // USE(JSVALUE32)
+++ /dev/null
-/*
- * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
- * Copyright (C) 2001 Peter Kelly (pmk@post.com)
- * Copyright (C) 2003, 2004, 2005, 2007, 2008 Apple Inc. All rights reserved.
- *
- * 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.
- *
- */
-
-#ifndef JSNumberCell_h
-#define JSNumberCell_h
-
-#include "CallFrame.h"
-#include "JSCell.h"
-#include "JSImmediate.h"
-#include "Collector.h"
-#include "UString.h"
-#include <stddef.h> // for size_t
-
-namespace JSC {
-
- extern const double NaN;
- extern const double Inf;
-
-#if USE(JSVALUE32)
- JSValue jsNumberCell(ExecState*, double);
-
- class Identifier;
- class JSCell;
- class JSObject;
- class JSString;
- class PropertySlot;
-
- struct ClassInfo;
- struct Instruction;
-
- class JSNumberCell : public JSCell {
- friend class JIT;
- friend JSValue jsNumberCell(JSGlobalData*, double);
- friend JSValue jsNumberCell(ExecState*, double);
-
- public:
- double value() const { return m_value; }
-
- virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const;
- virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue& value);
- virtual bool toBoolean(ExecState*) const;
- virtual double toNumber(ExecState*) const;
- virtual UString toString(ExecState*) const;
- virtual JSObject* toObject(ExecState*) const;
-
- virtual JSObject* toThisObject(ExecState*) const;
- virtual JSValue getJSNumber();
-
- void* operator new(size_t size, ExecState* exec)
- {
- return exec->heap()->allocateNumber(size);
- }
-
- void* operator new(size_t size, JSGlobalData* globalData)
- {
- return globalData->heap.allocateNumber(size);
- }
-
- static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(NumberType, OverridesGetOwnPropertySlot | NeedsThisConversion), AnonymousSlotCount); }
-
- private:
- JSNumberCell(JSGlobalData* globalData, double value)
- : JSCell(globalData->numberStructure.get())
- , m_value(value)
- {
- }
-
- JSNumberCell(ExecState* exec, double value)
- : JSCell(exec->globalData().numberStructure.get())
- , m_value(value)
- {
- }
-
- virtual bool getUInt32(uint32_t&) const;
-
- double m_value;
- };
-
- JSValue jsNumberCell(JSGlobalData*, double);
-
- inline bool isNumberCell(JSValue v)
- {
- return v.isCell() && v.asCell()->isNumber();
- }
-
- inline JSNumberCell* asNumberCell(JSValue v)
- {
- ASSERT(isNumberCell(v));
- return static_cast<JSNumberCell*>(v.asCell());
- }
-
- ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, ExecState* exec, double d)
- {
- *this = jsNumberCell(exec, d);
- }
-
- inline JSValue::JSValue(ExecState* exec, double d)
- {
- JSValue v = JSImmediate::from(d);
- *this = v ? v : jsNumberCell(exec, d);
- }
-
- inline JSValue::JSValue(ExecState* exec, int i)
- {
- JSValue v = JSImmediate::from(i);
- *this = v ? v : jsNumberCell(exec, i);
- }
-
- inline JSValue::JSValue(ExecState* exec, unsigned i)
- {
- JSValue v = JSImmediate::from(i);
- *this = v ? v : jsNumberCell(exec, i);
- }
-
- inline JSValue::JSValue(ExecState* exec, long i)
- {
- JSValue v = JSImmediate::from(i);
- *this = v ? v : jsNumberCell(exec, i);
- }
-
- inline JSValue::JSValue(ExecState* exec, unsigned long i)
- {
- JSValue v = JSImmediate::from(i);
- *this = v ? v : jsNumberCell(exec, i);
- }
-
- inline JSValue::JSValue(ExecState* exec, long long i)
- {
- JSValue v = JSImmediate::from(i);
- *this = v ? v : jsNumberCell(exec, static_cast<double>(i));
- }
-
- inline JSValue::JSValue(ExecState* exec, unsigned long long i)
- {
- JSValue v = JSImmediate::from(i);
- *this = v ? v : jsNumberCell(exec, static_cast<double>(i));
- }
-
- inline JSValue::JSValue(JSGlobalData* globalData, double d)
- {
- JSValue v = JSImmediate::from(d);
- *this = v ? v : jsNumberCell(globalData, d);
- }
-
- inline JSValue::JSValue(JSGlobalData* globalData, int i)
- {
- JSValue v = JSImmediate::from(i);
- *this = v ? v : jsNumberCell(globalData, i);
- }
-
- inline JSValue::JSValue(JSGlobalData* globalData, unsigned i)
- {
- JSValue v = JSImmediate::from(i);
- *this = v ? v : jsNumberCell(globalData, i);
- }
-
- inline bool JSValue::isDouble() const
- {
- return isNumberCell(asValue());
- }
-
- inline double JSValue::asDouble() const
- {
- return asNumberCell(asValue())->value();
- }
-
- inline bool JSValue::isNumber() const
- {
- return JSImmediate::isNumber(asValue()) || isDouble();
- }
-
- inline double JSValue::uncheckedGetNumber() const
- {
- ASSERT(isNumber());
- return JSImmediate::isImmediate(asValue()) ? JSImmediate::toDouble(asValue()) : asDouble();
- }
-
-#endif // USE(JSVALUE32)
-
-#if USE(JSVALUE64)
- ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, ExecState*, double d)
- {
- *this = JSImmediate::fromNumberOutsideIntegerRange(d);
- }
-
- inline JSValue::JSValue(ExecState*, double d)
- {
- JSValue v = JSImmediate::from(d);
- ASSERT(v);
- *this = v;
- }
-
- inline JSValue::JSValue(ExecState*, int i)
- {
- JSValue v = JSImmediate::from(i);
- ASSERT(v);
- *this = v;
- }
-
- inline JSValue::JSValue(ExecState*, unsigned i)
- {
- JSValue v = JSImmediate::from(i);
- ASSERT(v);
- *this = v;
- }
-
- inline JSValue::JSValue(ExecState*, long i)
- {
- JSValue v = JSImmediate::from(i);
- ASSERT(v);
- *this = v;
- }
-
- inline JSValue::JSValue(ExecState*, unsigned long i)
- {
- JSValue v = JSImmediate::from(i);
- ASSERT(v);
- *this = v;
- }
-
- inline JSValue::JSValue(ExecState*, long long i)
- {
- JSValue v = JSImmediate::from(static_cast<double>(i));
- ASSERT(v);
- *this = v;
- }
-
- inline JSValue::JSValue(ExecState*, unsigned long long i)
- {
- JSValue v = JSImmediate::from(static_cast<double>(i));
- ASSERT(v);
- *this = v;
- }
-
- inline JSValue::JSValue(JSGlobalData*, double d)
- {
- JSValue v = JSImmediate::from(d);
- ASSERT(v);
- *this = v;
- }
-
- inline JSValue::JSValue(JSGlobalData*, int i)
- {
- JSValue v = JSImmediate::from(i);
- ASSERT(v);
- *this = v;
- }
-
- inline JSValue::JSValue(JSGlobalData*, unsigned i)
- {
- JSValue v = JSImmediate::from(i);
- ASSERT(v);
- *this = v;
- }
-
- inline bool JSValue::isDouble() const
- {
- return JSImmediate::isDouble(asValue());
- }
-
- inline double JSValue::asDouble() const
- {
- return JSImmediate::doubleValue(asValue());
- }
-
- inline bool JSValue::isNumber() const
- {
- return JSImmediate::isNumber(asValue());
- }
-
- inline double JSValue::uncheckedGetNumber() const
- {
- ASSERT(isNumber());
- return JSImmediate::toDouble(asValue());
- }
-
-#endif // USE(JSVALUE64)
-
-#if USE(JSVALUE32) || USE(JSVALUE64)
-
- inline JSValue::JSValue(ExecState*, char i)
- {
- ASSERT(JSImmediate::from(i));
- *this = JSImmediate::from(i);
- }
-
- inline JSValue::JSValue(ExecState*, unsigned char i)
- {
- ASSERT(JSImmediate::from(i));
- *this = JSImmediate::from(i);
- }
-
- inline JSValue::JSValue(ExecState*, short i)
- {
- ASSERT(JSImmediate::from(i));
- *this = JSImmediate::from(i);
- }
-
- inline JSValue::JSValue(ExecState*, unsigned short i)
- {
- ASSERT(JSImmediate::from(i));
- *this = JSImmediate::from(i);
- }
-
- inline JSValue jsNaN(ExecState* exec)
- {
- return jsNumber(exec, NaN);
- }
-
- inline JSValue jsNaN(JSGlobalData* globalData)
- {
- return jsNumber(globalData, NaN);
- }
-
- // --- JSValue inlines ----------------------------
-
- ALWAYS_INLINE JSValue JSValue::toJSNumber(ExecState* exec) const
- {
- return isNumber() ? asValue() : jsNumber(exec, this->toNumber(exec));
- }
-
- inline bool JSValue::getNumber(double &result) const
- {
- if (isInt32())
- result = asInt32();
- else if (LIKELY(isDouble()))
- result = asDouble();
- else {
- ASSERT(!isNumber());
- return false;
- }
- return true;
- }
-
-#endif // USE(JSVALUE32) || USE(JSVALUE64)
-
-} // namespace JSC
-
-#endif // JSNumberCell_h
#include "Error.h"
#include "ExceptionHelpers.h"
#include "JSArray.h"
+#include "JSGlobalObject.h"
#include "LiteralParser.h"
+#include "Local.h"
+#include "LocalScope.h"
#include "Lookup.h"
#include "PropertyNameArray.h"
-#include "StringBuilder.h"
+#include "UStringBuilder.h"
+#include "UStringConcatenate.h"
#include <wtf/MathExtras.h>
namespace JSC {
ASSERT_CLASS_FITS_IN_CELL(JSONObject);
-static JSValue JSC_HOST_CALL JSONProtoFuncParse(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL JSONProtoFuncStringify(ExecState*, JSObject*, JSValue, const ArgList&);
+static EncodedJSValue JSC_HOST_CALL JSONProtoFuncParse(ExecState*);
+static EncodedJSValue JSC_HOST_CALL JSONProtoFuncStringify(ExecState*);
}
namespace JSC {
+JSONObject::JSONObject(JSGlobalObject* globalObject, Structure* structure)
+ : JSObjectWithGlobalObject(globalObject, structure)
+{
+ ASSERT(inherits(&s_info));
+}
+
// PropertyNameForFunctionCall objects must be on the stack, since the JSValue that they create is not marked.
class PropertyNameForFunctionCall {
public:
mutable JSValue m_value;
};
-class Stringifier : public Noncopyable {
+class Stringifier {
+ WTF_MAKE_NONCOPYABLE(Stringifier);
public:
- Stringifier(ExecState*, JSValue replacer, JSValue space);
- ~Stringifier();
- JSValue stringify(JSValue);
+ Stringifier(ExecState*, const Local<Unknown>& replacer, const Local<Unknown>& space);
+ Local<Unknown> stringify(Handle<Unknown>);
- void markAggregate(MarkStack&);
+ void visitAggregate(SlotVisitor&);
private:
class Holder {
public:
- Holder(JSObject*);
+ Holder(JSGlobalData&, JSObject*);
- JSObject* object() const { return m_object; }
+ JSObject* object() const { return m_object.get(); }
- bool appendNextProperty(Stringifier&, StringBuilder&);
+ bool appendNextProperty(Stringifier&, UStringBuilder&);
private:
- JSObject* const m_object;
+ Local<JSObject> m_object;
const bool m_isArray;
bool m_isJSArray;
unsigned m_index;
friend class Holder;
- static void appendQuotedString(StringBuilder&, const UString&);
+ static void appendQuotedString(UStringBuilder&, const UString&);
JSValue toJSON(JSValue, const PropertyNameForFunctionCall&);
enum StringifyResult { StringifyFailed, StringifySucceeded, StringifyFailedDueToUndefinedValue };
- StringifyResult appendStringifiedValue(StringBuilder&, JSValue, JSObject* holder, const PropertyNameForFunctionCall&);
+ StringifyResult appendStringifiedValue(UStringBuilder&, JSValue, JSObject* holder, const PropertyNameForFunctionCall&);
bool willIndent() const;
void indent();
void unindent();
- void startNewLine(StringBuilder&) const;
+ void startNewLine(UStringBuilder&) const;
- Stringifier* const m_nextStringifierToMark;
ExecState* const m_exec;
- const JSValue m_replacer;
+ const Local<Unknown> m_replacer;
bool m_usingArrayReplacer;
PropertyNameArray m_arrayReplacerPropertyNames;
CallType m_replacerCallType;
CallData m_replacerCallData;
const UString m_gap;
- HashSet<JSObject*> m_holderCycleDetector;
Vector<Holder, 16> m_holderStack;
UString m_repeatedGap;
UString m_indent;
if (!value.isObject())
return value;
JSObject* object = asObject(value);
- if (object->inherits(&NumberObject::info))
- return jsNumber(exec, object->toNumber(exec));
- if (object->inherits(&StringObject::info))
+ if (object->inherits(&NumberObject::s_info))
+ return jsNumber(object->toNumber(exec));
+ if (object->inherits(&StringObject::s_info))
return jsString(exec, object->toString(exec));
- if (object->inherits(&BooleanObject::info))
+ if (object->inherits(&BooleanObject::s_info))
return object->toPrimitive(exec);
return value;
}
// If the space value is a string, use it as the gap string, otherwise use no gap string.
UString spaces = space.getString(exec);
- if (spaces.size() > maxGapLength) {
- spaces = spaces.substr(0, maxGapLength);
+ if (spaces.length() > maxGapLength) {
+ spaces = spaces.substringSharingImpl(0, maxGapLength);
}
return spaces;
}
if (m_identifier)
m_value = jsString(exec, m_identifier->ustring());
else
- m_value = jsNumber(exec, m_number);
+ m_value = jsNumber(m_number);
}
return m_value;
}
// ------------------------------ Stringifier --------------------------------
-Stringifier::Stringifier(ExecState* exec, JSValue replacer, JSValue space)
- : m_nextStringifierToMark(exec->globalData().firstStringifierToMark)
- , m_exec(exec)
+Stringifier::Stringifier(ExecState* exec, const Local<Unknown>& replacer, const Local<Unknown>& space)
+ : m_exec(exec)
, m_replacer(replacer)
, m_usingArrayReplacer(false)
, m_arrayReplacerPropertyNames(exec)
, m_replacerCallType(CallTypeNone)
- , m_gap(gap(exec, space))
+ , m_gap(gap(exec, space.get()))
{
- exec->globalData().firstStringifierToMark = this;
-
if (!m_replacer.isObject())
return;
- if (asObject(m_replacer)->inherits(&JSArray::info)) {
+ if (m_replacer.asObject()->inherits(&JSArray::s_info)) {
m_usingArrayReplacer = true;
- JSObject* array = asObject(m_replacer);
+ Handle<JSObject> array = m_replacer.asObject();
unsigned length = array->get(exec, exec->globalData().propertyNames->length).toUInt32(exec);
for (unsigned i = 0; i < length; ++i) {
JSValue name = array->get(exec, i);
}
if (name.isObject()) {
- if (!asObject(name)->inherits(&NumberObject::info) && !asObject(name)->inherits(&StringObject::info))
+ if (!asObject(name)->inherits(&NumberObject::s_info) && !asObject(name)->inherits(&StringObject::s_info))
continue;
propertyName = name.toString(exec);
if (exec->hadException())
return;
}
- m_replacerCallType = asObject(m_replacer)->getCallData(m_replacerCallData);
-}
-
-Stringifier::~Stringifier()
-{
- ASSERT(m_exec->globalData().firstStringifierToMark == this);
- m_exec->globalData().firstStringifierToMark = m_nextStringifierToMark;
+ m_replacerCallType = m_replacer.asObject()->getCallData(m_replacerCallData);
}
-void Stringifier::markAggregate(MarkStack& markStack)
-{
- for (Stringifier* stringifier = this; stringifier; stringifier = stringifier->m_nextStringifierToMark) {
- size_t size = m_holderStack.size();
- for (size_t i = 0; i < size; ++i)
- markStack.append(m_holderStack[i].object());
- }
-}
-
-JSValue Stringifier::stringify(JSValue value)
+Local<Unknown> Stringifier::stringify(Handle<Unknown> value)
{
JSObject* object = constructEmptyObject(m_exec);
if (m_exec->hadException())
- return jsNull();
+ return Local<Unknown>(m_exec->globalData(), jsNull());
PropertyNameForFunctionCall emptyPropertyName(m_exec->globalData().propertyNames->emptyIdentifier);
- object->putDirect(m_exec->globalData().propertyNames->emptyIdentifier, value);
+ object->putDirect(m_exec->globalData(), m_exec->globalData().propertyNames->emptyIdentifier, value.get());
- StringBuilder result;
- if (appendStringifiedValue(result, value, object, emptyPropertyName) != StringifySucceeded)
- return jsUndefined();
+ UStringBuilder result;
+ if (appendStringifiedValue(result, value.get(), object, emptyPropertyName) != StringifySucceeded)
+ return Local<Unknown>(m_exec->globalData(), jsUndefined());
if (m_exec->hadException())
- return jsNull();
+ return Local<Unknown>(m_exec->globalData(), jsNull());
- return jsString(m_exec, result.build());
+ return Local<Unknown>(m_exec->globalData(), jsString(m_exec, result.toUString()));
}
-void Stringifier::appendQuotedString(StringBuilder& builder, const UString& value)
+void Stringifier::appendQuotedString(UStringBuilder& builder, const UString& value)
{
- int length = value.size();
-
- // String length plus 2 for quote marks plus 8 so we can accomodate a few escaped characters.
- builder.reserveCapacity(builder.size() + length + 2 + 8);
+ int length = value.length();
builder.append('"');
- const UChar* data = value.data();
+ const UChar* data = value.characters();
for (int i = 0; i < length; ++i) {
int start = i;
while (i < length && (data[i] > 0x1F && data[i] != '"' && data[i] != '\\'))
static const char hexDigits[] = "0123456789abcdef";
UChar ch = data[i];
UChar hex[] = { '\\', 'u', hexDigits[(ch >> 12) & 0xF], hexDigits[(ch >> 8) & 0xF], hexDigits[(ch >> 4) & 0xF], hexDigits[ch & 0xF] };
- builder.append(hex, sizeof(hex) / sizeof(UChar));
+ builder.append(hex, WTF_ARRAY_LENGTH(hex));
break;
}
}
return value;
JSValue list[] = { propertyName.value(m_exec) };
- ArgList args(list, sizeof(list) / sizeof(JSValue));
+ ArgList args(list, WTF_ARRAY_LENGTH(list));
return call(m_exec, object, callType, callData, value, args);
}
-Stringifier::StringifyResult Stringifier::appendStringifiedValue(StringBuilder& builder, JSValue value, JSObject* holder, const PropertyNameForFunctionCall& propertyName)
+Stringifier::StringifyResult Stringifier::appendStringifiedValue(UStringBuilder& builder, JSValue value, JSObject* holder, const PropertyNameForFunctionCall& propertyName)
{
// Call the toJSON function.
value = toJSON(value, propertyName);
// Call the replacer function.
if (m_replacerCallType != CallTypeNone) {
JSValue list[] = { propertyName.value(m_exec), value };
- ArgList args(list, sizeof(list) / sizeof(JSValue));
- value = call(m_exec, m_replacer, m_replacerCallType, m_replacerCallData, holder, args);
+ ArgList args(list, WTF_ARRAY_LENGTH(list));
+ value = call(m_exec, m_replacer.get(), m_replacerCallType, m_replacerCallData, holder, args);
if (m_exec->hadException())
return StringifyFailed;
}
- if (value.isUndefined() && !holder->inherits(&JSArray::info))
+ if (value.isUndefined() && !holder->inherits(&JSArray::s_info))
return StringifyFailedDueToUndefinedValue;
if (value.isNull()) {
if (!isfinite(numericValue))
builder.append("null");
else
- builder.append(UString::from(numericValue));
+ builder.append(UString::number(numericValue));
return StringifySucceeded;
}
CallData callData;
if (object->getCallData(callData) != CallTypeNone) {
- if (holder->inherits(&JSArray::info)) {
+ if (holder->inherits(&JSArray::s_info)) {
builder.append("null");
return StringifySucceeded;
}
}
// Handle cycle detection, and put the holder on the stack.
- if (!m_holderCycleDetector.add(object).second) {
- throwError(m_exec, TypeError, "JSON.stringify cannot serialize cyclic structures.");
- return StringifyFailed;
+ for (unsigned i = 0; i < m_holderStack.size(); i++) {
+ if (m_holderStack[i].object() == object) {
+ throwError(m_exec, createTypeError(m_exec, "JSON.stringify cannot serialize cyclic structures."));
+ return StringifyFailed;
+ }
}
bool holderStackWasEmpty = m_holderStack.isEmpty();
- m_holderStack.append(object);
+ m_holderStack.append(Holder(m_exec->globalData(), object));
if (!holderStackWasEmpty)
return StringifySucceeded;
return StringifyFailed;
if (!--tickCount) {
if (localTimeoutChecker.didTimeOut(m_exec)) {
- m_exec->setException(createInterruptedExecutionException(&m_exec->globalData()));
+ throwError(m_exec, createInterruptedExecutionException(&m_exec->globalData()));
return StringifyFailed;
}
tickCount = localTimeoutChecker.ticksUntilNextCheck();
}
}
- m_holderCycleDetector.remove(m_holderStack.last().object());
m_holderStack.removeLast();
} while (!m_holderStack.isEmpty());
return StringifySucceeded;
inline void Stringifier::indent()
{
// Use a single shared string, m_repeatedGap, so we don't keep allocating new ones as we indent and unindent.
- unsigned newSize = m_indent.size() + m_gap.size();
- if (newSize > m_repeatedGap.size())
- m_repeatedGap = makeString(m_repeatedGap, m_gap);
- ASSERT(newSize <= m_repeatedGap.size());
- m_indent = m_repeatedGap.substr(0, newSize);
+ unsigned newSize = m_indent.length() + m_gap.length();
+ if (newSize > m_repeatedGap.length())
+ m_repeatedGap = makeUString(m_repeatedGap, m_gap);
+ ASSERT(newSize <= m_repeatedGap.length());
+ m_indent = m_repeatedGap.substringSharingImpl(0, newSize);
}
inline void Stringifier::unindent()
{
- ASSERT(m_indent.size() >= m_gap.size());
- m_indent = m_repeatedGap.substr(0, m_indent.size() - m_gap.size());
+ ASSERT(m_indent.length() >= m_gap.length());
+ m_indent = m_repeatedGap.substringSharingImpl(0, m_indent.length() - m_gap.length());
}
-inline void Stringifier::startNewLine(StringBuilder& builder) const
+inline void Stringifier::startNewLine(UStringBuilder& builder) const
{
if (m_gap.isEmpty())
return;
builder.append(m_indent);
}
-inline Stringifier::Holder::Holder(JSObject* object)
- : m_object(object)
- , m_isArray(object->inherits(&JSArray::info))
+inline Stringifier::Holder::Holder(JSGlobalData& globalData, JSObject* object)
+ : m_object(globalData, object)
+ , m_isArray(object->inherits(&JSArray::s_info))
, m_index(0)
{
}
-bool Stringifier::Holder::appendNextProperty(Stringifier& stringifier, StringBuilder& builder)
+bool Stringifier::Holder::appendNextProperty(Stringifier& stringifier, UStringBuilder& builder)
{
ASSERT(m_index <= m_size);
// First time through, initialize.
if (!m_index) {
if (m_isArray) {
- m_isJSArray = isJSArray(&exec->globalData(), m_object);
+ m_isJSArray = isJSArray(&exec->globalData(), m_object.get());
m_size = m_object->get(exec, exec->globalData().propertyNames->length).toUInt32(exec);
builder.append('[');
} else {
// Last time through, finish up and return false.
if (m_index == m_size) {
stringifier.unindent();
- if (m_size && builder[builder.size() - 1] != '{')
+ if (m_size && builder[builder.length() - 1] != '{')
stringifier.startNewLine(builder);
builder.append(m_isArray ? ']' : '}');
return false;
if (m_isArray) {
// Get the value.
JSValue value;
- if (m_isJSArray && asArray(m_object)->canGetIndex(index))
- value = asArray(m_object)->getIndex(index);
+ if (m_isJSArray && asArray(m_object.get())->canGetIndex(index))
+ value = asArray(m_object.get())->getIndex(index);
else {
- PropertySlot slot(m_object);
+ PropertySlot slot(m_object.get());
if (!m_object->getOwnPropertySlot(exec, index, slot))
slot.setUndefined();
if (exec->hadException())
stringifier.startNewLine(builder);
// Append the stringified value.
- stringifyResult = stringifier.appendStringifiedValue(builder, value, m_object, index);
+ stringifyResult = stringifier.appendStringifiedValue(builder, value, m_object.get(), index);
} else {
// Get the value.
- PropertySlot slot(m_object);
+ PropertySlot slot(m_object.get());
Identifier& propertyName = m_propertyNames->propertyNameVector()[index];
if (!m_object->getOwnPropertySlot(exec, propertyName, slot))
return true;
if (exec->hadException())
return false;
- rollBackPoint = builder.size();
+ rollBackPoint = builder.length();
// Append the separator string.
if (builder[rollBackPoint - 1] != '{')
builder.append(' ');
// Append the stringified value.
- stringifyResult = stringifier.appendStringifiedValue(builder, value, m_object, propertyName);
+ stringifyResult = stringifier.appendStringifiedValue(builder, value, m_object.get(), propertyName);
}
// From this point on, no access to the this pointer or to any members, because the
// ------------------------------ JSONObject --------------------------------
-const ClassInfo JSONObject::info = { "JSON", 0, 0, ExecState::jsonTable };
+const ClassInfo JSONObject::s_info = { "JSON", &JSObjectWithGlobalObject::s_info, 0, ExecState::jsonTable };
/* Source for JSONObject.lut.h
@begin jsonTable
- parse JSONProtoFuncParse DontEnum|Function 1
- stringify JSONProtoFuncStringify DontEnum|Function 1
+ parse JSONProtoFuncParse DontEnum|Function 2
+ stringify JSONProtoFuncStringify DontEnum|Function 3
@end
*/
return getStaticFunctionDescriptor<JSObject>(exec, ExecState::jsonTable(exec), this, propertyName, descriptor);
}
-void JSONObject::markStringifiers(MarkStack& markStack, Stringifier* stringifier)
-{
- stringifier->markAggregate(markStack);
-}
-
class Walker {
public:
- Walker(ExecState* exec, JSObject* function, CallType callType, CallData callData)
+ Walker(ExecState* exec, Handle<JSObject> function, CallType callType, CallData callData)
: m_exec(exec)
- , m_function(function)
+ , m_function(exec->globalData(), function)
, m_callType(callType)
, m_callData(callData)
{
{
JSValue args[] = { property, unfiltered };
ArgList argList(args, 2);
- return call(m_exec, m_function, m_callType, m_callData, thisObj, argList);
+ return call(m_exec, m_function.get(), m_callType, m_callData, thisObj, argList);
}
friend class Holder;
ExecState* m_exec;
- JSObject* m_function;
+ Local<JSObject> m_function;
CallType m_callType;
CallData m_callData;
};
{
Vector<PropertyNameArray, 16> propertyStack;
Vector<uint32_t, 16> indexStack;
- Vector<JSObject*, 16> objectStack;
- Vector<JSArray*, 16> arrayStack;
+ LocalStack<JSObject, 16> objectStack(m_exec->globalData());
+ LocalStack<JSArray, 16> arrayStack(m_exec->globalData());
Vector<WalkerState, 16> stateStack;
WalkerState state = StateUnknown;
arrayStartState:
case ArrayStartState: {
ASSERT(inValue.isObject());
- ASSERT(isJSArray(&m_exec->globalData(), asObject(inValue)) || asObject(inValue)->inherits(&JSArray::info));
- if (objectStack.size() + arrayStack.size() > maximumFilterRecursion) {
- m_exec->setException(createStackOverflowError(m_exec));
- return jsUndefined();
- }
+ ASSERT(isJSArray(&m_exec->globalData(), asObject(inValue)) || asObject(inValue)->inherits(&JSArray::s_info));
+ if (objectStack.size() + arrayStack.size() > maximumFilterRecursion)
+ return throwError(m_exec, createStackOverflowError(m_exec));
JSArray* array = asArray(inValue);
- arrayStack.append(array);
+ arrayStack.push(array);
indexStack.append(0);
// fallthrough
}
arrayStartVisitMember:
case ArrayStartVisitMember: {
if (!--tickCount) {
- if (localTimeoutChecker.didTimeOut(m_exec)) {
- m_exec->setException(createInterruptedExecutionException(&m_exec->globalData()));
- return jsUndefined();
- }
+ if (localTimeoutChecker.didTimeOut(m_exec))
+ return throwError(m_exec, createInterruptedExecutionException(&m_exec->globalData()));
tickCount = localTimeoutChecker.ticksUntilNextCheck();
}
- JSArray* array = arrayStack.last();
+ JSArray* array = arrayStack.peek();
uint32_t index = indexStack.last();
if (index == array->length()) {
outValue = array;
- arrayStack.removeLast();
+ arrayStack.pop();
indexStack.removeLast();
break;
}
// fallthrough
}
case ArrayEndVisitMember: {
- JSArray* array = arrayStack.last();
- JSValue filteredValue = callReviver(array, jsString(m_exec, UString::from(indexStack.last())), outValue);
+ JSArray* array = arrayStack.peek();
+ JSValue filteredValue = callReviver(array, jsString(m_exec, UString::number(indexStack.last())), outValue);
if (filteredValue.isUndefined())
array->deleteProperty(m_exec, indexStack.last());
else {
if (isJSArray(&m_exec->globalData(), array) && array->canSetIndex(indexStack.last()))
- array->setIndex(indexStack.last(), filteredValue);
+ array->setIndex(m_exec->globalData(), indexStack.last(), filteredValue);
else
array->put(m_exec, indexStack.last(), filteredValue);
}
objectStartState:
case ObjectStartState: {
ASSERT(inValue.isObject());
- ASSERT(!isJSArray(&m_exec->globalData(), asObject(inValue)) && !asObject(inValue)->inherits(&JSArray::info));
- if (objectStack.size() + arrayStack.size() > maximumFilterRecursion) {
- m_exec->setException(createStackOverflowError(m_exec));
- return jsUndefined();
- }
+ ASSERT(!isJSArray(&m_exec->globalData(), asObject(inValue)) && !asObject(inValue)->inherits(&JSArray::s_info));
+ if (objectStack.size() + arrayStack.size() > maximumFilterRecursion)
+ return throwError(m_exec, createStackOverflowError(m_exec));
JSObject* object = asObject(inValue);
- objectStack.append(object);
+ objectStack.push(object);
indexStack.append(0);
propertyStack.append(PropertyNameArray(m_exec));
object->getOwnPropertyNames(m_exec, propertyStack.last());
objectStartVisitMember:
case ObjectStartVisitMember: {
if (!--tickCount) {
- if (localTimeoutChecker.didTimeOut(m_exec)) {
- m_exec->setException(createInterruptedExecutionException(&m_exec->globalData()));
- return jsUndefined();
- }
+ if (localTimeoutChecker.didTimeOut(m_exec))
+ return throwError(m_exec, createInterruptedExecutionException(&m_exec->globalData()));
tickCount = localTimeoutChecker.ticksUntilNextCheck();
}
- JSObject* object = objectStack.last();
+ JSObject* object = objectStack.peek();
uint32_t index = indexStack.last();
PropertyNameArray& properties = propertyStack.last();
if (index == properties.size()) {
outValue = object;
- objectStack.removeLast();
+ objectStack.pop();
indexStack.removeLast();
propertyStack.removeLast();
break;
// fallthrough
}
case ObjectEndVisitMember: {
- JSObject* object = objectStack.last();
+ JSObject* object = objectStack.peek();
Identifier prop = propertyStack.last()[indexStack.last()];
PutPropertySlot slot;
JSValue filteredValue = callReviver(object, jsString(m_exec, prop.ustring()), outValue);
break;
}
JSObject* object = asObject(inValue);
- if (isJSArray(&m_exec->globalData(), object) || object->inherits(&JSArray::info))
+ if (isJSArray(&m_exec->globalData(), object) || object->inherits(&JSArray::s_info))
goto arrayStartState;
goto objectStartState;
}
stateStack.removeLast();
if (!--tickCount) {
- if (localTimeoutChecker.didTimeOut(m_exec)) {
- m_exec->setException(createInterruptedExecutionException(&m_exec->globalData()));
- return jsUndefined();
- }
+ if (localTimeoutChecker.didTimeOut(m_exec))
+ return throwError(m_exec, createInterruptedExecutionException(&m_exec->globalData()));
tickCount = localTimeoutChecker.ticksUntilNextCheck();
}
}
}
// ECMA-262 v5 15.12.2
-JSValue JSC_HOST_CALL JSONProtoFuncParse(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL JSONProtoFuncParse(ExecState* exec)
{
- if (args.isEmpty())
- return throwError(exec, GeneralError, "JSON.parse requires at least one parameter");
- JSValue value = args.at(0);
+ if (!exec->argumentCount())
+ return throwVMError(exec, createError(exec, "JSON.parse requires at least one parameter"));
+ JSValue value = exec->argument(0);
UString source = value.toString(exec);
if (exec->hadException())
- return jsNull();
-
- LiteralParser jsonParser(exec, source, LiteralParser::StrictJSON);
+ return JSValue::encode(jsNull());
+
+ LocalScope scope(exec->globalData());
+ LiteralParser jsonParser(exec, source.characters(), source.length(), LiteralParser::StrictJSON);
JSValue unfiltered = jsonParser.tryLiteralParse();
if (!unfiltered)
- return throwError(exec, SyntaxError, "Unable to parse JSON string");
+ return throwVMError(exec, createSyntaxError(exec, "Unable to parse JSON string"));
- if (args.size() < 2)
- return unfiltered;
+ if (exec->argumentCount() < 2)
+ return JSValue::encode(unfiltered);
- JSValue function = args.at(1);
+ JSValue function = exec->argument(1);
CallData callData;
- CallType callType = function.getCallData(callData);
+ CallType callType = getCallData(function, callData);
if (callType == CallTypeNone)
- return unfiltered;
- return Walker(exec, asObject(function), callType, callData).walk(unfiltered);
+ return JSValue::encode(unfiltered);
+ return JSValue::encode(Walker(exec, Local<JSObject>(exec->globalData(), asObject(function)), callType, callData).walk(unfiltered));
}
// ECMA-262 v5 15.12.3
-JSValue JSC_HOST_CALL JSONProtoFuncStringify(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL JSONProtoFuncStringify(ExecState* exec)
{
- if (args.isEmpty())
- return throwError(exec, GeneralError, "No input to stringify");
- JSValue value = args.at(0);
- JSValue replacer = args.at(1);
- JSValue space = args.at(2);
- return Stringifier(exec, replacer, space).stringify(value);
+ if (!exec->argumentCount())
+ return throwVMError(exec, createError(exec, "No input to stringify"));
+ LocalScope scope(exec->globalData());
+ Local<Unknown> value(exec->globalData(), exec->argument(0));
+ Local<Unknown> replacer(exec->globalData(), exec->argument(1));
+ Local<Unknown> space(exec->globalData(), exec->argument(2));
+ return JSValue::encode(Stringifier(exec, replacer, space).stringify(value).get());
}
UString JSONStringify(ExecState* exec, JSValue value, unsigned indent)
{
- JSValue result = Stringifier(exec, jsNull(), jsNumber(exec, indent)).stringify(value);
+ LocalScope scope(exec->globalData());
+ Local<Unknown> result = Stringifier(exec, Local<Unknown>(exec->globalData(), jsNull()), Local<Unknown>(exec->globalData(), jsNumber(indent))).stringify(Local<Unknown>(exec->globalData(), value));
if (result.isUndefinedOrNull())
return UString();
return result.getString(exec);
#ifndef JSONObject_h
#define JSONObject_h
-#include "JSObject.h"
+#include "JSObjectWithGlobalObject.h"
namespace JSC {
class Stringifier;
- class JSONObject : public JSObject {
+ class JSONObject : public JSObjectWithGlobalObject {
public:
- JSONObject(NonNullPassRefPtr<Structure> structure)
- : JSObject(structure)
- {
- }
+ JSONObject(JSGlobalObject*, Structure*);
- static PassRefPtr<Structure> createStructure(JSValue prototype)
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
+ return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
}
-
- static void markStringifiers(MarkStack&, Stringifier*);
+
+ static const ClassInfo s_info;
protected:
static const unsigned StructureFlags = OverridesGetOwnPropertySlot | JSObject::StructureFlags;
virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
- virtual const ClassInfo* classInfo() const { return &info; }
- static const ClassInfo info;
};
UString JSONStringify(ExecState* exec, JSValue value, unsigned indent);
#include "DatePrototype.h"
#include "ErrorConstructor.h"
#include "GetterSetter.h"
+#include "JSFunction.h"
#include "JSGlobalObject.h"
#include "NativeErrorConstructor.h"
#include "ObjectPrototype.h"
namespace JSC {
ASSERT_CLASS_FITS_IN_CELL(JSObject);
+ASSERT_CLASS_FITS_IN_CELL(JSNonFinalObject);
+ASSERT_CLASS_FITS_IN_CELL(JSFinalObject);
+
+const char* StrictModeReadonlyPropertyWriteError = "Attempted to assign to readonly property.";
+
+const ClassInfo JSObject::s_info = { "Object", 0, 0, 0 };
static inline void getClassPropertyNames(ExecState* exec, const ClassInfo* classInfo, PropertyNameArray& propertyNames, EnumerationMode mode)
{
}
}
-void JSObject::markChildren(MarkStack& markStack)
+void JSObject::visitChildren(SlotVisitor& visitor)
{
+ ASSERT_GC_OBJECT_INHERITS(this, &s_info);
#ifndef NDEBUG
- bool wasCheckingForDefaultMarkViolation = markStack.m_isCheckingForDefaultMarkViolation;
- markStack.m_isCheckingForDefaultMarkViolation = false;
+ bool wasCheckingForDefaultMarkViolation = visitor.m_isCheckingForDefaultMarkViolation;
+ visitor.m_isCheckingForDefaultMarkViolation = false;
#endif
- markChildrenDirect(markStack);
+ visitChildrenDirect(visitor);
#ifndef NDEBUG
- markStack.m_isCheckingForDefaultMarkViolation = wasCheckingForDefaultMarkViolation;
+ visitor.m_isCheckingForDefaultMarkViolation = wasCheckingForDefaultMarkViolation;
#endif
}
UString JSObject::className() const
{
const ClassInfo* info = classInfo();
- if (info)
- return info->className;
- return "Object";
+ ASSERT(info);
+ return info->className;
}
bool JSObject::getOwnPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
static void throwSetterError(ExecState* exec)
{
- throwError(exec, TypeError, "setting a property that has only a getter");
+ throwError(exec, createTypeError(exec, "setting a property that has only a getter"));
}
// ECMA 8.6.2.2
// Setting __proto__ to a non-object, non-null value is silently ignored to match Mozilla.
if (!value.isObject() && !value.isNull())
return;
-
- JSValue nextPrototypeValue = value;
- while (nextPrototypeValue && nextPrototypeValue.isObject()) {
- JSObject* nextPrototype = asObject(nextPrototypeValue)->unwrappedObject();
- if (nextPrototype == this) {
- throwError(exec, GeneralError, "cyclic __proto__ value");
- return;
- }
- nextPrototypeValue = nextPrototype->prototype();
- }
-
- setPrototype(value);
+ if (!setPrototypeWithCycleCheck(exec->globalData(), value))
+ throwError(exec, createError(exec, "cyclic __proto__ value"));
return;
}
for (JSObject* obj = this; !obj->structure()->hasGetterSetterProperties(); obj = asObject(prototype)) {
prototype = obj->prototype();
if (prototype.isNull()) {
- putDirectInternal(exec->globalData(), propertyName, value, 0, true, slot);
+ if (!putDirectInternal(exec->globalData(), propertyName, value, 0, true, slot) && slot.isStrictMode())
+ throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
return;
}
}
unsigned attributes;
JSCell* specificValue;
- if ((m_structure->get(propertyName, attributes, specificValue) != WTF::notFound) && attributes & ReadOnly)
+ if ((m_structure->get(exec->globalData(), propertyName, attributes, specificValue) != WTF::notFound) && attributes & ReadOnly) {
+ if (slot.isStrictMode())
+ throwError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError));
return;
+ }
for (JSObject* obj = this; ; obj = asObject(prototype)) {
- if (JSValue gs = obj->getDirect(propertyName)) {
+ if (JSValue gs = obj->getDirect(exec->globalData(), propertyName)) {
if (gs.isGetterSetter()) {
JSObject* setterFunc = asGetterSetter(gs)->setter();
if (!setterFunc) {
break;
}
- putDirectInternal(exec->globalData(), propertyName, value, 0, true, slot);
+ if (!putDirectInternal(exec->globalData(), propertyName, value, 0, true, slot) && slot.isStrictMode())
+ throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
return;
}
put(exec, Identifier::from(exec, propertyName), value, slot);
}
+void JSObject::putWithAttributes(JSGlobalData* globalData, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
+{
+ putDirectInternal(*globalData, propertyName, value, attributes, checkReadOnly, slot);
+}
+
+void JSObject::putWithAttributes(JSGlobalData* globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
+{
+ putDirectInternal(*globalData, propertyName, value, attributes);
+}
+
+void JSObject::putWithAttributes(JSGlobalData* globalData, unsigned propertyName, JSValue value, unsigned attributes)
+{
+ putWithAttributes(globalData, Identifier::from(globalData, propertyName), value, attributes);
+}
+
void JSObject::putWithAttributes(ExecState* exec, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
{
putDirectInternal(exec->globalData(), propertyName, value, attributes, checkReadOnly, slot);
{
unsigned attributes;
JSCell* specificValue;
- if (m_structure->get(propertyName, attributes, specificValue) != WTF::notFound) {
+ if (m_structure->get(exec->globalData(), propertyName, attributes, specificValue) != WTF::notFound) {
if ((attributes & DontDelete))
return false;
- removeDirect(propertyName);
+ removeDirect(exec->globalData(), propertyName);
return true;
}
{
JSValue function = object->get(exec, propertyName);
CallData callData;
- CallType callType = function.getCallData(callData);
+ CallType callType = getCallData(function, callData);
if (callType == CallTypeNone)
return exec->exception();
ASSERT(!exec->hadException());
- return throwError(exec, TypeError, "No default value");
+ return throwError(exec, createTypeError(exec, "No default value"));
}
const HashEntry* JSObject::findPropertyHashEntry(ExecState* exec, const Identifier& propertyName) const
void JSObject::defineGetter(ExecState* exec, const Identifier& propertyName, JSObject* getterFunction, unsigned attributes)
{
- JSValue object = getDirect(propertyName);
+ JSValue object = getDirect(exec->globalData(), propertyName);
if (object && object.isGetterSetter()) {
ASSERT(m_structure->hasGetterSetterProperties());
- asGetterSetter(object)->setGetter(getterFunction);
+ asGetterSetter(object)->setGetter(exec->globalData(), getterFunction);
return;
}
+ JSGlobalData& globalData = exec->globalData();
PutPropertySlot slot;
GetterSetter* getterSetter = new (exec) GetterSetter(exec);
- putDirectInternal(exec->globalData(), propertyName, getterSetter, attributes | Getter, true, slot);
+ putDirectInternal(globalData, propertyName, getterSetter, attributes | Getter, true, slot);
// putDirect will change our Structure if we add a new property. For
// getters and setters, though, we also need to change our Structure
// if we override an existing non-getter or non-setter.
if (slot.type() != PutPropertySlot::NewProperty) {
- if (!m_structure->isDictionary()) {
- RefPtr<Structure> structure = Structure::getterSetterTransition(m_structure);
- setStructure(structure.release());
- }
+ if (!m_structure->isDictionary())
+ setStructure(exec->globalData(), Structure::getterSetterTransition(globalData, m_structure.get()));
}
m_structure->setHasGetterSetterProperties(true);
- getterSetter->setGetter(getterFunction);
+ getterSetter->setGetter(globalData, getterFunction);
}
void JSObject::defineSetter(ExecState* exec, const Identifier& propertyName, JSObject* setterFunction, unsigned attributes)
{
- JSValue object = getDirect(propertyName);
+ JSValue object = getDirect(exec->globalData(), propertyName);
if (object && object.isGetterSetter()) {
ASSERT(m_structure->hasGetterSetterProperties());
- asGetterSetter(object)->setSetter(setterFunction);
+ asGetterSetter(object)->setSetter(exec->globalData(), setterFunction);
return;
}
// getters and setters, though, we also need to change our Structure
// if we override an existing non-getter or non-setter.
if (slot.type() != PutPropertySlot::NewProperty) {
- if (!m_structure->isDictionary()) {
- RefPtr<Structure> structure = Structure::getterSetterTransition(m_structure);
- setStructure(structure.release());
- }
+ if (!m_structure->isDictionary())
+ setStructure(exec->globalData(), Structure::getterSetterTransition(exec->globalData(), m_structure.get()));
}
m_structure->setHasGetterSetterProperties(true);
- getterSetter->setSetter(setterFunction);
+ getterSetter->setSetter(exec->globalData(), setterFunction);
}
-JSValue JSObject::lookupGetter(ExecState*, const Identifier& propertyName)
+JSValue JSObject::lookupGetter(ExecState* exec, const Identifier& propertyName)
{
JSObject* object = this;
while (true) {
- if (JSValue value = object->getDirect(propertyName)) {
+ if (JSValue value = object->getDirect(exec->globalData(), propertyName)) {
if (!value.isGetterSetter())
return jsUndefined();
JSObject* functionObject = asGetterSetter(value)->getter();
}
}
-JSValue JSObject::lookupSetter(ExecState*, const Identifier& propertyName)
+JSValue JSObject::lookupSetter(ExecState* exec, const Identifier& propertyName)
{
JSObject* object = this;
while (true) {
- if (JSValue value = object->getDirect(propertyName)) {
+ if (JSValue value = object->getDirect(exec->globalData(), propertyName)) {
if (!value.isGetterSetter())
return jsUndefined();
JSObject* functionObject = asGetterSetter(value)->setter();
return false;
if (!proto.isObject()) {
- throwError(exec, TypeError, "instanceof called on an object with an invalid prototype property.");
+ throwError(exec, createTypeError(exec, "instanceof called on an object with an invalid prototype property."));
return false;
}
return descriptor.enumerable();
}
-bool JSObject::getPropertySpecificValue(ExecState*, const Identifier& propertyName, JSCell*& specificValue) const
+bool JSObject::getPropertySpecificValue(ExecState* exec, const Identifier& propertyName, JSCell*& specificValue) const
{
unsigned attributes;
- if (m_structure->get(propertyName, attributes, specificValue) != WTF::notFound)
+ if (m_structure->get(exec->globalData(), propertyName, attributes, specificValue) != WTF::notFound)
return true;
// This could be a function within the static table? - should probably
void JSObject::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
{
- m_structure->getPropertyNames(propertyNames, mode);
+ m_structure->getPropertyNames(exec->globalData(), propertyNames, mode);
getClassPropertyNames(exec, classInfo(), propertyNames, mode);
}
return primitive.toString(exec);
}
-JSObject* JSObject::toObject(ExecState*) const
+JSObject* JSObject::toObject(ExecState*, JSGlobalObject*) const
{
return const_cast<JSObject*>(this);
}
return const_cast<JSObject*>(this);
}
+JSValue JSObject::toStrictThisObject(ExecState*) const
+{
+ return const_cast<JSObject*>(this);
+}
+
JSObject* JSObject::unwrappedObject()
{
return this;
}
-void JSObject::removeDirect(const Identifier& propertyName)
+void JSObject::seal(JSGlobalData& globalData)
+{
+ if (isSealed(globalData))
+ return;
+ preventExtensions(globalData);
+ setStructure(globalData, Structure::sealTransition(globalData, m_structure.get()));
+}
+
+void JSObject::freeze(JSGlobalData& globalData)
+{
+ if (isFrozen(globalData))
+ return;
+ preventExtensions(globalData);
+ setStructure(globalData, Structure::freezeTransition(globalData, m_structure.get()));
+}
+
+void JSObject::preventExtensions(JSGlobalData& globalData)
+{
+ if (isExtensible())
+ setStructure(globalData, Structure::preventExtensionsTransition(globalData, m_structure.get()));
+}
+
+void JSObject::removeDirect(JSGlobalData& globalData, const Identifier& propertyName)
{
+ if (m_structure->get(globalData, propertyName) == WTF::notFound)
+ return;
+
size_t offset;
if (m_structure->isUncacheableDictionary()) {
- offset = m_structure->removePropertyWithoutTransition(propertyName);
+ offset = m_structure->removePropertyWithoutTransition(globalData, propertyName);
if (offset != WTF::notFound)
- putDirectOffset(offset, jsUndefined());
+ putUndefinedAtDirectOffset(offset);
return;
}
- RefPtr<Structure> structure = Structure::removePropertyTransition(m_structure, propertyName, offset);
- setStructure(structure.release());
+ setStructure(globalData, Structure::removePropertyTransition(globalData, m_structure.get(), propertyName, offset));
if (offset != WTF::notFound)
- putDirectOffset(offset, jsUndefined());
+ putUndefinedAtDirectOffset(offset);
}
void JSObject::putDirectFunction(ExecState* exec, InternalFunction* function, unsigned attr)
{
- putDirectFunction(Identifier(exec, function->name(exec)), function, attr);
+ putDirectFunction(exec->globalData(), Identifier(exec, function->name(exec)), function, attr);
+}
+
+void JSObject::putDirectFunction(ExecState* exec, JSFunction* function, unsigned attr)
+{
+ putDirectFunction(exec->globalData(), Identifier(exec, function->name(exec)), function, attr);
}
void JSObject::putDirectFunctionWithoutTransition(ExecState* exec, InternalFunction* function, unsigned attr)
{
- putDirectFunctionWithoutTransition(Identifier(exec, function->name(exec)), function, attr);
+ putDirectFunctionWithoutTransition(exec->globalData(), Identifier(exec, function->name(exec)), function, attr);
}
-NEVER_INLINE void JSObject::fillGetterPropertySlot(PropertySlot& slot, JSValue* location)
+void JSObject::putDirectFunctionWithoutTransition(ExecState* exec, JSFunction* function, unsigned attr)
{
- if (JSObject* getterFunction = asGetterSetter(*location)->getter()) {
+ putDirectFunctionWithoutTransition(exec->globalData(), Identifier(exec, function->name(exec)), function, attr);
+}
+
+NEVER_INLINE void JSObject::fillGetterPropertySlot(PropertySlot& slot, WriteBarrierBase<Unknown>* location)
+{
+ if (JSObject* getterFunction = asGetterSetter(location->get())->getter()) {
if (!structure()->isDictionary())
slot.setCacheableGetterSlot(this, getterFunction, offsetForLocation(location));
else
slot.setUndefined();
}
-Structure* JSObject::createInheritorID()
+Structure* JSObject::createInheritorID(JSGlobalData& globalData)
{
- m_inheritorID = JSObject::createStructure(this);
+ m_inheritorID.set(globalData, this, createEmptyObjectStructure(globalData, this));
+ ASSERT(m_inheritorID->isEmpty());
return m_inheritorID.get();
}
void JSObject::allocatePropertyStorage(size_t oldSize, size_t newSize)
{
- allocatePropertyStorageInline(oldSize, newSize);
+ ASSERT(newSize > oldSize);
+
+ // It's important that this function not rely on m_structure, since
+ // we might be in the middle of a transition.
+ bool wasInline = (oldSize < JSObject::baseExternalStorageCapacity);
+
+ PropertyStorage oldPropertyStorage = m_propertyStorage;
+ PropertyStorage newPropertyStorage = new WriteBarrierBase<Unknown>[newSize];
+
+ for (unsigned i = 0; i < oldSize; ++i)
+ newPropertyStorage[i] = oldPropertyStorage[i];
+
+ if (!wasInline)
+ delete [] oldPropertyStorage;
+
+ m_propertyStorage = newPropertyStorage;
}
-bool JSObject::getOwnPropertyDescriptor(ExecState*, const Identifier& propertyName, PropertyDescriptor& descriptor)
+bool JSObject::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
{
unsigned attributes = 0;
JSCell* cell = 0;
- size_t offset = m_structure->get(propertyName, attributes, cell);
+ size_t offset = m_structure->get(exec->globalData(), propertyName, attributes, cell);
if (offset == WTF::notFound)
return false;
descriptor.setDescriptor(getDirectOffset(offset), attributes);
}
}
-static bool putDescriptor(ExecState* exec, JSObject* target, const Identifier& propertyName, PropertyDescriptor& descriptor, unsigned attributes, JSValue oldValue)
+static bool putDescriptor(ExecState* exec, JSObject* target, const Identifier& propertyName, PropertyDescriptor& descriptor, unsigned attributes, const PropertyDescriptor& oldDescriptor)
{
if (descriptor.isGenericDescriptor() || descriptor.isDataDescriptor()) {
- target->putWithAttributes(exec, propertyName, descriptor.value() ? descriptor.value() : oldValue, attributes & ~(Getter | Setter));
+ if (descriptor.isGenericDescriptor() && oldDescriptor.isAccessorDescriptor()) {
+ GetterSetter* accessor = new (exec) GetterSetter(exec);
+ if (oldDescriptor.getter()) {
+ attributes |= Getter;
+ accessor->setGetter(exec->globalData(), asObject(oldDescriptor.getter()));
+ }
+ if (oldDescriptor.setter()) {
+ attributes |= Setter;
+ accessor->setSetter(exec->globalData(), asObject(oldDescriptor.setter()));
+ }
+ target->putWithAttributes(exec, propertyName, accessor, attributes);
+ return true;
+ }
+ JSValue newValue = jsUndefined();
+ if (descriptor.value())
+ newValue = descriptor.value();
+ else if (oldDescriptor.value())
+ newValue = oldDescriptor.value();
+ target->putWithAttributes(exec, propertyName, newValue, attributes & ~(Getter | Setter));
return true;
}
attributes &= ~ReadOnly;
{
// If we have a new property we can just put it on normally
PropertyDescriptor current;
- if (!getOwnPropertyDescriptor(exec, propertyName, current))
- return putDescriptor(exec, this, propertyName, descriptor, descriptor.attributes(), jsUndefined());
+ if (!getOwnPropertyDescriptor(exec, propertyName, current)) {
+ // unless extensions are prevented!
+ if (!isExtensible()) {
+ if (throwException)
+ throwError(exec, createTypeError(exec, "Attempting to define property on object that is not extensible."));
+ return false;
+ }
+ PropertyDescriptor oldDescriptor;
+ oldDescriptor.setValue(jsUndefined());
+ return putDescriptor(exec, this, propertyName, descriptor, descriptor.attributes(), oldDescriptor);
+ }
if (descriptor.isEmpty())
return true;
if (!current.configurable()) {
if (descriptor.configurable()) {
if (throwException)
- throwError(exec, TypeError, "Attempting to configurable attribute of unconfigurable property.");
+ throwError(exec, createTypeError(exec, "Attempting to configurable attribute of unconfigurable property."));
return false;
}
if (descriptor.enumerablePresent() && descriptor.enumerable() != current.enumerable()) {
if (throwException)
- throwError(exec, TypeError, "Attempting to change enumerable attribute of unconfigurable property.");
+ throwError(exec, createTypeError(exec, "Attempting to change enumerable attribute of unconfigurable property."));
return false;
}
}
if (descriptor.isGenericDescriptor()) {
if (!current.attributesEqual(descriptor)) {
deleteProperty(exec, propertyName);
- putDescriptor(exec, this, propertyName, descriptor, current.attributesWithOverride(descriptor), current.value());
+ putDescriptor(exec, this, propertyName, descriptor, current.attributesWithOverride(descriptor), current);
}
return true;
}
if (descriptor.isDataDescriptor() != current.isDataDescriptor()) {
if (!current.configurable()) {
if (throwException)
- throwError(exec, TypeError, "Attempting to change access mechanism for an unconfigurable property.");
+ throwError(exec, createTypeError(exec, "Attempting to change access mechanism for an unconfigurable property."));
return false;
}
deleteProperty(exec, propertyName);
- return putDescriptor(exec, this, propertyName, descriptor, current.attributesWithOverride(descriptor), current.value() ? current.value() : jsUndefined());
+ return putDescriptor(exec, this, propertyName, descriptor, current.attributesWithOverride(descriptor), current);
}
// Changing the value and attributes of an existing property
if (!current.configurable()) {
if (!current.writable() && descriptor.writable()) {
if (throwException)
- throwError(exec, TypeError, "Attempting to change writable attribute of unconfigurable property.");
+ throwError(exec, createTypeError(exec, "Attempting to change writable attribute of unconfigurable property."));
return false;
}
if (!current.writable()) {
if (descriptor.value() || !JSValue::strictEqual(exec, current.value(), descriptor.value())) {
if (throwException)
- throwError(exec, TypeError, "Attempting to change value of a readonly property.");
+ throwError(exec, createTypeError(exec, "Attempting to change value of a readonly property."));
return false;
}
}
return true;
}
deleteProperty(exec, propertyName);
- return putDescriptor(exec, this, propertyName, descriptor, current.attributesWithOverride(descriptor), current.value());
+ return putDescriptor(exec, this, propertyName, descriptor, current.attributesWithOverride(descriptor), current);
}
// Changing the accessor functions of an existing accessor property
ASSERT(descriptor.isAccessorDescriptor());
if (!current.configurable()) {
- if (descriptor.setterPresent() && !(current.setter() && JSValue::strictEqual(exec, current.setter(), descriptor.setter()))) {
+ if (descriptor.setterPresent() && !(current.setterPresent() && JSValue::strictEqual(exec, current.setter(), descriptor.setter()))) {
if (throwException)
- throwError(exec, TypeError, "Attempting to change the setter of an unconfigurable property.");
+ throwError(exec, createTypeError(exec, "Attempting to change the setter of an unconfigurable property."));
return false;
}
- if (descriptor.getterPresent() && !(current.getter() && JSValue::strictEqual(exec, current.getter(), descriptor.getter()))) {
+ if (descriptor.getterPresent() && !(current.getterPresent() && JSValue::strictEqual(exec, current.getter(), descriptor.getter()))) {
if (throwException)
- throwError(exec, TypeError, "Attempting to change the getter of an unconfigurable property.");
+ throwError(exec, createTypeError(exec, "Attempting to change the getter of an unconfigurable property."));
return false;
}
}
- JSValue accessor = getDirect(propertyName);
+ JSValue accessor = getDirect(exec->globalData(), propertyName);
if (!accessor)
return false;
GetterSetter* getterSetter = asGetterSetter(accessor);
if (current.attributesEqual(descriptor)) {
if (descriptor.setter())
- getterSetter->setSetter(asObject(descriptor.setter()));
+ getterSetter->setSetter(exec->globalData(), asObject(descriptor.setter()));
if (descriptor.getter())
- getterSetter->setGetter(asObject(descriptor.getter()));
+ getterSetter->setGetter(exec->globalData(), asObject(descriptor.getter()));
return true;
}
deleteProperty(exec, propertyName);
attrs |= Setter;
if (descriptor.getter())
attrs |= Getter;
- putDirect(propertyName, getterSetter, attrs);
+ putDirect(exec->globalData(), propertyName, getterSetter, attrs);
return true;
}
+JSObject* throwTypeError(ExecState* exec, const UString& message)
+{
+ return throwError(exec, createTypeError(exec, message));
+}
+
} // namespace JSC
#include "Completion.h"
#include "CallFrame.h"
#include "JSCell.h"
-#include "JSNumberCell.h"
#include "MarkStack.h"
#include "PropertySlot.h"
#include "PutPropertySlot.h"
class Structure;
struct HashTable;
+ JSObject* throwTypeError(ExecState*, const UString&);
+ extern const char* StrictModeReadonlyPropertyWriteError;
+
// ECMA 262-3 8.6.1
// Property attributes
enum Attribute {
Setter = 1 << 6 // property is a setter
};
- typedef EncodedJSValue* PropertyStorage;
- typedef const EncodedJSValue* ConstPropertyStorage;
+ typedef WriteBarrierBase<Unknown>* PropertyStorage;
+ typedef const WriteBarrierBase<Unknown>* ConstPropertyStorage;
class JSObject : public JSCell {
friend class BatchedTransitionOptimizer;
friend class JIT;
friend class JSCell;
+ friend void setUpStaticFunctionSlot(ExecState* exec, const HashEntry* entry, JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot);
public:
- explicit JSObject(NonNullPassRefPtr<Structure>);
-
- virtual void markChildren(MarkStack&);
- ALWAYS_INLINE void markChildrenDirect(MarkStack& markStack);
+ virtual void visitChildren(SlotVisitor&);
+ ALWAYS_INLINE void visitChildrenDirect(SlotVisitor&);
// The inline virtual destructor cannot be the first virtual function declared
// in the class as it results in the vtable being generated as a weak symbol
virtual ~JSObject();
JSValue prototype() const;
- void setPrototype(JSValue prototype);
+ void setPrototype(JSGlobalData&, JSValue prototype);
+ bool setPrototypeWithCycleCheck(JSGlobalData&, JSValue prototype);
- void setStructure(NonNullPassRefPtr<Structure>);
- Structure* inheritorID();
+ void setStructure(JSGlobalData&, Structure*);
+ Structure* inheritorID(JSGlobalData&);
virtual UString className() const;
virtual void put(ExecState*, const Identifier& propertyName, JSValue value, PutPropertySlot&);
virtual void put(ExecState*, unsigned propertyName, JSValue value);
+ virtual void putWithAttributes(JSGlobalData*, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot);
+ virtual void putWithAttributes(JSGlobalData*, const Identifier& propertyName, JSValue value, unsigned attributes);
+ virtual void putWithAttributes(JSGlobalData*, unsigned propertyName, JSValue value, unsigned attributes);
virtual void putWithAttributes(ExecState*, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot);
virtual void putWithAttributes(ExecState*, const Identifier& propertyName, JSValue value, unsigned attributes);
virtual void putWithAttributes(ExecState*, unsigned propertyName, JSValue value, unsigned attributes);
virtual bool toBoolean(ExecState*) const;
virtual double toNumber(ExecState*) const;
virtual UString toString(ExecState*) const;
- virtual JSObject* toObject(ExecState*) const;
+ virtual JSObject* toObject(ExecState*, JSGlobalObject*) const;
virtual JSObject* toThisObject(ExecState*) const;
+ virtual JSValue toStrictThisObject(ExecState*) const;
virtual JSObject* unwrappedObject();
bool getPropertySpecificValue(ExecState* exec, const Identifier& propertyName, JSCell*& specificFunction) const;
// This get function only looks at the property map.
- JSValue getDirect(const Identifier& propertyName) const
+ JSValue getDirect(JSGlobalData& globalData, const Identifier& propertyName) const
{
- size_t offset = m_structure->get(propertyName);
+ size_t offset = m_structure->get(globalData, propertyName);
return offset != WTF::notFound ? getDirectOffset(offset) : JSValue();
}
- JSValue* getDirectLocation(const Identifier& propertyName)
+ WriteBarrierBase<Unknown>* getDirectLocation(JSGlobalData& globalData, const Identifier& propertyName)
{
- size_t offset = m_structure->get(propertyName);
+ size_t offset = m_structure->get(globalData, propertyName);
return offset != WTF::notFound ? locationForOffset(offset) : 0;
}
- JSValue* getDirectLocation(const Identifier& propertyName, unsigned& attributes)
+ WriteBarrierBase<Unknown>* getDirectLocation(JSGlobalData& globalData, const Identifier& propertyName, unsigned& attributes)
{
JSCell* specificFunction;
- size_t offset = m_structure->get(propertyName, attributes, specificFunction);
+ size_t offset = m_structure->get(globalData, propertyName, attributes, specificFunction);
return offset != WTF::notFound ? locationForOffset(offset) : 0;
}
- size_t offsetForLocation(JSValue* location) const
+ size_t offsetForLocation(WriteBarrierBase<Unknown>* location) const
{
- return location - reinterpret_cast<const JSValue*>(propertyStorage());
+ return location - propertyStorage();
}
- void transitionTo(Structure*);
+ void transitionTo(JSGlobalData&, Structure*);
- void removeDirect(const Identifier& propertyName);
- bool hasCustomProperties() { return !m_structure->isEmpty(); }
+ void removeDirect(JSGlobalData&, const Identifier& propertyName);
+ bool hasCustomProperties() { return m_structure->didTransition(); }
bool hasGetterSetterProperties() { return m_structure->hasGetterSetterProperties(); }
- void putDirect(const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot);
- void putDirect(const Identifier& propertyName, JSValue value, unsigned attr = 0);
- void putDirect(const Identifier& propertyName, JSValue value, PutPropertySlot&);
+ bool putDirect(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attr, bool checkReadOnly, PutPropertySlot&);
+ void putDirect(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attr = 0);
+ bool putDirect(JSGlobalData&, const Identifier& propertyName, JSValue, PutPropertySlot&);
- void putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attr = 0);
- void putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot);
+ void putDirectFunction(JSGlobalData&, const Identifier& propertyName, JSCell*, unsigned attr = 0);
+ void putDirectFunction(JSGlobalData&, const Identifier& propertyName, JSCell*, unsigned attr, bool checkReadOnly, PutPropertySlot&);
void putDirectFunction(ExecState* exec, InternalFunction* function, unsigned attr = 0);
+ void putDirectFunction(ExecState* exec, JSFunction* function, unsigned attr = 0);
- void putDirectWithoutTransition(const Identifier& propertyName, JSValue value, unsigned attr = 0);
- void putDirectFunctionWithoutTransition(const Identifier& propertyName, JSCell* value, unsigned attr = 0);
+ void putDirectWithoutTransition(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attr = 0);
+ void putDirectFunctionWithoutTransition(JSGlobalData&, const Identifier& propertyName, JSCell* value, unsigned attr = 0);
void putDirectFunctionWithoutTransition(ExecState* exec, InternalFunction* function, unsigned attr = 0);
+ void putDirectFunctionWithoutTransition(ExecState* exec, JSFunction* function, unsigned attr = 0);
// Fast access to known property offsets.
- JSValue getDirectOffset(size_t offset) const { return JSValue::decode(propertyStorage()[offset]); }
- void putDirectOffset(size_t offset, JSValue value) { propertyStorage()[offset] = JSValue::encode(value); }
+ JSValue getDirectOffset(size_t offset) const { return propertyStorage()[offset].get(); }
+ void putDirectOffset(JSGlobalData& globalData, size_t offset, JSValue value) { propertyStorage()[offset].set(globalData, this, value); }
+ void putUndefinedAtDirectOffset(size_t offset) { propertyStorage()[offset].setUndefined(); }
- void fillGetterPropertySlot(PropertySlot&, JSValue* location);
+ void fillGetterPropertySlot(PropertySlot&, WriteBarrierBase<Unknown>* location);
virtual void defineGetter(ExecState*, const Identifier& propertyName, JSObject* getterFunction, unsigned attributes = 0);
virtual void defineSetter(ExecState*, const Identifier& propertyName, JSObject* setterFunction, unsigned attributes = 0);
virtual bool isGlobalObject() const { return false; }
virtual bool isVariableObject() const { return false; }
virtual bool isActivationObject() const { return false; }
- virtual bool isNotAnObjectErrorStub() const { return false; }
+ virtual bool isStrictModeFunction() const { return false; }
+ virtual bool isErrorInstance() const { return false; }
+
+ void seal(JSGlobalData&);
+ void freeze(JSGlobalData&);
+ virtual void preventExtensions(JSGlobalData&);
+ bool isSealed(JSGlobalData& globalData) { return m_structure->isSealed(globalData); }
+ bool isFrozen(JSGlobalData& globalData) { return m_structure->isFrozen(globalData); }
+ bool isExtensible() { return m_structure->isExtensible(); }
virtual ComplType exceptionType() const { return Throw; }
void allocatePropertyStorage(size_t oldSize, size_t newSize);
- void allocatePropertyStorageInline(size_t oldSize, size_t newSize);
- bool isUsingInlineStorage() const { return m_structure->isUsingInlineStorage(); }
+ bool isUsingInlineStorage() const { return static_cast<const void*>(m_propertyStorage) == static_cast<const void*>(this + 1); }
- static const unsigned inlineStorageCapacity = sizeof(EncodedJSValue) == 2 * sizeof(void*) ? 4 : 3;
- static const unsigned nonInlineBaseStorageCapacity = 16;
+ static const unsigned baseExternalStorageCapacity = 16;
- static PassRefPtr<Structure> createStructure(JSValue prototype)
+ void flattenDictionaryObject(JSGlobalData& globalData)
{
- return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
+ m_structure->flattenDictionaryStructure(globalData, this);
}
- void flattenDictionaryObject()
+ void putAnonymousValue(JSGlobalData& globalData, unsigned index, JSValue value)
+ {
+ ASSERT(index < m_structure->anonymousSlotCount());
+ locationForOffset(index)->set(globalData, this, value);
+ }
+ void clearAnonymousValue(unsigned index)
+ {
+ ASSERT(index < m_structure->anonymousSlotCount());
+ locationForOffset(index)->clear();
+ }
+ JSValue getAnonymousValue(unsigned index) const
{
- m_structure->flattenDictionaryStructure(this);
+ ASSERT(index < m_structure->anonymousSlotCount());
+ return locationForOffset(index)->get();
}
+ static size_t offsetOfInlineStorage();
+
+ static JS_EXPORTDATA const ClassInfo s_info;
+
protected:
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
+ {
+ return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
+ }
+
static const unsigned StructureFlags = 0;
- void putAnonymousValue(unsigned index, JSValue value)
+ void putThisToAnonymousValue(unsigned index)
{
- ASSERT(index < m_structure->anonymousSlotCount());
- *locationForOffset(index) = value;
+ locationForOffset(index)->setWithoutWriteBarrier(this);
}
- JSValue getAnonymousValue(unsigned index) const
+
+ // To instantiate objects you likely want JSFinalObject, below.
+ // To create derived types you likely want JSNonFinalObject, below.
+ JSObject(JSGlobalData&, Structure*, PropertyStorage inlineStorage);
+ JSObject(VPtrStealingHackType, PropertyStorage inlineStorage)
+ : JSCell(VPtrStealingHack)
+ , m_propertyStorage(inlineStorage)
{
- ASSERT(index < m_structure->anonymousSlotCount());
- return *locationForOffset(index);
}
private:
void getString(ExecState* exec);
void isObject();
void isString();
-#if USE(JSVALUE32)
- void isNumber();
-#endif
-
- ConstPropertyStorage propertyStorage() const { return (isUsingInlineStorage() ? m_inlineStorage : m_externalStorage); }
- PropertyStorage propertyStorage() { return (isUsingInlineStorage() ? m_inlineStorage : m_externalStorage); }
+
+ ConstPropertyStorage propertyStorage() const { return m_propertyStorage; }
+ PropertyStorage propertyStorage() { return m_propertyStorage; }
- const JSValue* locationForOffset(size_t offset) const
+ const WriteBarrierBase<Unknown>* locationForOffset(size_t offset) const
{
- return reinterpret_cast<const JSValue*>(&propertyStorage()[offset]);
+ return &propertyStorage()[offset];
}
- JSValue* locationForOffset(size_t offset)
+ WriteBarrierBase<Unknown>* locationForOffset(size_t offset)
{
- return reinterpret_cast<JSValue*>(&propertyStorage()[offset]);
+ return &propertyStorage()[offset];
}
- void putDirectInternal(const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot, JSCell*);
- void putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot);
+ bool putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attr, bool checkReadOnly, PutPropertySlot&, JSCell*);
+ bool putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attr, bool checkReadOnly, PutPropertySlot&);
void putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue value, unsigned attr = 0);
bool inlineGetOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
const HashEntry* findPropertyHashEntry(ExecState*, const Identifier& propertyName) const;
- Structure* createInheritorID();
-
- union {
- PropertyStorage m_externalStorage;
- EncodedJSValue m_inlineStorage[inlineStorageCapacity];
- };
+ Structure* createInheritorID(JSGlobalData&);
- RefPtr<Structure> m_inheritorID;
+ PropertyStorage m_propertyStorage;
+ WriteBarrier<Structure> m_inheritorID;
};
+
+
+#if USE(JSVALUE32_64)
+#define JSNonFinalObject_inlineStorageCapacity 4
+#define JSFinalObject_inlineStorageCapacity 6
+#else
+#define JSNonFinalObject_inlineStorageCapacity 2
+#define JSFinalObject_inlineStorageCapacity 4
+#endif
+
+COMPILE_ASSERT((JSFinalObject_inlineStorageCapacity >= JSNonFinalObject_inlineStorageCapacity), final_storage_is_at_least_as_large_as_non_final);
+
+ // JSNonFinalObject is a type of JSObject that has some internal storage,
+ // but also preserves some space in the collector cell for additional
+ // data members in derived types.
+ class JSNonFinalObject : public JSObject {
+ friend class JSObject;
+
+ public:
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
+ {
+ return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
+ }
+
+ protected:
+ explicit JSNonFinalObject(VPtrStealingHackType)
+ : JSObject(VPtrStealingHack, m_inlineStorage)
+ {
+ }
+ explicit JSNonFinalObject(JSGlobalData& globalData, Structure* structure)
+ : JSObject(globalData, structure, m_inlineStorage)
+ {
+ ASSERT(!(OBJECT_OFFSETOF(JSNonFinalObject, m_inlineStorage) % sizeof(double)));
+ ASSERT(this->structure()->propertyStorageCapacity() == JSNonFinalObject_inlineStorageCapacity);
+ }
+
+ private:
+ WriteBarrier<Unknown> m_inlineStorage[JSNonFinalObject_inlineStorageCapacity];
+ };
+
+ // JSFinalObject is a type of JSObject that contains sufficent internal
+ // storage to fully make use of the colloctor cell containing it.
+ class JSFinalObject : public JSObject {
+ friend class JSObject;
+
+ public:
+ static JSFinalObject* create(ExecState* exec, Structure* structure)
+ {
+ return new (exec) JSFinalObject(exec->globalData(), structure);
+ }
+
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
+ {
+ return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
+ }
+
+ private:
+ explicit JSFinalObject(JSGlobalData& globalData, Structure* structure)
+ : JSObject(globalData, structure, m_inlineStorage)
+ {
+ ASSERT(OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage) % sizeof(double) == 0);
+ ASSERT(this->structure()->propertyStorageCapacity() == JSFinalObject_inlineStorageCapacity);
+ }
+
+ static const unsigned StructureFlags = JSObject::StructureFlags | IsJSFinalObject;
+
+ WriteBarrierBase<Unknown> m_inlineStorage[JSFinalObject_inlineStorageCapacity];
+ };
+
+inline size_t JSObject::offsetOfInlineStorage()
+{
+ ASSERT(OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage) == OBJECT_OFFSETOF(JSNonFinalObject, m_inlineStorage));
+ return OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage);
+}
+
+inline JSObject* constructEmptyObject(ExecState* exec, Structure* structure)
+{
+ return JSFinalObject::create(exec, structure);
+}
+
+inline Structure* createEmptyObjectStructure(JSGlobalData& globalData, JSValue prototype)
+{
+ return JSFinalObject::createStructure(globalData, prototype);
+}
+
inline JSObject* asObject(JSCell* cell)
{
ASSERT(cell->isObject());
return asObject(value.asCell());
}
-inline JSObject::JSObject(NonNullPassRefPtr<Structure> structure)
- : JSCell(structure.releaseRef()) // ~JSObject balances this ref()
+inline JSObject::JSObject(JSGlobalData& globalData, Structure* structure, PropertyStorage inlineStorage)
+ : JSCell(globalData, structure)
+ , m_propertyStorage(inlineStorage)
{
- ASSERT(m_structure->propertyStorageCapacity() == inlineStorageCapacity);
+ ASSERT(inherits(&s_info));
+ ASSERT(m_structure->propertyStorageCapacity() < baseExternalStorageCapacity);
ASSERT(m_structure->isEmpty());
ASSERT(prototype().isNull() || Heap::heap(this) == Heap::heap(prototype()));
-#if USE(JSVALUE64) || USE(JSVALUE32_64)
- ASSERT(OBJECT_OFFSETOF(JSObject, m_inlineStorage) % sizeof(double) == 0);
-#endif
+ ASSERT(static_cast<void*>(inlineStorage) == static_cast<void*>(this + 1));
+ ASSERT(m_structure->typeInfo().type() == ObjectType);
}
inline JSObject::~JSObject()
{
- ASSERT(m_structure);
if (!isUsingInlineStorage())
- delete [] m_externalStorage;
- m_structure->deref();
+ delete [] m_propertyStorage;
}
inline JSValue JSObject::prototype() const
return m_structure->storedPrototype();
}
-inline void JSObject::setPrototype(JSValue prototype)
+inline bool JSObject::setPrototypeWithCycleCheck(JSGlobalData& globalData, JSValue prototype)
+{
+ JSValue nextPrototypeValue = prototype;
+ while (nextPrototypeValue && nextPrototypeValue.isObject()) {
+ JSObject* nextPrototype = asObject(nextPrototypeValue)->unwrappedObject();
+ if (nextPrototype == this)
+ return false;
+ nextPrototypeValue = nextPrototype->prototype();
+ }
+ setPrototype(globalData, prototype);
+ return true;
+}
+
+inline void JSObject::setPrototype(JSGlobalData& globalData, JSValue prototype)
{
ASSERT(prototype);
- RefPtr<Structure> newStructure = Structure::changePrototypeTransition(m_structure, prototype);
- setStructure(newStructure.release());
+ setStructure(globalData, Structure::changePrototypeTransition(globalData, m_structure.get(), prototype));
}
-inline void JSObject::setStructure(NonNullPassRefPtr<Structure> structure)
+inline void JSObject::setStructure(JSGlobalData& globalData, Structure* structure)
{
- m_structure->deref();
- m_structure = structure.releaseRef(); // ~JSObject balances this ref()
+ ASSERT(structure->typeInfo().overridesVisitChildren() == m_structure->typeInfo().overridesVisitChildren());
+ m_structure.set(globalData, this, structure);
}
-inline Structure* JSObject::inheritorID()
+inline Structure* JSObject::inheritorID(JSGlobalData& globalData)
{
- if (m_inheritorID)
+ if (m_inheritorID) {
+ ASSERT(m_inheritorID->isEmpty());
return m_inheritorID.get();
- return createInheritorID();
+ }
+ return createInheritorID(globalData);
}
inline bool Structure::isUsingInlineStorage() const
{
- return (propertyStorageCapacity() == JSObject::inlineStorageCapacity);
+ return propertyStorageCapacity() < JSObject::baseExternalStorageCapacity;
}
inline bool JSCell::inherits(const ClassInfo* info) const
ALWAYS_INLINE bool JSObject::inlineGetOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
{
- if (JSValue* location = getDirectLocation(propertyName)) {
- if (m_structure->hasGetterSetterProperties() && location[0].isGetterSetter())
+ if (WriteBarrierBase<Unknown>* location = getDirectLocation(exec->globalData(), propertyName)) {
+ if (m_structure->hasGetterSetterProperties() && location->isGetterSetter())
fillGetterPropertySlot(slot, location);
else
- slot.setValueSlot(this, location, offsetForLocation(location));
+ slot.setValue(this, location->get(), offsetForLocation(location));
return true;
}
return jsUndefined();
}
-inline void JSObject::putDirectInternal(const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot, JSCell* specificFunction)
+inline bool JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot, JSCell* specificFunction)
{
ASSERT(value);
ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
if (m_structure->isDictionary()) {
unsigned currentAttributes;
JSCell* currentSpecificFunction;
- size_t offset = m_structure->get(propertyName, currentAttributes, currentSpecificFunction);
+ size_t offset = m_structure->get(globalData, propertyName, currentAttributes, currentSpecificFunction);
if (offset != WTF::notFound) {
// If there is currently a specific function, and there now either isn't,
// or the new value is different, then despecify.
if (currentSpecificFunction && (specificFunction != currentSpecificFunction))
- m_structure->despecifyDictionaryFunction(propertyName);
+ m_structure->despecifyDictionaryFunction(globalData, propertyName);
if (checkReadOnly && currentAttributes & ReadOnly)
- return;
- putDirectOffset(offset, value);
+ return false;
+
+ putDirectOffset(globalData, offset, value);
// At this point, the objects structure only has a specific value set if previously there
// had been one set, and if the new value being specified is the same (otherwise we would
// have despecified, above). So, if currentSpecificFunction is not set, or if the new
// If there was previously a value, and the new value is the same, then we cannot cache.
if (!currentSpecificFunction || (specificFunction != currentSpecificFunction))
slot.setExistingProperty(this, offset);
- return;
+ return true;
}
+ if (checkReadOnly && !isExtensible())
+ return false;
+
size_t currentCapacity = m_structure->propertyStorageCapacity();
- offset = m_structure->addPropertyWithoutTransition(propertyName, attributes, specificFunction);
+ offset = m_structure->addPropertyWithoutTransition(globalData, propertyName, attributes, specificFunction);
if (currentCapacity != m_structure->propertyStorageCapacity())
allocatePropertyStorage(currentCapacity, m_structure->propertyStorageCapacity());
ASSERT(offset < m_structure->propertyStorageCapacity());
- putDirectOffset(offset, value);
+ putDirectOffset(globalData, offset, value);
// See comment on setNewProperty call below.
if (!specificFunction)
slot.setNewProperty(this, offset);
- return;
+ return true;
}
size_t offset;
size_t currentCapacity = m_structure->propertyStorageCapacity();
- if (RefPtr<Structure> structure = Structure::addPropertyTransitionToExistingStructure(m_structure, propertyName, attributes, specificFunction, offset)) {
+ if (Structure* structure = Structure::addPropertyTransitionToExistingStructure(m_structure.get(), propertyName, attributes, specificFunction, offset)) {
if (currentCapacity != structure->propertyStorageCapacity())
allocatePropertyStorage(currentCapacity, structure->propertyStorageCapacity());
ASSERT(offset < structure->propertyStorageCapacity());
- setStructure(structure.release());
- putDirectOffset(offset, value);
+ setStructure(globalData, structure);
+ putDirectOffset(globalData, offset, value);
// This is a new property; transitions with specific values are not currently cachable,
// so leave the slot in an uncachable state.
if (!specificFunction)
slot.setNewProperty(this, offset);
- return;
+ return true;
}
unsigned currentAttributes;
JSCell* currentSpecificFunction;
- offset = m_structure->get(propertyName, currentAttributes, currentSpecificFunction);
+ offset = m_structure->get(globalData, propertyName, currentAttributes, currentSpecificFunction);
if (offset != WTF::notFound) {
if (checkReadOnly && currentAttributes & ReadOnly)
- return;
+ return false;
// There are three possibilities here:
// (1) There is an existing specific value set, and we're overwriting with *the same value*.
if (currentSpecificFunction) {
// case (1) Do the put, then return leaving the slot uncachable.
if (specificFunction == currentSpecificFunction) {
- putDirectOffset(offset, value);
- return;
+ putDirectOffset(globalData, offset, value);
+ return true;
}
// case (2) Despecify, fall through to (3).
- setStructure(Structure::despecifyFunctionTransition(m_structure, propertyName));
+ setStructure(globalData, Structure::despecifyFunctionTransition(globalData, m_structure.get(), propertyName));
}
// case (3) set the slot, do the put, return.
slot.setExistingProperty(this, offset);
- putDirectOffset(offset, value);
- return;
+ putDirectOffset(globalData, offset, value);
+ return true;
}
- // If we have a specific function, we may have got to this point if there is
- // already a transition with the correct property name and attributes, but
- // specialized to a different function. In this case we just want to give up
- // and despecialize the transition.
- // In this case we clear the value of specificFunction which will result
- // in us adding a non-specific transition, and any subsequent lookup in
- // Structure::addPropertyTransitionToExistingStructure will just use that.
- if (specificFunction && m_structure->hasTransition(propertyName, attributes))
- specificFunction = 0;
+ if (checkReadOnly && !isExtensible())
+ return false;
- RefPtr<Structure> structure = Structure::addPropertyTransition(m_structure, propertyName, attributes, specificFunction, offset);
+ Structure* structure = Structure::addPropertyTransition(globalData, m_structure.get(), propertyName, attributes, specificFunction, offset);
if (currentCapacity != structure->propertyStorageCapacity())
allocatePropertyStorage(currentCapacity, structure->propertyStorageCapacity());
ASSERT(offset < structure->propertyStorageCapacity());
- setStructure(structure.release());
- putDirectOffset(offset, value);
+ setStructure(globalData, structure);
+ putDirectOffset(globalData, offset, value);
// This is a new property; transitions with specific values are not currently cachable,
// so leave the slot in an uncachable state.
if (!specificFunction)
slot.setNewProperty(this, offset);
+ return true;
}
-inline void JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
+inline bool JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
{
ASSERT(value);
ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
- putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, getJSFunction(globalData, value));
+ return putDirectInternal(globalData, propertyName, value, attributes, checkReadOnly, slot, getJSFunction(globalData, value));
}
inline void JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
{
PutPropertySlot slot;
- putDirectInternal(propertyName, value, attributes, false, slot, getJSFunction(globalData, value));
+ putDirectInternal(globalData, propertyName, value, attributes, false, slot, getJSFunction(globalData, value));
}
-inline void JSObject::putDirect(const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
+inline bool JSObject::putDirect(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
{
ASSERT(value);
ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
- putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, 0);
+ return putDirectInternal(globalData, propertyName, value, attributes, checkReadOnly, slot, 0);
}
-inline void JSObject::putDirect(const Identifier& propertyName, JSValue value, unsigned attributes)
+inline void JSObject::putDirect(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
{
PutPropertySlot slot;
- putDirectInternal(propertyName, value, attributes, false, slot, 0);
+ putDirectInternal(globalData, propertyName, value, attributes, false, slot, 0);
}
-inline void JSObject::putDirect(const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
+inline bool JSObject::putDirect(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
{
- putDirectInternal(propertyName, value, 0, false, slot, 0);
+ return putDirectInternal(globalData, propertyName, value, 0, false, slot, 0);
}
-inline void JSObject::putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
+inline void JSObject::putDirectFunction(JSGlobalData& globalData, const Identifier& propertyName, JSCell* value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
{
- putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, value);
+ putDirectInternal(globalData, propertyName, value, attributes, checkReadOnly, slot, value);
}
-inline void JSObject::putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attr)
+inline void JSObject::putDirectFunction(JSGlobalData& globalData, const Identifier& propertyName, JSCell* value, unsigned attr)
{
PutPropertySlot slot;
- putDirectInternal(propertyName, value, attr, false, slot, value);
+ putDirectInternal(globalData, propertyName, value, attr, false, slot, value);
}
-inline void JSObject::putDirectWithoutTransition(const Identifier& propertyName, JSValue value, unsigned attributes)
+inline void JSObject::putDirectWithoutTransition(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
{
size_t currentCapacity = m_structure->propertyStorageCapacity();
- size_t offset = m_structure->addPropertyWithoutTransition(propertyName, attributes, 0);
+ size_t offset = m_structure->addPropertyWithoutTransition(globalData, propertyName, attributes, 0);
if (currentCapacity != m_structure->propertyStorageCapacity())
allocatePropertyStorage(currentCapacity, m_structure->propertyStorageCapacity());
- putDirectOffset(offset, value);
+ putDirectOffset(globalData, offset, value);
}
-inline void JSObject::putDirectFunctionWithoutTransition(const Identifier& propertyName, JSCell* value, unsigned attributes)
+inline void JSObject::putDirectFunctionWithoutTransition(JSGlobalData& globalData, const Identifier& propertyName, JSCell* value, unsigned attributes)
{
size_t currentCapacity = m_structure->propertyStorageCapacity();
- size_t offset = m_structure->addPropertyWithoutTransition(propertyName, attributes, value);
+ size_t offset = m_structure->addPropertyWithoutTransition(globalData, propertyName, attributes, value);
if (currentCapacity != m_structure->propertyStorageCapacity())
allocatePropertyStorage(currentCapacity, m_structure->propertyStorageCapacity());
- putDirectOffset(offset, value);
+ putDirectOffset(globalData, offset, value);
}
-inline void JSObject::transitionTo(Structure* newStructure)
+inline void JSObject::transitionTo(JSGlobalData& globalData, Structure* newStructure)
{
if (m_structure->propertyStorageCapacity() != newStructure->propertyStorageCapacity())
allocatePropertyStorage(m_structure->propertyStorageCapacity(), newStructure->propertyStorageCapacity());
- setStructure(newStructure);
+ setStructure(globalData, newStructure);
}
inline JSValue JSObject::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const
asCell()->put(exec, propertyName, value, slot);
}
-inline void JSValue::putDirect(ExecState*, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
+inline void JSValue::putDirect(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
{
ASSERT(isCell() && isObject());
- asObject(asCell())->putDirect(propertyName, value, slot);
+ if (!asObject(asCell())->putDirect(exec->globalData(), propertyName, value, slot) && slot.isStrictMode())
+ throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
}
inline void JSValue::put(ExecState* exec, unsigned propertyName, JSValue value)
asCell()->put(exec, propertyName, value);
}
-ALWAYS_INLINE void JSObject::allocatePropertyStorageInline(size_t oldSize, size_t newSize)
-{
- ASSERT(newSize > oldSize);
-
- // It's important that this function not rely on m_structure, since
- // we might be in the middle of a transition.
- bool wasInline = (oldSize == JSObject::inlineStorageCapacity);
-
- PropertyStorage oldPropertyStorage = (wasInline ? m_inlineStorage : m_externalStorage);
- PropertyStorage newPropertyStorage = new EncodedJSValue[newSize];
-
- for (unsigned i = 0; i < oldSize; ++i)
- newPropertyStorage[i] = oldPropertyStorage[i];
-
- if (!wasInline)
- delete [] oldPropertyStorage;
-
- m_externalStorage = newPropertyStorage;
-}
-
-ALWAYS_INLINE void JSObject::markChildrenDirect(MarkStack& markStack)
+ALWAYS_INLINE void JSObject::visitChildrenDirect(SlotVisitor& visitor)
{
- JSCell::markChildren(markStack);
+ JSCell::visitChildren(visitor);
- markStack.append(prototype());
-
PropertyStorage storage = propertyStorage();
size_t storageSize = m_structure->propertyStorageSize();
- markStack.appendValues(reinterpret_cast<JSValue*>(storage), storageSize);
+ visitor.appendValues(storage, storageSize);
+ if (m_inheritorID)
+ visitor.append(&m_inheritorID);
}
// --- JSValue inlines ----------------------------
return isString() ? static_cast<JSString*>(asCell()) : jsString(exec, toThisObject(exec)->toString(exec));
}
+inline JSValue JSValue::toStrictThisObject(ExecState* exec) const
+{
+ if (!isObject())
+ return *this;
+ return asObject(asCell())->toStrictThisObject(exec);
+}
+
+ALWAYS_INLINE JSObject* Register::function() const
+{
+ if (!jsValue())
+ return 0;
+ return asObject(jsValue());
+}
+
+ALWAYS_INLINE Register Register::withCallee(JSObject* callee)
+{
+ Register r;
+ r = JSValue(callee);
+ return r;
+}
+
} // namespace JSC
#endif // JSObject_h
--- /dev/null
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "JSObjectWithGlobalObject.h"
+
+#include "JSGlobalObject.h"
+
+namespace JSC {
+
+JSObjectWithGlobalObject::JSObjectWithGlobalObject(JSGlobalObject* globalObject, Structure* structure)
+ : JSNonFinalObject(globalObject->globalData(), structure)
+{
+ COMPILE_ASSERT(AnonymousSlotCount == 1, AnonymousSlotCount_must_be_one);
+ ASSERT(!globalObject || globalObject->isGlobalObject());
+ if (!globalObject)
+ clearAnonymousValue(GlobalObjectSlot);
+ else
+ putAnonymousValue(globalObject->globalData(), GlobalObjectSlot, globalObject);
+}
+
+JSObjectWithGlobalObject::JSObjectWithGlobalObject(JSGlobalData& globalData, JSGlobalObject* globalObject, Structure* structure)
+ : JSNonFinalObject(globalData, structure)
+{
+ COMPILE_ASSERT(AnonymousSlotCount == 1, AnonymousSlotCount_must_be_one);
+ ASSERT(!globalObject || globalObject->isGlobalObject());
+ if (!globalObject)
+ clearAnonymousValue(GlobalObjectSlot);
+ else
+ putAnonymousValue(globalData, GlobalObjectSlot, globalObject);
+}
+
+} // namespace JSC
--- /dev/null
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef JSObjectWithGlobalObject_h
+#define JSObjectWithGlobalObject_h
+
+#include "JSGlobalObject.h"
+
+namespace JSC {
+
+class JSGlobalObject;
+
+class JSObjectWithGlobalObject : public JSNonFinalObject {
+public:
+ static Structure* createStructure(JSGlobalData& globalData, JSValue proto)
+ {
+ return Structure::create(globalData, proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
+ }
+
+ JSGlobalObject* globalObject() const
+ {
+ return asGlobalObject((getAnonymousValue(GlobalObjectSlot).asCell()));
+ }
+
+protected:
+ JSObjectWithGlobalObject(JSGlobalObject*, Structure*);
+ JSObjectWithGlobalObject(JSGlobalData&, JSGlobalObject*, Structure*);
+
+ JSObjectWithGlobalObject(VPtrStealingHackType)
+ : JSNonFinalObject(VPtrStealingHack)
+ {
+ // Should only be used by JSFunction when we aquire the JSFunction vptr.
+ }
+ static const unsigned AnonymousSlotCount = JSObject::AnonymousSlotCount + 1;
+ static const unsigned GlobalObjectSlot = 0;
+};
+
+} // namespace JSC
+
+#endif // JSObjectWithGlobalObject_h
ASSERT_CLASS_FITS_IN_CELL(JSPropertyNameIterator);
+const ClassInfo JSPropertyNameIterator::s_info = { "JSPropertyNameIterator", 0, 0, 0 };
+
inline JSPropertyNameIterator::JSPropertyNameIterator(ExecState* exec, PropertyNameArrayData* propertyNameArrayData, size_t numCacheableSlots)
- : JSCell(exec->globalData().propertyNameIteratorStructure.get())
- , m_cachedStructure(0)
+ : JSCell(exec->globalData(), exec->globalData().propertyNameIteratorStructure.get())
, m_numCacheableSlots(numCacheableSlots)
, m_jsStringsSize(propertyNameArrayData->propertyNameVector().size())
- , m_jsStrings(new JSValue[m_jsStringsSize])
+ , m_jsStrings(adoptArrayPtr(new WriteBarrier<Unknown>[m_jsStringsSize]))
{
PropertyNameArrayData::PropertyNameVector& propertyNameVector = propertyNameArrayData->propertyNameVector();
for (size_t i = 0; i < m_jsStringsSize; ++i)
- m_jsStrings[i] = jsOwnedString(exec, propertyNameVector[i].ustring());
-}
-
-JSPropertyNameIterator::~JSPropertyNameIterator()
-{
- if (m_cachedStructure)
- m_cachedStructure->clearEnumerationCache(this);
+ m_jsStrings[i].set(exec->globalData(), this, jsOwnedString(exec, propertyNameVector[i].ustring()));
}
JSPropertyNameIterator* JSPropertyNameIterator::create(ExecState* exec, JSObject* o)
size_t count = normalizePrototypeChain(exec, o);
StructureChain* structureChain = o->structure()->prototypeChain(exec);
- RefPtr<Structure>* structure = structureChain->head();
+ WriteBarrier<Structure>* structure = structureChain->head();
for (size_t i = 0; i < count; ++i) {
if (structure[i]->typeInfo().overridesGetPropertyNames())
return jsPropertyNameIterator;
}
- jsPropertyNameIterator->setCachedPrototypeChain(structureChain);
- jsPropertyNameIterator->setCachedStructure(o->structure());
- o->structure()->setEnumerationCache(jsPropertyNameIterator);
+ jsPropertyNameIterator->setCachedPrototypeChain(exec->globalData(), structureChain);
+ jsPropertyNameIterator->setCachedStructure(exec->globalData(), o->structure());
+ o->structure()->setEnumerationCache(exec->globalData(), jsPropertyNameIterator);
return jsPropertyNameIterator;
}
JSValue JSPropertyNameIterator::get(ExecState* exec, JSObject* base, size_t i)
{
- JSValue& identifier = m_jsStrings[i];
- if (m_cachedStructure == base->structure() && m_cachedPrototypeChain == base->structure()->prototypeChain(exec))
+ JSValue identifier = m_jsStrings[i].get();
+ if (m_cachedStructure.get() == base->structure() && m_cachedPrototypeChain.get() == base->structure()->prototypeChain(exec))
return identifier;
if (!base->hasProperty(exec, Identifier(exec, asString(identifier)->value(exec))))
return identifier;
}
-void JSPropertyNameIterator::markChildren(MarkStack& markStack)
+void JSPropertyNameIterator::visitChildren(SlotVisitor& visitor)
{
- markStack.appendValues(m_jsStrings.get(), m_jsStringsSize, MayContainNullValues);
+ ASSERT_GC_OBJECT_INHERITS(this, &s_info);
+ ASSERT(structure()->typeInfo().overridesVisitChildren());
+ visitor.appendValues(m_jsStrings.get(), m_jsStringsSize, MayContainNullValues);
+ if (m_cachedPrototypeChain)
+ visitor.append(&m_cachedPrototypeChain);
}
} // namespace JSC
public:
static JSPropertyNameIterator* create(ExecState*, JSObject*);
- static PassRefPtr<Structure> createStructure(JSValue prototype)
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(CompoundType, OverridesMarkChildren), AnonymousSlotCount);
+ return Structure::create(globalData, prototype, TypeInfo(CompoundType, OverridesVisitChildren), AnonymousSlotCount, &s_info);
}
-
- virtual ~JSPropertyNameIterator();
virtual bool isPropertyNameIterator() const { return true; }
- virtual void markChildren(MarkStack&);
+ virtual void visitChildren(SlotVisitor&);
bool getOffset(size_t i, int& offset)
{
JSValue get(ExecState*, JSObject*, size_t i);
size_t size() { return m_jsStringsSize; }
- void setCachedStructure(Structure* structure)
+ void setCachedStructure(JSGlobalData& globalData, Structure* structure)
{
ASSERT(!m_cachedStructure);
ASSERT(structure);
- m_cachedStructure = structure;
+ m_cachedStructure.set(globalData, this, structure);
}
Structure* cachedStructure() { return m_cachedStructure.get(); }
- void setCachedPrototypeChain(NonNullPassRefPtr<StructureChain> cachedPrototypeChain) { m_cachedPrototypeChain = cachedPrototypeChain; }
+ void setCachedPrototypeChain(JSGlobalData& globalData, StructureChain* cachedPrototypeChain) { m_cachedPrototypeChain.set(globalData, this, cachedPrototypeChain); }
StructureChain* cachedPrototypeChain() { return m_cachedPrototypeChain.get(); }
+
+ static const ClassInfo s_info;
private:
JSPropertyNameIterator(ExecState*, PropertyNameArrayData* propertyNameArrayData, size_t numCacheableSlot);
- RefPtr<Structure> m_cachedStructure;
- RefPtr<StructureChain> m_cachedPrototypeChain;
+ WriteBarrier<Structure> m_cachedStructure;
+ WriteBarrier<StructureChain> m_cachedPrototypeChain;
uint32_t m_numCacheableSlots;
uint32_t m_jsStringsSize;
- OwnArrayPtr<JSValue> m_jsStrings;
+ OwnArrayPtr<WriteBarrier<Unknown> > m_jsStrings;
};
- inline void Structure::setEnumerationCache(JSPropertyNameIterator* enumerationCache)
+ inline void Structure::setEnumerationCache(JSGlobalData& globalData, JSPropertyNameIterator* enumerationCache)
{
ASSERT(!isDictionary());
- m_enumerationCache = enumerationCache;
+ m_enumerationCache.set(globalData, this, enumerationCache);
}
- inline void Structure::clearEnumerationCache(JSPropertyNameIterator* enumerationCache)
+ inline JSPropertyNameIterator* Structure::enumerationCache()
{
- m_enumerationCache.clear(enumerationCache);
+ return m_enumerationCache.get();
}
- inline JSPropertyNameIterator* Structure::enumerationCache()
+ ALWAYS_INLINE JSPropertyNameIterator* Register::propertyNameIterator() const
{
- return m_enumerationCache.get();
+ return static_cast<JSPropertyNameIterator*>(jsValue().asCell());
}
} // namespace JSC
#include "JSStaticScopeObject.h"
-namespace JSC {
+#include "Error.h"
+namespace JSC {
ASSERT_CLASS_FITS_IN_CELL(JSStaticScopeObject);
-void JSStaticScopeObject::markChildren(MarkStack& markStack)
+void JSStaticScopeObject::visitChildren(SlotVisitor& visitor)
{
- JSVariableObject::markChildren(markStack);
- markStack.append(d()->registerStore.jsValue());
+ ASSERT_GC_OBJECT_INHERITS(this, &s_info);
+ COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
+ ASSERT(structure()->typeInfo().overridesVisitChildren());
+ JSVariableObject::visitChildren(visitor);
+ visitor.append(&m_registerStore);
}
JSObject* JSStaticScopeObject::toThisObject(ExecState* exec) const
return exec->globalThisValue();
}
-void JSStaticScopeObject::put(ExecState*, const Identifier& propertyName, JSValue value, PutPropertySlot&)
+JSValue JSStaticScopeObject::toStrictThisObject(ExecState*) const
+{
+ return jsNull();
+}
+
+void JSStaticScopeObject::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
{
- if (symbolTablePut(propertyName, value))
+ if (slot.isStrictMode()) {
+ // Double lookup in strict mode, but this only occurs when
+ // a) indirectly writing to an exception slot
+ // b) writing to a function expression name
+ // (a) is unlikely, and (b) is an error.
+ // Also with a single entry the symbol table lookup should simply be
+ // a pointer compare.
+ PropertySlot slot;
+ bool isWritable = true;
+ symbolTableGet(propertyName, slot, isWritable);
+ if (!isWritable) {
+ throwError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError));
+ return;
+ }
+ }
+ if (symbolTablePut(exec->globalData(), propertyName, value))
return;
ASSERT_NOT_REACHED();
}
-void JSStaticScopeObject::putWithAttributes(ExecState*, const Identifier& propertyName, JSValue value, unsigned attributes)
+void JSStaticScopeObject::putWithAttributes(ExecState* exec, const Identifier& propertyName, JSValue value, unsigned attributes)
{
- if (symbolTablePutWithAttributes(propertyName, value, attributes))
+ if (symbolTablePutWithAttributes(exec->globalData(), propertyName, value, attributes))
return;
ASSERT_NOT_REACHED();
return false;
}
-JSStaticScopeObject::~JSStaticScopeObject()
-{
- ASSERT(d());
- delete d();
-}
-
-inline bool JSStaticScopeObject::getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot& slot)
+bool JSStaticScopeObject::getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot& slot)
{
return symbolTableGet(propertyName, slot);
}
namespace JSC{
class JSStaticScopeObject : public JSVariableObject {
- protected:
- using JSVariableObject::JSVariableObjectData;
- struct JSStaticScopeObjectData : public JSVariableObjectData {
- JSStaticScopeObjectData()
- : JSVariableObjectData(&symbolTable, ®isterStore + 1)
- {
- }
- SymbolTable symbolTable;
- Register registerStore;
- };
-
public:
JSStaticScopeObject(ExecState* exec, const Identifier& ident, JSValue value, unsigned attributes)
- : JSVariableObject(exec->globalData().staticScopeStructure, new JSStaticScopeObjectData())
+ : JSVariableObject(exec->globalData(), exec->globalData().staticScopeStructure.get(), &m_symbolTable, reinterpret_cast<Register*>(&m_registerStore + 1))
{
- d()->registerStore = value;
- symbolTable().add(ident.ustring().rep(), SymbolTableEntry(-1, attributes));
+ m_registerStore.set(exec->globalData(), this, value);
+ symbolTable().add(ident.impl(), SymbolTableEntry(-1, attributes));
}
- virtual ~JSStaticScopeObject();
- virtual void markChildren(MarkStack&);
+
+ virtual void visitChildren(SlotVisitor&);
bool isDynamicScope(bool& requiresDynamicChecks) const;
virtual JSObject* toThisObject(ExecState*) const;
+ virtual JSValue toStrictThisObject(ExecState*) const;
virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
virtual void put(ExecState*, const Identifier&, JSValue, PutPropertySlot&);
void putWithAttributes(ExecState*, const Identifier&, JSValue, unsigned attributes);
- static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); }
+ static Structure* createStructure(JSGlobalData& globalData, JSValue proto) { return Structure::create(globalData, proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); }
protected:
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | NeedsThisConversion | OverridesMarkChildren | OverridesGetPropertyNames | JSVariableObject::StructureFlags;
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | NeedsThisConversion | OverridesVisitChildren | OverridesGetPropertyNames | JSVariableObject::StructureFlags;
private:
- JSStaticScopeObjectData* d() { return static_cast<JSStaticScopeObjectData*>(JSVariableObject::d); }
+ SymbolTable m_symbolTable;
+ WriteBarrier<Unknown> m_registerStore;
};
}
#include "JSString.h"
#include "JSGlobalObject.h"
+#include "JSGlobalObjectFunctions.h"
#include "JSObject.h"
#include "Operations.h"
#include "StringObject.h"
namespace JSC {
-static const unsigned resolveRopeForSubstringCutoff = 4;
+static const unsigned substringFromRopeCutoff = 4;
+
+const ClassInfo JSString::s_info = { "string", 0, 0, 0 };
+
+void JSString::resolveRope(ExecState* exec) const
+{
+ ASSERT(isRope());
+
+ UChar* buffer;
+ if (PassRefPtr<StringImpl> newImpl = StringImpl::tryCreateUninitialized(m_length, buffer))
+ m_value = newImpl;
+ else {
+ outOfMemory(exec);
+ return;
+ }
+
+ RopeImpl::Fiber currentFiber = m_fibers[0];
+
+ if ((m_fiberCount > 2) || (RopeImpl::isRope(currentFiber))
+ || ((m_fiberCount == 2) && (RopeImpl::isRope(m_fibers[1])))) {
+ resolveRopeSlowCase(exec, buffer);
+ return;
+ }
+
+ UChar* position = buffer;
+ StringImpl* string = static_cast<StringImpl*>(currentFiber);
+ unsigned length = string->length();
+ StringImpl::copyChars(position, string->characters(), length);
+
+ if (m_fiberCount > 1) {
+ position += length;
+ currentFiber = m_fibers[1];
+ string = static_cast<StringImpl*>(currentFiber);
+ length = string->length();
+ StringImpl::copyChars(position, string->characters(), length);
+ position += length;
+ }
+
+ ASSERT((buffer + m_length) == position);
+ for (unsigned i = 0; i < m_fiberCount; ++i) {
+ RopeImpl::deref(m_fibers[i]);
+ m_fibers[i] = 0;
+ }
+ m_fiberCount = 0;
+
+ ASSERT(!isRope());
+}
// Overview: this methods converts a JSString from holding a string in rope form
// down to a simple UString representation. It does so by building up the string
// representing the rope is likely imbalanced with more nodes down the left side
// (since appending to the string is likely more common) - and as such resolving
// in this fashion should minimize work queue size. (If we built the queue forwards
-// we would likely have to place all of the constituent UStringImpls into the
+// we would likely have to place all of the constituent StringImpls into the
// Vector before performing any concatenation, but by working backwards we likely
// only fill the queue with the number of substrings at any given level in a
-// rope-of-ropes.)
-void JSString::resolveRope(ExecState* exec) const
+// rope-of-ropes.)
+void JSString::resolveRopeSlowCase(ExecState* exec, UChar* buffer) const
{
- ASSERT(isRope());
+ UNUSED_PARAM(exec);
- // Allocate the buffer to hold the final string, position initially points to the end.
- UChar* buffer;
- if (PassRefPtr<UStringImpl> newImpl = UStringImpl::tryCreateUninitialized(m_length, buffer))
- m_value = newImpl;
- else {
- for (unsigned i = 0; i < m_fiberCount; ++i) {
- RopeImpl::deref(m_other.m_fibers[i]);
- m_other.m_fibers[i] = 0;
- }
- m_fiberCount = 0;
- ASSERT(!isRope());
- ASSERT(m_value == UString());
- if (exec)
- throwOutOfMemoryError(exec);
- return;
- }
UChar* position = buffer + m_length;
// Start with the current RopeImpl.
Vector<RopeImpl::Fiber, 32> workQueue;
RopeImpl::Fiber currentFiber;
for (unsigned i = 0; i < (m_fiberCount - 1); ++i)
- workQueue.append(m_other.m_fibers[i]);
- currentFiber = m_other.m_fibers[m_fiberCount - 1];
+ workQueue.append(m_fibers[i]);
+ currentFiber = m_fibers[m_fiberCount - 1];
while (true) {
if (RopeImpl::isRope(currentFiber)) {
RopeImpl* rope = static_cast<RopeImpl*>(currentFiber);
workQueue.append(rope->fibers()[i]);
currentFiber = rope->fibers()[fiberCountMinusOne];
} else {
- UStringImpl* string = static_cast<UStringImpl*>(currentFiber);
+ StringImpl* string = static_cast<StringImpl*>(currentFiber);
unsigned length = string->length();
position -= length;
- UStringImpl::copyChars(position, string->characters(), length);
+ StringImpl::copyChars(position, string->characters(), length);
// Was this the last item in the work queue?
if (workQueue.isEmpty()) {
// Create a string from the UChar buffer, clear the rope RefPtr.
ASSERT(buffer == position);
for (unsigned i = 0; i < m_fiberCount; ++i) {
- RopeImpl::deref(m_other.m_fibers[i]);
- m_other.m_fibers[i] = 0;
+ RopeImpl::deref(m_fibers[i]);
+ m_fibers[i] = 0;
}
m_fiberCount = 0;
-
+
ASSERT(!isRope());
return;
}
}
}
}
-
+
+void JSString::outOfMemory(ExecState* exec) const
+{
+ for (unsigned i = 0; i < m_fiberCount; ++i) {
+ RopeImpl::deref(m_fibers[i]);
+ m_fibers[i] = 0;
+ }
+ m_fiberCount = 0;
+ ASSERT(!isRope());
+ ASSERT(m_value == UString());
+ if (exec)
+ throwOutOfMemoryError(exec);
+}
+
// This function construsts a substring out of a rope without flattening by reusing the existing fibers.
// This can reduce memory usage substantially. Since traversing ropes is slow the function will revert
// back to flattening if the rope turns out to be long.
JSString* JSString::substringFromRope(ExecState* exec, unsigned substringStart, unsigned substringLength)
{
ASSERT(isRope());
-
+ ASSERT(substringLength);
+
JSGlobalData* globalData = &exec->globalData();
UString substringFibers[3];
unsigned fiberEnd = 0;
RopeIterator end;
- for (RopeIterator it(m_other.m_fibers, m_fiberCount); it != end; ++it) {
+ for (RopeIterator it(m_fibers.data(), m_fiberCount); it != end; ++it) {
++fiberCount;
- UStringImpl* fiberString = *it;
+ StringImpl* fiberString = *it;
unsigned fiberStart = fiberEnd;
fiberEnd = fiberStart + fiberString->length();
if (fiberEnd <= substringStart)
if (copyStart == fiberStart && copyEnd == fiberEnd)
substringFibers[substringFiberCount++] = UString(fiberString);
else
- substringFibers[substringFiberCount++] = UString(UStringImpl::create(fiberString, copyStart - fiberStart, copyEnd - copyStart));
+ substringFibers[substringFiberCount++] = UString(StringImpl::create(fiberString, copyStart - fiberStart, copyEnd - copyStart));
if (fiberEnd >= substringEnd)
break;
- if (fiberCount > resolveRopeForSubstringCutoff || substringFiberCount >= 3) {
+ if (fiberCount > substringFromRopeCutoff || substringFiberCount >= 3) {
// This turned out to be a really inefficient rope. Just flatten it.
resolveRope(exec);
return jsSubstring(&exec->globalData(), m_value, substringStart, substringLength);
if (substringLength == 1) {
ASSERT(substringFiberCount == 1);
- UChar c = substringFibers[0].data()[0];
- if (c <= 0xFF)
+ UChar c = substringFibers[0].characters()[0];
+ if (c <= maxSingleCharacterString)
return globalData->smallStrings.singleCharacterString(globalData, c);
}
if (substringFiberCount == 1)
JSValue JSString::replaceCharacter(ExecState* exec, UChar character, const UString& replacement)
{
if (!isRope()) {
- unsigned matchPosition = m_value.find(character);
- if (matchPosition == UString::NotFound)
+ size_t matchPosition = m_value.find(character);
+ if (matchPosition == notFound)
return JSValue(this);
- return jsString(exec, m_value.substr(0, matchPosition), replacement, m_value.substr(matchPosition + 1));
+ return jsString(exec, m_value.substringSharingImpl(0, matchPosition), replacement, m_value.substringSharingImpl(matchPosition + 1));
}
RopeIterator end;
// Count total fibers and find matching string.
size_t fiberCount = 0;
- UStringImpl* matchString = 0;
- int matchPosition = -1;
- for (RopeIterator it(m_other.m_fibers, m_fiberCount); it != end; ++it) {
+ StringImpl* matchString = 0;
+ size_t matchPosition = notFound;
+ for (RopeIterator it(m_fibers.data(), m_fiberCount); it != end; ++it) {
++fiberCount;
if (matchString)
continue;
- UStringImpl* string = *it;
+ StringImpl* string = *it;
matchPosition = string->find(character);
- if (matchPosition == -1)
+ if (matchPosition == notFound)
continue;
matchString = string;
}
if (!matchString)
return this;
- RopeBuilder builder(replacement.size() ? fiberCount + 2 : fiberCount + 1);
+ RopeBuilder builder(replacement.length() ? fiberCount + 2 : fiberCount + 1);
if (UNLIKELY(builder.isOutOfMemory()))
return throwOutOfMemoryError(exec);
- for (RopeIterator it(m_other.m_fibers, m_fiberCount); it != end; ++it) {
- UStringImpl* string = *it;
+ for (RopeIterator it(m_fibers.data(), m_fiberCount); it != end; ++it) {
+ StringImpl* string = *it;
if (string != matchString) {
builder.append(UString(string));
continue;
}
- builder.append(UString(string).substr(0, matchPosition));
- if (replacement.size())
+ builder.append(UString(string).substringSharingImpl(0, matchPosition));
+ if (replacement.length())
builder.append(replacement);
- builder.append(UString(string).substr(matchPosition + 1));
+ builder.append(UString(string).substringSharingImpl(matchPosition + 1));
matchString = 0;
}
if (exec->exception())
return jsString(exec, "");
ASSERT(!isRope());
- ASSERT(i < m_value.size());
+ ASSERT(i < m_value.length());
return jsSingleCharacterSubstring(exec, m_value, i);
}
bool JSString::getPrimitiveNumber(ExecState* exec, double& number, JSValue& result)
{
result = this;
- number = value(exec).toDouble();
+ number = jsToNumber(value(exec));
return false;
}
double JSString::toNumber(ExecState* exec) const
{
- return value(exec).toDouble();
+ return jsToNumber(value(exec));
}
UString JSString::toString(ExecState* exec) const
return value(exec);
}
-inline StringObject* StringObject::create(ExecState* exec, JSString* string)
+inline StringObject* StringObject::create(ExecState* exec, JSGlobalObject* globalObject, JSString* string)
{
- return new (exec) StringObject(exec->lexicalGlobalObject()->stringObjectStructure(), string);
+ return new (exec) StringObject(exec->globalData(), globalObject->stringObjectStructure(), string);
}
-JSObject* JSString::toObject(ExecState* exec) const
+JSObject* JSString::toObject(ExecState* exec, JSGlobalObject* globalObject) const
{
- return StringObject::create(exec, const_cast<JSString*>(this));
+ return StringObject::create(exec, globalObject, const_cast<JSString*>(this));
}
JSObject* JSString::toThisObject(ExecState* exec) const
{
- return StringObject::create(exec, const_cast<JSString*>(this));
+ return StringObject::create(exec, exec->lexicalGlobalObject(), const_cast<JSString*>(this));
}
bool JSString::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
bool JSString::getStringPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
{
if (propertyName == exec->propertyNames().length) {
- descriptor.setDescriptor(jsNumber(exec, m_length), DontEnum | DontDelete | ReadOnly);
+ descriptor.setDescriptor(jsNumber(m_length), DontEnum | DontDelete | ReadOnly);
return true;
}
bool isStrictUInt32;
- unsigned i = propertyName.toStrictUInt32(&isStrictUInt32);
+ unsigned i = propertyName.toUInt32(isStrictUInt32);
if (isStrictUInt32 && i < m_length) {
descriptor.setDescriptor(getIndex(exec, i), DontDelete | ReadOnly);
return true;
#include "CallFrame.h"
#include "CommonIdentifiers.h"
#include "Identifier.h"
-#include "JSNumberCell.h"
#include "PropertyDescriptor.h"
#include "PropertySlot.h"
#include "RopeImpl.h"
+#include "Structure.h"
namespace JSC {
JSString* jsOwnedString(JSGlobalData*, const UString&);
JSString* jsOwnedString(ExecState*, const UString&);
- typedef void (*JSStringFinalizerCallback)(JSString*, void* context);
- JSString* jsStringWithFinalizer(ExecState*, const UString&, JSStringFinalizerCallback callback, void* context);
-
class JS_EXPORTCLASS JSString : public JSCell {
public:
friend class JIT;
void append(const UString& string)
{
ASSERT(m_rope);
- m_rope->initializeFiber(m_index, string.rep());
+ m_rope->initializeFiber(m_index, string.impl());
}
void append(JSString* jsString)
{
if (jsString->isRope()) {
for (unsigned i = 0; i < jsString->m_fiberCount; ++i)
- append(jsString->m_other.m_fibers[i]);
+ append(jsString->m_fibers[i]);
} else
append(jsString->string());
}
return *this;
}
- UStringImpl* operator*()
+ StringImpl* operator*()
{
WorkItem& item = m_workQueue.last();
RopeImpl::Fiber fiber = item.fibers[item.i];
ASSERT(!RopeImpl::isRope(fiber));
- return static_cast<UStringImpl*>(fiber);
+ return static_cast<StringImpl*>(fiber);
}
bool operator!=(const RopeIterator& other) const
};
ALWAYS_INLINE JSString(JSGlobalData* globalData, const UString& value)
- : JSCell(globalData->stringStructure.get())
- , m_length(value.size())
+ : JSCell(*globalData, globalData->stringStructure.get())
+ , m_length(value.length())
, m_value(value)
, m_fiberCount(0)
{
ASSERT(!m_value.isNull());
- Heap::heap(this)->reportExtraMemoryCost(value.cost());
+ Heap::heap(this)->reportExtraMemoryCost(value.impl()->cost());
}
enum HasOtherOwnerType { HasOtherOwner };
JSString(JSGlobalData* globalData, const UString& value, HasOtherOwnerType)
- : JSCell(globalData->stringStructure.get())
- , m_length(value.size())
+ : JSCell(*globalData, globalData->stringStructure.get())
+ , m_length(value.length())
, m_value(value)
, m_fiberCount(0)
{
ASSERT(!m_value.isNull());
}
- JSString(JSGlobalData* globalData, PassRefPtr<UStringImpl> value, HasOtherOwnerType)
- : JSCell(globalData->stringStructure.get())
+ JSString(JSGlobalData* globalData, PassRefPtr<StringImpl> value, HasOtherOwnerType)
+ : JSCell(*globalData, globalData->stringStructure.get())
, m_length(value->length())
, m_value(value)
, m_fiberCount(0)
ASSERT(!m_value.isNull());
}
JSString(JSGlobalData* globalData, PassRefPtr<RopeImpl> rope)
- : JSCell(globalData->stringStructure.get())
+ : JSCell(*globalData, globalData->stringStructure.get())
, m_length(rope->length())
, m_fiberCount(1)
{
- m_other.m_fibers[0] = rope.releaseRef();
+ m_fibers[0] = rope.leakRef();
}
// This constructor constructs a new string by concatenating s1 & s2.
// This should only be called with fiberCount <= 3.
JSString(JSGlobalData* globalData, unsigned fiberCount, JSString* s1, JSString* s2)
- : JSCell(globalData->stringStructure.get())
+ : JSCell(*globalData, globalData->stringStructure.get())
, m_length(s1->length() + s2->length())
, m_fiberCount(fiberCount)
{
// This constructor constructs a new string by concatenating s1 & s2.
// This should only be called with fiberCount <= 3.
JSString(JSGlobalData* globalData, unsigned fiberCount, JSString* s1, const UString& u2)
- : JSCell(globalData->stringStructure.get())
- , m_length(s1->length() + u2.size())
+ : JSCell(*globalData, globalData->stringStructure.get())
+ , m_length(s1->length() + u2.length())
, m_fiberCount(fiberCount)
{
ASSERT(fiberCount <= s_maxInternalRopeLength);
// This constructor constructs a new string by concatenating s1 & s2.
// This should only be called with fiberCount <= 3.
JSString(JSGlobalData* globalData, unsigned fiberCount, const UString& u1, JSString* s2)
- : JSCell(globalData->stringStructure.get())
- , m_length(u1.size() + s2->length())
+ : JSCell(*globalData, globalData->stringStructure.get())
+ , m_length(u1.length() + s2->length())
, m_fiberCount(fiberCount)
{
ASSERT(fiberCount <= s_maxInternalRopeLength);
// value must require a fiberCount of at least one implies that the length
// for each value must be exactly 1!
JSString(ExecState* exec, JSValue v1, JSValue v2, JSValue v3)
- : JSCell(exec->globalData().stringStructure.get())
+ : JSCell(exec->globalData(), exec->globalData().stringStructure.get())
, m_length(0)
, m_fiberCount(s_maxInternalRopeLength)
{
// This constructor constructs a new string by concatenating u1 & u2.
JSString(JSGlobalData* globalData, const UString& u1, const UString& u2)
- : JSCell(globalData->stringStructure.get())
- , m_length(u1.size() + u2.size())
+ : JSCell(*globalData, globalData->stringStructure.get())
+ , m_length(u1.length() + u2.length())
, m_fiberCount(2)
{
unsigned index = 0;
// This constructor constructs a new string by concatenating u1, u2 & u3.
JSString(JSGlobalData* globalData, const UString& u1, const UString& u2, const UString& u3)
- : JSCell(globalData->stringStructure.get())
- , m_length(u1.size() + u2.size() + u3.size())
+ : JSCell(*globalData, globalData->stringStructure.get())
+ , m_length(u1.length() + u2.length() + u3.length())
, m_fiberCount(s_maxInternalRopeLength)
{
unsigned index = 0;
ASSERT(index <= s_maxInternalRopeLength);
}
- JSString(JSGlobalData* globalData, const UString& value, JSStringFinalizerCallback finalizer, void* context)
- : JSCell(globalData->stringStructure.get())
- , m_length(value.size())
- , m_value(value)
- , m_fiberCount(0)
- {
- ASSERT(!m_value.isNull());
- // nasty hack because we can't union non-POD types
- m_other.m_finalizerCallback = finalizer;
- m_other.m_finalizerContext = context;
- Heap::heap(this)->reportExtraMemoryCost(value.cost());
- }
-
~JSString()
{
ASSERT(vptr() == JSGlobalData::jsStringVPtr);
for (unsigned i = 0; i < m_fiberCount; ++i)
- RopeImpl::deref(m_other.m_fibers[i]);
-
- if (!m_fiberCount && m_other.m_finalizerCallback)
- m_other.m_finalizerCallback(this, m_other.m_finalizerContext);
+ RopeImpl::deref(m_fibers[i]);
}
const UString& value(ExecState* exec) const
JSValue replaceCharacter(ExecState*, UChar, const UString& replacement);
- static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(StringType, OverridesGetOwnPropertySlot | NeedsThisConversion), AnonymousSlotCount); }
+ static Structure* createStructure(JSGlobalData& globalData, JSValue proto)
+ {
+ return Structure::create(globalData, proto, TypeInfo(StringType, OverridesGetOwnPropertySlot | NeedsThisConversion), AnonymousSlotCount, &s_info);
+ }
+
+ static const ClassInfo s_info;
private:
- enum VPtrStealingHackType { VPtrStealingHack };
JSString(VPtrStealingHackType)
- : JSCell(0)
+ : JSCell(VPtrStealingHack)
, m_fiberCount(0)
{
}
void resolveRope(ExecState*) const;
+ void resolveRopeSlowCase(ExecState*, UChar*) const;
+ void outOfMemory(ExecState*) const;
JSString* substringFromRope(ExecState*, unsigned offset, unsigned length);
void appendStringInConstruct(unsigned& index, const UString& string)
{
- UStringImpl* impl = string.rep();
+ StringImpl* impl = string.impl();
impl->ref();
- m_other.m_fibers[index++] = impl;
+ m_fibers[index++] = impl;
}
void appendStringInConstruct(unsigned& index, JSString* jsString)
{
if (jsString->isRope()) {
for (unsigned i = 0; i < jsString->m_fiberCount; ++i) {
- RopeImpl::Fiber fiber = jsString->m_other.m_fibers[i];
+ RopeImpl::Fiber fiber = jsString->m_fibers[i];
fiber->ref();
- m_other.m_fibers[index++] = fiber;
+ m_fibers[index++] = fiber;
}
} else
appendStringInConstruct(index, jsString->string());
void appendValueInConstructAndIncrementLength(ExecState* exec, unsigned& index, JSValue v)
{
if (v.isString()) {
- ASSERT(asCell(v)->isString());
- JSString* s = static_cast<JSString*>(asCell(v));
- ASSERT(s->size() == 1);
+ ASSERT(v.asCell()->isString());
+ JSString* s = static_cast<JSString*>(v.asCell());
+ ASSERT(s->fiberCount() == 1);
appendStringInConstruct(index, s);
m_length += s->length();
} else {
UString u(v.toString(exec));
- UStringImpl* impl = u.rep();
+ StringImpl* impl = u.impl();
impl->ref();
- m_other.m_fibers[index++] = impl;
- m_length += u.size();
+ m_fibers[index++] = impl;
+ m_length += u.length();
}
}
virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue& value);
virtual bool toBoolean(ExecState*) const;
virtual double toNumber(ExecState*) const;
- virtual JSObject* toObject(ExecState*) const;
+ virtual JSObject* toObject(ExecState*, JSGlobalObject*) const;
virtual UString toString(ExecState*) const;
virtual JSObject* toThisObject(ExecState*) const;
unsigned m_length;
mutable UString m_value;
mutable unsigned m_fiberCount;
- // This structure exists to support a temporary workaround for a GC issue.
- struct JSStringFinalizerStruct {
- JSStringFinalizerStruct() : m_finalizerCallback(0) {}
- union {
- mutable RopeImpl::Fiber m_fibers[s_maxInternalRopeLength];
- struct {
- JSStringFinalizerCallback m_finalizerCallback;
- void* m_finalizerContext;
- };
- };
- } m_other;
+ mutable FixedArray<RopeImpl::Fiber, s_maxInternalRopeLength> m_fibers;
bool isRope() const { return m_fiberCount; }
UString& string() { ASSERT(!isRope()); return m_value; }
- unsigned size() { return m_fiberCount ? m_fiberCount : 1; }
+ unsigned fiberCount() { return m_fiberCount ? m_fiberCount : 1; }
friend JSValue jsString(ExecState* exec, JSString* s1, JSString* s2);
friend JSValue jsString(ExecState* exec, const UString& u1, JSString* s2);
friend JSValue jsString(ExecState* exec, JSString* s1, const UString& u2);
friend JSValue jsString(ExecState* exec, Register* strings, unsigned count);
- friend JSValue jsString(ExecState* exec, JSValue thisValue, const ArgList& args);
- friend JSString* jsStringWithFinalizer(ExecState*, const UString&, JSStringFinalizerCallback callback, void* context);
+ friend JSValue jsString(ExecState* exec, JSValue thisValue);
friend JSString* jsSubstring(ExecState* exec, JSString* s, unsigned offset, unsigned length);
};
inline JSString* asString(JSValue value)
{
- ASSERT(asCell(value)->isString());
- return static_cast<JSString*>(asCell(value));
+ ASSERT(value.asCell()->isString());
+ return static_cast<JSString*>(value.asCell());
}
inline JSString* jsEmptyString(JSGlobalData* globalData)
inline JSString* jsSingleCharacterString(JSGlobalData* globalData, UChar c)
{
- if (c <= 0xFF)
+ if (c <= maxSingleCharacterString)
return globalData->smallStrings.singleCharacterString(globalData, c);
return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(&c, 1)));
}
inline JSString* jsSingleCharacterSubstring(ExecState* exec, const UString& s, unsigned offset)
{
JSGlobalData* globalData = &exec->globalData();
- ASSERT(offset < static_cast<unsigned>(s.size()));
- UChar c = s.data()[offset];
- if (c <= 0xFF)
+ ASSERT(offset < static_cast<unsigned>(s.length()));
+ UChar c = s.characters()[offset];
+ if (c <= maxSingleCharacterString)
return globalData->smallStrings.singleCharacterString(globalData, c);
- return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(UStringImpl::create(s.rep(), offset, 1))));
+ return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(StringImpl::create(s.impl(), offset, 1))));
}
inline JSString* jsNontrivialString(JSGlobalData* globalData, const char* s)
inline JSString* jsNontrivialString(JSGlobalData* globalData, const UString& s)
{
- ASSERT(s.size() > 1);
+ ASSERT(s.length() > 1);
return fixupVPtr(globalData, new (globalData) JSString(globalData, s));
}
ASSERT(canGetIndex(i));
if (isRope())
return getIndexSlowCase(exec, i);
- ASSERT(i < m_value.size());
+ ASSERT(i < m_value.length());
return jsSingleCharacterSubstring(exec, m_value, i);
}
inline JSString* jsString(JSGlobalData* globalData, const UString& s)
{
- int size = s.size();
+ int size = s.length();
if (!size)
return globalData->smallStrings.emptyString(globalData);
if (size == 1) {
- UChar c = s.data()[0];
- if (c <= 0xFF)
+ UChar c = s.characters()[0];
+ if (c <= maxSingleCharacterString)
return globalData->smallStrings.singleCharacterString(globalData, c);
}
return fixupVPtr(globalData, new (globalData) JSString(globalData, s));
}
- inline JSString* jsStringWithFinalizer(ExecState* exec, const UString& s, JSStringFinalizerCallback callback, void* context)
- {
- ASSERT(s.size() && (s.size() > 1 || s.data()[0] > 0xFF));
- JSGlobalData* globalData = &exec->globalData();
- return fixupVPtr(globalData, new (globalData) JSString(globalData, s, callback, context));
- }
-
inline JSString* jsSubstring(ExecState* exec, JSString* s, unsigned offset, unsigned length)
{
ASSERT(offset <= static_cast<unsigned>(s->length()));
inline JSString* jsSubstring(JSGlobalData* globalData, const UString& s, unsigned offset, unsigned length)
{
- ASSERT(offset <= static_cast<unsigned>(s.size()));
- ASSERT(length <= static_cast<unsigned>(s.size()));
- ASSERT(offset + length <= static_cast<unsigned>(s.size()));
+ ASSERT(offset <= static_cast<unsigned>(s.length()));
+ ASSERT(length <= static_cast<unsigned>(s.length()));
+ ASSERT(offset + length <= static_cast<unsigned>(s.length()));
if (!length)
return globalData->smallStrings.emptyString(globalData);
if (length == 1) {
- UChar c = s.data()[offset];
- if (c <= 0xFF)
+ UChar c = s.characters()[offset];
+ if (c <= maxSingleCharacterString)
return globalData->smallStrings.singleCharacterString(globalData, c);
}
- return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(UStringImpl::create(s.rep(), offset, length)), JSString::HasOtherOwner));
+ return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(StringImpl::create(s.impl(), offset, length)), JSString::HasOtherOwner));
}
inline JSString* jsOwnedString(JSGlobalData* globalData, const UString& s)
{
- int size = s.size();
+ int size = s.length();
if (!size)
return globalData->smallStrings.emptyString(globalData);
if (size == 1) {
- UChar c = s.data()[0];
- if (c <= 0xFF)
+ UChar c = s.characters()[0];
+ if (c <= maxSingleCharacterString)
return globalData->smallStrings.singleCharacterString(globalData, c);
}
return fixupVPtr(globalData, new (globalData) JSString(globalData, s, JSString::HasOtherOwner));
ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
{
if (propertyName == exec->propertyNames().length) {
- slot.setValue(jsNumber(exec, m_length));
+ slot.setValue(jsNumber(m_length));
return true;
}
bool isStrictUInt32;
- unsigned i = propertyName.toStrictUInt32(&isStrictUInt32);
+ unsigned i = propertyName.toUInt32(isStrictUInt32);
if (isStrictUInt32 && i < m_length) {
slot.setValue(getIndex(exec, i));
return true;
inline UString JSValue::toPrimitiveString(ExecState* exec) const
{
- if (isString())
- return static_cast<JSString*>(asCell())->value(exec);
+ ASSERT(!isString());
if (isInt32())
return exec->globalData().numericStrings.add(asInt32());
if (isDouble())
#include "ExceptionHelpers.h"
#include "JSString.h"
+#include "UStringConcatenate.h"
#include "Vector.h"
namespace JSC {
void append(const UString& str)
{
- m_okay &= buffer.tryAppend(str.data(), str.size());
+ m_okay &= buffer.tryAppend(str.characters(), str.length());
}
JSValue build(ExecState* exec)
template<typename StringType1, typename StringType2>
inline JSValue jsMakeNontrivialString(ExecState* exec, StringType1 string1, StringType2 string2)
{
- PassRefPtr<UStringImpl> result = tryMakeString(string1, string2);
+ PassRefPtr<StringImpl> result = WTF::tryMakeString(string1, string2);
if (!result)
return throwOutOfMemoryError(exec);
return jsNontrivialString(exec, result);
template<typename StringType1, typename StringType2, typename StringType3>
inline JSValue jsMakeNontrivialString(ExecState* exec, StringType1 string1, StringType2 string2, StringType3 string3)
{
- PassRefPtr<UStringImpl> result = tryMakeString(string1, string2, string3);
+ PassRefPtr<StringImpl> result = WTF::tryMakeString(string1, string2, string3);
if (!result)
return throwOutOfMemoryError(exec);
return jsNontrivialString(exec, result);
template<typename StringType1, typename StringType2, typename StringType3, typename StringType4>
inline JSValue jsMakeNontrivialString(ExecState* exec, StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4)
{
- PassRefPtr<UStringImpl> result = tryMakeString(string1, string2, string3, string4);
+ PassRefPtr<StringImpl> result = WTF::tryMakeString(string1, string2, string3, string4);
if (!result)
return throwOutOfMemoryError(exec);
return jsNontrivialString(exec, result);
template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5>
inline JSValue jsMakeNontrivialString(ExecState* exec, StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5)
{
- PassRefPtr<UStringImpl> result = tryMakeString(string1, string2, string3, string4, string5);
+ PassRefPtr<StringImpl> result = WTF::tryMakeString(string1, string2, string3, string4, string5);
if (!result)
return throwOutOfMemoryError(exec);
return jsNontrivialString(exec, result);
template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6>
inline JSValue jsMakeNontrivialString(ExecState* exec, StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6)
{
- PassRefPtr<UStringImpl> result = tryMakeString(string1, string2, string3, string4, string5, string6);
+ PassRefPtr<StringImpl> result = WTF::tryMakeString(string1, string2, string3, string4, string5, string6);
if (!result)
return throwOutOfMemoryError(exec);
return jsNontrivialString(exec, result);
NumberType = 3,
NullType = 4,
StringType = 5,
+ LeafType = 6,
// The CompoundType value must come before any JSType that may have children
- CompoundType = 6,
- ObjectType = 7,
- GetterSetterType = 8
+ CompoundType = 7,
+ ObjectType = 8,
+ GetterSetterType = 9
};
} // namespace JSC
namespace JSC {
- // WebCore uses MasqueradesAsUndefined to make document.all and style.filter undetectable.
- static const unsigned MasqueradesAsUndefined = 1;
+ static const unsigned MasqueradesAsUndefined = 1; // WebCore uses MasqueradesAsUndefined to make document.all and style.filter undetectable.
static const unsigned ImplementsHasInstance = 1 << 1;
static const unsigned OverridesHasInstance = 1 << 2;
static const unsigned ImplementsDefaultHasInstance = 1 << 3;
static const unsigned NeedsThisConversion = 1 << 4;
static const unsigned OverridesGetOwnPropertySlot = 1 << 5;
- static const unsigned OverridesMarkChildren = 1 << 6;
+ static const unsigned OverridesVisitChildren = 1 << 6;
static const unsigned OverridesGetPropertyNames = 1 << 7;
+ static const unsigned IsJSFinalObject = 1 << 8;
+ static const unsigned ProhibitsPropertyCaching = 1 << 9;
class TypeInfo {
- friend class JIT;
public:
TypeInfo(JSType type, unsigned flags = 0)
: m_type(type)
+ , m_flags(flags & 0xff)
+ , m_flags2(flags >> 8)
{
- ASSERT(flags <= 0xFF);
- ASSERT(type <= 0xFF);
+ ASSERT(flags <= 0x3ff);
+ ASSERT(type <= 0xff);
+ ASSERT(type >= CompoundType || !(flags & OverridesVisitChildren));
// ImplementsDefaultHasInstance means (ImplementsHasInstance & !OverridesHasInstance)
- if ((flags & (ImplementsHasInstance | OverridesHasInstance)) == ImplementsHasInstance)
- m_flags = flags | ImplementsDefaultHasInstance;
- else
- m_flags = flags;
+ if ((m_flags & (ImplementsHasInstance | OverridesHasInstance)) == ImplementsHasInstance)
+ m_flags |= ImplementsDefaultHasInstance;
}
JSType type() const { return (JSType)m_type; }
bool overridesHasInstance() const { return m_flags & OverridesHasInstance; }
bool needsThisConversion() const { return m_flags & NeedsThisConversion; }
bool overridesGetOwnPropertySlot() const { return m_flags & OverridesGetOwnPropertySlot; }
- bool overridesMarkChildren() const { return m_flags & OverridesMarkChildren; }
+ bool overridesVisitChildren() const { return m_flags & OverridesVisitChildren; }
bool overridesGetPropertyNames() const { return m_flags & OverridesGetPropertyNames; }
+ unsigned isFinal() const { return m_flags2 & (IsJSFinalObject >> 8); }
+ unsigned prohibitsPropertyCaching() const { return m_flags2 & (ProhibitsPropertyCaching >> 8); }
unsigned flags() const { return m_flags; }
+ static ptrdiff_t flagsOffset()
+ {
+ return OBJECT_OFFSETOF(TypeInfo, m_flags);
+ }
+
+ static ptrdiff_t typeOffset()
+ {
+ return OBJECT_OFFSETOF(TypeInfo, m_type);
+ }
+
private:
unsigned char m_type;
unsigned char m_flags;
+ unsigned char m_flags2;
};
}
#include "BooleanConstructor.h"
#include "BooleanPrototype.h"
+#include "Error.h"
#include "ExceptionHelpers.h"
#include "JSGlobalObject.h"
#include "JSFunction.h"
return trunc(toNumber(exec));
}
-JSObject* JSValue::toObjectSlowCase(ExecState* exec) const
+JSObject* JSValue::toObjectSlowCase(ExecState* exec, JSGlobalObject* globalObject) const
{
ASSERT(!isCell());
if (isInt32() || isDouble())
- return constructNumber(exec, asValue());
+ return constructNumber(exec, globalObject, asValue());
if (isTrue() || isFalse())
- return constructBooleanFromImmediateBoolean(exec, asValue());
+ return constructBooleanFromImmediateBoolean(exec, globalObject, asValue());
+
ASSERT(isUndefinedOrNull());
- JSNotAnObjectErrorStub* exception = createNotAnObjectErrorStub(exec, isNull());
- exec->setException(exception);
- return new (exec) JSNotAnObject(exec, exception);
+ throwError(exec, createNotAnObjectError(exec, *this));
+ return new (exec) JSNotAnObject(exec);
}
JSObject* JSValue::toThisObjectSlowCase(ExecState* exec) const
ASSERT(!isCell());
if (isInt32() || isDouble())
- return constructNumber(exec, asValue());
+ return constructNumber(exec, exec->lexicalGlobalObject(), asValue());
if (isTrue() || isFalse())
- return constructBooleanFromImmediateBoolean(exec, asValue());
+ return constructBooleanFromImmediateBoolean(exec, exec->lexicalGlobalObject(), asValue());
ASSERT(isUndefinedOrNull());
return exec->globalThisValue();
}
{
ASSERT(!isCell());
if (isNumber())
- return constructNumber(exec, asValue());
+ return constructNumber(exec, exec->lexicalGlobalObject(), asValue());
if (isBoolean())
- return constructBooleanFromImmediateBoolean(exec, asValue());
-
- JSNotAnObjectErrorStub* exception = createNotAnObjectErrorStub(exec, isNull());
- exec->setException(exception);
- return new (exec) JSNotAnObject(exec, exception);
+ return constructBooleanFromImmediateBoolean(exec, exec->lexicalGlobalObject(), asValue());
+
+ ASSERT(isUndefinedOrNull());
+ throwError(exec, createNotAnObjectError(exec, *this));
+ return new (exec) JSNotAnObject(exec);
}
JSObject* JSValue::synthesizePrototype(ExecState* exec) const
if (isBoolean())
return exec->lexicalGlobalObject()->booleanPrototype();
- JSNotAnObjectErrorStub* exception = createNotAnObjectErrorStub(exec, isNull());
- exec->setException(exception);
- return new (exec) JSNotAnObject(exec, exception);
+ ASSERT(isUndefinedOrNull());
+ throwError(exec, createNotAnObjectError(exec, *this));
+ return new (exec) JSNotAnObject(exec);
}
#ifndef NDEBUG
snprintf(description, size, "False");
else if (isNull())
snprintf(description, size, "Null");
- else {
- ASSERT(isUndefined());
+ else if (isUndefined())
snprintf(description, size, "Undefined");
- }
+ else
+ snprintf(description, size, "INVALID");
return description;
}
#endif
-int32_t toInt32SlowCase(double d, bool& ok)
+// This in the ToInt32 operation is defined in section 9.5 of the ECMA-262 spec.
+// Note that this operation is identical to ToUInt32 other than to interpretation
+// of the resulting bit-pattern (as such this metod is also called to implement
+// ToUInt32).
+//
+// The operation can be descibed as round towards zero, then select the 32 least
+// bits of the resulting value in 2s-complement representation.
+int32_t toInt32(double number)
{
- ok = true;
-
- if (d >= -D32 / 2 && d < D32 / 2)
- return static_cast<int32_t>(d);
-
- if (isnan(d) || isinf(d)) {
- ok = false;
+ int64_t bits = WTF::bitwise_cast<int64_t>(number);
+ int32_t exp = (static_cast<int32_t>(bits >> 52) & 0x7ff) - 0x3ff;
+
+ // If exponent < 0 there will be no bits to the left of the decimal point
+ // after rounding; if the exponent is > 83 then no bits of precision can be
+ // left in the low 32-bit range of the result (IEEE-754 doubles have 52 bits
+ // of fractional precision).
+ // Note this case handles 0, -0, and all infinte, NaN, & denormal value.
+ if (exp < 0 || exp > 83)
return 0;
- }
- double d32 = fmod(trunc(d), D32);
- if (d32 >= D32 / 2)
- d32 -= D32;
- else if (d32 < -D32 / 2)
- d32 += D32;
- return static_cast<int32_t>(d32);
-}
-
-uint32_t toUInt32SlowCase(double d, bool& ok)
-{
- ok = true;
-
- if (d >= 0.0 && d < D32)
- return static_cast<uint32_t>(d);
-
- if (isnan(d) || isinf(d)) {
- ok = false;
- return 0;
+ // Select the appropriate 32-bits from the floating point mantissa. If the
+ // exponent is 52 then the bits we need to select are already aligned to the
+ // lowest bits of the 64-bit integer representation of tghe number, no need
+ // to shift. If the exponent is greater than 52 we need to shift the value
+ // left by (exp - 52), if the value is less than 52 we need to shift right
+ // accordingly.
+ int32_t result = (exp > 52)
+ ? static_cast<int32_t>(bits << (exp - 52))
+ : static_cast<int32_t>(bits >> (52 - exp));
+
+ // IEEE-754 double precision values are stored omitting an implicit 1 before
+ // the decimal point; we need to reinsert this now. We may also the shifted
+ // invalid bits into the result that are not a part of the mantissa (the sign
+ // and exponent bits from the floatingpoint representation); mask these out.
+ if (exp < 32) {
+ int32_t missingOne = 1 << exp;
+ result &= missingOne - 1;
+ result += missingOne;
}
- double d32 = fmod(trunc(d), D32);
- if (d32 < 0)
- d32 += D32;
- return static_cast<uint32_t>(d32);
+ // If the input value was negative (we could test either 'number' or 'bits',
+ // but testing 'bits' is likely faster) invert the result appropriately.
+ return bits < 0 ? -result : result;
}
NEVER_INLINE double nonInlineNaN()
#endif
}
+bool JSValue::isValidCallee()
+{
+ return asObject(asObject(asCell())->getAnonymousValue(0))->isGlobalObject();
+}
+
} // namespace JSC
#ifndef JSValue_h
#define JSValue_h
-#include "CallData.h"
-#include "ConstructData.h"
#include <math.h>
#include <stddef.h> // for size_t
#include <stdint.h>
#include <wtf/Assertions.h>
#include <wtf/HashTraits.h>
#include <wtf/MathExtras.h>
+#include <wtf/StdLibExtras.h>
namespace JSC {
+ extern const double NaN;
+ extern const double Inf;
+
+ class ExecState;
class Identifier;
class JSCell;
class JSGlobalData;
- class JSImmediate;
+ class JSGlobalObject;
class JSObject;
class JSString;
class PropertySlot;
struct ClassInfo;
struct Instruction;
+ template <class T> class WriteBarrierBase;
+
enum PreferredPrimitiveType { NoPreference, PreferNumber, PreferString };
+
#if USE(JSVALUE32_64)
typedef int64_t EncodedJSValue;
#else
typedef void* EncodedJSValue;
#endif
+
+ union EncodedValueDescriptor {
+ int64_t asInt64;
+#if USE(JSVALUE32_64)
+ double asDouble;
+#elif USE(JSVALUE64)
+ JSCell* ptr;
+#endif
+
+#if CPU(BIG_ENDIAN)
+ struct {
+ int32_t tag;
+ int32_t payload;
+ } asBits;
+#else
+ struct {
+ int32_t payload;
+ int32_t tag;
+ } asBits;
+#endif
+ };
double nonInlineNaN();
- int32_t toInt32SlowCase(double, bool& ok);
- uint32_t toUInt32SlowCase(double, bool& ok);
+
+ // This implements ToInt32, defined in ECMA-262 9.5.
+ int32_t toInt32(double);
+
+ // This implements ToUInt32, defined in ECMA-262 9.6.
+ inline uint32_t toUInt32(double number)
+ {
+ // As commented in the spec, the operation of ToInt32 and ToUint32 only differ
+ // in how the result is interpreted; see NOTEs in sections 9.5 and 9.6.
+ return toInt32(number);
+ }
class JSValue {
- friend class JSImmediate;
friend struct EncodedJSValueHashTraits;
friend class JIT;
friend class JITStubs;
friend class SpecializedThunkJIT;
public:
- static EncodedJSValue encode(JSValue value);
- static JSValue decode(EncodedJSValue ptr);
-#if !USE(JSVALUE32_64)
- private:
- static JSValue makeImmediate(intptr_t value);
- intptr_t immediateValue();
- public:
-#endif
+ static EncodedJSValue encode(JSValue);
+ static JSValue decode(EncodedJSValue);
+
enum JSNullTag { JSNull };
enum JSUndefinedTag { JSUndefined };
enum JSTrueTag { JSTrue };
JSValue(const JSCell* ptr);
// Numbers
- JSValue(EncodeAsDoubleTag, ExecState*, double);
- JSValue(ExecState*, double);
- JSValue(ExecState*, char);
- JSValue(ExecState*, unsigned char);
- JSValue(ExecState*, short);
- JSValue(ExecState*, unsigned short);
- JSValue(ExecState*, int);
- JSValue(ExecState*, unsigned);
- JSValue(ExecState*, long);
- JSValue(ExecState*, unsigned long);
- JSValue(ExecState*, long long);
- JSValue(ExecState*, unsigned long long);
- JSValue(JSGlobalData*, double);
- JSValue(JSGlobalData*, int);
- JSValue(JSGlobalData*, unsigned);
+ JSValue(EncodeAsDoubleTag, double);
+ explicit JSValue(double);
+ explicit JSValue(char);
+ explicit JSValue(unsigned char);
+ explicit JSValue(short);
+ explicit JSValue(unsigned short);
+ explicit JSValue(int);
+ explicit JSValue(unsigned);
+ explicit JSValue(long);
+ explicit JSValue(unsigned long);
+ explicit JSValue(long long);
+ explicit JSValue(unsigned long long);
operator bool() const;
bool operator==(const JSValue& other) const;
UString getString(ExecState* exec) const; // null string if not a string
JSObject* getObject() const; // 0 if not an object
- CallType getCallData(CallData&);
- ConstructType getConstructData(ConstructData&);
-
// Extracting integer values.
bool getUInt32(uint32_t&) const;
UString toString(ExecState*) const;
UString toPrimitiveString(ExecState*) const;
JSObject* toObject(ExecState*) const;
+ JSObject* toObject(ExecState*, JSGlobalObject*) const;
// Integer conversions.
double toInteger(ExecState*) const;
double toIntegerPreserveNaN(ExecState*) const;
int32_t toInt32(ExecState*) const;
- int32_t toInt32(ExecState*, bool& ok) const;
uint32_t toUInt32(ExecState*) const;
- uint32_t toUInt32(ExecState*, bool& ok) const;
#if ENABLE(JSC_ZOMBIES)
bool isZombie() const;
bool needsThisConversion() const;
JSObject* toThisObject(ExecState*) const;
+ JSValue toStrictThisObject(ExecState*) const;
UString toThisString(ExecState*) const;
JSString* toThisJSString(ExecState*) const;
bool isCell() const;
JSCell* asCell() const;
+ bool isValidCallee();
#ifndef NDEBUG
char* description();
#endif
private:
+ template <class T> JSValue(WriteBarrierBase<T>);
+
enum HashTableDeletedValueTag { HashTableDeletedValue };
JSValue(HashTableDeletedValueTag);
inline const JSValue asValue() const { return *this; }
- JSObject* toObjectSlowCase(ExecState*) const;
+ JSObject* toObjectSlowCase(ExecState*, JSGlobalObject*) const;
JSObject* toThisObjectSlowCase(ExecState*) const;
JSObject* synthesizePrototype(ExecState*) const;
JSObject* synthesizeObject(ExecState*) const;
#if USE(JSVALUE32_64)
+ /*
+ * On 32-bit platforms USE(JSVALUE32_64) should be defined, and we use a NaN-encoded
+ * form for immediates.
+ *
+ * The encoding makes use of unused NaN space in the IEEE754 representation. Any value
+ * with the top 13 bits set represents a QNaN (with the sign bit set). QNaN values
+ * can encode a 51-bit payload. Hardware produced and C-library payloads typically
+ * have a payload of zero. We assume that non-zero payloads are available to encode
+ * pointer and integer values. Since any 64-bit bit pattern where the top 15 bits are
+ * all set represents a NaN with a non-zero payload, we can use this space in the NaN
+ * ranges to encode other values (however there are also other ranges of NaN space that
+ * could have been selected).
+ *
+ * For JSValues that do not contain a double value, the high 32 bits contain the tag
+ * values listed in the enums below, which all correspond to NaN-space. In the case of
+ * cell, integer and bool values the lower 32 bits (the 'payload') contain the pointer
+ * integer or boolean value; in the case of all other tags the payload is 0.
+ */
enum { Int32Tag = 0xffffffff };
- enum { CellTag = 0xfffffffe };
- enum { TrueTag = 0xfffffffd };
- enum { FalseTag = 0xfffffffc };
- enum { NullTag = 0xfffffffb };
- enum { UndefinedTag = 0xfffffffa };
- enum { EmptyValueTag = 0xfffffff9 };
- enum { DeletedValueTag = 0xfffffff8 };
-
+ enum { BooleanTag = 0xfffffffe };
+ enum { NullTag = 0xfffffffd };
+ enum { UndefinedTag = 0xfffffffc };
+ enum { CellTag = 0xfffffffb };
+ enum { EmptyValueTag = 0xfffffffa };
+ enum { DeletedValueTag = 0xfffffff9 };
+
enum { LowestTag = DeletedValueTag };
-
+
uint32_t tag() const;
int32_t payload() const;
-
- union {
- EncodedJSValue asEncodedJSValue;
- double asDouble;
-#if CPU(BIG_ENDIAN)
- struct {
- int32_t tag;
- int32_t payload;
- } asBits;
-#else
- struct {
- int32_t payload;
- int32_t tag;
- } asBits;
+#elif USE(JSVALUE64)
+ /*
+ * On 64-bit platforms USE(JSVALUE64) should be defined, and we use a NaN-encoded
+ * form for immediates.
+ *
+ * The encoding makes use of unused NaN space in the IEEE754 representation. Any value
+ * with the top 13 bits set represents a QNaN (with the sign bit set). QNaN values
+ * can encode a 51-bit payload. Hardware produced and C-library payloads typically
+ * have a payload of zero. We assume that non-zero payloads are available to encode
+ * pointer and integer values. Since any 64-bit bit pattern where the top 15 bits are
+ * all set represents a NaN with a non-zero payload, we can use this space in the NaN
+ * ranges to encode other values (however there are also other ranges of NaN space that
+ * could have been selected).
+ *
+ * This range of NaN space is represented by 64-bit numbers begining with the 16-bit
+ * hex patterns 0xFFFE and 0xFFFF - we rely on the fact that no valid double-precision
+ * numbers will begin fall in these ranges.
+ *
+ * The top 16-bits denote the type of the encoded JSValue:
+ *
+ * Pointer { 0000:PPPP:PPPP:PPPP
+ * / 0001:****:****:****
+ * Double { ...
+ * \ FFFE:****:****:****
+ * Integer { FFFF:0000:IIII:IIII
+ *
+ * The scheme we have implemented encodes double precision values by performing a
+ * 64-bit integer addition of the value 2^48 to the number. After this manipulation
+ * no encoded double-precision value will begin with the pattern 0x0000 or 0xFFFF.
+ * Values must be decoded by reversing this operation before subsequent floating point
+ * operations my be peformed.
+ *
+ * 32-bit signed integers are marked with the 16-bit tag 0xFFFF.
+ *
+ * The tag 0x0000 denotes a pointer, or another form of tagged immediate. Boolean,
+ * null and undefined values are represented by specific, invalid pointer values:
+ *
+ * False: 0x06
+ * True: 0x07
+ * Undefined: 0x0a
+ * Null: 0x02
+ *
+ * These values have the following properties:
+ * - Bit 1 (TagBitTypeOther) is set for all four values, allowing real pointers to be
+ * quickly distinguished from all immediate values, including these invalid pointers.
+ * - With bit 3 is masked out (TagBitUndefined) Undefined and Null share the
+ * same value, allowing null & undefined to be quickly detected.
+ *
+ * No valid JSValue will have the bit pattern 0x0, this is used to represent array
+ * holes, and as a C++ 'no value' result (e.g. JSValue() has an internal value of 0).
+ */
+
+ // These values are #defines since using static const integers here is a ~1% regression!
+
+ // This value is 2^48, used to encode doubles such that the encoded value will begin
+ // with a 16-bit pattern within the range 0x0001..0xFFFE.
+ #define DoubleEncodeOffset 0x1000000000000ll
+ // If all bits in the mask are set, this indicates an integer number,
+ // if any but not all are set this value is a double precision number.
+ #define TagTypeNumber 0xffff000000000000ll
+
+ // All non-numeric (bool, null, undefined) immediates have bit 2 set.
+ #define TagBitTypeOther 0x2ll
+ #define TagBitBool 0x4ll
+ #define TagBitUndefined 0x8ll
+ // Combined integer value for non-numeric immediates.
+ #define ValueFalse (TagBitTypeOther | TagBitBool | false)
+ #define ValueTrue (TagBitTypeOther | TagBitBool | true)
+ #define ValueUndefined (TagBitTypeOther | TagBitUndefined)
+ #define ValueNull (TagBitTypeOther)
+
+ // TagMask is used to check for all types of immediate values (either number or 'other').
+ #define TagMask (TagTypeNumber | TagBitTypeOther)
+
+ // These special values are never visible to JavaScript code; Empty is used to represent
+ // Array holes, and for uninitialized JSValues. Deleted is used in hash table code.
+ // These values would map to cell types in the JSValue encoding, but not valid GC cell
+ // pointer should have either of these values (Empty is null, deleted is at an invalid
+ // alignment for a GC cell, and in the zero page).
+ #define ValueEmpty 0x0ll
+ #define ValueDeleted 0x4ll
#endif
- } u;
-#else // USE(JSVALUE32_64)
- JSCell* m_ptr;
-#endif // USE(JSVALUE32_64)
+
+ EncodedValueDescriptor u;
};
#if USE(JSVALUE32_64)
return b ? JSValue(JSValue::JSTrue) : JSValue(JSValue::JSFalse);
}
- ALWAYS_INLINE JSValue jsDoubleNumber(ExecState* exec, double d)
- {
- return JSValue(JSValue::EncodeAsDouble, exec, d);
- }
-
- ALWAYS_INLINE JSValue jsNumber(ExecState* exec, double d)
- {
- return JSValue(exec, d);
- }
-
- ALWAYS_INLINE JSValue jsNumber(ExecState* exec, char i)
- {
- return JSValue(exec, i);
- }
-
- ALWAYS_INLINE JSValue jsNumber(ExecState* exec, unsigned char i)
+ ALWAYS_INLINE JSValue jsDoubleNumber(double d)
{
- return JSValue(exec, i);
+ return JSValue(JSValue::EncodeAsDouble, d);
}
- ALWAYS_INLINE JSValue jsNumber(ExecState* exec, short i)
+ ALWAYS_INLINE JSValue jsNumber(double d)
{
- return JSValue(exec, i);
+ return JSValue(d);
}
- ALWAYS_INLINE JSValue jsNumber(ExecState* exec, unsigned short i)
+ ALWAYS_INLINE JSValue jsNumber(char i)
{
- return JSValue(exec, i);
+ return JSValue(i);
}
- ALWAYS_INLINE JSValue jsNumber(ExecState* exec, int i)
+ ALWAYS_INLINE JSValue jsNumber(unsigned char i)
{
- return JSValue(exec, i);
+ return JSValue(i);
}
- ALWAYS_INLINE JSValue jsNumber(ExecState* exec, unsigned i)
+ ALWAYS_INLINE JSValue jsNumber(short i)
{
- return JSValue(exec, i);
+ return JSValue(i);
}
- ALWAYS_INLINE JSValue jsNumber(ExecState* exec, long i)
+ ALWAYS_INLINE JSValue jsNumber(unsigned short i)
{
- return JSValue(exec, i);
+ return JSValue(i);
}
- ALWAYS_INLINE JSValue jsNumber(ExecState* exec, unsigned long i)
+ ALWAYS_INLINE JSValue jsNumber(int i)
{
- return JSValue(exec, i);
+ return JSValue(i);
}
- ALWAYS_INLINE JSValue jsNumber(ExecState* exec, long long i)
+ ALWAYS_INLINE JSValue jsNumber(unsigned i)
{
- return JSValue(exec, i);
+ return JSValue(i);
}
- ALWAYS_INLINE JSValue jsNumber(ExecState* exec, unsigned long long i)
+ ALWAYS_INLINE JSValue jsNumber(long i)
{
- return JSValue(exec, i);
+ return JSValue(i);
}
- ALWAYS_INLINE JSValue jsNumber(JSGlobalData* globalData, double d)
+ ALWAYS_INLINE JSValue jsNumber(unsigned long i)
{
- return JSValue(globalData, d);
+ return JSValue(i);
}
- ALWAYS_INLINE JSValue jsNumber(JSGlobalData* globalData, int i)
+ ALWAYS_INLINE JSValue jsNumber(long long i)
{
- return JSValue(globalData, i);
+ return JSValue(i);
}
- ALWAYS_INLINE JSValue jsNumber(JSGlobalData* globalData, unsigned i)
+ ALWAYS_INLINE JSValue jsNumber(unsigned long long i)
{
- return JSValue(globalData, i);
+ return JSValue(i);
}
inline bool operator==(const JSValue a, const JSCell* b) { return a == JSValue(b); }
inline bool operator!=(const JSValue a, const JSCell* b) { return a != JSValue(b); }
inline bool operator!=(const JSCell* a, const JSValue b) { return JSValue(a) != b; }
- inline int32_t toInt32(double val)
- {
- if (!(val >= -2147483648.0 && val < 2147483648.0)) {
- bool ignored;
- return toInt32SlowCase(val, ignored);
- }
- return static_cast<int32_t>(val);
- }
-
- inline uint32_t toUInt32(double val)
- {
- if (!(val >= 0.0 && val < 4294967296.0)) {
- bool ignored;
- return toUInt32SlowCase(val, ignored);
- }
- return static_cast<uint32_t>(val);
- }
-
- // FIXME: We should deprecate this and just use JSValue::asCell() instead.
- JSCell* asCell(JSValue);
-
- inline JSCell* asCell(JSValue value)
- {
- return value.asCell();
- }
-
- ALWAYS_INLINE int32_t JSValue::toInt32(ExecState* exec) const
- {
- if (isInt32())
- return asInt32();
- bool ignored;
- return toInt32SlowCase(toNumber(exec), ignored);
- }
-
- inline uint32_t JSValue::toUInt32(ExecState* exec) const
- {
- if (isUInt32())
- return asInt32();
- bool ignored;
- return toUInt32SlowCase(toNumber(exec), ignored);
- }
-
- inline int32_t JSValue::toInt32(ExecState* exec, bool& ok) const
- {
- if (isInt32()) {
- ok = true;
- return asInt32();
- }
- return toInt32SlowCase(toNumber(exec), ok);
- }
-
- inline uint32_t JSValue::toUInt32(ExecState* exec, bool& ok) const
- {
- if (isUInt32()) {
- ok = true;
- return asInt32();
- }
- return toUInt32SlowCase(toNumber(exec), ok);
- }
-
-#if USE(JSVALUE32_64)
- inline JSValue jsNaN(ExecState* exec)
- {
- return JSValue(exec, nonInlineNaN());
- }
-
- // JSValue member functions.
- inline EncodedJSValue JSValue::encode(JSValue value)
- {
- return value.u.asEncodedJSValue;
- }
-
- inline JSValue JSValue::decode(EncodedJSValue encodedJSValue)
- {
- JSValue v;
- v.u.asEncodedJSValue = encodedJSValue;
-#if ENABLE(JSC_ZOMBIES)
- ASSERT(!v.isZombie());
-#endif
- return v;
- }
-
- inline JSValue::JSValue()
- {
- u.asBits.tag = EmptyValueTag;
- u.asBits.payload = 0;
- }
-
- inline JSValue::JSValue(JSNullTag)
- {
- u.asBits.tag = NullTag;
- u.asBits.payload = 0;
- }
-
- inline JSValue::JSValue(JSUndefinedTag)
- {
- u.asBits.tag = UndefinedTag;
- u.asBits.payload = 0;
- }
-
- inline JSValue::JSValue(JSTrueTag)
- {
- u.asBits.tag = TrueTag;
- u.asBits.payload = 0;
- }
-
- inline JSValue::JSValue(JSFalseTag)
- {
- u.asBits.tag = FalseTag;
- u.asBits.payload = 0;
- }
-
- inline JSValue::JSValue(HashTableDeletedValueTag)
- {
- u.asBits.tag = DeletedValueTag;
- u.asBits.payload = 0;
- }
-
- inline JSValue::JSValue(JSCell* ptr)
- {
- if (ptr)
- u.asBits.tag = CellTag;
- else
- u.asBits.tag = EmptyValueTag;
- u.asBits.payload = reinterpret_cast<int32_t>(ptr);
-#if ENABLE(JSC_ZOMBIES)
- ASSERT(!isZombie());
-#endif
- }
-
- inline JSValue::JSValue(const JSCell* ptr)
- {
- if (ptr)
- u.asBits.tag = CellTag;
- else
- u.asBits.tag = EmptyValueTag;
- u.asBits.payload = reinterpret_cast<int32_t>(const_cast<JSCell*>(ptr));
-#if ENABLE(JSC_ZOMBIES)
- ASSERT(!isZombie());
-#endif
- }
-
- inline JSValue::operator bool() const
- {
- ASSERT(tag() != DeletedValueTag);
- return tag() != EmptyValueTag;
- }
-
- inline bool JSValue::operator==(const JSValue& other) const
- {
- return u.asEncodedJSValue == other.u.asEncodedJSValue;
- }
-
- inline bool JSValue::operator!=(const JSValue& other) const
- {
- return u.asEncodedJSValue != other.u.asEncodedJSValue;
- }
-
- inline bool JSValue::isUndefined() const
- {
- return tag() == UndefinedTag;
- }
-
- inline bool JSValue::isNull() const
- {
- return tag() == NullTag;
- }
-
- inline bool JSValue::isUndefinedOrNull() const
- {
- return isUndefined() || isNull();
- }
-
- inline bool JSValue::isCell() const
- {
- return tag() == CellTag;
- }
-
- inline bool JSValue::isInt32() const
- {
- return tag() == Int32Tag;
- }
-
- inline bool JSValue::isUInt32() const
- {
- return tag() == Int32Tag && asInt32() > -1;
- }
-
- inline bool JSValue::isDouble() const
- {
- return tag() < LowestTag;
- }
-
- inline bool JSValue::isTrue() const
- {
- return tag() == TrueTag;
- }
-
- inline bool JSValue::isFalse() const
- {
- return tag() == FalseTag;
- }
-
- inline uint32_t JSValue::tag() const
- {
- return u.asBits.tag;
- }
-
- inline int32_t JSValue::payload() const
- {
- return u.asBits.payload;
- }
-
- inline int32_t JSValue::asInt32() const
- {
- ASSERT(isInt32());
- return u.asBits.payload;
- }
-
- inline uint32_t JSValue::asUInt32() const
- {
- ASSERT(isUInt32());
- return u.asBits.payload;
- }
-
- inline double JSValue::asDouble() const
- {
- ASSERT(isDouble());
- return u.asDouble;
- }
-
- ALWAYS_INLINE JSCell* JSValue::asCell() const
- {
- ASSERT(isCell());
- return reinterpret_cast<JSCell*>(u.asBits.payload);
- }
-
- ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, ExecState*, double d)
- {
- u.asDouble = d;
- }
-
- inline JSValue::JSValue(ExecState* exec, double d)
- {
- const int32_t asInt32 = static_cast<int32_t>(d);
- if (asInt32 != d || (!asInt32 && signbit(d))) { // true for -0.0
- u.asDouble = d;
- return;
- }
- *this = JSValue(exec, static_cast<int32_t>(d));
- }
-
- inline JSValue::JSValue(ExecState* exec, char i)
- {
- *this = JSValue(exec, static_cast<int32_t>(i));
- }
-
- inline JSValue::JSValue(ExecState* exec, unsigned char i)
- {
- *this = JSValue(exec, static_cast<int32_t>(i));
- }
-
- inline JSValue::JSValue(ExecState* exec, short i)
- {
- *this = JSValue(exec, static_cast<int32_t>(i));
- }
-
- inline JSValue::JSValue(ExecState* exec, unsigned short i)
- {
- *this = JSValue(exec, static_cast<int32_t>(i));
- }
-
- inline JSValue::JSValue(ExecState*, int i)
- {
- u.asBits.tag = Int32Tag;
- u.asBits.payload = i;
- }
-
- inline JSValue::JSValue(ExecState* exec, unsigned i)
- {
- if (static_cast<int32_t>(i) < 0) {
- *this = JSValue(exec, static_cast<double>(i));
- return;
- }
- *this = JSValue(exec, static_cast<int32_t>(i));
- }
-
- inline JSValue::JSValue(ExecState* exec, long i)
- {
- if (static_cast<int32_t>(i) != i) {
- *this = JSValue(exec, static_cast<double>(i));
- return;
- }
- *this = JSValue(exec, static_cast<int32_t>(i));
- }
-
- inline JSValue::JSValue(ExecState* exec, unsigned long i)
- {
- if (static_cast<uint32_t>(i) != i) {
- *this = JSValue(exec, static_cast<double>(i));
- return;
- }
- *this = JSValue(exec, static_cast<uint32_t>(i));
- }
-
- inline JSValue::JSValue(ExecState* exec, long long i)
- {
- if (static_cast<int32_t>(i) != i) {
- *this = JSValue(exec, static_cast<double>(i));
- return;
- }
- *this = JSValue(exec, static_cast<int32_t>(i));
- }
-
- inline JSValue::JSValue(ExecState* exec, unsigned long long i)
- {
- if (static_cast<uint32_t>(i) != i) {
- *this = JSValue(exec, static_cast<double>(i));
- return;
- }
- *this = JSValue(exec, static_cast<uint32_t>(i));
- }
-
- inline JSValue::JSValue(JSGlobalData* globalData, double d)
- {
- const int32_t asInt32 = static_cast<int32_t>(d);
- if (asInt32 != d || (!asInt32 && signbit(d))) { // true for -0.0
- u.asDouble = d;
- return;
- }
- *this = JSValue(globalData, static_cast<int32_t>(d));
- }
-
- inline JSValue::JSValue(JSGlobalData*, int i)
- {
- u.asBits.tag = Int32Tag;
- u.asBits.payload = i;
- }
-
- inline JSValue::JSValue(JSGlobalData* globalData, unsigned i)
- {
- if (static_cast<int32_t>(i) < 0) {
- *this = JSValue(globalData, static_cast<double>(i));
- return;
- }
- *this = JSValue(globalData, static_cast<int32_t>(i));
- }
-
- inline bool JSValue::isNumber() const
- {
- return isInt32() || isDouble();
- }
-
- inline bool JSValue::isBoolean() const
- {
- return isTrue() || isFalse();
- }
-
- inline bool JSValue::getBoolean(bool& v) const
- {
- if (isTrue()) {
- v = true;
- return true;
- }
- if (isFalse()) {
- v = false;
- return true;
- }
-
- return false;
- }
-
- inline bool JSValue::getBoolean() const
- {
- ASSERT(isBoolean());
- return tag() == TrueTag;
- }
-
- inline double JSValue::uncheckedGetNumber() const
- {
- ASSERT(isNumber());
- return isInt32() ? asInt32() : asDouble();
- }
-
- ALWAYS_INLINE JSValue JSValue::toJSNumber(ExecState* exec) const
- {
- return isNumber() ? asValue() : jsNumber(exec, this->toNumber(exec));
- }
-
- inline bool JSValue::getNumber(double& result) const
- {
- if (isInt32()) {
- result = asInt32();
- return true;
- }
- if (isDouble()) {
- result = asDouble();
- return true;
- }
- return false;
- }
-
-#else // USE(JSVALUE32_64)
-
- // JSValue member functions.
- inline EncodedJSValue JSValue::encode(JSValue value)
- {
- return reinterpret_cast<EncodedJSValue>(value.m_ptr);
- }
-
- inline JSValue JSValue::decode(EncodedJSValue ptr)
- {
- return JSValue(reinterpret_cast<JSCell*>(ptr));
- }
-
- inline JSValue JSValue::makeImmediate(intptr_t value)
- {
- return JSValue(reinterpret_cast<JSCell*>(value));
- }
-
- inline intptr_t JSValue::immediateValue()
- {
- return reinterpret_cast<intptr_t>(m_ptr);
- }
-
- // 0x0 can never occur naturally because it has a tag of 00, indicating a pointer value, but a payload of 0x0, which is in the (invalid) zero page.
- inline JSValue::JSValue()
- : m_ptr(0)
- {
- }
+ bool isZombie(const JSCell*);
- // 0x4 can never occur naturally because it has a tag of 00, indicating a pointer value, but a payload of 0x4, which is in the (invalid) zero page.
- inline JSValue::JSValue(HashTableDeletedValueTag)
- : m_ptr(reinterpret_cast<JSCell*>(0x4))
- {
- }
-
- inline JSValue::JSValue(JSCell* ptr)
- : m_ptr(ptr)
- {
-#if ENABLE(JSC_ZOMBIES)
- ASSERT(!isZombie());
-#endif
- }
-
- inline JSValue::JSValue(const JSCell* ptr)
- : m_ptr(const_cast<JSCell*>(ptr))
- {
-#if ENABLE(JSC_ZOMBIES)
- ASSERT(!isZombie());
-#endif
- }
-
- inline JSValue::operator bool() const
- {
- return m_ptr;
- }
-
- inline bool JSValue::operator==(const JSValue& other) const
- {
- return m_ptr == other.m_ptr;
- }
-
- inline bool JSValue::operator!=(const JSValue& other) const
- {
- return m_ptr != other.m_ptr;
- }
-
- inline bool JSValue::isUndefined() const
- {
- return asValue() == jsUndefined();
- }
-
- inline bool JSValue::isNull() const
- {
- return asValue() == jsNull();
- }
-#endif // USE(JSVALUE32_64)
-
- typedef std::pair<JSValue, UString> ValueStringPair;
} // namespace JSC
#endif // JSValue_h
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef JSValueInlineMethods_h
+#define JSValueInlineMethods_h
+
+#include "JSValue.h"
+
+namespace JSC {
+
+ ALWAYS_INLINE int32_t JSValue::toInt32(ExecState* exec) const
+ {
+ if (isInt32())
+ return asInt32();
+ return JSC::toInt32(toNumber(exec));
+ }
+
+ inline uint32_t JSValue::toUInt32(ExecState* exec) const
+ {
+ // See comment on JSC::toUInt32, above.
+ return toInt32(exec);
+ }
+
+ inline bool JSValue::isUInt32() const
+ {
+ return isInt32() && asInt32() >= 0;
+ }
+
+ inline uint32_t JSValue::asUInt32() const
+ {
+ ASSERT(isUInt32());
+ return asInt32();
+ }
+
+ inline double JSValue::uncheckedGetNumber() const
+ {
+ ASSERT(isNumber());
+ return isInt32() ? asInt32() : asDouble();
+ }
+
+ ALWAYS_INLINE JSValue JSValue::toJSNumber(ExecState* exec) const
+ {
+ return isNumber() ? asValue() : jsNumber(this->toNumber(exec));
+ }
+
+ inline JSValue jsNaN()
+ {
+ return JSValue(nonInlineNaN());
+ }
+
+ inline bool JSValue::getNumber(double& result) const
+ {
+ if (isInt32()) {
+ result = asInt32();
+ return true;
+ }
+ if (isDouble()) {
+ result = asDouble();
+ return true;
+ }
+ return false;
+ }
+
+ inline bool JSValue::getBoolean(bool& v) const
+ {
+ if (isTrue()) {
+ v = true;
+ return true;
+ }
+ if (isFalse()) {
+ v = false;
+ return true;
+ }
+
+ return false;
+ }
+
+ inline JSValue::JSValue(char i)
+ {
+ *this = JSValue(static_cast<int32_t>(i));
+ }
+
+ inline JSValue::JSValue(unsigned char i)
+ {
+ *this = JSValue(static_cast<int32_t>(i));
+ }
+
+ inline JSValue::JSValue(short i)
+ {
+ *this = JSValue(static_cast<int32_t>(i));
+ }
+
+ inline JSValue::JSValue(unsigned short i)
+ {
+ *this = JSValue(static_cast<int32_t>(i));
+ }
+
+ inline JSValue::JSValue(unsigned i)
+ {
+ if (static_cast<int32_t>(i) < 0) {
+ *this = JSValue(EncodeAsDouble, static_cast<double>(i));
+ return;
+ }
+ *this = JSValue(static_cast<int32_t>(i));
+ }
+
+ inline JSValue::JSValue(long i)
+ {
+ if (static_cast<int32_t>(i) != i) {
+ *this = JSValue(EncodeAsDouble, static_cast<double>(i));
+ return;
+ }
+ *this = JSValue(static_cast<int32_t>(i));
+ }
+
+ inline JSValue::JSValue(unsigned long i)
+ {
+ if (static_cast<uint32_t>(i) != i) {
+ *this = JSValue(EncodeAsDouble, static_cast<double>(i));
+ return;
+ }
+ *this = JSValue(static_cast<uint32_t>(i));
+ }
+
+ inline JSValue::JSValue(long long i)
+ {
+ if (static_cast<int32_t>(i) != i) {
+ *this = JSValue(EncodeAsDouble, static_cast<double>(i));
+ return;
+ }
+ *this = JSValue(static_cast<int32_t>(i));
+ }
+
+ inline JSValue::JSValue(unsigned long long i)
+ {
+ if (static_cast<uint32_t>(i) != i) {
+ *this = JSValue(EncodeAsDouble, static_cast<double>(i));
+ return;
+ }
+ *this = JSValue(static_cast<uint32_t>(i));
+ }
+
+ inline JSValue::JSValue(double d)
+ {
+ const int32_t asInt32 = static_cast<int32_t>(d);
+ if (asInt32 != d || (!asInt32 && signbit(d))) { // true for -0.0
+ *this = JSValue(EncodeAsDouble, d);
+ return;
+ }
+ *this = JSValue(static_cast<int32_t>(d));
+ }
+
+#if USE(JSVALUE32_64)
+ inline EncodedJSValue JSValue::encode(JSValue value)
+ {
+ return value.u.asInt64;
+ }
+
+ inline JSValue JSValue::decode(EncodedJSValue encodedJSValue)
+ {
+ JSValue v;
+ v.u.asInt64 = encodedJSValue;
+ return v;
+ }
+
+ inline JSValue::JSValue()
+ {
+ u.asBits.tag = EmptyValueTag;
+ u.asBits.payload = 0;
+ }
+
+ inline JSValue::JSValue(JSNullTag)
+ {
+ u.asBits.tag = NullTag;
+ u.asBits.payload = 0;
+ }
+
+ inline JSValue::JSValue(JSUndefinedTag)
+ {
+ u.asBits.tag = UndefinedTag;
+ u.asBits.payload = 0;
+ }
+
+ inline JSValue::JSValue(JSTrueTag)
+ {
+ u.asBits.tag = BooleanTag;
+ u.asBits.payload = 1;
+ }
+
+ inline JSValue::JSValue(JSFalseTag)
+ {
+ u.asBits.tag = BooleanTag;
+ u.asBits.payload = 0;
+ }
+
+ inline JSValue::JSValue(HashTableDeletedValueTag)
+ {
+ u.asBits.tag = DeletedValueTag;
+ u.asBits.payload = 0;
+ }
+
+ inline JSValue::JSValue(JSCell* ptr)
+ {
+ if (ptr)
+ u.asBits.tag = CellTag;
+ else
+ u.asBits.tag = EmptyValueTag;
+ u.asBits.payload = reinterpret_cast<int32_t>(ptr);
+#if ENABLE(JSC_ZOMBIES)
+ ASSERT(!isZombie());
+#endif
+ }
+
+ inline JSValue::JSValue(const JSCell* ptr)
+ {
+ if (ptr)
+ u.asBits.tag = CellTag;
+ else
+ u.asBits.tag = EmptyValueTag;
+ u.asBits.payload = reinterpret_cast<int32_t>(const_cast<JSCell*>(ptr));
+#if ENABLE(JSC_ZOMBIES)
+ ASSERT(!isZombie());
+#endif
+ }
+
+ inline JSValue::operator bool() const
+ {
+ ASSERT(tag() != DeletedValueTag);
+ return tag() != EmptyValueTag;
+ }
+
+ inline bool JSValue::operator==(const JSValue& other) const
+ {
+ return u.asInt64 == other.u.asInt64;
+ }
+
+ inline bool JSValue::operator!=(const JSValue& other) const
+ {
+ return u.asInt64 != other.u.asInt64;
+ }
+
+ inline bool JSValue::isUndefined() const
+ {
+ return tag() == UndefinedTag;
+ }
+
+ inline bool JSValue::isNull() const
+ {
+ return tag() == NullTag;
+ }
+
+ inline bool JSValue::isUndefinedOrNull() const
+ {
+ return isUndefined() || isNull();
+ }
+
+ inline bool JSValue::isCell() const
+ {
+ return tag() == CellTag;
+ }
+
+ inline bool JSValue::isInt32() const
+ {
+ return tag() == Int32Tag;
+ }
+
+ inline bool JSValue::isDouble() const
+ {
+ return tag() < LowestTag;
+ }
+
+ inline bool JSValue::isTrue() const
+ {
+ return tag() == BooleanTag && payload();
+ }
+
+ inline bool JSValue::isFalse() const
+ {
+ return tag() == BooleanTag && !payload();
+ }
+
+ inline uint32_t JSValue::tag() const
+ {
+ return u.asBits.tag;
+ }
+
+ inline int32_t JSValue::payload() const
+ {
+ return u.asBits.payload;
+ }
+
+ inline int32_t JSValue::asInt32() const
+ {
+ ASSERT(isInt32());
+ return u.asBits.payload;
+ }
+
+ inline double JSValue::asDouble() const
+ {
+ ASSERT(isDouble());
+ return u.asDouble;
+ }
+
+ ALWAYS_INLINE JSCell* JSValue::asCell() const
+ {
+ ASSERT(isCell());
+ return reinterpret_cast<JSCell*>(u.asBits.payload);
+ }
+
+ ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, double d)
+ {
+ u.asDouble = d;
+ }
+
+ inline JSValue::JSValue(int i)
+ {
+ u.asBits.tag = Int32Tag;
+ u.asBits.payload = i;
+ }
+
+ inline bool JSValue::isNumber() const
+ {
+ return isInt32() || isDouble();
+ }
+
+ inline bool JSValue::isBoolean() const
+ {
+ return isTrue() || isFalse();
+ }
+
+ inline bool JSValue::getBoolean() const
+ {
+ ASSERT(isBoolean());
+ return payload();
+ }
+
+#else // USE(JSVALUE32_64)
+
+ // JSValue member functions.
+ inline EncodedJSValue JSValue::encode(JSValue value)
+ {
+ return value.u.ptr;
+ }
+
+ inline JSValue JSValue::decode(EncodedJSValue ptr)
+ {
+ return JSValue(reinterpret_cast<JSCell*>(ptr));
+ }
+
+ // 0x0 can never occur naturally because it has a tag of 00, indicating a pointer value, but a payload of 0x0, which is in the (invalid) zero page.
+ inline JSValue::JSValue()
+ {
+ u.asInt64 = ValueEmpty;
+ }
+
+ // 0x4 can never occur naturally because it has a tag of 00, indicating a pointer value, but a payload of 0x4, which is in the (invalid) zero page.
+ inline JSValue::JSValue(HashTableDeletedValueTag)
+ {
+ u.asInt64 = ValueDeleted;
+ }
+
+ inline JSValue::JSValue(JSCell* ptr)
+ {
+ u.ptr = ptr;
+#if ENABLE(JSC_ZOMBIES)
+ ASSERT(!isZombie());
+#endif
+ }
+
+ inline JSValue::JSValue(const JSCell* ptr)
+ {
+ u.ptr = const_cast<JSCell*>(ptr);
+#if ENABLE(JSC_ZOMBIES)
+ ASSERT(!isZombie());
+#endif
+ }
+
+ inline JSValue::operator bool() const
+ {
+ return u.ptr;
+ }
+
+ inline bool JSValue::operator==(const JSValue& other) const
+ {
+ return u.ptr == other.u.ptr;
+ }
+
+ inline bool JSValue::operator!=(const JSValue& other) const
+ {
+ return u.ptr != other.u.ptr;
+ }
+
+ inline bool JSValue::isUndefined() const
+ {
+ return asValue() == jsUndefined();
+ }
+
+ inline bool JSValue::isNull() const
+ {
+ return asValue() == jsNull();
+ }
+
+ inline bool JSValue::isTrue() const
+ {
+ return asValue() == JSValue(JSTrue);
+ }
+
+ inline bool JSValue::isFalse() const
+ {
+ return asValue() == JSValue(JSFalse);
+ }
+
+ inline bool JSValue::getBoolean() const
+ {
+ ASSERT(asValue() == jsBoolean(true) || asValue() == jsBoolean(false));
+ return asValue() == jsBoolean(true);
+ }
+
+ inline int32_t JSValue::asInt32() const
+ {
+ ASSERT(isInt32());
+ return static_cast<int32_t>(u.asInt64);
+ }
+
+ inline bool JSValue::isDouble() const
+ {
+ return isNumber() && !isInt32();
+ }
+
+ inline JSValue::JSValue(JSNullTag)
+ {
+ u.asInt64 = ValueNull;
+ }
+
+ inline JSValue::JSValue(JSUndefinedTag)
+ {
+ u.asInt64 = ValueUndefined;
+ }
+
+ inline JSValue::JSValue(JSTrueTag)
+ {
+ u.asInt64 = ValueTrue;
+ }
+
+ inline JSValue::JSValue(JSFalseTag)
+ {
+ u.asInt64 = ValueFalse;
+ }
+
+ inline bool JSValue::isUndefinedOrNull() const
+ {
+ // Undefined and null share the same value, bar the 'undefined' bit in the extended tag.
+ return (u.asInt64 & ~TagBitUndefined) == ValueNull;
+ }
+
+ inline bool JSValue::isBoolean() const
+ {
+ return (u.asInt64 & ~1) == ValueFalse;
+ }
+
+ inline bool JSValue::isCell() const
+ {
+ return !(u.asInt64 & TagMask);
+ }
+
+ inline bool JSValue::isInt32() const
+ {
+ return (u.asInt64 & TagTypeNumber) == TagTypeNumber;
+ }
+
+ inline intptr_t reinterpretDoubleToIntptr(double value)
+ {
+ return bitwise_cast<intptr_t>(value);
+ }
+ inline double reinterpretIntptrToDouble(intptr_t value)
+ {
+ return bitwise_cast<double>(value);
+ }
+
+ ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, double d)
+ {
+ u.asInt64 = reinterpretDoubleToIntptr(d) + DoubleEncodeOffset;
+ }
+
+ inline JSValue::JSValue(int i)
+ {
+ u.asInt64 = TagTypeNumber | static_cast<uint32_t>(i);
+ }
+
+ inline double JSValue::asDouble() const
+ {
+ return reinterpretIntptrToDouble(u.asInt64 - DoubleEncodeOffset);
+ }
+
+ inline bool JSValue::isNumber() const
+ {
+ return u.asInt64 & TagTypeNumber;
+ }
+
+ ALWAYS_INLINE JSCell* JSValue::asCell() const
+ {
+ ASSERT(isCell());
+ return u.ptr;
+ }
+
+#endif // USE(JSVALUE64)
+
+} // namespace JSC
+
+#endif // JSValueInlineMethods_h
bool JSVariableObject::deleteProperty(ExecState* exec, const Identifier& propertyName)
{
- if (symbolTable().contains(propertyName.ustring().rep()))
+ if (symbolTable().contains(propertyName.impl()))
return false;
return JSObject::deleteProperty(exec, propertyName);
bool JSVariableObject::symbolTableGet(const Identifier& propertyName, PropertyDescriptor& descriptor)
{
- SymbolTableEntry entry = symbolTable().inlineGet(propertyName.ustring().rep());
+ SymbolTableEntry entry = symbolTable().inlineGet(propertyName.impl());
if (!entry.isNull()) {
- descriptor.setDescriptor(registerAt(entry.getIndex()).jsValue(), entry.getAttributes() | DontDelete);
+ descriptor.setDescriptor(registerAt(entry.getIndex()).get(), entry.getAttributes() | DontDelete);
return true;
}
return false;
class Register;
- class JSVariableObject : public JSObject {
+ class JSVariableObject : public JSNonFinalObject {
friend class JIT;
public:
- SymbolTable& symbolTable() const { return *d->symbolTable; }
+ SymbolTable& symbolTable() const { return *m_symbolTable; }
virtual void putWithAttributes(ExecState*, const Identifier&, JSValue, unsigned attributes) = 0;
virtual bool isVariableObject() const;
virtual bool isDynamicScope(bool& requiresDynamicChecks) const = 0;
- Register& registerAt(int index) const { return d->registers[index]; }
+ WriteBarrier<Unknown>& registerAt(int index) const { return m_registers[index]; }
- static PassRefPtr<Structure> createStructure(JSValue prototype)
+ WriteBarrier<Unknown>* const * addressOfRegisters() const { return &m_registers; }
+
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
+ return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
}
protected:
static const unsigned StructureFlags = OverridesGetPropertyNames | JSObject::StructureFlags;
- // Subclasses of JSVariableObject can subclass this struct to add data
- // without increasing their own size (since there's a hard limit on the
- // size of a JSCell).
- struct JSVariableObjectData {
- JSVariableObjectData(SymbolTable* symbolTable, Register* registers)
- : symbolTable(symbolTable)
- , registers(registers)
- {
- ASSERT(symbolTable);
- }
-
- SymbolTable* symbolTable; // Maps name -> offset from "r" in register file.
- Register* registers; // "r" in the register file.
- OwnArrayPtr<Register> registerArray; // Independent copy of registers, used when a variable object copies its registers out of the register file.
-
- private:
- JSVariableObjectData(const JSVariableObjectData&);
- JSVariableObjectData& operator=(const JSVariableObjectData&);
- };
-
- JSVariableObject(NonNullPassRefPtr<Structure> structure, JSVariableObjectData* data)
- : JSObject(structure)
- , d(data) // Subclass owns this pointer.
+
+ JSVariableObject(JSGlobalData& globalData, Structure* structure, SymbolTable* symbolTable, Register* registers)
+ : JSNonFinalObject(globalData, structure)
+ , m_symbolTable(symbolTable)
+ , m_registers(reinterpret_cast<WriteBarrier<Unknown>*>(registers))
{
+ ASSERT(m_symbolTable);
+ COMPILE_ASSERT(sizeof(WriteBarrier<Unknown>) == sizeof(Register), Register_should_be_same_size_as_WriteBarrier);
}
- Register* copyRegisterArray(Register* src, size_t count);
- void setRegisters(Register* r, Register* registerArray);
+ PassOwnArrayPtr<WriteBarrier<Unknown> > copyRegisterArray(JSGlobalData&, WriteBarrier<Unknown>* src, size_t count, size_t callframeStarts);
+ void setRegisters(WriteBarrier<Unknown>* registers, PassOwnArrayPtr<WriteBarrier<Unknown> > registerArray);
bool symbolTableGet(const Identifier&, PropertySlot&);
bool symbolTableGet(const Identifier&, PropertyDescriptor&);
bool symbolTableGet(const Identifier&, PropertySlot&, bool& slotIsWriteable);
- bool symbolTablePut(const Identifier&, JSValue);
- bool symbolTablePutWithAttributes(const Identifier&, JSValue, unsigned attributes);
+ bool symbolTablePut(JSGlobalData&, const Identifier&, JSValue);
+ bool symbolTablePutWithAttributes(JSGlobalData&, const Identifier&, JSValue, unsigned attributes);
- JSVariableObjectData* d;
+ SymbolTable* m_symbolTable; // Maps name -> offset from "r" in register file.
+ WriteBarrier<Unknown>* m_registers; // "r" in the register file.
+ OwnArrayPtr<WriteBarrier<Unknown> > m_registerArray; // Independent copy of registers, used when a variable object copies its registers out of the register file.
};
inline bool JSVariableObject::symbolTableGet(const Identifier& propertyName, PropertySlot& slot)
{
- SymbolTableEntry entry = symbolTable().inlineGet(propertyName.ustring().rep());
+ SymbolTableEntry entry = symbolTable().inlineGet(propertyName.impl());
if (!entry.isNull()) {
- slot.setRegisterSlot(®isterAt(entry.getIndex()));
+ slot.setValue(registerAt(entry.getIndex()).get());
return true;
}
return false;
inline bool JSVariableObject::symbolTableGet(const Identifier& propertyName, PropertySlot& slot, bool& slotIsWriteable)
{
- SymbolTableEntry entry = symbolTable().inlineGet(propertyName.ustring().rep());
+ SymbolTableEntry entry = symbolTable().inlineGet(propertyName.impl());
if (!entry.isNull()) {
- slot.setRegisterSlot(®isterAt(entry.getIndex()));
+ slot.setValue(registerAt(entry.getIndex()).get());
slotIsWriteable = !entry.isReadOnly();
return true;
}
return false;
}
- inline bool JSVariableObject::symbolTablePut(const Identifier& propertyName, JSValue value)
+ inline bool JSVariableObject::symbolTablePut(JSGlobalData& globalData, const Identifier& propertyName, JSValue value)
{
ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
- SymbolTableEntry entry = symbolTable().inlineGet(propertyName.ustring().rep());
+ SymbolTableEntry entry = symbolTable().inlineGet(propertyName.impl());
if (entry.isNull())
return false;
if (entry.isReadOnly())
return true;
- registerAt(entry.getIndex()) = value;
+ registerAt(entry.getIndex()).set(globalData, this, value);
return true;
}
- inline bool JSVariableObject::symbolTablePutWithAttributes(const Identifier& propertyName, JSValue value, unsigned attributes)
+ inline bool JSVariableObject::symbolTablePutWithAttributes(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
{
ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
- SymbolTable::iterator iter = symbolTable().find(propertyName.ustring().rep());
+ SymbolTable::iterator iter = symbolTable().find(propertyName.impl());
if (iter == symbolTable().end())
return false;
SymbolTableEntry& entry = iter->second;
ASSERT(!entry.isNull());
entry.setAttributes(attributes);
- registerAt(entry.getIndex()) = value;
+ registerAt(entry.getIndex()).set(globalData, this, value);
return true;
}
- inline Register* JSVariableObject::copyRegisterArray(Register* src, size_t count)
+ inline PassOwnArrayPtr<WriteBarrier<Unknown> > JSVariableObject::copyRegisterArray(JSGlobalData& globalData, WriteBarrier<Unknown>* src, size_t count, size_t callframeStarts)
{
- Register* registerArray = new Register[count];
- memcpy(registerArray, src, count * sizeof(Register));
+ OwnArrayPtr<WriteBarrier<Unknown> > registerArray = adoptArrayPtr(new WriteBarrier<Unknown>[count]);
+ for (size_t i = 0; i < callframeStarts; i++)
+ registerArray[i].set(globalData, this, src[i].get());
+ for (size_t i = callframeStarts + RegisterFile::CallFrameHeaderSize; i < count; i++)
+ registerArray[i].set(globalData, this, src[i].get());
- return registerArray;
+ return registerArray.release();
}
- inline void JSVariableObject::setRegisters(Register* registers, Register* registerArray)
+ inline void JSVariableObject::setRegisters(WriteBarrier<Unknown>* registers, PassOwnArrayPtr<WriteBarrier<Unknown> > registerArray)
{
- ASSERT(registerArray != d->registerArray.get());
- d->registerArray.set(registerArray);
- d->registers = registers;
+ ASSERT(registerArray != m_registerArray);
+ m_registerArray = registerArray;
+ m_registers = registers;
}
} // namespace JSC
ASSERT_CLASS_FITS_IN_CELL(JSWrapperObject);
-void JSWrapperObject::markChildren(MarkStack& markStack)
+void JSWrapperObject::visitChildren(SlotVisitor& visitor)
{
- JSObject::markChildren(markStack);
+ ASSERT_GC_OBJECT_INHERITS(this, &s_info);
+ COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
+ ASSERT(structure()->typeInfo().overridesVisitChildren());
+ JSObject::visitChildren(visitor);
if (m_internalValue)
- markStack.append(m_internalValue);
+ visitor.append(&m_internalValue);
}
} // namespace JSC
// This class is used as a base for classes such as String,
// Number, Boolean and Date which are wrappers for primitive types.
- class JSWrapperObject : public JSObject {
+ class JSWrapperObject : public JSNonFinalObject {
protected:
- explicit JSWrapperObject(NonNullPassRefPtr<Structure>);
+ explicit JSWrapperObject(JSGlobalData&, Structure*);
public:
- JSValue internalValue() const { return m_internalValue; }
- void setInternalValue(JSValue);
+ JSValue internalValue() const;
+ void setInternalValue(JSGlobalData&, JSValue);
- static PassRefPtr<Structure> createStructure(JSValue prototype)
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
+ return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
}
protected:
- static const unsigned AnonymousSlotCount = 1 + JSObject::AnonymousSlotCount;
+ static const unsigned StructureFlags = OverridesVisitChildren | JSNonFinalObject::StructureFlags;
private:
- virtual void markChildren(MarkStack&);
+ virtual void visitChildren(SlotVisitor&);
- JSValue m_internalValue;
+ WriteBarrier<Unknown> m_internalValue;
};
- inline JSWrapperObject::JSWrapperObject(NonNullPassRefPtr<Structure> structure)
- : JSObject(structure)
+ inline JSWrapperObject::JSWrapperObject(JSGlobalData& globalData, Structure* structure)
+ : JSNonFinalObject(globalData, structure)
{
- putAnonymousValue(0, jsNull());
}
- inline void JSWrapperObject::setInternalValue(JSValue value)
+ inline JSValue JSWrapperObject::internalValue() const
+ {
+ return m_internalValue.get();
+ }
+
+ inline void JSWrapperObject::setInternalValue(JSGlobalData& globalData, JSValue value)
{
ASSERT(value);
ASSERT(!value.isObject());
- m_internalValue = value;
- putAnonymousValue(0, value);
+ m_internalValue.set(globalData, this, value);
}
} // namespace JSC
#include "config.h"
#include "JSZombie.h"
#include "ClassInfo.h"
+#include "JSObject.h"
+#include "ScopeChain.h"
#if ENABLE(JSC_ZOMBIES)
const ClassInfo JSZombie::s_info = { "Zombie", 0, 0, 0 };
-Structure* JSZombie::leakedZombieStructure() {
- static Structure* structure = 0;
- if (!structure) {
- Structure::startIgnoringLeaks();
- structure = Structure::create(jsNull(), TypeInfo(UnspecifiedType)).releaseRef();
- Structure::stopIgnoringLeaks();
- }
- return structure;
-}
-
}
#endif // ENABLE(JSC_ZOMBIES)
#define JSZombie_h
#include "JSCell.h"
+#include "Structure.h"
#if ENABLE(JSC_ZOMBIES)
namespace JSC {
class JSZombie : public JSCell {
public:
- JSZombie(const ClassInfo* oldInfo, Structure* structure)
- : JSCell(structure)
+ JSZombie(JSGlobalData& globalData, const ClassInfo* oldInfo, Structure* structure)
+ : JSCell(globalData, structure)
, m_oldInfo(oldInfo)
{
+ ASSERT(inherits(&s_info));
}
+
virtual bool isZombie() const { return true; }
- virtual const ClassInfo* classInfo() const { return &s_info; }
- static Structure* leakedZombieStructure();
virtual bool isGetterSetter() const { ASSERT_NOT_REACHED(); return false; }
virtual bool isAPIValueWrapper() const { ASSERT_NOT_REACHED(); return false; }
virtual double toNumber(ExecState*) const { ASSERT_NOT_REACHED(); return 0.0; }
virtual UString toString(ExecState*) const { ASSERT_NOT_REACHED(); return ""; }
virtual JSObject* toObject(ExecState*) const { ASSERT_NOT_REACHED(); return 0; }
- virtual void markChildren(MarkStack&) { ASSERT_NOT_REACHED(); }
+ virtual void visitChildren(SlotVisitor&) { ASSERT_NOT_REACHED(); }
virtual void put(ExecState*, const Identifier&, JSValue, PutPropertySlot&) { ASSERT_NOT_REACHED(); }
virtual void put(ExecState*, unsigned, JSValue) { ASSERT_NOT_REACHED(); }
virtual bool deleteProperty(ExecState*, const Identifier&) { ASSERT_NOT_REACHED(); return false; }
virtual bool deleteProperty(ExecState*, unsigned) { ASSERT_NOT_REACHED(); return false; }
virtual JSObject* toThisObject(ExecState*) const { ASSERT_NOT_REACHED(); return 0; }
+ virtual JSValue toStrictThisObject(ExecState*) const { ASSERT_NOT_REACHED(); return JSValue(); }
virtual JSValue getJSNumber() { ASSERT_NOT_REACHED(); return jsNull(); }
virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&) { ASSERT_NOT_REACHED(); return false; }
virtual bool getOwnPropertySlot(ExecState*, unsigned, PropertySlot&) { ASSERT_NOT_REACHED(); return false; }
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
+ {
+ return Structure::create(globalData, prototype, TypeInfo(LeafType, 0), AnonymousSlotCount, &s_info);
+ }
+
static const ClassInfo s_info;
+
private:
const ClassInfo* m_oldInfo;
};
#include "JSArray.h"
#include "JSString.h"
#include "Lexer.h"
-#include "StringBuilder.h"
+#include "UStringBuilder.h"
#include <wtf/ASCIICType.h>
#include <wtf/dtoa.h>
namespace JSC {
-LiteralParser::TokenType LiteralParser::Lexer::lex(LiteralParserToken& token)
+static inline bool isJSONWhiteSpace(const UChar& c)
{
- while (m_ptr < m_end && isASCIISpace(*m_ptr))
+ // The JSON RFC 4627 defines a list of allowed characters to be considered
+ // insignificant white space: http://www.ietf.org/rfc/rfc4627.txt (2. JSON Grammar).
+ return c == ' ' || c == 0x9 || c == 0xA || c == 0xD;
+}
+
+bool LiteralParser::tryJSONPParse(Vector<JSONPData>& results, bool needsFullSourceInfo)
+{
+ if (m_lexer.next() != TokIdentifier)
+ return false;
+ do {
+ Vector<JSONPPathEntry> path;
+ // Unguarded next to start off the lexer
+ Identifier name = Identifier(m_exec, m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start);
+ JSONPPathEntry entry;
+ if (name == m_exec->globalData().propertyNames->varKeyword) {
+ if (m_lexer.next() != TokIdentifier)
+ return false;
+ entry.m_type = JSONPPathEntryTypeDeclare;
+ entry.m_pathEntryName = Identifier(m_exec, m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start);
+ path.append(entry);
+ } else {
+ entry.m_type = JSONPPathEntryTypeDot;
+ entry.m_pathEntryName = Identifier(m_exec, m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start);
+ path.append(entry);
+ }
+ if (m_exec->globalData().lexer->isKeyword(entry.m_pathEntryName))
+ return false;
+ TokenType tokenType = m_lexer.next();
+ while (tokenType != TokAssign) {
+ switch (tokenType) {
+ case TokLBracket: {
+ entry.m_type = JSONPPathEntryTypeLookup;
+ if (m_lexer.next() != TokNumber)
+ return false;
+ double doubleIndex = m_lexer.currentToken().numberToken;
+ int index = (int)doubleIndex;
+ if (index != doubleIndex || index < 0)
+ return false;
+ entry.m_pathIndex = index;
+ if (m_lexer.next() != TokRBracket)
+ return false;
+ break;
+ }
+ case TokDot: {
+ entry.m_type = JSONPPathEntryTypeDot;
+ if (m_lexer.next() != TokIdentifier)
+ return false;
+ entry.m_pathEntryName = Identifier(m_exec, m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start);
+ break;
+ }
+ case TokLParen: {
+ if (path.last().m_type != JSONPPathEntryTypeDot || needsFullSourceInfo)
+ return false;
+ path.last().m_type = JSONPPathEntryTypeCall;
+ entry = path.last();
+ goto startJSON;
+ }
+ default:
+ return false;
+ }
+ path.append(entry);
+ tokenType = m_lexer.next();
+ }
+ startJSON:
+ m_lexer.next();
+ results.append(JSONPData());
+ results.last().m_value.set(m_exec->globalData(), parse(StartParseExpression));
+ if (!results.last().m_value)
+ return false;
+ results.last().m_path.swap(path);
+ if (entry.m_type == JSONPPathEntryTypeCall) {
+ if (m_lexer.currentToken().type != TokRParen)
+ return false;
+ m_lexer.next();
+ }
+ if (m_lexer.currentToken().type != TokSemi)
+ break;
+ m_lexer.next();
+ } while (m_lexer.currentToken().type == TokIdentifier);
+ return m_lexer.currentToken().type == TokEnd;
+}
+
+ALWAYS_INLINE const Identifier LiteralParser::makeIdentifier(const UChar* characters, size_t length)
+{
+ if (!length)
+ return m_exec->globalData().propertyNames->emptyIdentifier;
+ if (characters[0] >= MaximumCachableCharacter)
+ return Identifier(&m_exec->globalData(), characters, length);
+
+ if (length == 1) {
+ if (!m_shortIdentifiers[characters[0]].isNull())
+ return m_shortIdentifiers[characters[0]];
+ m_shortIdentifiers[characters[0]] = Identifier(&m_exec->globalData(), characters, length);
+ return m_shortIdentifiers[characters[0]];
+ }
+ if (!m_recentIdentifiers[characters[0]].isNull() && Identifier::equal(m_recentIdentifiers[characters[0]].impl(), characters, length))
+ return m_recentIdentifiers[characters[0]];
+ m_recentIdentifiers[characters[0]] = Identifier(&m_exec->globalData(), characters, length);
+ return m_recentIdentifiers[characters[0]];
+}
+
+template <LiteralParser::ParserMode mode> LiteralParser::TokenType LiteralParser::Lexer::lex(LiteralParserToken& token)
+{
+ while (m_ptr < m_end && isJSONWhiteSpace(*m_ptr))
++m_ptr;
ASSERT(m_ptr <= m_end);
case '(':
token.type = TokLParen;
token.end = ++m_ptr;
- return TokLBracket;
+ return TokLParen;
case ')':
token.type = TokRParen;
token.end = ++m_ptr;
- return TokRBracket;
+ return TokRParen;
case '{':
token.type = TokLBrace;
token.end = ++m_ptr;
token.end = ++m_ptr;
return TokColon;
case '"':
- if (m_mode == StrictJSON)
- return lexString<StrictJSON>(token);
- return lexString<NonStrictJSON>(token);
+ return lexString<mode, '"'>(token);
case 't':
if (m_end - m_ptr >= 4 && m_ptr[1] == 'r' && m_ptr[2] == 'u' && m_ptr[3] == 'e') {
m_ptr += 4;
token.end = m_ptr;
return TokNull;
}
- break;
+ break;
case '-':
case '0':
case '1':
case '9':
return lexNumber(token);
}
+ if (m_ptr < m_end) {
+ if (*m_ptr == '.') {
+ token.type = TokDot;
+ token.end = ++m_ptr;
+ return TokDot;
+ }
+ if (*m_ptr == '=') {
+ token.type = TokAssign;
+ token.end = ++m_ptr;
+ return TokAssign;
+ }
+ if (*m_ptr == ';') {
+ token.type = TokSemi;
+ token.end = ++m_ptr;
+ return TokAssign;
+ }
+ if (isASCIIAlpha(*m_ptr) || *m_ptr == '_' || *m_ptr == '$') {
+ while (m_ptr < m_end && (isASCIIAlphanumeric(*m_ptr) || *m_ptr == '_' || *m_ptr == '$'))
+ m_ptr++;
+ token.stringToken = token.start;
+ token.stringLength = m_ptr - token.start;
+ token.type = TokIdentifier;
+ token.end = m_ptr;
+ return TokIdentifier;
+ }
+ if (*m_ptr == '\'') {
+ if (mode == StrictJSON)
+ return TokError;
+ return lexString<mode, '\''>(token);
+ }
+ }
return TokError;
}
-template <LiteralParser::ParserMode mode> static inline bool isSafeStringCharacter(UChar c)
+LiteralParser::TokenType LiteralParser::Lexer::next()
+{
+ if (m_mode == NonStrictJSON)
+ return lex<NonStrictJSON>(m_currentToken);
+ if (m_mode == JSONP)
+ return lex<JSONP>(m_currentToken);
+ return lex<StrictJSON>(m_currentToken);
+}
+
+template <LiteralParser::ParserMode mode, UChar terminator> static inline bool isSafeStringCharacter(UChar c)
{
- return (c >= ' ' && (mode == LiteralParser::StrictJSON || c <= 0xff) && c != '\\' && c != '"') || c == '\t';
+ return (c >= ' ' && (mode == LiteralParser::StrictJSON || c <= 0xff) && c != '\\' && c != terminator) || c == '\t';
}
// "inline" is required here to help WINSCW compiler resolve specialized argument in templated functions.
-template <LiteralParser::ParserMode mode> inline LiteralParser::TokenType LiteralParser::Lexer::lexString(LiteralParserToken& token)
+template <LiteralParser::ParserMode mode, UChar terminator> inline LiteralParser::TokenType LiteralParser::Lexer::lexString(LiteralParserToken& token)
{
++m_ptr;
- const UChar* runStart;
- StringBuilder builder;
+ const UChar* runStart = m_ptr;
+ UStringBuilder builder;
do {
runStart = m_ptr;
- while (m_ptr < m_end && isSafeStringCharacter<mode>(*m_ptr))
+ while (m_ptr < m_end && isSafeStringCharacter<mode, terminator>(*m_ptr))
++m_ptr;
- if (runStart < m_ptr)
+ if (builder.length())
builder.append(runStart, m_ptr - runStart);
- if ((mode == StrictJSON) && m_ptr < m_end && *m_ptr == '\\') {
+ if ((mode != NonStrictJSON) && m_ptr < m_end && *m_ptr == '\\') {
+ if (builder.isEmpty() && runStart < m_ptr)
+ builder.append(runStart, m_ptr - runStart);
++m_ptr;
if (m_ptr >= m_end)
return TokError;
break;
default:
+ if (*m_ptr == '\'' && mode != StrictJSON) {
+ builder.append('\'');
+ m_ptr++;
+ break;
+ }
return TokError;
}
}
- } while ((mode == StrictJSON) && m_ptr != runStart && (m_ptr < m_end) && *m_ptr != '"');
+ } while ((mode != NonStrictJSON) && m_ptr != runStart && (m_ptr < m_end) && *m_ptr != terminator);
- if (m_ptr >= m_end || *m_ptr != '"')
+ if (m_ptr >= m_end || *m_ptr != terminator)
return TokError;
- token.stringToken = builder.build();
+ if (builder.isEmpty()) {
+ token.stringBuffer = UString();
+ token.stringToken = runStart;
+ token.stringLength = m_ptr - runStart;
+ } else {
+ token.stringBuffer = builder.toUString();
+ token.stringToken = token.stringBuffer.characters();
+ token.stringLength = token.stringBuffer.length();
+ }
token.type = TokString;
token.end = ++m_ptr;
return TokString;
++m_ptr;
while (m_ptr < m_end && isASCIIDigit(*m_ptr))
++m_ptr;
+ } else if (m_ptr < m_end && (*m_ptr != 'e' && *m_ptr != 'E') && (m_ptr - token.start) < 10) {
+ int result = 0;
+ token.type = TokNumber;
+ token.end = m_ptr;
+ const UChar* digit = token.start;
+ int negative = 1;
+ if (*digit == '-') {
+ negative = -1;
+ digit++;
+ }
+
+ while (digit < m_ptr)
+ result = result * 10 + (*digit++) - '0';
+ result *= negative;
+ token.numberToken = result;
+ return TokNumber;
}
// ([eE][+-]? [0-9]+)?
objectStack.append(object);
TokenType type = m_lexer.next();
- if (type == TokString) {
+ if (type == TokString || (m_mode != StrictJSON && type == TokIdentifier)) {
Lexer::LiteralParserToken identifierToken = m_lexer.currentToken();
// Check for colon
return JSValue();
m_lexer.next();
- identifierStack.append(Identifier(m_exec, identifierToken.stringToken));
+ identifierStack.append(makeIdentifier(identifierToken.stringToken, identifierToken.stringLength));
stateStack.append(DoParseObjectEndExpression);
goto startParseExpression;
- } else if (type != TokRBrace)
+ }
+ if (type != TokRBrace)
return JSValue();
m_lexer.next();
lastValue = objectStack.last();
doParseObjectStartExpression:
case DoParseObjectStartExpression: {
TokenType type = m_lexer.next();
- if (type != TokString)
+ if (type != TokString && (m_mode == StrictJSON || type != TokIdentifier))
return JSValue();
Lexer::LiteralParserToken identifierToken = m_lexer.currentToken();
return JSValue();
m_lexer.next();
- identifierStack.append(Identifier(m_exec, identifierToken.stringToken));
+ identifierStack.append(makeIdentifier(identifierToken.stringToken, identifierToken.stringLength));
stateStack.append(DoParseObjectEndExpression);
goto startParseExpression;
}
case DoParseObjectEndExpression:
{
- asObject(objectStack.last())->putDirect(identifierStack.last(), lastValue);
+ asObject(objectStack.last())->putDirect(m_exec->globalData(), identifierStack.last(), lastValue);
identifierStack.removeLast();
if (m_lexer.currentToken().type == TokComma)
goto doParseObjectStartExpression;
case TokString: {
Lexer::LiteralParserToken stringToken = m_lexer.currentToken();
m_lexer.next();
- lastValue = jsString(m_exec, stringToken.stringToken);
+ lastValue = jsString(m_exec, makeIdentifier(stringToken.stringToken, stringToken.stringLength).ustring());
break;
}
case TokNumber: {
Lexer::LiteralParserToken numberToken = m_lexer.currentToken();
m_lexer.next();
- lastValue = jsNumber(m_exec, numberToken.numberToken);
+ lastValue = jsNumber(numberToken.numberToken);
break;
}
case TokNull:
#ifndef LiteralParser_h
#define LiteralParser_h
+#include "Identifier.h"
#include "JSGlobalObjectFunctions.h"
#include "JSValue.h"
#include "UString.h"
class LiteralParser {
public:
- typedef enum { StrictJSON, NonStrictJSON } ParserMode;
- LiteralParser(ExecState* exec, const UString& s, ParserMode mode)
+ typedef enum { StrictJSON, NonStrictJSON, JSONP } ParserMode;
+ LiteralParser(ExecState* exec, const UChar* characters, unsigned length, ParserMode mode)
: m_exec(exec)
- , m_lexer(s, mode)
+ , m_lexer(characters, length, mode)
, m_mode(mode)
{
}
{
m_lexer.next();
JSValue result = parse(m_mode == StrictJSON ? StartParseExpression : StartParseStatement);
+ if (m_lexer.currentToken().type == TokSemi)
+ m_lexer.next();
if (m_lexer.currentToken().type != TokEnd)
return JSValue();
return result;
}
+
+ enum JSONPPathEntryType {
+ JSONPPathEntryTypeDeclare, // var pathEntryName = JSON
+ JSONPPathEntryTypeDot, // <prior entries>.pathEntryName = JSON
+ JSONPPathEntryTypeLookup, // <prior entries>[pathIndex] = JSON
+ JSONPPathEntryTypeCall // <prior entries>(JSON)
+ };
+
+ struct JSONPPathEntry {
+ JSONPPathEntryType m_type;
+ Identifier m_pathEntryName;
+ int m_pathIndex;
+ };
+
+ struct JSONPData {
+ Vector<JSONPPathEntry> m_path;
+ Strong<Unknown> m_value;
+ };
+
+ bool tryJSONPParse(Vector<JSONPData>&, bool needsFullSourceInfo);
+
private:
enum ParserState { StartParseObject, StartParseArray, StartParseExpression,
StartParseStatement, StartParseStatementEndStatement,
enum TokenType { TokLBracket, TokRBracket, TokLBrace, TokRBrace,
TokString, TokIdentifier, TokNumber, TokColon,
TokLParen, TokRParen, TokComma, TokTrue, TokFalse,
- TokNull, TokEnd, TokError };
-
+ TokNull, TokEnd, TokDot, TokAssign, TokSemi, TokError };
+
class Lexer {
public:
struct LiteralParserToken {
TokenType type;
const UChar* start;
const UChar* end;
- UString stringToken;
- double numberToken;
+ UString stringBuffer;
+ union {
+ double numberToken;
+ struct {
+ const UChar* stringToken;
+ int stringLength;
+ };
+ };
};
- Lexer(const UString& s, ParserMode mode)
- : m_string(s)
- , m_mode(mode)
- , m_ptr(s.data())
- , m_end(s.data() + s.size())
+ Lexer(const UChar* characters, unsigned length, ParserMode mode)
+ : m_mode(mode)
+ , m_ptr(characters)
+ , m_end(characters + length)
{
}
- TokenType next()
- {
- return lex(m_currentToken);
- }
+ TokenType next();
const LiteralParserToken& currentToken()
{
}
private:
- TokenType lex(LiteralParserToken&);
- template <ParserMode mode> TokenType lexString(LiteralParserToken&);
- TokenType lexNumber(LiteralParserToken&);
+ template <ParserMode mode> TokenType lex(LiteralParserToken&);
+ template <ParserMode mode, UChar terminator> ALWAYS_INLINE TokenType lexString(LiteralParserToken&);
+ ALWAYS_INLINE TokenType lexNumber(LiteralParserToken&);
LiteralParserToken m_currentToken;
UString m_string;
ParserMode m_mode;
ExecState* m_exec;
LiteralParser::Lexer m_lexer;
ParserMode m_mode;
+ static unsigned const MaximumCachableCharacter = 128;
+ FixedArray<Identifier, MaximumCachableCharacter> m_shortIdentifiers;
+ FixedArray<Identifier, MaximumCachableCharacter> m_recentIdentifiers;
+ ALWAYS_INLINE const Identifier makeIdentifier(const UChar* characters, size_t length);
};
+
}
#endif
#include "config.h"
#include "Lookup.h"
+#include "Executable.h"
#include "JSFunction.h"
-#include "PrototypeFunction.h"
namespace JSC {
for (int i = 0; i < compactSize; ++i)
entries[i].setKey(0);
for (int i = 0; values[i].key; ++i) {
- UString::Rep* identifier = Identifier::add(globalData, values[i].key).releaseRef();
+ StringImpl* identifier = Identifier::add(globalData, values[i].key).leakRef();
int hashIndex = identifier->existingHash() & compactHashSizeMask;
HashEntry* entry = &entries[hashIndex];
if (table) {
int max = compactSize;
for (int i = 0; i != max; ++i) {
- if (UString::Rep* key = table[i].key())
+ if (StringImpl* key = table[i].key())
key->deref();
}
delete [] table;
void setUpStaticFunctionSlot(ExecState* exec, const HashEntry* entry, JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot)
{
+ ASSERT(thisObj->structure()->anonymousSlotCount() > 0);
+ ASSERT(thisObj->getAnonymousValue(0).isCell() && asObject(thisObj->getAnonymousValue(0).asCell())->isGlobalObject());
ASSERT(entry->attributes() & Function);
- JSValue* location = thisObj->getDirectLocation(propertyName);
+ WriteBarrierBase<Unknown>* location = thisObj->getDirectLocation(exec->globalData(), propertyName);
if (!location) {
- InternalFunction* function;
+ JSFunction* function;
+ JSGlobalObject* globalObject = asGlobalObject(thisObj->getAnonymousValue(0).asCell());
#if ENABLE(JIT) && ENABLE(JIT_OPTIMIZE_NATIVE_CALL)
if (entry->generator())
- function = new (exec) NativeFunctionWrapper(exec, exec->lexicalGlobalObject()->prototypeFunctionStructure(), entry->functionLength(), propertyName, exec->globalData().getThunk(entry->generator()), entry->function());
+ function = new (exec) JSFunction(exec, globalObject, globalObject->functionStructure(), entry->functionLength(), propertyName, exec->globalData().getHostFunction(entry->function(), entry->generator()));
else
#endif
- function = new (exec) NativeFunctionWrapper(exec, exec->lexicalGlobalObject()->prototypeFunctionStructure(), entry->functionLength(), propertyName, entry->function());
+ function = new (exec) JSFunction(exec, globalObject, globalObject->functionStructure(), entry->functionLength(), propertyName, entry->function());
- thisObj->putDirectFunction(propertyName, function, entry->attributes());
- location = thisObj->getDirectLocation(propertyName);
+ thisObj->putDirectFunction(exec->globalData(), propertyName, function, entry->attributes());
+ location = thisObj->getDirectLocation(exec->globalData(), propertyName);
}
- slot.setValueSlot(thisObj, location, thisObj->offsetForLocation(location));
+ slot.setValue(thisObj, location->get(), thisObj->offsetForLocation(location));
}
} // namespace JSC
typedef PropertySlot::GetValueFunc GetFunction;
typedef void (*PutFunction)(ExecState*, JSObject* baseObject, JSValue value);
- class HashEntry : public FastAllocBase {
+ class HashEntry {
+ WTF_MAKE_FAST_ALLOCATED;
public:
- void initialize(UString::Rep* key, unsigned char attributes, intptr_t v1, intptr_t v2
+ void initialize(StringImpl* key, unsigned char attributes, intptr_t v1, intptr_t v2
#if ENABLE(JIT)
, ThunkGenerator generator = 0
#endif
m_next = 0;
}
- void setKey(UString::Rep* key) { m_key = key; }
- UString::Rep* key() const { return m_key; }
+ void setKey(StringImpl* key) { m_key = key; }
+ StringImpl* key() const { return m_key; }
unsigned char attributes() const { return m_attributes; }
-#if ENABLE(JIT)
+#if ENABLE(JIT) && ENABLE(JIT_OPTIMIZE_NATIVE_CALL)
ThunkGenerator generator() const { ASSERT(m_attributes & Function); return m_u.function.generator; }
#endif
NativeFunction function() const { ASSERT(m_attributes & Function); return m_u.function.functionValue; }
HashEntry* next() const { return m_next; }
private:
- UString::Rep* m_key;
+ StringImpl* m_key;
unsigned char m_attributes; // JSObject attributes
union {
{
ASSERT(table);
- const HashEntry* entry = &table[identifier.ustring().rep()->existingHash() & compactHashSizeMask];
+ const HashEntry* entry = &table[identifier.impl()->existingHash() & compactHashSizeMask];
if (!entry->key())
return 0;
do {
- if (entry->key() == identifier.ustring().rep())
+ if (entry->key() == identifier.impl())
return entry;
entry = entry->next();
} while (entry);
if (entry->attributes() & Function) { // function: put as override property
if (LIKELY(value.isCell()))
- thisObj->putDirectFunction(propertyName, value.asCell());
+ thisObj->putDirectFunction(exec->globalData(), propertyName, value.asCell());
else
- thisObj->putDirect(propertyName, value);
+ thisObj->putDirect(exec->globalData(), propertyName, value);
} else if (!(entry->attributes() & ReadOnly))
entry->propertyPutter()(exec, thisObj, value);
+++ /dev/null
-/*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "MarkStack.h"
-
-namespace JSC {
-
-size_t MarkStack::s_pageSize = 0;
-
-void MarkStack::compact()
-{
- ASSERT(s_pageSize);
- m_values.shrinkAllocation(s_pageSize);
- m_markSets.shrinkAllocation(s_pageSize);
-}
-
-}
+++ /dev/null
-/*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef MarkStack_h
-#define MarkStack_h
-
-#include "JSValue.h"
-#include <wtf/Noncopyable.h>
-
-namespace JSC {
-
- class JSGlobalData;
- class Register;
-
- enum MarkSetProperties { MayContainNullValues, NoNullValues };
-
- class MarkStack : Noncopyable {
- public:
- MarkStack(void* jsArrayVPtr)
- : m_jsArrayVPtr(jsArrayVPtr)
-#ifndef NDEBUG
- , m_isCheckingForDefaultMarkViolation(false)
-#endif
- {
- }
-
- ALWAYS_INLINE void append(JSValue);
- void append(JSCell*);
-
- ALWAYS_INLINE void appendValues(Register* values, size_t count, MarkSetProperties properties = NoNullValues)
- {
- appendValues(reinterpret_cast<JSValue*>(values), count, properties);
- }
-
- ALWAYS_INLINE void appendValues(JSValue* values, size_t count, MarkSetProperties properties = NoNullValues)
- {
- if (count)
- m_markSets.append(MarkSet(values, values + count, properties));
- }
-
- inline void drain();
- void compact();
-
- ~MarkStack()
- {
- ASSERT(m_markSets.isEmpty());
- ASSERT(m_values.isEmpty());
- }
-
- private:
- void markChildren(JSCell*);
-
- struct MarkSet {
- MarkSet(JSValue* values, JSValue* end, MarkSetProperties properties)
- : m_values(values)
- , m_end(end)
- , m_properties(properties)
- {
- ASSERT(values);
- }
- JSValue* m_values;
- JSValue* m_end;
- MarkSetProperties m_properties;
- };
-
- static void* allocateStack(size_t size);
- static void releaseStack(void* addr, size_t size);
-
- static void initializePagesize();
- static size_t pageSize()
- {
- if (!s_pageSize)
- initializePagesize();
- return s_pageSize;
- }
-
- template <typename T> struct MarkStackArray {
- MarkStackArray()
- : m_top(0)
- , m_allocated(MarkStack::pageSize())
- , m_capacity(m_allocated / sizeof(T))
- {
- m_data = reinterpret_cast<T*>(allocateStack(m_allocated));
- }
-
- ~MarkStackArray()
- {
- releaseStack(m_data, m_allocated);
- }
-
- void expand()
- {
- size_t oldAllocation = m_allocated;
- m_allocated *= 2;
- m_capacity = m_allocated / sizeof(T);
- void* newData = allocateStack(m_allocated);
- memcpy(newData, m_data, oldAllocation);
- releaseStack(m_data, oldAllocation);
- m_data = reinterpret_cast<T*>(newData);
- }
-
- inline void append(const T& v)
- {
- if (m_top == m_capacity)
- expand();
- m_data[m_top++] = v;
- }
-
- inline T removeLast()
- {
- ASSERT(m_top);
- return m_data[--m_top];
- }
-
- inline T& last()
- {
- ASSERT(m_top);
- return m_data[m_top - 1];
- }
-
- inline bool isEmpty()
- {
- return m_top == 0;
- }
-
- inline size_t size() { return m_top; }
-
- inline void shrinkAllocation(size_t size)
- {
- ASSERT(size <= m_allocated);
- ASSERT(0 == (size % MarkStack::pageSize()));
- if (size == m_allocated)
- return;
-#if OS(WINDOWS) || OS(SYMBIAN) || PLATFORM(BREWMP)
- // We cannot release a part of a region with VirtualFree. To get around this,
- // we'll release the entire region and reallocate the size that we want.
- releaseStack(m_data, m_allocated);
- m_data = reinterpret_cast<T*>(allocateStack(size));
-#else
- releaseStack(reinterpret_cast<char*>(m_data) + size, m_allocated - size);
-#endif
- m_allocated = size;
- m_capacity = m_allocated / sizeof(T);
- }
-
- private:
- size_t m_top;
- size_t m_allocated;
- size_t m_capacity;
- T* m_data;
- };
-
- void* m_jsArrayVPtr;
- MarkStackArray<MarkSet> m_markSets;
- MarkStackArray<JSCell*> m_values;
- static size_t s_pageSize;
-
-#ifndef NDEBUG
- public:
- bool m_isCheckingForDefaultMarkViolation;
-#endif
- };
-}
-
-#endif
+++ /dev/null
-/*
- * Copyright (C) 2009 Company 100, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-
-#include "MarkStack.h"
-
-#include "FastMalloc.h"
-
-namespace JSC {
-
-void MarkStack::initializePagesize()
-{
- MarkStack::s_pageSize = 4096;
-}
-
-void* MarkStack::allocateStack(size_t size)
-{
- return fastMalloc(size);
-}
-
-void MarkStack::releaseStack(void* addr, size_t)
-{
- return fastFree(addr);
-}
-
-}
+++ /dev/null
-/*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "MarkStack.h"
-
-#if OS(UNIX) && !OS(SYMBIAN)
-
-#include <unistd.h>
-#include <sys/mman.h>
-
-namespace JSC {
-
-void MarkStack::initializePagesize()
-{
- MarkStack::s_pageSize = getpagesize();
-}
-
-void* MarkStack::allocateStack(size_t size)
-{
- return mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
-}
-void MarkStack::releaseStack(void* addr, size_t size)
-{
- munmap(addr, size);
-}
-
-}
-
-#endif
+++ /dev/null
-/*
- Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
-
- 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 "MarkStack.h"
-
-#if OS(SYMBIAN)
-
-#include <e32hal.h>
-
-namespace JSC {
-
-void MarkStack::initializePagesize()
-{
- TInt page_size;
- UserHal::PageSizeInBytes(page_size);
- MarkStack::s_pageSize = page_size;
-}
-
-void* MarkStack::allocateStack(size_t size)
-{
- return fastMalloc(size);
-}
-
-void MarkStack::releaseStack(void* addr, size_t size)
-{
- return fastFree(addr);
-}
-
-}
-
-#endif
+++ /dev/null
-/*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "MarkStack.h"
-
-#if OS(WINDOWS)
-
-#include "windows.h"
-
-namespace JSC {
-
-void MarkStack::initializePagesize()
-{
- SYSTEM_INFO system_info;
- GetSystemInfo(&system_info);
- MarkStack::s_pageSize = system_info.dwPageSize;
-}
-
-void* MarkStack::allocateStack(size_t size)
-{
- return VirtualAlloc(0, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
-}
-void MarkStack::releaseStack(void* addr, size_t)
-{
- // According to http://msdn.microsoft.com/en-us/library/aa366892(VS.85).aspx,
- // dwSize must be 0 if dwFreeType is MEM_RELEASE.
- VirtualFree(addr, 0, MEM_RELEASE);
-}
-
-}
-
-#endif
ASSERT_CLASS_FITS_IN_CELL(MathObject);
-static JSValue JSC_HOST_CALL mathProtoFuncAbs(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL mathProtoFuncACos(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL mathProtoFuncASin(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL mathProtoFuncATan(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL mathProtoFuncATan2(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL mathProtoFuncCeil(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL mathProtoFuncCos(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL mathProtoFuncExp(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL mathProtoFuncFloor(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL mathProtoFuncLog(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL mathProtoFuncMax(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL mathProtoFuncMin(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL mathProtoFuncPow(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL mathProtoFuncRandom(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL mathProtoFuncRound(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL mathProtoFuncSin(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL mathProtoFuncSqrt(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL mathProtoFuncTan(ExecState*, JSObject*, JSValue, const ArgList&);
+static EncodedJSValue JSC_HOST_CALL mathProtoFuncAbs(ExecState*);
+static EncodedJSValue JSC_HOST_CALL mathProtoFuncACos(ExecState*);
+static EncodedJSValue JSC_HOST_CALL mathProtoFuncASin(ExecState*);
+static EncodedJSValue JSC_HOST_CALL mathProtoFuncATan(ExecState*);
+static EncodedJSValue JSC_HOST_CALL mathProtoFuncATan2(ExecState*);
+static EncodedJSValue JSC_HOST_CALL mathProtoFuncCeil(ExecState*);
+static EncodedJSValue JSC_HOST_CALL mathProtoFuncCos(ExecState*);
+static EncodedJSValue JSC_HOST_CALL mathProtoFuncExp(ExecState*);
+static EncodedJSValue JSC_HOST_CALL mathProtoFuncFloor(ExecState*);
+static EncodedJSValue JSC_HOST_CALL mathProtoFuncLog(ExecState*);
+static EncodedJSValue JSC_HOST_CALL mathProtoFuncMax(ExecState*);
+static EncodedJSValue JSC_HOST_CALL mathProtoFuncMin(ExecState*);
+static EncodedJSValue JSC_HOST_CALL mathProtoFuncPow(ExecState*);
+static EncodedJSValue JSC_HOST_CALL mathProtoFuncRandom(ExecState*);
+static EncodedJSValue JSC_HOST_CALL mathProtoFuncRound(ExecState*);
+static EncodedJSValue JSC_HOST_CALL mathProtoFuncSin(ExecState*);
+static EncodedJSValue JSC_HOST_CALL mathProtoFuncSqrt(ExecState*);
+static EncodedJSValue JSC_HOST_CALL mathProtoFuncTan(ExecState*);
}
namespace JSC {
-// ------------------------------ MathObject --------------------------------
-
-const ClassInfo MathObject::info = { "Math", 0, 0, ExecState::mathTable };
+const ClassInfo MathObject::s_info = { "Math", &JSObjectWithGlobalObject::s_info, 0, ExecState::mathTable };
/* Source for MathObject.lut.h
@begin mathTable
@end
*/
-MathObject::MathObject(ExecState* exec, NonNullPassRefPtr<Structure> structure)
- : JSObject(structure)
+MathObject::MathObject(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
+ : JSObjectWithGlobalObject(globalObject, structure)
{
- putDirectWithoutTransition(Identifier(exec, "E"), jsNumber(exec, exp(1.0)), DontDelete | DontEnum | ReadOnly);
- putDirectWithoutTransition(Identifier(exec, "LN2"), jsNumber(exec, log(2.0)), DontDelete | DontEnum | ReadOnly);
- putDirectWithoutTransition(Identifier(exec, "LN10"), jsNumber(exec, log(10.0)), DontDelete | DontEnum | ReadOnly);
- putDirectWithoutTransition(Identifier(exec, "LOG2E"), jsNumber(exec, 1.0 / log(2.0)), DontDelete | DontEnum | ReadOnly);
- putDirectWithoutTransition(Identifier(exec, "LOG10E"), jsNumber(exec, 1.0 / log(10.0)), DontDelete | DontEnum | ReadOnly);
- putDirectWithoutTransition(Identifier(exec, "PI"), jsNumber(exec, piDouble), DontDelete | DontEnum | ReadOnly);
- putDirectWithoutTransition(Identifier(exec, "SQRT1_2"), jsNumber(exec, sqrt(0.5)), DontDelete | DontEnum | ReadOnly);
- putDirectWithoutTransition(Identifier(exec, "SQRT2"), jsNumber(exec, sqrt(2.0)), DontDelete | DontEnum | ReadOnly);
-}
+ ASSERT(inherits(&s_info));
-// ECMA 15.8
+ putDirectWithoutTransition(exec->globalData(), Identifier(exec, "E"), jsNumber(exp(1.0)), DontDelete | DontEnum | ReadOnly);
+ putDirectWithoutTransition(exec->globalData(), Identifier(exec, "LN2"), jsNumber(log(2.0)), DontDelete | DontEnum | ReadOnly);
+ putDirectWithoutTransition(exec->globalData(), Identifier(exec, "LN10"), jsNumber(log(10.0)), DontDelete | DontEnum | ReadOnly);
+ putDirectWithoutTransition(exec->globalData(), Identifier(exec, "LOG2E"), jsNumber(1.0 / log(2.0)), DontDelete | DontEnum | ReadOnly);
+ putDirectWithoutTransition(exec->globalData(), Identifier(exec, "LOG10E"), jsNumber(0.4342944819032518), DontDelete | DontEnum | ReadOnly); // See ECMA-262 15.8.1.5
+ putDirectWithoutTransition(exec->globalData(), Identifier(exec, "PI"), jsNumber(piDouble), DontDelete | DontEnum | ReadOnly);
+ putDirectWithoutTransition(exec->globalData(), Identifier(exec, "SQRT1_2"), jsNumber(sqrt(0.5)), DontDelete | DontEnum | ReadOnly);
+ putDirectWithoutTransition(exec->globalData(), Identifier(exec, "SQRT2"), jsNumber(sqrt(2.0)), DontDelete | DontEnum | ReadOnly);
+}
bool MathObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot &slot)
{
// ------------------------------ Functions --------------------------------
-JSValue JSC_HOST_CALL mathProtoFuncAbs(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL mathProtoFuncAbs(ExecState* exec)
{
- return jsNumber(exec, fabs(args.at(0).toNumber(exec)));
+ return JSValue::encode(jsNumber(fabs(exec->argument(0).toNumber(exec))));
}
-JSValue JSC_HOST_CALL mathProtoFuncACos(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL mathProtoFuncACos(ExecState* exec)
{
- return jsDoubleNumber(exec, acos(args.at(0).toNumber(exec)));
+ return JSValue::encode(jsDoubleNumber(acos(exec->argument(0).toNumber(exec))));
}
-JSValue JSC_HOST_CALL mathProtoFuncASin(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL mathProtoFuncASin(ExecState* exec)
{
- return jsDoubleNumber(exec, asin(args.at(0).toNumber(exec)));
+ return JSValue::encode(jsDoubleNumber(asin(exec->argument(0).toNumber(exec))));
}
-JSValue JSC_HOST_CALL mathProtoFuncATan(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL mathProtoFuncATan(ExecState* exec)
{
- return jsDoubleNumber(exec, atan(args.at(0).toNumber(exec)));
+ return JSValue::encode(jsDoubleNumber(atan(exec->argument(0).toNumber(exec))));
}
-JSValue JSC_HOST_CALL mathProtoFuncATan2(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL mathProtoFuncATan2(ExecState* exec)
{
- return jsDoubleNumber(exec, atan2(args.at(0).toNumber(exec), args.at(1).toNumber(exec)));
+ double arg0 = exec->argument(0).toNumber(exec);
+ double arg1 = exec->argument(1).toNumber(exec);
+ return JSValue::encode(jsDoubleNumber(atan2(arg0, arg1)));
}
-JSValue JSC_HOST_CALL mathProtoFuncCeil(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL mathProtoFuncCeil(ExecState* exec)
{
- return jsNumber(exec, ceil(args.at(0).toNumber(exec)));
+ return JSValue::encode(jsNumber(ceil(exec->argument(0).toNumber(exec))));
}
-JSValue JSC_HOST_CALL mathProtoFuncCos(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL mathProtoFuncCos(ExecState* exec)
{
- return jsDoubleNumber(exec, cos(args.at(0).toNumber(exec)));
+ return JSValue::encode(jsDoubleNumber(cos(exec->argument(0).toNumber(exec))));
}
-JSValue JSC_HOST_CALL mathProtoFuncExp(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL mathProtoFuncExp(ExecState* exec)
{
- return jsDoubleNumber(exec, exp(args.at(0).toNumber(exec)));
+ return JSValue::encode(jsDoubleNumber(exp(exec->argument(0).toNumber(exec))));
}
-JSValue JSC_HOST_CALL mathProtoFuncFloor(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL mathProtoFuncFloor(ExecState* exec)
{
- return jsNumber(exec, floor(args.at(0).toNumber(exec)));
+ return JSValue::encode(jsNumber(floor(exec->argument(0).toNumber(exec))));
}
-JSValue JSC_HOST_CALL mathProtoFuncLog(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL mathProtoFuncLog(ExecState* exec)
{
- return jsDoubleNumber(exec, log(args.at(0).toNumber(exec)));
+ return JSValue::encode(jsDoubleNumber(log(exec->argument(0).toNumber(exec))));
}
-JSValue JSC_HOST_CALL mathProtoFuncMax(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL mathProtoFuncMax(ExecState* exec)
{
- unsigned argsCount = args.size();
+ unsigned argsCount = exec->argumentCount();
double result = -Inf;
for (unsigned k = 0; k < argsCount; ++k) {
- double val = args.at(k).toNumber(exec);
+ double val = exec->argument(k).toNumber(exec);
if (isnan(val)) {
result = NaN;
break;
if (val > result || (val == 0 && result == 0 && !signbit(val)))
result = val;
}
- return jsNumber(exec, result);
+ return JSValue::encode(jsNumber(result));
}
-JSValue JSC_HOST_CALL mathProtoFuncMin(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL mathProtoFuncMin(ExecState* exec)
{
- unsigned argsCount = args.size();
+ unsigned argsCount = exec->argumentCount();
double result = +Inf;
for (unsigned k = 0; k < argsCount; ++k) {
- double val = args.at(k).toNumber(exec);
+ double val = exec->argument(k).toNumber(exec);
if (isnan(val)) {
result = NaN;
break;
if (val < result || (val == 0 && result == 0 && signbit(val)))
result = val;
}
- return jsNumber(exec, result);
+ return JSValue::encode(jsNumber(result));
}
-JSValue JSC_HOST_CALL mathProtoFuncPow(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL mathProtoFuncPow(ExecState* exec)
{
// ECMA 15.8.2.1.13
- double arg = args.at(0).toNumber(exec);
- double arg2 = args.at(1).toNumber(exec);
+ double arg = exec->argument(0).toNumber(exec);
+ double arg2 = exec->argument(1).toNumber(exec);
if (isnan(arg2))
- return jsNaN(exec);
+ return JSValue::encode(jsNaN());
if (isinf(arg2) && fabs(arg) == 1)
- return jsNaN(exec);
- return jsNumber(exec, pow(arg, arg2));
+ return JSValue::encode(jsNaN());
+ return JSValue::encode(jsNumber(pow(arg, arg2)));
}
-JSValue JSC_HOST_CALL mathProtoFuncRandom(ExecState* exec, JSObject*, JSValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL mathProtoFuncRandom(ExecState* exec)
{
- return jsDoubleNumber(exec, exec->lexicalGlobalObject()->weakRandomNumber());
+ return JSValue::encode(jsDoubleNumber(exec->lexicalGlobalObject()->weakRandomNumber()));
}
-JSValue JSC_HOST_CALL mathProtoFuncRound(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL mathProtoFuncRound(ExecState* exec)
{
- double arg = args.at(0).toNumber(exec);
+ double arg = exec->argument(0).toNumber(exec);
double integer = ceil(arg);
- return jsNumber(exec, integer - (integer - arg > 0.5));
+ return JSValue::encode(jsNumber(integer - (integer - arg > 0.5)));
}
-JSValue JSC_HOST_CALL mathProtoFuncSin(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL mathProtoFuncSin(ExecState* exec)
{
- return exec->globalData().cachedSin(exec, args.at(0).toNumber(exec));
+ return JSValue::encode(exec->globalData().cachedSin(exec->argument(0).toNumber(exec)));
}
-JSValue JSC_HOST_CALL mathProtoFuncSqrt(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL mathProtoFuncSqrt(ExecState* exec)
{
- return jsDoubleNumber(exec, sqrt(args.at(0).toNumber(exec)));
+ return JSValue::encode(jsDoubleNumber(sqrt(exec->argument(0).toNumber(exec))));
}
-JSValue JSC_HOST_CALL mathProtoFuncTan(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL mathProtoFuncTan(ExecState* exec)
{
- return jsDoubleNumber(exec, tan(args.at(0).toNumber(exec)));
+ return JSValue::encode(jsDoubleNumber(tan(exec->argument(0).toNumber(exec))));
}
} // namespace JSC
#ifndef MathObject_h
#define MathObject_h
-#include "JSObject.h"
+#include "JSObjectWithGlobalObject.h"
namespace JSC {
- class MathObject : public JSObject {
+ class MathObject : public JSObjectWithGlobalObject {
public:
- MathObject(ExecState*, NonNullPassRefPtr<Structure>);
+ MathObject(ExecState*, JSGlobalObject*, Structure*);
virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
- virtual const ClassInfo* classInfo() const { return &info; }
- static const ClassInfo info;
+ static const ClassInfo s_info;
- static PassRefPtr<Structure> createStructure(JSValue prototype)
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
+ return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
}
protected:
--- /dev/null
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "MemoryStatistics.h"
+
+#include "ExecutableAllocator.h"
+#include "JSGlobalData.h"
+#include "RegisterFile.h"
+
+namespace JSC {
+
+GlobalMemoryStatistics globalMemoryStatistics()
+{
+ GlobalMemoryStatistics stats;
+
+ stats.stackBytes = RegisterFile::committedByteCount();
+#if ENABLE(EXECUTABLE_ALLOCATOR_FIXED)
+ stats.JITBytes = ExecutableAllocator::committedByteCount();
+#else
+ stats.JITBytes = 0;
+#endif
+ return stats;
+}
+
+}
+
+
--- /dev/null
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MemoryStatistics_h
+#define MemoryStatistics_h
+
+#include "Heap.h"
+
+class JSGlobalData;
+
+namespace JSC {
+
+struct GlobalMemoryStatistics {
+ size_t stackBytes;
+ size_t JITBytes;
+};
+
+GlobalMemoryStatistics globalMemoryStatistics();
+
+}
+
+#endif // MemoryStatistics_h
+
ASSERT_CLASS_FITS_IN_CELL(NativeErrorConstructor);
-const ClassInfo NativeErrorConstructor::info = { "Function", &InternalFunction::info, 0, 0 };
+const ClassInfo NativeErrorConstructor::s_info = { "Function", &InternalFunction::s_info, 0, 0 };
-NativeErrorConstructor::NativeErrorConstructor(ExecState* exec, NonNullPassRefPtr<Structure> structure, NonNullPassRefPtr<Structure> prototypeStructure, const UString& nameAndMessage)
- : InternalFunction(&exec->globalData(), structure, Identifier(exec, nameAndMessage))
+NativeErrorConstructor::NativeErrorConstructor(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, Structure* prototypeStructure, const UString& nameAndMessage)
+ : InternalFunction(&exec->globalData(), globalObject, structure, Identifier(exec, nameAndMessage))
{
- NativeErrorPrototype* prototype = new (exec) NativeErrorPrototype(exec, prototypeStructure, nameAndMessage, this);
+ ASSERT(inherits(&s_info));
- putDirect(exec->propertyNames().length, jsNumber(exec, 1), DontDelete | ReadOnly | DontEnum); // ECMA 15.11.7.5
- putDirect(exec->propertyNames().prototype, prototype, DontDelete | ReadOnly | DontEnum);
- m_errorStructure = ErrorInstance::createStructure(prototype);
-}
+ NativeErrorPrototype* prototype = new (exec) NativeErrorPrototype(exec, globalObject, prototypeStructure, nameAndMessage, this);
+ putDirect(exec->globalData(), exec->propertyNames().length, jsNumber(1), DontDelete | ReadOnly | DontEnum); // ECMA 15.11.7.5
+ putDirect(exec->globalData(), exec->propertyNames().prototype, prototype, DontDelete | ReadOnly | DontEnum);
+ m_errorStructure.set(exec->globalData(), this, ErrorInstance::createStructure(exec->globalData(), prototype));
+ ASSERT(m_errorStructure);
+ ASSERT(m_errorStructure->typeInfo().type() == ObjectType);
+}
-ErrorInstance* NativeErrorConstructor::construct(ExecState* exec, const ArgList& args)
+void NativeErrorConstructor::visitChildren(SlotVisitor& visitor)
{
- ErrorInstance* object = new (exec) ErrorInstance(m_errorStructure);
- if (!args.at(0).isUndefined())
- object->putDirect(exec->propertyNames().message, jsString(exec, args.at(0).toString(exec)));
- return object;
+ ASSERT_GC_OBJECT_INHERITS(this, &s_info);
+ COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
+ ASSERT(structure()->typeInfo().overridesVisitChildren());
+ InternalFunction::visitChildren(visitor);
+ if (m_errorStructure)
+ visitor.append(&m_errorStructure);
}
-static JSObject* constructWithNativeErrorConstructor(ExecState* exec, JSObject* constructor, const ArgList& args)
+static EncodedJSValue JSC_HOST_CALL constructWithNativeErrorConstructor(ExecState* exec)
{
- return static_cast<NativeErrorConstructor*>(constructor)->construct(exec, args);
+ JSValue message = exec->argumentCount() ? exec->argument(0) : jsUndefined();
+ Structure* errorStructure = static_cast<NativeErrorConstructor*>(exec->callee())->errorStructure();
+ ASSERT(errorStructure);
+ return JSValue::encode(ErrorInstance::create(exec, errorStructure, message));
}
ConstructType NativeErrorConstructor::getConstructData(ConstructData& constructData)
return ConstructTypeHost;
}
-static JSValue JSC_HOST_CALL callNativeErrorConstructor(ExecState* exec, JSObject* constructor, JSValue, const ArgList& args)
+static EncodedJSValue JSC_HOST_CALL callNativeErrorConstructor(ExecState* exec)
{
- return static_cast<NativeErrorConstructor*>(constructor)->construct(exec, args);
+ JSValue message = exec->argumentCount() ? exec->argument(0) : jsUndefined();
+ Structure* errorStructure = static_cast<NativeErrorConstructor*>(exec->callee())->errorStructure();
+ return JSValue::encode(ErrorInstance::create(exec, errorStructure, message));
}
CallType NativeErrorConstructor::getCallData(CallData& callData)
class NativeErrorConstructor : public InternalFunction {
public:
- NativeErrorConstructor(ExecState*, NonNullPassRefPtr<Structure> structure, NonNullPassRefPtr<Structure> prototypeStructure, const UString&);
+ NativeErrorConstructor(ExecState*, JSGlobalObject*, Structure*, Structure* prototypeStructure, const UString&);
- static const ClassInfo info;
+ static const ClassInfo s_info;
- ErrorInstance* construct(ExecState*, const ArgList&);
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
+ {
+ return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
+ }
+
+ Structure* errorStructure() { return m_errorStructure.get(); }
private:
+ static const unsigned StructureFlags = OverridesVisitChildren | InternalFunction::StructureFlags;
virtual ConstructType getConstructData(ConstructData&);
virtual CallType getCallData(CallData&);
+ virtual void visitChildren(SlotVisitor&);
- virtual const ClassInfo* classInfo() const { return &info; }
-
- RefPtr<Structure> m_errorStructure;
+ WriteBarrier<Structure> m_errorStructure;
};
} // namespace JSC
#include "NativeErrorPrototype.h"
#include "ErrorPrototype.h"
+#include "JSGlobalObject.h"
#include "JSString.h"
#include "NativeErrorConstructor.h"
#include "UString.h"
ASSERT_CLASS_FITS_IN_CELL(NativeErrorPrototype);
-NativeErrorPrototype::NativeErrorPrototype(ExecState* exec, NonNullPassRefPtr<Structure> structure, const UString& nameAndMessage, NativeErrorConstructor* constructor)
- : JSObject(structure)
+NativeErrorPrototype::NativeErrorPrototype(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, const UString& nameAndMessage, NativeErrorConstructor* constructor)
+ : JSObjectWithGlobalObject(globalObject, structure)
{
- putDirect(exec->propertyNames().name, jsString(exec, nameAndMessage), 0);
- putDirect(exec->propertyNames().message, jsString(exec, nameAndMessage), 0);
- putDirect(exec->propertyNames().constructor, constructor, DontEnum);
+ putDirect(exec->globalData(), exec->propertyNames().name, jsString(exec, nameAndMessage), 0);
+ putDirect(exec->globalData(), exec->propertyNames().message, jsString(exec, nameAndMessage), 0);
+ putDirect(exec->globalData(), exec->propertyNames().constructor, constructor, DontEnum);
}
} // namespace JSC
#ifndef NativeErrorPrototype_h
#define NativeErrorPrototype_h
-#include "JSObject.h"
+#include "JSObjectWithGlobalObject.h"
namespace JSC {
class NativeErrorConstructor;
- class NativeErrorPrototype : public JSObject {
+ class NativeErrorPrototype : public JSObjectWithGlobalObject {
public:
- NativeErrorPrototype(ExecState*, NonNullPassRefPtr<Structure>, const UString&, NativeErrorConstructor*);
+ NativeErrorPrototype(ExecState*, JSGlobalObject*, Structure*, const UString&, NativeErrorConstructor*);
};
} // namespace JSC
+++ /dev/null
-/*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef NativeFunctionWrapper_h
-#define NativeFunctionWrapper_h
-
-namespace JSC {
-#if ENABLE(JIT) && ENABLE(JIT_OPTIMIZE_NATIVE_CALL)
- class JSFunction;
- typedef JSFunction NativeFunctionWrapper;
-#else
- class PrototypeFunction;
- typedef PrototypeFunction NativeFunctionWrapper;
-#endif
-}
-
-#endif
/*
* Copyright (C) 1999-2000,2003 Harri Porten (porten@kde.org)
- * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008, 2011 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
namespace JSC {
-const ClassInfo NumberConstructor::info = { "Function", &InternalFunction::info, 0, ExecState::numberTable };
+const ClassInfo NumberConstructor::s_info = { "Function", &InternalFunction::s_info, 0, ExecState::numberConstructorTable };
/* Source for NumberConstructor.lut.h
-@begin numberTable
+@begin numberConstructorTable
NaN numberConstructorNaNValue DontEnum|DontDelete|ReadOnly
NEGATIVE_INFINITY numberConstructorNegInfinity DontEnum|DontDelete|ReadOnly
POSITIVE_INFINITY numberConstructorPosInfinity DontEnum|DontDelete|ReadOnly
@end
*/
-NumberConstructor::NumberConstructor(ExecState* exec, NonNullPassRefPtr<Structure> structure, NumberPrototype* numberPrototype)
- : InternalFunction(&exec->globalData(), structure, Identifier(exec, numberPrototype->info.className))
+NumberConstructor::NumberConstructor(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, NumberPrototype* numberPrototype)
+ : InternalFunction(&exec->globalData(), globalObject, structure, Identifier(exec, numberPrototype->s_info.className))
{
+ ASSERT(inherits(&s_info));
+
// Number.Prototype
- putDirectWithoutTransition(exec->propertyNames().prototype, numberPrototype, DontEnum | DontDelete | ReadOnly);
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().prototype, numberPrototype, DontEnum | DontDelete | ReadOnly);
// no. of arguments for constructor
- putDirectWithoutTransition(exec->propertyNames().length, jsNumber(exec, 1), ReadOnly | DontEnum | DontDelete);
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(1), ReadOnly | DontEnum | DontDelete);
}
bool NumberConstructor::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
{
- return getStaticValueSlot<NumberConstructor, InternalFunction>(exec, ExecState::numberTable(exec), this, propertyName, slot);
+ return getStaticValueSlot<NumberConstructor, InternalFunction>(exec, ExecState::numberConstructorTable(exec), this, propertyName, slot);
}
bool NumberConstructor::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
{
- return getStaticValueDescriptor<NumberConstructor, InternalFunction>(exec, ExecState::numberTable(exec), this, propertyName, descriptor);
+ return getStaticValueDescriptor<NumberConstructor, InternalFunction>(exec, ExecState::numberConstructorTable(exec), this, propertyName, descriptor);
}
-static JSValue numberConstructorNaNValue(ExecState* exec, JSValue, const Identifier&)
+static JSValue numberConstructorNaNValue(ExecState*, JSValue, const Identifier&)
{
- return jsNaN(exec);
+ return jsNaN();
}
-static JSValue numberConstructorNegInfinity(ExecState* exec, JSValue, const Identifier&)
+static JSValue numberConstructorNegInfinity(ExecState*, JSValue, const Identifier&)
{
- return jsNumber(exec, -Inf);
+ return jsNumber(-Inf);
}
-static JSValue numberConstructorPosInfinity(ExecState* exec, JSValue, const Identifier&)
+static JSValue numberConstructorPosInfinity(ExecState*, JSValue, const Identifier&)
{
- return jsNumber(exec, Inf);
+ return jsNumber(Inf);
}
-static JSValue numberConstructorMaxValue(ExecState* exec, JSValue, const Identifier&)
+static JSValue numberConstructorMaxValue(ExecState*, JSValue, const Identifier&)
{
- return jsNumber(exec, 1.7976931348623157E+308);
+ return jsNumber(1.7976931348623157E+308);
}
-static JSValue numberConstructorMinValue(ExecState* exec, JSValue, const Identifier&)
+static JSValue numberConstructorMinValue(ExecState*, JSValue, const Identifier&)
{
- return jsNumber(exec, 5E-324);
+ return jsNumber(5E-324);
}
// ECMA 15.7.1
-static JSObject* constructWithNumberConstructor(ExecState* exec, JSObject*, const ArgList& args)
+static EncodedJSValue JSC_HOST_CALL constructWithNumberConstructor(ExecState* exec)
{
- NumberObject* object = new (exec) NumberObject(exec->lexicalGlobalObject()->numberObjectStructure());
- double n = args.isEmpty() ? 0 : args.at(0).toNumber(exec);
- object->setInternalValue(jsNumber(exec, n));
- return object;
+ NumberObject* object = new (exec) NumberObject(exec->globalData(), asInternalFunction(exec->callee())->globalObject()->numberObjectStructure());
+ double n = exec->argumentCount() ? exec->argument(0).toNumber(exec) : 0;
+ object->setInternalValue(exec->globalData(), jsNumber(n));
+ return JSValue::encode(object);
}
ConstructType NumberConstructor::getConstructData(ConstructData& constructData)
}
// ECMA 15.7.2
-static JSValue JSC_HOST_CALL callNumberConstructor(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+static EncodedJSValue JSC_HOST_CALL callNumberConstructor(ExecState* exec)
{
- return jsNumber(exec, args.isEmpty() ? 0 : args.at(0).toNumber(exec));
+ return JSValue::encode(jsNumber(!exec->argumentCount() ? 0 : exec->argument(0).toNumber(exec)));
}
CallType NumberConstructor::getCallData(CallData& callData)
class NumberConstructor : public InternalFunction {
public:
- NumberConstructor(ExecState*, NonNullPassRefPtr<Structure>, NumberPrototype*);
+ NumberConstructor(ExecState*, JSGlobalObject*, Structure*, NumberPrototype*);
virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
JSValue getValueProperty(ExecState*, int token) const;
- static const ClassInfo info;
+ static const ClassInfo s_info;
- static PassRefPtr<Structure> createStructure(JSValue proto)
+ static Structure* createStructure(JSGlobalData& globalData, JSValue proto)
{
- return Structure::create(proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
+ return Structure::create(globalData, proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
}
enum { NaNValue, NegInfinity, PosInfinity, MaxValue, MinValue };
private:
virtual ConstructType getConstructData(ConstructData&);
virtual CallType getCallData(CallData&);
-
- virtual const ClassInfo* classInfo() const { return &info; }
};
} // namespace JSC
ASSERT_CLASS_FITS_IN_CELL(NumberObject);
-const ClassInfo NumberObject::info = { "Number", 0, 0, 0 };
+const ClassInfo NumberObject::s_info = { "Number", &JSWrapperObject::s_info, 0, 0 };
-NumberObject::NumberObject(NonNullPassRefPtr<Structure> structure)
- : JSWrapperObject(structure)
+NumberObject::NumberObject(JSGlobalData& globalData, Structure* structure)
+ : JSWrapperObject(globalData, structure)
{
+ ASSERT(inherits(&s_info));
}
JSValue NumberObject::getJSNumber()
return internalValue();
}
-NumberObject* constructNumber(ExecState* exec, JSValue number)
+NumberObject* constructNumber(ExecState* exec, JSGlobalObject* globalObject, JSValue number)
{
- NumberObject* object = new (exec) NumberObject(exec->lexicalGlobalObject()->numberObjectStructure());
- object->setInternalValue(number);
+ NumberObject* object = new (exec) NumberObject(exec->globalData(), globalObject->numberObjectStructure());
+ object->setInternalValue(exec->globalData(), number);
return object;
}
class NumberObject : public JSWrapperObject {
public:
- explicit NumberObject(NonNullPassRefPtr<Structure>);
+ explicit NumberObject(JSGlobalData&, Structure*);
- static const ClassInfo info;
+ static const ClassInfo s_info;
- static PassRefPtr<Structure> createStructure(JSValue prototype)
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
+ return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
}
- protected:
-#if USE(JSVALUE32)
- static const unsigned StructureFlags = OverridesMarkChildren | JSWrapperObject::StructureFlags;
-#else
- static const unsigned StructureFlags = JSWrapperObject::StructureFlags;
-#endif
-
private:
- virtual const ClassInfo* classInfo() const { return &info; }
-
virtual JSValue getJSNumber();
};
- NumberObject* constructNumber(ExecState*, JSValue);
+ NumberObject* constructNumber(ExecState*, JSGlobalObject*, JSValue);
} // namespace JSC
/*
* Copyright (C) 1999-2000,2003 Harri Porten (porten@kde.org)
- * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008, 2011 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
#include "Error.h"
#include "JSFunction.h"
#include "JSString.h"
-#include "JSStringBuilder.h"
#include "Operations.h"
-#include "PrototypeFunction.h"
-#include "StringBuilder.h"
#include "dtoa.h"
#include <wtf/Assertions.h>
+#include <wtf/DecimalNumber.h>
#include <wtf/MathExtras.h>
#include <wtf/Vector.h>
namespace JSC {
-ASSERT_CLASS_FITS_IN_CELL(NumberPrototype);
+static EncodedJSValue JSC_HOST_CALL numberProtoFuncToString(ExecState*);
+static EncodedJSValue JSC_HOST_CALL numberProtoFuncToLocaleString(ExecState*);
+static EncodedJSValue JSC_HOST_CALL numberProtoFuncValueOf(ExecState*);
+static EncodedJSValue JSC_HOST_CALL numberProtoFuncToFixed(ExecState*);
+static EncodedJSValue JSC_HOST_CALL numberProtoFuncToExponential(ExecState*);
+static EncodedJSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState*);
+
+}
+
+#include "NumberPrototype.lut.h"
+
+namespace JSC {
-static JSValue JSC_HOST_CALL numberProtoFuncToString(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL numberProtoFuncToLocaleString(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL numberProtoFuncValueOf(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL numberProtoFuncToFixed(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL numberProtoFuncToExponential(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState*, JSObject*, JSValue, const ArgList&);
+const ClassInfo NumberPrototype::s_info = { "Number", &NumberObject::s_info, 0, ExecState::numberPrototypeTable };
-// ECMA 15.7.4
+/* Source for NumberPrototype.lut.h
+@begin numberPrototypeTable
+ toString numberProtoFuncToString DontEnum|Function 1
+ toLocaleString numberProtoFuncToLocaleString DontEnum|Function 0
+ valueOf numberProtoFuncValueOf DontEnum|Function 0
+ toFixed numberProtoFuncToFixed DontEnum|Function 1
+ toExponential numberProtoFuncToExponential DontEnum|Function 1
+ toPrecision numberProtoFuncToPrecision DontEnum|Function 1
+@end
+*/
-NumberPrototype::NumberPrototype(ExecState* exec, NonNullPassRefPtr<Structure> structure, Structure* prototypeFunctionStructure)
- : NumberObject(structure)
+ASSERT_CLASS_FITS_IN_CELL(NumberPrototype);
+
+NumberPrototype::NumberPrototype(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
+ : NumberObject(exec->globalData(), structure)
{
- setInternalValue(jsNumber(exec, 0));
+ setInternalValue(exec->globalData(), jsNumber(0));
- // The constructor will be added later, after NumberConstructor has been constructed
+ ASSERT(inherits(&s_info));
+ putAnonymousValue(globalObject->globalData(), 0, globalObject);
+}
+
+bool NumberPrototype::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot &slot)
+{
+ return getStaticFunctionSlot<NumberObject>(exec, ExecState::numberPrototypeTable(exec), this, propertyName, slot);
+}
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().toString, numberProtoFuncToString), DontEnum);
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 0, exec->propertyNames().toLocaleString, numberProtoFuncToLocaleString), DontEnum);
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 0, exec->propertyNames().valueOf, numberProtoFuncValueOf), DontEnum);
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().toFixed, numberProtoFuncToFixed), DontEnum);
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().toExponential, numberProtoFuncToExponential), DontEnum);
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().toPrecision, numberProtoFuncToPrecision), DontEnum);
+bool NumberPrototype::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ return getStaticFunctionDescriptor<NumberObject>(exec, ExecState::numberPrototypeTable(exec), this, propertyName, descriptor);
}
// ------------------------------ Functions ---------------------------
-// ECMA 15.7.4.2 - 15.7.4.7
+static ALWAYS_INLINE bool toThisNumber(JSValue thisValue, double &x)
+{
+ JSValue v = thisValue.getJSNumber();
+ if (UNLIKELY(!v))
+ return false;
+ x = v.uncheckedGetNumber();
+ return true;
+}
-static UString integerPartNoExp(double d)
+static ALWAYS_INLINE bool getIntegerArgumentInRange(ExecState* exec, int low, int high, int& result, bool& isUndefined)
{
- int decimalPoint;
- int sign;
- char result[80];
- WTF::dtoa(result, d, 0, &decimalPoint, &sign, NULL);
- bool resultIsInfOrNan = (decimalPoint == 9999);
- size_t length = strlen(result);
-
- StringBuilder builder;
- builder.append(sign ? "-" : "");
- if (resultIsInfOrNan)
- builder.append((const char*)result);
- else if (decimalPoint <= 0)
- builder.append("0");
- else {
- Vector<char, 1024> buf(decimalPoint + 1);
-
- // FIXME: Remove use of strncpy()
- if (static_cast<int>(length) <= decimalPoint) {
- ASSERT(decimalPoint < 1024);
- memcpy(buf.data(), result, length);
- memset(buf.data() + length, '0', decimalPoint - length);
- } else
- strncpy(buf.data(), result, decimalPoint);
- buf[decimalPoint] = '\0';
-
- builder.append((const char*)(buf.data()));
+ result = 0;
+ isUndefined = false;
+
+ JSValue argument0 = exec->argument(0);
+ if (argument0.isUndefined()) {
+ isUndefined = true;
+ return true;
}
- return builder.build();
+ double asDouble = argument0.toInteger(exec);
+ if (asDouble < low || asDouble > high)
+ return false;
+
+ result = static_cast<int>(asDouble);
+ return true;
}
-static UString charSequence(char c, int count)
+// toExponential converts a number to a string, always formatting as an expoential.
+// This method takes an optional argument specifying a number of *decimal places*
+// to round the significand to (or, put another way, this method optionally rounds
+// to argument-plus-one significant figures).
+EncodedJSValue JSC_HOST_CALL numberProtoFuncToExponential(ExecState* exec)
{
- Vector<char, 2048> buf(count + 1, c);
- buf[count] = '\0';
+ // Get x (the double value of this, which should be a Number).
+ double x;
+ if (!toThisNumber(exec->hostThisValue(), x))
+ return throwVMTypeError(exec);
+
+ // Get the argument.
+ int decimalPlacesInExponent;
+ bool isUndefined;
+ if (!getIntegerArgumentInRange(exec, 0, 20, decimalPlacesInExponent, isUndefined))
+ return throwVMError(exec, createRangeError(exec, "toExponential() argument must be between 0 and 20"));
+
+ // Handle NaN and Infinity.
+ if (isnan(x) || isinf(x))
+ return JSValue::encode(jsString(exec, UString::number(x)));
+
+ // Round if the argument is not undefined, always format as exponential.
+ NumberToStringBuffer buffer;
+ unsigned length = isUndefined
+ ? DecimalNumber(x).toStringExponential(buffer, WTF::NumberToStringBufferLength)
+ : DecimalNumber(x, RoundingSignificantFigures, decimalPlacesInExponent + 1).toStringExponential(buffer, WTF::NumberToStringBufferLength);
- return UString(buf.data());
+ return JSValue::encode(jsString(exec, UString(buffer, length)));
}
-static double intPow10(int e)
+// toFixed converts a number to a string, always formatting as an a decimal fraction.
+// This method takes an argument specifying a number of decimal places to round the
+// significand to. However when converting large values (1e+21 and above) this
+// method will instead fallback to calling ToString.
+EncodedJSValue JSC_HOST_CALL numberProtoFuncToFixed(ExecState* exec)
{
- // This function uses the "exponentiation by squaring" algorithm and
- // long double to quickly and precisely calculate integer powers of 10.0.
-
- // This is a handy workaround for <rdar://problem/4494756>
-
- if (e == 0)
- return 1.0;
-
- bool negative = e < 0;
- unsigned exp = negative ? -e : e;
-
- long double result = 10.0;
- bool foundOne = false;
- for (int bit = 31; bit >= 0; bit--) {
- if (!foundOne) {
- if ((exp >> bit) & 1)
- foundOne = true;
- } else {
- result = result * result;
- if ((exp >> bit) & 1)
- result = result * 10.0;
- }
- }
+ // Get x (the double value of this, which should be a Number).
+ JSValue thisValue = exec->hostThisValue();
+ JSValue v = thisValue.getJSNumber();
+ if (!v)
+ return throwVMTypeError(exec);
+ double x = v.uncheckedGetNumber();
+
+ // Get the argument.
+ int decimalPlaces;
+ bool isUndefined; // This is ignored; undefined treated as 0.
+ if (!getIntegerArgumentInRange(exec, 0, 20, decimalPlaces, isUndefined))
+ return throwVMError(exec, createRangeError(exec, "toFixed() argument must be between 0 and 20"));
+
+ // 15.7.4.5.7 states "If x >= 10^21, then let m = ToString(x)"
+ // This also covers Ininity, and structure the check so that NaN
+ // values are also handled by numberToString
+ if (!(fabs(x) < 1e+21))
+ return JSValue::encode(jsString(exec, UString::number(x)));
+
+ // The check above will return false for NaN or Infinity, these will be
+ // handled by numberToString.
+ ASSERT(!isnan(x) && !isinf(x));
+
+ // Convert to decimal with rounding, and format as decimal.
+ NumberToStringBuffer buffer;
+ unsigned length = DecimalNumber(x, RoundingDecimalPlaces, decimalPlaces).toStringDecimal(buffer, WTF::NumberToStringBufferLength);
+ return JSValue::encode(jsString(exec, UString(buffer, length)));
+}
+
+// toPrecision converts a number to a string, takeing an argument specifying a
+// number of significant figures to round the significand to. For positive
+// exponent, all values that can be represented using a decimal fraction will
+// be, e.g. when rounding to 3 s.f. any value up to 999 will be formated as a
+// decimal, whilst 1000 is converted to the exponential representation 1.00e+3.
+// For negative exponents values >= 1e-6 are formated as decimal fractions,
+// with smaller values converted to exponential representation.
+EncodedJSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState* exec)
+{
+ // Get x (the double value of this, which should be a Number).
+ JSValue thisValue = exec->hostThisValue();
+ JSValue v = thisValue.getJSNumber();
+ if (!v)
+ return throwVMTypeError(exec);
+ double x = v.uncheckedGetNumber();
+
+ // Get the argument.
+ int significantFigures;
+ bool isUndefined;
+ if (!getIntegerArgumentInRange(exec, 1, 21, significantFigures, isUndefined))
+ return throwVMError(exec, createRangeError(exec, "toPrecision() argument must be between 1 and 21"));
- if (negative)
- return static_cast<double>(1.0 / result);
- return static_cast<double>(result);
+ // To precision called with no argument is treated as ToString.
+ if (isUndefined)
+ return JSValue::encode(jsString(exec, UString::number(x)));
+
+ // Handle NaN and Infinity.
+ if (isnan(x) || isinf(x))
+ return JSValue::encode(jsString(exec, UString::number(x)));
+
+ // Convert to decimal with rounding.
+ DecimalNumber number(x, RoundingSignificantFigures, significantFigures);
+ // If number is in the range 1e-6 <= x < pow(10, significantFigures) then format
+ // as decimal. Otherwise, format the number as an exponential. Decimal format
+ // demands a minimum of (exponent + 1) digits to represent a number, for example
+ // 1234 (1.234e+3) requires 4 digits. (See ECMA-262 15.7.4.7.10.c)
+ NumberToStringBuffer buffer;
+ unsigned length = number.exponent() >= -6 && number.exponent() < significantFigures
+ ? number.toStringDecimal(buffer, WTF::NumberToStringBufferLength)
+ : number.toStringExponential(buffer, WTF::NumberToStringBufferLength);
+ return JSValue::encode(jsString(exec, UString(buffer, length)));
}
-JSValue JSC_HOST_CALL numberProtoFuncToString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL numberProtoFuncToString(ExecState* exec)
{
+ JSValue thisValue = exec->hostThisValue();
JSValue v = thisValue.getJSNumber();
if (!v)
- return throwError(exec, TypeError);
+ return throwVMTypeError(exec);
- JSValue radixValue = args.at(0);
+ JSValue radixValue = exec->argument(0);
int radix;
if (radixValue.isInt32())
radix = radixValue.asInt32();
radix = static_cast<int>(radixValue.toInteger(exec)); // nan -> 0
if (radix == 10)
- return jsString(exec, v.toString(exec));
+ return JSValue::encode(jsString(exec, v.toString(exec)));
static const char* const digits = "0123456789abcdefghijklmnopqrstuvwxyz";
int x = v.asInt32();
if (static_cast<unsigned>(x) < 36) { // Exclude negatives
JSGlobalData* globalData = &exec->globalData();
- return globalData->smallStrings.singleCharacterString(globalData, digits[x]);
+ return JSValue::encode(globalData->smallStrings.singleCharacterString(globalData, digits[x]));
}
}
}
if (radix < 2 || radix > 36)
- return throwError(exec, RangeError, "toString() radix argument must be between 2 and 36");
+ return throwVMError(exec, createRangeError(exec, "toString() radix argument must be between 2 and 36"));
// INT_MAX results in 1024 characters left of the dot with radix 2
// give the same space on the right side. safety checks are in place
const char* lastCharInString = s + sizeof(s) - 1;
double x = v.uncheckedGetNumber();
if (isnan(x) || isinf(x))
- return jsString(exec, UString::from(x));
+ return JSValue::encode(jsString(exec, UString::number(x)));
bool isNegative = x < 0.0;
if (isNegative)
*p = '\0';
ASSERT(p < s + sizeof(s));
- return jsString(exec, startOfResultString);
+ return JSValue::encode(jsString(exec, startOfResultString));
}
-JSValue JSC_HOST_CALL numberProtoFuncToLocaleString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL numberProtoFuncToLocaleString(ExecState* exec)
{
+ JSValue thisValue = exec->hostThisValue();
// FIXME: Not implemented yet.
JSValue v = thisValue.getJSNumber();
if (!v)
- return throwError(exec, TypeError);
+ return throwVMTypeError(exec);
- return jsString(exec, v.toString(exec));
+ return JSValue::encode(jsString(exec, v.toString(exec)));
}
-JSValue JSC_HOST_CALL numberProtoFuncValueOf(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL numberProtoFuncValueOf(ExecState* exec)
{
+ JSValue thisValue = exec->hostThisValue();
JSValue v = thisValue.getJSNumber();
if (!v)
- return throwError(exec, TypeError);
-
- return v;
-}
-
-JSValue JSC_HOST_CALL numberProtoFuncToFixed(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
-{
- JSValue v = thisValue.getJSNumber();
- if (!v)
- return throwError(exec, TypeError);
-
- JSValue fractionDigits = args.at(0);
- double df = fractionDigits.toInteger(exec);
- if (!(df >= 0 && df <= 20))
- return throwError(exec, RangeError, "toFixed() digits argument must be between 0 and 20");
- int f = static_cast<int>(df);
-
- double x = v.uncheckedGetNumber();
- if (isnan(x))
- return jsNontrivialString(exec, "NaN");
+ return throwVMTypeError(exec);
- UString s;
- if (x < 0) {
- s = "-";
- x = -x;
- } else {
- s = "";
- if (x == -0.0)
- x = 0;
- }
-
- if (x >= pow(10.0, 21.0))
- return jsString(exec, makeString(s, UString::from(x)));
-
- const double tenToTheF = pow(10.0, f);
- double n = floor(x * tenToTheF);
- if (fabs(n / tenToTheF - x) >= fabs((n + 1) / tenToTheF - x))
- n++;
-
- UString m = integerPartNoExp(n);
-
- int k = m.size();
- if (k <= f) {
- StringBuilder z;
- for (int i = 0; i < f + 1 - k; i++)
- z.append('0');
- z.append(m);
- m = z.build();
- k = f + 1;
- ASSERT(k == static_cast<int>(m.size()));
- }
- int kMinusf = k - f;
-
- if (kMinusf < static_cast<int>(m.size()))
- return jsString(exec, makeString(s, m.substr(0, kMinusf), ".", m.substr(kMinusf)));
- return jsString(exec, makeString(s, m.substr(0, kMinusf)));
-}
-
-static void fractionalPartToString(char* buf, int& i, const char* result, int resultLength, int fractionalDigits)
-{
- if (fractionalDigits <= 0)
- return;
-
- int fDigitsInResult = static_cast<int>(resultLength) - 1;
- buf[i++] = '.';
- if (fDigitsInResult > 0) {
- if (fractionalDigits < fDigitsInResult) {
- strncpy(buf + i, result + 1, fractionalDigits);
- i += fractionalDigits;
- } else {
- ASSERT(i + resultLength - 1 < 80);
- memcpy(buf + i, result + 1, resultLength - 1);
- i += static_cast<int>(resultLength) - 1;
- }
- }
-
- for (int j = 0; j < fractionalDigits - fDigitsInResult; j++)
- buf[i++] = '0';
-}
-
-static void exponentialPartToString(char* buf, int& i, int decimalPoint)
-{
- buf[i++] = 'e';
- // decimalPoint can't be more than 3 digits decimal given the
- // nature of float representation
- int exponential = decimalPoint - 1;
- buf[i++] = (exponential >= 0) ? '+' : '-';
- if (exponential < 0)
- exponential *= -1;
- if (exponential >= 100)
- buf[i++] = static_cast<char>('0' + exponential / 100);
- if (exponential >= 10)
- buf[i++] = static_cast<char>('0' + (exponential % 100) / 10);
- buf[i++] = static_cast<char>('0' + exponential % 10);
-}
-
-JSValue JSC_HOST_CALL numberProtoFuncToExponential(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
-{
- JSValue v = thisValue.getJSNumber();
- if (!v)
- return throwError(exec, TypeError);
-
- double x = v.uncheckedGetNumber();
-
- if (isnan(x) || isinf(x))
- return jsString(exec, UString::from(x));
-
- JSValue fractionalDigitsValue = args.at(0);
- double df = fractionalDigitsValue.toInteger(exec);
- if (!(df >= 0 && df <= 20))
- return throwError(exec, RangeError, "toExponential() argument must between 0 and 20");
- int fractionalDigits = static_cast<int>(df);
- bool includeAllDigits = fractionalDigitsValue.isUndefined();
-
- int decimalAdjust = 0;
- if (x && !includeAllDigits) {
- double logx = floor(log10(fabs(x)));
- x /= pow(10.0, logx);
- const double tenToTheF = pow(10.0, fractionalDigits);
- double fx = floor(x * tenToTheF) / tenToTheF;
- double cx = ceil(x * tenToTheF) / tenToTheF;
-
- if (fabs(fx - x) < fabs(cx - x))
- x = fx;
- else
- x = cx;
-
- decimalAdjust = static_cast<int>(logx);
- }
-
- if (isnan(x))
- return jsNontrivialString(exec, "NaN");
-
- if (x == -0.0) // (-0.0).toExponential() should print as 0 instead of -0
- x = 0;
-
- int decimalPoint;
- int sign;
- char result[80];
- WTF::dtoa(result, x, 0, &decimalPoint, &sign, NULL);
- size_t resultLength = strlen(result);
- decimalPoint += decimalAdjust;
-
- int i = 0;
- char buf[80]; // digit + '.' + fractionDigits (max 20) + 'e' + sign + exponent (max?)
- if (sign)
- buf[i++] = '-';
-
- // ? 9999 is the magical "result is Inf or NaN" value. what's 999??
- if (decimalPoint == 999) {
- ASSERT(i + resultLength < 80);
- memcpy(buf + i, result, resultLength);
- buf[i + resultLength] = '\0';
- } else {
- buf[i++] = result[0];
-
- if (includeAllDigits)
- fractionalDigits = static_cast<int>(resultLength) - 1;
-
- fractionalPartToString(buf, i, result, resultLength, fractionalDigits);
- exponentialPartToString(buf, i, decimalPoint);
- buf[i++] = '\0';
- }
- ASSERT(i <= 80);
-
- return jsString(exec, buf);
-}
-
-JSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
-{
- JSValue v = thisValue.getJSNumber();
- if (!v)
- return throwError(exec, TypeError);
-
- double doublePrecision = args.at(0).toIntegerPreserveNaN(exec);
- double x = v.uncheckedGetNumber();
- if (args.at(0).isUndefined() || isnan(x) || isinf(x))
- return jsString(exec, v.toString(exec));
-
- UString s;
- if (x < 0) {
- s = "-";
- x = -x;
- } else
- s = "";
-
- if (!(doublePrecision >= 1 && doublePrecision <= 21)) // true for NaN
- return throwError(exec, RangeError, "toPrecision() argument must be between 1 and 21");
- int precision = static_cast<int>(doublePrecision);
-
- int e = 0;
- UString m;
- if (x) {
- e = static_cast<int>(log10(x));
- double tens = intPow10(e - precision + 1);
- double n = floor(x / tens);
- if (n < intPow10(precision - 1)) {
- e = e - 1;
- tens = intPow10(e - precision + 1);
- n = floor(x / tens);
- }
-
- if (fabs((n + 1.0) * tens - x) <= fabs(n * tens - x))
- ++n;
- // maintain n < 10^(precision)
- if (n >= intPow10(precision)) {
- n /= 10.0;
- e += 1;
- }
- ASSERT(intPow10(precision - 1) <= n);
- ASSERT(n < intPow10(precision));
-
- m = integerPartNoExp(n);
- if (e < -6 || e >= precision) {
- if (m.size() > 1)
- m = makeString(m.substr(0, 1), ".", m.substr(1));
- if (e >= 0)
- return jsMakeNontrivialString(exec, s, m, "e+", UString::from(e));
- return jsMakeNontrivialString(exec, s, m, "e-", UString::from(-e));
- }
- } else {
- m = charSequence('0', precision);
- e = 0;
- }
-
- if (e == precision - 1)
- return jsString(exec, makeString(s, m));
- if (e >= 0) {
- if (e + 1 < static_cast<int>(m.size()))
- return jsString(exec, makeString(s, m.substr(0, e + 1), ".", m.substr(e + 1)));
- return jsString(exec, makeString(s, m));
- }
- return jsMakeNontrivialString(exec, s, "0.", charSequence('0', -(e + 1)), m);
+ return JSValue::encode(v);
}
} // namespace JSC
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2011 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
class NumberPrototype : public NumberObject {
public:
- NumberPrototype(ExecState*, NonNullPassRefPtr<Structure>, Structure* prototypeFunctionStructure);
+ NumberPrototype(ExecState*, JSGlobalObject*, Structure*);
+
+ static const ClassInfo s_info;
+
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
+ {
+ return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
+ }
+
+ protected:
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | NumberObject::StructureFlags;
+ static const unsigned AnonymousSlotCount = NumberObject::AnonymousSlotCount + 1;
+
+ private:
+ virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
+ virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
};
} // namespace JSC
#define NumericStrings_h
#include "UString.h"
+#include <wtf/FixedArray.h>
#include <wtf/HashFunctions.h>
namespace JSC {
if (d == entry.key && !entry.value.isNull())
return entry.value;
entry.key = d;
- entry.value = UString::from(d);
+ entry.value = UString::number(d);
return entry.value;
}
if (i == entry.key && !entry.value.isNull())
return entry.value;
entry.key = i;
- entry.value = UString::from(i);
+ entry.value = UString::number(i);
return entry.value;
}
if (i == entry.key && !entry.value.isNull())
return entry.value;
entry.key = i;
- entry.value = UString::from(i);
+ entry.value = UString::number(i);
return entry.value;
}
private:
{
ASSERT(i < cacheSize);
if (smallIntCache[i].isNull())
- smallIntCache[i] = UString::from(i);
+ smallIntCache[i] = UString::number(i);
return smallIntCache[i];
}
- CacheEntry<double> doubleCache[cacheSize];
- CacheEntry<int> intCache[cacheSize];
- CacheEntry<unsigned> unsignedCache[cacheSize];
- UString smallIntCache[cacheSize];
+ FixedArray<CacheEntry<double>, cacheSize> doubleCache;
+ FixedArray<CacheEntry<int>, cacheSize> intCache;
+ FixedArray<CacheEntry<unsigned>, cacheSize> unsignedCache;
+ FixedArray<UString, cacheSize> smallIntCache;
};
} // namespace JSC
#include "ObjectConstructor.h"
#include "Error.h"
+#include "ExceptionHelpers.h"
#include "JSFunction.h"
#include "JSArray.h"
#include "JSGlobalObject.h"
+#include "Lookup.h"
#include "ObjectPrototype.h"
#include "PropertyDescriptor.h"
#include "PropertyNameArray.h"
-#include "PrototypeFunction.h"
namespace JSC {
ASSERT_CLASS_FITS_IN_CELL(ObjectConstructor);
-static JSValue JSC_HOST_CALL objectConstructorGetPrototypeOf(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptor(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL objectConstructorGetOwnPropertyNames(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL objectConstructorKeys(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL objectConstructorDefineProperty(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL objectConstructorDefineProperties(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL objectConstructorCreate(ExecState*, JSObject*, JSValue, const ArgList&);
+static EncodedJSValue JSC_HOST_CALL objectConstructorGetPrototypeOf(ExecState*);
+static EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptor(ExecState*);
+static EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyNames(ExecState*);
+static EncodedJSValue JSC_HOST_CALL objectConstructorKeys(ExecState*);
+static EncodedJSValue JSC_HOST_CALL objectConstructorDefineProperty(ExecState*);
+static EncodedJSValue JSC_HOST_CALL objectConstructorDefineProperties(ExecState*);
+static EncodedJSValue JSC_HOST_CALL objectConstructorCreate(ExecState*);
+static EncodedJSValue JSC_HOST_CALL objectConstructorSeal(ExecState*);
+static EncodedJSValue JSC_HOST_CALL objectConstructorFreeze(ExecState*);
+static EncodedJSValue JSC_HOST_CALL objectConstructorPreventExtensions(ExecState*);
+static EncodedJSValue JSC_HOST_CALL objectConstructorIsSealed(ExecState*);
+static EncodedJSValue JSC_HOST_CALL objectConstructorIsFrozen(ExecState*);
+static EncodedJSValue JSC_HOST_CALL objectConstructorIsExtensible(ExecState*);
-ObjectConstructor::ObjectConstructor(ExecState* exec, NonNullPassRefPtr<Structure> structure, ObjectPrototype* objectPrototype, Structure* prototypeFunctionStructure)
-: InternalFunction(&exec->globalData(), structure, Identifier(exec, "Object"))
+}
+
+#include "ObjectConstructor.lut.h"
+
+namespace JSC {
+
+const ClassInfo ObjectConstructor::s_info = { "Function", &InternalFunction::s_info, 0, ExecState::objectConstructorTable };
+
+/* Source for ObjectConstructor.lut.h
+@begin objectConstructorTable
+ getPrototypeOf objectConstructorGetPrototypeOf DontEnum|Function 1
+ getOwnPropertyDescriptor objectConstructorGetOwnPropertyDescriptor DontEnum|Function 2
+ getOwnPropertyNames objectConstructorGetOwnPropertyNames DontEnum|Function 1
+ keys objectConstructorKeys DontEnum|Function 1
+ defineProperty objectConstructorDefineProperty DontEnum|Function 3
+ defineProperties objectConstructorDefineProperties DontEnum|Function 2
+ create objectConstructorCreate DontEnum|Function 2
+ seal objectConstructorSeal DontEnum|Function 1
+ freeze objectConstructorFreeze DontEnum|Function 1
+ preventExtensions objectConstructorPreventExtensions DontEnum|Function 1
+ isSealed objectConstructorIsSealed DontEnum|Function 1
+ isFrozen objectConstructorIsFrozen DontEnum|Function 1
+ isExtensible objectConstructorIsExtensible DontEnum|Function 1
+@end
+*/
+
+ObjectConstructor::ObjectConstructor(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, ObjectPrototype* objectPrototype)
+ : InternalFunction(&exec->globalData(), globalObject, structure, Identifier(exec, "Object"))
{
// ECMA 15.2.3.1
- putDirectWithoutTransition(exec->propertyNames().prototype, objectPrototype, DontEnum | DontDelete | ReadOnly);
-
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().prototype, objectPrototype, DontEnum | DontDelete | ReadOnly);
// no. of arguments for constructor
- putDirectWithoutTransition(exec->propertyNames().length, jsNumber(exec, 1), ReadOnly | DontEnum | DontDelete);
-
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().getPrototypeOf, objectConstructorGetPrototypeOf), DontEnum);
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 2, exec->propertyNames().getOwnPropertyDescriptor, objectConstructorGetOwnPropertyDescriptor), DontEnum);
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().getOwnPropertyNames, objectConstructorGetOwnPropertyNames), DontEnum);
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().keys, objectConstructorKeys), DontEnum);
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 3, exec->propertyNames().defineProperty, objectConstructorDefineProperty), DontEnum);
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 2, exec->propertyNames().defineProperties, objectConstructorDefineProperties), DontEnum);
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 2, exec->propertyNames().create, objectConstructorCreate), DontEnum);
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(1), ReadOnly | DontEnum | DontDelete);
+}
+
+bool ObjectConstructor::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot &slot)
+{
+ return getStaticFunctionSlot<JSObject>(exec, ExecState::objectConstructorTable(exec), this, propertyName, slot);
+}
+
+bool ObjectConstructor::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ return getStaticFunctionDescriptor<JSObject>(exec, ExecState::objectConstructorTable(exec), this, propertyName, descriptor);
}
// ECMA 15.2.2
-static ALWAYS_INLINE JSObject* constructObject(ExecState* exec, const ArgList& args)
+static ALWAYS_INLINE JSObject* constructObject(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args)
{
JSValue arg = args.at(0);
if (arg.isUndefinedOrNull())
- return new (exec) JSObject(exec->lexicalGlobalObject()->emptyObjectStructure());
- return arg.toObject(exec);
+ return constructEmptyObject(exec, globalObject);
+ return arg.toObject(exec, globalObject);
}
-static JSObject* constructWithObjectConstructor(ExecState* exec, JSObject*, const ArgList& args)
+static EncodedJSValue JSC_HOST_CALL constructWithObjectConstructor(ExecState* exec)
{
- return constructObject(exec, args);
+ ArgList args(exec);
+ return JSValue::encode(constructObject(exec, asInternalFunction(exec->callee())->globalObject(), args));
}
ConstructType ObjectConstructor::getConstructData(ConstructData& constructData)
return ConstructTypeHost;
}
-static JSValue JSC_HOST_CALL callObjectConstructor(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+static EncodedJSValue JSC_HOST_CALL callObjectConstructor(ExecState* exec)
{
- return constructObject(exec, args);
+ ArgList args(exec);
+ return JSValue::encode(constructObject(exec, asInternalFunction(exec->callee())->globalObject(), args));
}
CallType ObjectConstructor::getCallData(CallData& callData)
return CallTypeHost;
}
-JSValue JSC_HOST_CALL objectConstructorGetPrototypeOf(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL objectConstructorGetPrototypeOf(ExecState* exec)
{
- if (!args.at(0).isObject())
- return throwError(exec, TypeError, "Requested prototype of a value that is not an object.");
- return asObject(args.at(0))->prototype();
+ if (!exec->argument(0).isObject())
+ return throwVMError(exec, createTypeError(exec, "Requested prototype of a value that is not an object."));
+ return JSValue::encode(asObject(exec->argument(0))->prototype());
}
-JSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptor(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptor(ExecState* exec)
{
- if (!args.at(0).isObject())
- return throwError(exec, TypeError, "Requested property descriptor of a value that is not an object.");
- UString propertyName = args.at(1).toString(exec);
+ if (!exec->argument(0).isObject())
+ return throwVMError(exec, createTypeError(exec, "Requested property descriptor of a value that is not an object."));
+ UString propertyName = exec->argument(1).toString(exec);
if (exec->hadException())
- return jsNull();
- JSObject* object = asObject(args.at(0));
+ return JSValue::encode(jsNull());
+ JSObject* object = asObject(exec->argument(0));
PropertyDescriptor descriptor;
if (!object->getOwnPropertyDescriptor(exec, Identifier(exec, propertyName), descriptor))
- return jsUndefined();
+ return JSValue::encode(jsUndefined());
if (exec->hadException())
- return jsUndefined();
+ return JSValue::encode(jsUndefined());
JSObject* description = constructEmptyObject(exec);
if (!descriptor.isAccessorDescriptor()) {
- description->putDirect(exec->propertyNames().value, descriptor.value() ? descriptor.value() : jsUndefined(), 0);
- description->putDirect(exec->propertyNames().writable, jsBoolean(descriptor.writable()), 0);
+ description->putDirect(exec->globalData(), exec->propertyNames().value, descriptor.value() ? descriptor.value() : jsUndefined(), 0);
+ description->putDirect(exec->globalData(), exec->propertyNames().writable, jsBoolean(descriptor.writable()), 0);
} else {
- description->putDirect(exec->propertyNames().get, descriptor.getter() ? descriptor.getter() : jsUndefined(), 0);
- description->putDirect(exec->propertyNames().set, descriptor.setter() ? descriptor.setter() : jsUndefined(), 0);
+ description->putDirect(exec->globalData(), exec->propertyNames().get, descriptor.getter() ? descriptor.getter() : jsUndefined(), 0);
+ description->putDirect(exec->globalData(), exec->propertyNames().set, descriptor.setter() ? descriptor.setter() : jsUndefined(), 0);
}
- description->putDirect(exec->propertyNames().enumerable, jsBoolean(descriptor.enumerable()), 0);
- description->putDirect(exec->propertyNames().configurable, jsBoolean(descriptor.configurable()), 0);
+ description->putDirect(exec->globalData(), exec->propertyNames().enumerable, jsBoolean(descriptor.enumerable()), 0);
+ description->putDirect(exec->globalData(), exec->propertyNames().configurable, jsBoolean(descriptor.configurable()), 0);
- return description;
+ return JSValue::encode(description);
}
// FIXME: Use the enumeration cache.
-JSValue JSC_HOST_CALL objectConstructorGetOwnPropertyNames(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyNames(ExecState* exec)
{
- if (!args.at(0).isObject())
- return throwError(exec, TypeError, "Requested property names of a value that is not an object.");
+ if (!exec->argument(0).isObject())
+ return throwVMError(exec, createTypeError(exec, "Requested property names of a value that is not an object."));
PropertyNameArray properties(exec);
- asObject(args.at(0))->getOwnPropertyNames(exec, properties, IncludeDontEnumProperties);
+ asObject(exec->argument(0))->getOwnPropertyNames(exec, properties, IncludeDontEnumProperties);
JSArray* names = constructEmptyArray(exec);
size_t numProperties = properties.size();
for (size_t i = 0; i < numProperties; i++)
names->push(exec, jsOwnedString(exec, properties[i].ustring()));
- return names;
+ return JSValue::encode(names);
}
// FIXME: Use the enumeration cache.
-JSValue JSC_HOST_CALL objectConstructorKeys(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL objectConstructorKeys(ExecState* exec)
{
- if (!args.at(0).isObject())
- return throwError(exec, TypeError, "Requested keys of a value that is not an object.");
+ if (!exec->argument(0).isObject())
+ return throwVMError(exec, createTypeError(exec, "Requested keys of a value that is not an object."));
PropertyNameArray properties(exec);
- asObject(args.at(0))->getOwnPropertyNames(exec, properties);
+ asObject(exec->argument(0))->getOwnPropertyNames(exec, properties);
JSArray* keys = constructEmptyArray(exec);
size_t numProperties = properties.size();
for (size_t i = 0; i < numProperties; i++)
keys->push(exec, jsOwnedString(exec, properties[i].ustring()));
- return keys;
+ return JSValue::encode(keys);
}
// ES5 8.10.5 ToPropertyDescriptor
static bool toPropertyDescriptor(ExecState* exec, JSValue in, PropertyDescriptor& desc)
{
if (!in.isObject()) {
- throwError(exec, TypeError, "Property description must be an object.");
+ throwError(exec, createTypeError(exec, "Property description must be an object."));
return false;
}
JSObject* description = asObject(in);
return false;
if (!get.isUndefined()) {
CallData callData;
- if (get.getCallData(callData) == CallTypeNone) {
- throwError(exec, TypeError, "Getter must be a function.");
+ if (getCallData(get, callData) == CallTypeNone) {
+ throwError(exec, createTypeError(exec, "Getter must be a function."));
return false;
}
} else
return false;
if (!set.isUndefined()) {
CallData callData;
- if (set.getCallData(callData) == CallTypeNone) {
- throwError(exec, TypeError, "Setter must be a function.");
+ if (getCallData(set, callData) == CallTypeNone) {
+ throwError(exec, createTypeError(exec, "Setter must be a function."));
return false;
}
} else
return true;
if (desc.value()) {
- throwError(exec, TypeError, "Invalid property. 'value' present on property with getter or setter.");
+ throwError(exec, createTypeError(exec, "Invalid property. 'value' present on property with getter or setter."));
return false;
}
if (desc.writablePresent()) {
- throwError(exec, TypeError, "Invalid property. 'writable' present on property with getter or setter.");
+ throwError(exec, createTypeError(exec, "Invalid property. 'writable' present on property with getter or setter."));
return false;
}
return true;
}
-JSValue JSC_HOST_CALL objectConstructorDefineProperty(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL objectConstructorDefineProperty(ExecState* exec)
{
- if (!args.at(0).isObject())
- return throwError(exec, TypeError, "Properties can only be defined on Objects.");
- JSObject* O = asObject(args.at(0));
- UString propertyName = args.at(1).toString(exec);
+ if (!exec->argument(0).isObject())
+ return throwVMError(exec, createTypeError(exec, "Properties can only be defined on Objects."));
+ JSObject* O = asObject(exec->argument(0));
+ UString propertyName = exec->argument(1).toString(exec);
if (exec->hadException())
- return jsNull();
+ return JSValue::encode(jsNull());
PropertyDescriptor descriptor;
- if (!toPropertyDescriptor(exec, args.at(2), descriptor))
- return jsNull();
+ if (!toPropertyDescriptor(exec, exec->argument(2), descriptor))
+ return JSValue::encode(jsNull());
ASSERT((descriptor.attributes() & (Getter | Setter)) || (!descriptor.isAccessorDescriptor()));
ASSERT(!exec->hadException());
O->defineOwnProperty(exec, Identifier(exec, propertyName), descriptor, true);
- return O;
+ return JSValue::encode(O);
}
static JSValue defineProperties(ExecState* exec, JSObject* object, JSObject* properties)
return object;
}
-JSValue JSC_HOST_CALL objectConstructorDefineProperties(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL objectConstructorDefineProperties(ExecState* exec)
+{
+ if (!exec->argument(0).isObject())
+ return throwVMError(exec, createTypeError(exec, "Properties can only be defined on Objects."));
+ if (!exec->argument(1).isObject())
+ return throwVMError(exec, createTypeError(exec, "Property descriptor list must be an Object."));
+ return JSValue::encode(defineProperties(exec, asObject(exec->argument(0)), asObject(exec->argument(1))));
+}
+
+EncodedJSValue JSC_HOST_CALL objectConstructorCreate(ExecState* exec)
+{
+ if (!exec->argument(0).isObject() && !exec->argument(0).isNull())
+ return throwVMError(exec, createTypeError(exec, "Object prototype may only be an Object or null."));
+ JSValue proto = exec->argument(0);
+ JSObject* newObject = proto.isObject() ? constructEmptyObject(exec, asObject(proto)->inheritorID(exec->globalData())) : constructEmptyObject(exec, exec->lexicalGlobalObject()->nullPrototypeObjectStructure());
+ if (exec->argument(1).isUndefined())
+ return JSValue::encode(newObject);
+ if (!exec->argument(1).isObject())
+ return throwVMError(exec, createTypeError(exec, "Property descriptor list must be an Object."));
+ return JSValue::encode(defineProperties(exec, newObject, asObject(exec->argument(1))));
+}
+
+EncodedJSValue JSC_HOST_CALL objectConstructorSeal(ExecState* exec)
+{
+ JSValue obj = exec->argument(0);
+ if (!obj.isObject())
+ return throwVMError(exec, createTypeError(exec, "Object.seal can only be called on Objects."));
+ asObject(obj)->seal(exec->globalData());
+ return JSValue::encode(obj);
+}
+
+EncodedJSValue JSC_HOST_CALL objectConstructorFreeze(ExecState* exec)
+{
+ JSValue obj = exec->argument(0);
+ if (!obj.isObject())
+ return throwVMError(exec, createTypeError(exec, "Object.freeze can only be called on Objects."));
+ asObject(obj)->freeze(exec->globalData());
+ return JSValue::encode(obj);
+}
+
+EncodedJSValue JSC_HOST_CALL objectConstructorPreventExtensions(ExecState* exec)
+{
+ JSValue obj = exec->argument(0);
+ if (!obj.isObject())
+ return throwVMError(exec, createTypeError(exec, "Object.preventExtensions can only be called on Objects."));
+ asObject(obj)->preventExtensions(exec->globalData());
+ return JSValue::encode(obj);
+}
+
+EncodedJSValue JSC_HOST_CALL objectConstructorIsSealed(ExecState* exec)
+{
+ JSValue obj = exec->argument(0);
+ if (!obj.isObject())
+ return throwVMError(exec, createTypeError(exec, "Object.isSealed can only be called on Objects."));
+ return JSValue::encode(jsBoolean(asObject(obj)->isSealed(exec->globalData())));
+}
+
+EncodedJSValue JSC_HOST_CALL objectConstructorIsFrozen(ExecState* exec)
{
- if (!args.at(0).isObject())
- return throwError(exec, TypeError, "Properties can only be defined on Objects.");
- if (!args.at(1).isObject())
- return throwError(exec, TypeError, "Property descriptor list must be an Object.");
- return defineProperties(exec, asObject(args.at(0)), asObject(args.at(1)));
+ JSValue obj = exec->argument(0);
+ if (!obj.isObject())
+ return throwVMError(exec, createTypeError(exec, "Object.isFrozen can only be called on Objects."));
+ return JSValue::encode(jsBoolean(asObject(obj)->isFrozen(exec->globalData())));
}
-JSValue JSC_HOST_CALL objectConstructorCreate(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL objectConstructorIsExtensible(ExecState* exec)
{
- if (!args.at(0).isObject() && !args.at(0).isNull())
- return throwError(exec, TypeError, "Object prototype may only be an Object or null.");
- JSObject* newObject = constructEmptyObject(exec);
- newObject->setPrototype(args.at(0));
- if (args.at(1).isUndefined())
- return newObject;
- if (!args.at(1).isObject())
- return throwError(exec, TypeError, "Property descriptor list must be an Object.");
- return defineProperties(exec, newObject, asObject(args.at(1)));
+ JSValue obj = exec->argument(0);
+ if (!obj.isObject())
+ return throwVMError(exec, createTypeError(exec, "Object.isExtensible can only be called on Objects."));
+ return JSValue::encode(jsBoolean(asObject(obj)->isExtensible()));
}
} // namespace JSC
class ObjectConstructor : public InternalFunction {
public:
- ObjectConstructor(ExecState*, NonNullPassRefPtr<Structure>, ObjectPrototype*, Structure* prototypeFunctionStructure);
+ ObjectConstructor(ExecState*, JSGlobalObject*, Structure*, ObjectPrototype*);
+
+ virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
+ virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
+
+ static const ClassInfo s_info;
+
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
+ {
+ return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
+ }
+
+ protected:
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InternalFunction::StructureFlags;
private:
virtual ConstructType getConstructData(ConstructData&);
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2011 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
#include "JSFunction.h"
#include "JSString.h"
#include "JSStringBuilder.h"
-#include "PrototypeFunction.h"
namespace JSC {
+static EncodedJSValue JSC_HOST_CALL objectProtoFuncValueOf(ExecState*);
+static EncodedJSValue JSC_HOST_CALL objectProtoFuncHasOwnProperty(ExecState*);
+static EncodedJSValue JSC_HOST_CALL objectProtoFuncIsPrototypeOf(ExecState*);
+static EncodedJSValue JSC_HOST_CALL objectProtoFuncDefineGetter(ExecState*);
+static EncodedJSValue JSC_HOST_CALL objectProtoFuncDefineSetter(ExecState*);
+static EncodedJSValue JSC_HOST_CALL objectProtoFuncLookupGetter(ExecState*);
+static EncodedJSValue JSC_HOST_CALL objectProtoFuncLookupSetter(ExecState*);
+static EncodedJSValue JSC_HOST_CALL objectProtoFuncPropertyIsEnumerable(ExecState*);
+static EncodedJSValue JSC_HOST_CALL objectProtoFuncToLocaleString(ExecState*);
+
+}
+
+#include "ObjectPrototype.lut.h"
+
+namespace JSC {
+
+const ClassInfo ObjectPrototype::s_info = { "Object", &JSNonFinalObject::s_info, 0, ExecState::objectPrototypeTable };
+
+/* Source for ObjectPrototype.lut.h
+@begin objectPrototypeTable
+ toString objectProtoFuncToString DontEnum|Function 0
+ toLocaleString objectProtoFuncToLocaleString DontEnum|Function 0
+ valueOf objectProtoFuncValueOf DontEnum|Function 0
+ hasOwnProperty objectProtoFuncHasOwnProperty DontEnum|Function 1
+ propertyIsEnumerable objectProtoFuncPropertyIsEnumerable DontEnum|Function 1
+ isPrototypeOf objectProtoFuncIsPrototypeOf DontEnum|Function 1
+ __defineGetter__ objectProtoFuncDefineGetter DontEnum|Function 2
+ __defineSetter__ objectProtoFuncDefineSetter DontEnum|Function 2
+ __lookupGetter__ objectProtoFuncLookupGetter DontEnum|Function 1
+ __lookupSetter__ objectProtoFuncLookupSetter DontEnum|Function 1
+@end
+*/
+
ASSERT_CLASS_FITS_IN_CELL(ObjectPrototype);
-static JSValue JSC_HOST_CALL objectProtoFuncValueOf(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL objectProtoFuncHasOwnProperty(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL objectProtoFuncIsPrototypeOf(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL objectProtoFuncDefineGetter(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL objectProtoFuncDefineSetter(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL objectProtoFuncLookupGetter(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL objectProtoFuncLookupSetter(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL objectProtoFuncPropertyIsEnumerable(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL objectProtoFuncToLocaleString(ExecState*, JSObject*, JSValue, const ArgList&);
-
-ObjectPrototype::ObjectPrototype(ExecState* exec, NonNullPassRefPtr<Structure> stucture, Structure* prototypeFunctionStructure)
- : JSObject(stucture)
+ObjectPrototype::ObjectPrototype(ExecState* exec, JSGlobalObject* globalObject, Structure* stucture)
+ : JSNonFinalObject(exec->globalData(), stucture)
, m_hasNoPropertiesWithUInt32Names(true)
{
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 0, exec->propertyNames().toString, objectProtoFuncToString), DontEnum);
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 0, exec->propertyNames().toLocaleString, objectProtoFuncToLocaleString), DontEnum);
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 0, exec->propertyNames().valueOf, objectProtoFuncValueOf), DontEnum);
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().hasOwnProperty, objectProtoFuncHasOwnProperty), DontEnum);
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().propertyIsEnumerable, objectProtoFuncPropertyIsEnumerable), DontEnum);
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().isPrototypeOf, objectProtoFuncIsPrototypeOf), DontEnum);
-
- // Mozilla extensions
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 2, exec->propertyNames().__defineGetter__, objectProtoFuncDefineGetter), DontEnum);
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 2, exec->propertyNames().__defineSetter__, objectProtoFuncDefineSetter), DontEnum);
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().__lookupGetter__, objectProtoFuncLookupGetter), DontEnum);
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().__lookupSetter__, objectProtoFuncLookupSetter), DontEnum);
+ ASSERT(inherits(&s_info));
+ putAnonymousValue(globalObject->globalData(), 0, globalObject);
}
void ObjectPrototype::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
{
- JSObject::put(exec, propertyName, value, slot);
+ JSNonFinalObject::put(exec, propertyName, value, slot);
if (m_hasNoPropertiesWithUInt32Names) {
bool isUInt32;
- propertyName.toStrictUInt32(&isUInt32);
+ propertyName.toUInt32(isUInt32);
m_hasNoPropertiesWithUInt32Names = !isUInt32;
}
}
{
if (m_hasNoPropertiesWithUInt32Names)
return false;
- return JSObject::getOwnPropertySlot(exec, propertyName, slot);
+ return JSNonFinalObject::getOwnPropertySlot(exec, propertyName, slot);
}
-// ------------------------------ Functions --------------------------------
+bool ObjectPrototype::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot &slot)
+{
+ return getStaticFunctionSlot<JSNonFinalObject>(exec, ExecState::objectPrototypeTable(exec), this, propertyName, slot);
+}
-// ECMA 15.2.4.2, 15.2.4.4, 15.2.4.5, 15.2.4.7
+bool ObjectPrototype::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ return getStaticFunctionDescriptor<JSNonFinalObject>(exec, ExecState::objectPrototypeTable(exec), this, propertyName, descriptor);
+}
+
+// ------------------------------ Functions --------------------------------
-JSValue JSC_HOST_CALL objectProtoFuncValueOf(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL objectProtoFuncValueOf(ExecState* exec)
{
- return thisValue.toThisObject(exec);
+ JSValue thisValue = exec->hostThisValue();
+ return JSValue::encode(thisValue.toThisObject(exec));
}
-JSValue JSC_HOST_CALL objectProtoFuncHasOwnProperty(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL objectProtoFuncHasOwnProperty(ExecState* exec)
{
- return jsBoolean(thisValue.toThisObject(exec)->hasOwnProperty(exec, Identifier(exec, args.at(0).toString(exec))));
+ JSValue thisValue = exec->hostThisValue();
+ return JSValue::encode(jsBoolean(thisValue.toThisObject(exec)->hasOwnProperty(exec, Identifier(exec, exec->argument(0).toString(exec)))));
}
-JSValue JSC_HOST_CALL objectProtoFuncIsPrototypeOf(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL objectProtoFuncIsPrototypeOf(ExecState* exec)
{
+ JSValue thisValue = exec->hostThisValue();
JSObject* thisObj = thisValue.toThisObject(exec);
- if (!args.at(0).isObject())
- return jsBoolean(false);
+ if (!exec->argument(0).isObject())
+ return JSValue::encode(jsBoolean(false));
- JSValue v = asObject(args.at(0))->prototype();
+ JSValue v = asObject(exec->argument(0))->prototype();
while (true) {
if (!v.isObject())
- return jsBoolean(false);
- if (v == thisObj)\v
- return jsBoolean(true);
+ return JSValue::encode(jsBoolean(false));
+ if (v == thisObj)
+ return JSValue::encode(jsBoolean(true));
v = asObject(v)->prototype();
}
}
-JSValue JSC_HOST_CALL objectProtoFuncDefineGetter(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL objectProtoFuncDefineGetter(ExecState* exec)
{
+ JSValue thisValue = exec->hostThisValue();
CallData callData;
- if (args.at(1).getCallData(callData) == CallTypeNone)
- return throwError(exec, SyntaxError, "invalid getter usage");
- thisValue.toThisObject(exec)->defineGetter(exec, Identifier(exec, args.at(0).toString(exec)), asObject(args.at(1)));
- return jsUndefined();
+ if (getCallData(exec->argument(1), callData) == CallTypeNone)
+ return throwVMError(exec, createSyntaxError(exec, "invalid getter usage"));
+ thisValue.toThisObject(exec)->defineGetter(exec, Identifier(exec, exec->argument(0).toString(exec)), asObject(exec->argument(1)));
+ return JSValue::encode(jsUndefined());
}
-JSValue JSC_HOST_CALL objectProtoFuncDefineSetter(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL objectProtoFuncDefineSetter(ExecState* exec)
{
+ JSValue thisValue = exec->hostThisValue();
CallData callData;
- if (args.at(1).getCallData(callData) == CallTypeNone)
- return throwError(exec, SyntaxError, "invalid setter usage");
- thisValue.toThisObject(exec)->defineSetter(exec, Identifier(exec, args.at(0).toString(exec)), asObject(args.at(1)));
- return jsUndefined();
+ if (getCallData(exec->argument(1), callData) == CallTypeNone)
+ return throwVMError(exec, createSyntaxError(exec, "invalid setter usage"));
+ thisValue.toThisObject(exec)->defineSetter(exec, Identifier(exec, exec->argument(0).toString(exec)), asObject(exec->argument(1)));
+ return JSValue::encode(jsUndefined());
}
-JSValue JSC_HOST_CALL objectProtoFuncLookupGetter(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL objectProtoFuncLookupGetter(ExecState* exec)
{
- return thisValue.toThisObject(exec)->lookupGetter(exec, Identifier(exec, args.at(0).toString(exec)));
+ JSValue thisValue = exec->hostThisValue();
+ return JSValue::encode(thisValue.toThisObject(exec)->lookupGetter(exec, Identifier(exec, exec->argument(0).toString(exec))));
}
-JSValue JSC_HOST_CALL objectProtoFuncLookupSetter(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL objectProtoFuncLookupSetter(ExecState* exec)
{
- return thisValue.toThisObject(exec)->lookupSetter(exec, Identifier(exec, args.at(0).toString(exec)));
+ JSValue thisValue = exec->hostThisValue();
+ return JSValue::encode(thisValue.toThisObject(exec)->lookupSetter(exec, Identifier(exec, exec->argument(0).toString(exec))));
}
-JSValue JSC_HOST_CALL objectProtoFuncPropertyIsEnumerable(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL objectProtoFuncPropertyIsEnumerable(ExecState* exec)
{
- return jsBoolean(thisValue.toThisObject(exec)->propertyIsEnumerable(exec, Identifier(exec, args.at(0).toString(exec))));
+ JSValue thisValue = exec->hostThisValue();
+ return JSValue::encode(jsBoolean(thisValue.toThisObject(exec)->propertyIsEnumerable(exec, Identifier(exec, exec->argument(0).toString(exec)))));
}
-JSValue JSC_HOST_CALL objectProtoFuncToLocaleString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL objectProtoFuncToLocaleString(ExecState* exec)
{
- return thisValue.toThisJSString(exec);
+ JSValue thisValue = exec->hostThisValue();
+ return JSValue::encode(thisValue.toThisJSString(exec));
}
-JSValue JSC_HOST_CALL objectProtoFuncToString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL objectProtoFuncToString(ExecState* exec)
{
- return jsMakeNontrivialString(exec, "[object ", thisValue.toThisObject(exec)->className(), "]");
+ JSValue thisValue = exec->hostThisValue();
+ return JSValue::encode(jsMakeNontrivialString(exec, "[object ", thisValue.toThisObject(exec)->className(), "]"));
}
} // namespace JSC
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2011 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
namespace JSC {
- class ObjectPrototype : public JSObject {
+ class ObjectPrototype : public JSNonFinalObject {
public:
- ObjectPrototype(ExecState*, NonNullPassRefPtr<Structure>, Structure* prototypeFunctionStructure);
+ ObjectPrototype(ExecState*, JSGlobalObject*, Structure*);
+
+ static const ClassInfo s_info;
+
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
+ {
+ return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
+ }
+
+ protected:
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | JSNonFinalObject::StructureFlags;
+ static const unsigned AnonymousSlotCount = JSNonFinalObject::AnonymousSlotCount + 1;
private:
virtual void put(ExecState*, const Identifier&, JSValue, PutPropertySlot&);
+ virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
+ virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
bool m_hasNoPropertiesWithUInt32Names;
};
- JSValue JSC_HOST_CALL objectProtoFuncToString(ExecState*, JSObject*, JSValue, const ArgList&);
+ EncodedJSValue JSC_HOST_CALL objectProtoFuncToString(ExecState*);
} // namespace JSC
if (p2.isString())
return jsString(callFrame, p1.toString(callFrame), asString(p2));
- return jsNumber(callFrame, p1.toNumber(callFrame) + p2.toNumber(callFrame));
+ return jsNumber(p1.toNumber(callFrame) + p2.toNumber(callFrame));
}
JSValue jsTypeStringForValue(CallFrame* callFrame, JSValue v)
if (!v.isCell())
return v.isNull();
- JSType type = asCell(v)->structure()->typeInfo().type();
+ JSType type = v.asCell()->structure()->typeInfo().type();
if (type == NumberType || type == StringType)
return false;
if (type == ObjectType) {
#include "ExceptionHelpers.h"
#include "Interpreter.h"
-#include "JSImmediate.h"
-#include "JSNumberCell.h"
#include "JSString.h"
+#include "JSValueInlineMethods.h"
namespace JSC {
if ((length1 + length2) < length1)
return throwOutOfMemoryError(exec);
- unsigned fiberCount = s1->size() + s2->size();
+ unsigned fiberCount = s1->fiberCount() + s2->fiberCount();
JSGlobalData* globalData = &exec->globalData();
if (fiberCount <= JSString::s_maxInternalRopeLength)
ALWAYS_INLINE JSValue jsString(ExecState* exec, const UString& u1, JSString* s2)
{
- unsigned length1 = u1.size();
+ unsigned length1 = u1.length();
if (!length1)
return s2;
unsigned length2 = s2->length();
if ((length1 + length2) < length1)
return throwOutOfMemoryError(exec);
- unsigned fiberCount = 1 + s2->size();
+ unsigned fiberCount = 1 + s2->fiberCount();
JSGlobalData* globalData = &exec->globalData();
if (fiberCount <= JSString::s_maxInternalRopeLength)
unsigned length1 = s1->length();
if (!length1)
return jsString(exec, u2);
- unsigned length2 = u2.size();
+ unsigned length2 = u2.length();
if (!length2)
return s1;
if ((length1 + length2) < length1)
return throwOutOfMemoryError(exec);
- unsigned fiberCount = s1->size() + 1;
+ unsigned fiberCount = s1->fiberCount() + 1;
JSGlobalData* globalData = &exec->globalData();
if (fiberCount <= JSString::s_maxInternalRopeLength)
ALWAYS_INLINE JSValue jsString(ExecState* exec, const UString& u1, const UString& u2)
{
- unsigned length1 = u1.size();
+ unsigned length1 = u1.length();
if (!length1)
return jsString(exec, u2);
- unsigned length2 = u2.size();
+ unsigned length2 = u2.length();
if (!length2)
return jsString(exec, u1);
if ((length1 + length2) < length1)
ALWAYS_INLINE JSValue jsString(ExecState* exec, const UString& u1, const UString& u2, const UString& u3)
{
- unsigned length1 = u1.size();
- unsigned length2 = u2.size();
- unsigned length3 = u3.size();
+ unsigned length1 = u1.length();
+ unsigned length2 = u2.length();
+ unsigned length3 = u3.length();
if (!length1)
return jsString(exec, u2, u3);
if (!length2)
for (unsigned i = 0; i < count; ++i) {
JSValue v = strings[i].jsValue();
if (LIKELY(v.isString()))
- fiberCount += asString(v)->size();
+ fiberCount += asString(v)->fiberCount();
else
++fiberCount;
}
return new (globalData) JSString(globalData, ropeBuilder.release());
}
- ALWAYS_INLINE JSValue jsString(ExecState* exec, JSValue thisValue, const ArgList& args)
+ ALWAYS_INLINE JSValue jsString(ExecState* exec, JSValue thisValue)
{
unsigned fiberCount = 0;
if (LIKELY(thisValue.isString()))
- fiberCount += asString(thisValue)->size();
+ fiberCount += asString(thisValue)->fiberCount();
else
++fiberCount;
- for (unsigned i = 0; i < args.size(); ++i) {
- JSValue v = args.at(i);
+ for (unsigned i = 0; i < exec->argumentCount(); ++i) {
+ JSValue v = exec->argument(i);
if (LIKELY(v.isString()))
- fiberCount += asString(v)->size();
+ fiberCount += asString(v)->fiberCount();
else
++fiberCount;
}
unsigned length = 0;
bool overflow = false;
- for (unsigned i = 0; i < args.size(); ++i) {
- JSValue v = args.at(i);
+ for (unsigned i = 0; i < exec->argumentCount(); ++i) {
+ JSValue v = exec->argument(i);
if (LIKELY(v.isString()))
ropeBuilder.append(asString(v));
else
{
double left = 0.0, right;
if (v1.getNumber(left) && v2.getNumber(right))
- return jsNumber(callFrame, left + right);
+ return jsNumber(left + right);
if (v1.isString()) {
return v2.isString()
inline size_t normalizePrototypeChain(CallFrame* callFrame, JSValue base, JSValue slotBase, const Identifier& propertyName, size_t& slotOffset)
{
- JSCell* cell = asCell(base);
+ JSCell* cell = base.asCell();
size_t count = 0;
while (slotBase != cell) {
if (v.isNull())
return 0;
- cell = asCell(v);
+ cell = v.asCell();
// Since we're accessing a prototype in a loop, it's a good bet that it
// should not be treated as a dictionary.
if (cell->structure()->isDictionary()) {
- asObject(cell)->flattenDictionaryObject();
+ asObject(cell)->flattenDictionaryObject(callFrame->globalData());
if (slotBase == cell)
- slotOffset = cell->structure()->get(propertyName);
+ slotOffset = cell->structure()->get(callFrame->globalData(), propertyName);
}
++count;
if (v.isNull())
return count;
- base = asCell(v);
+ base = v.asCell();
// Since we're accessing a prototype in a loop, it's a good bet that it
// should not be treated as a dictionary.
if (base->structure()->isDictionary())
- asObject(base)->flattenDictionaryObject();
+ asObject(base)->flattenDictionaryObject(callFrame->globalData());
++count;
}
}
- ALWAYS_INLINE JSValue resolveBase(CallFrame* callFrame, Identifier& property, ScopeChainNode* scopeChain)
+ ALWAYS_INLINE JSValue resolveBase(CallFrame* callFrame, Identifier& property, ScopeChainNode* scopeChain, bool isStrictPut)
{
ScopeChainIterator iter = scopeChain->begin();
ScopeChainIterator next = iter;
PropertySlot slot;
JSObject* base;
while (true) {
- base = *iter;
- if (next == end || base->getPropertySlot(callFrame, property, slot))
+ base = iter->get();
+ if (next == end) {
+ if (isStrictPut && !base->getPropertySlot(callFrame, property, slot))
+ return JSValue();
+ return base;
+ }
+ if (base->getPropertySlot(callFrame, property, slot))
return base;
iter = next;
#define PropertyMapHashTable_h
#include "UString.h"
+#include "WriteBarrier.h"
+#include <wtf/HashTable.h>
+#include <wtf/PassOwnPtr.h>
#include <wtf/Vector.h>
+
+#ifndef NDEBUG
+#define DUMP_PROPERTYMAP_STATS 0
+#else
+#define DUMP_PROPERTYMAP_STATS 0
+#endif
+
+#if DUMP_PROPERTYMAP_STATS
+
+extern int numProbes;
+extern int numCollisions;
+extern int numRehashes;
+extern int numRemoves;
+
+#endif
+
+#define PROPERTY_MAP_DELETED_ENTRY_KEY ((StringImpl*)1)
+
namespace JSC {
- struct PropertyMapEntry {
- UString::Rep* key;
- unsigned offset;
- unsigned attributes;
- JSCell* specificValue;
- unsigned index;
-
- PropertyMapEntry(UString::Rep* key, unsigned attributes, JSCell* specificValue)
- : key(key)
- , offset(0)
- , attributes(attributes)
- , specificValue(specificValue)
- , index(0)
+inline bool isPowerOf2(unsigned v)
+{
+ // Taken from http://www.cs.utk.edu/~vose/c-stuff/bithacks.html
+
+ return !(v & (v - 1)) && v;
+}
+
+inline unsigned nextPowerOf2(unsigned v)
+{
+ // Taken from http://www.cs.utk.edu/~vose/c-stuff/bithacks.html
+ // Devised by Sean Anderson, Sepember 14, 2001
+
+ v--;
+ v |= v >> 1;
+ v |= v >> 2;
+ v |= v >> 4;
+ v |= v >> 8;
+ v |= v >> 16;
+ v++;
+
+ return v;
+}
+
+struct PropertyMapEntry {
+ StringImpl* key;
+ unsigned offset;
+ unsigned attributes;
+ WriteBarrier<JSCell> specificValue;
+
+ PropertyMapEntry(JSGlobalData& globalData, JSCell* owner, StringImpl* key, unsigned offset, unsigned attributes, JSCell* specificValue)
+ : key(key)
+ , offset(offset)
+ , attributes(attributes)
+ , specificValue(globalData, owner, specificValue, WriteBarrier<JSCell>::MayBeNull)
+ {
+ }
+};
+
+class PropertyTable {
+ WTF_MAKE_FAST_ALLOCATED;
+
+ // This is the implementation for 'iterator' and 'const_iterator',
+ // used for iterating over the table in insertion order.
+ template<typename T>
+ class ordered_iterator {
+ public:
+ ordered_iterator<T>& operator++()
{
+ m_valuePtr = skipDeletedEntries(m_valuePtr + 1);
+ return *this;
}
- PropertyMapEntry(UString::Rep* key, unsigned offset, unsigned attributes, JSCell* specificValue, unsigned index)
- : key(key)
- , offset(offset)
- , attributes(attributes)
- , specificValue(specificValue)
- , index(index)
+ bool operator==(const ordered_iterator<T>& other)
{
+ return m_valuePtr == other.m_valuePtr;
+ }
+
+ bool operator!=(const ordered_iterator<T>& other)
+ {
+ return m_valuePtr != other.m_valuePtr;
+ }
+
+ T& operator*()
+ {
+ return *m_valuePtr;
}
- };
- // lastIndexUsed is an ever-increasing index used to identify the order items
- // were inserted into the property map. It's required that getEnumerablePropertyNames
- // return the properties in the order they were added for compatibility with other
- // browsers' JavaScript implementations.
- struct PropertyMapHashTable {
- unsigned sizeMask;
- unsigned size;
- unsigned keyCount;
- unsigned deletedSentinelCount;
- unsigned lastIndexUsed;
- Vector<unsigned>* deletedOffsets;
- unsigned entryIndices[1];
-
- PropertyMapEntry* entries()
+ T* operator->()
{
- // The entries vector comes after the indices vector.
- // The 0th item in the entries vector is not really used; it has to
- // have a 0 in its key to allow the hash table lookup to handle deleted
- // sentinels without any special-case code, but the other fields are unused.
- return reinterpret_cast<PropertyMapEntry*>(&entryIndices[size]);
+ return m_valuePtr;
}
- static size_t allocationSize(unsigned size)
+ ordered_iterator(T* valuePtr)
+ : m_valuePtr(valuePtr)
{
- // We never let a hash table get more than half full,
- // So the number of indices we need is the size of the hash table.
- // But the number of entries is half that (plus one for the deleted sentinel).
- return sizeof(PropertyMapHashTable)
- + (size - 1) * sizeof(unsigned)
- + (1 + size / 2) * sizeof(PropertyMapEntry);
}
+
+ private:
+ T* m_valuePtr;
};
+public:
+ typedef StringImpl* KeyType;
+ typedef PropertyMapEntry ValueType;
+
+ // The in order iterator provides overloaded * and -> to access the Value at the current position.
+ typedef ordered_iterator<ValueType> iterator;
+ typedef ordered_iterator<const ValueType> const_iterator;
+
+ // The find_iterator is a pair of a pointer to a Value* an the entry in the index.
+ // If 'find' does not find an entry then iter.first will be 0, and iter.second will
+ // give the point in m_index where an entry should be inserted.
+ typedef std::pair<ValueType*, unsigned> find_iterator;
+
+ // Constructor is passed an initial capacity, a PropertyTable to copy, or both.
+ explicit PropertyTable(unsigned initialCapacity);
+ PropertyTable(JSGlobalData&, JSCell*, const PropertyTable&);
+ PropertyTable(JSGlobalData&, JSCell*, unsigned initialCapacity, const PropertyTable&);
+ ~PropertyTable();
+
+ // Ordered iteration methods.
+ iterator begin();
+ iterator end();
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ // Find a value in the table.
+ find_iterator find(const KeyType& key);
+ // Add a value to the table
+ std::pair<find_iterator, bool> add(const ValueType& entry);
+ // Remove a value from the table.
+ void remove(const find_iterator& iter);
+ void remove(const KeyType& key);
+
+ // Returns the number of values in the hashtable.
+ unsigned size() const;
+
+ // Checks if there are any values in the hashtable.
+ bool isEmpty() const;
+
+ // Number of slots in the property storage array in use, included deletedOffsets.
+ unsigned propertyStorageSize() const;
+
+ // Used to maintain a list of unused entries in the property storage.
+ void clearDeletedOffsets();
+ bool hasDeletedOffset();
+ unsigned getDeletedOffset();
+ void addDeletedOffset(unsigned offset);
+
+ // Copy this PropertyTable, ensuring the copy has at least the capacity provided.
+ PassOwnPtr<PropertyTable> copy(JSGlobalData&, JSCell* owner, unsigned newCapacity);
+
+#ifndef NDEBUG
+ size_t sizeInMemory();
+ void checkConsistency();
+#endif
+
+private:
+ PropertyTable(const PropertyTable&);
+ // Used to insert a value known not to be in the table, and where we know capacity to be available.
+ void reinsert(const ValueType& entry);
+
+ // Rehash the table. Used to grow, or to recover deleted slots.
+ void rehash(unsigned newCapacity);
+
+ // The capacity of the table of values is half of the size of the index.
+ unsigned tableCapacity() const;
+
+ // We keep an extra deleted slot after the array to make iteration work,
+ // and to use for deleted values. Index values into the array are 1-based,
+ // so this is tableCapacity() + 1.
+ // For example, if m_tableSize is 16, then tableCapacity() is 8 - but the
+ // values array is actually 9 long (the 9th used for the deleted value/
+ // iteration guard). The 8 valid entries are numbered 1..8, so the
+ // deleted index is 9 (0 being reserved for empty).
+ unsigned deletedEntryIndex() const;
+
+ // Used in iterator creation/progression.
+ template<typename T>
+ static T* skipDeletedEntries(T* valuePtr);
+
+ // The table of values lies after the hash index.
+ ValueType* table();
+ const ValueType* table() const;
+
+ // total number of used entries in the values array - by either valid entries, or deleted ones.
+ unsigned usedCount() const;
+
+ // The size in bytes of data needed for by the table.
+ size_t dataSize();
+
+ // Calculates the appropriate table size (rounds up to a power of two).
+ static unsigned sizeForCapacity(unsigned capacity);
+
+ // Check if capacity is available.
+ bool canInsert();
+
+ unsigned m_indexSize;
+ unsigned m_indexMask;
+ unsigned* m_index;
+ unsigned m_keyCount;
+ unsigned m_deletedCount;
+ OwnPtr< Vector<unsigned> > m_deletedOffsets;
+
+ static const unsigned MinimumTableSize = 16;
+ static const unsigned EmptyEntryIndex = 0;
+};
+
+inline PropertyTable::PropertyTable(unsigned initialCapacity)
+ : m_indexSize(sizeForCapacity(initialCapacity))
+ , m_indexMask(m_indexSize - 1)
+ , m_index(static_cast<unsigned*>(fastZeroedMalloc(dataSize())))
+ , m_keyCount(0)
+ , m_deletedCount(0)
+{
+ ASSERT(isPowerOf2(m_indexSize));
+}
+
+inline PropertyTable::PropertyTable(JSGlobalData&, JSCell* owner, const PropertyTable& other)
+ : m_indexSize(other.m_indexSize)
+ , m_indexMask(other.m_indexMask)
+ , m_index(static_cast<unsigned*>(fastMalloc(dataSize())))
+ , m_keyCount(other.m_keyCount)
+ , m_deletedCount(other.m_deletedCount)
+{
+ ASSERT(isPowerOf2(m_indexSize));
+
+ memcpy(m_index, other.m_index, dataSize());
+
+ iterator end = this->end();
+ for (iterator iter = begin(); iter != end; ++iter) {
+ iter->key->ref();
+ Heap::writeBarrier(owner, iter->specificValue.get());
+ }
+
+ // Copy the m_deletedOffsets vector.
+ Vector<unsigned>* otherDeletedOffsets = other.m_deletedOffsets.get();
+ if (otherDeletedOffsets)
+ m_deletedOffsets = adoptPtr(new Vector<unsigned>(*otherDeletedOffsets));
+}
+
+inline PropertyTable::PropertyTable(JSGlobalData&, JSCell* owner, unsigned initialCapacity, const PropertyTable& other)
+ : m_indexSize(sizeForCapacity(initialCapacity))
+ , m_indexMask(m_indexSize - 1)
+ , m_index(static_cast<unsigned*>(fastZeroedMalloc(dataSize())))
+ , m_keyCount(0)
+ , m_deletedCount(0)
+{
+ ASSERT(isPowerOf2(m_indexSize));
+ ASSERT(initialCapacity >= other.m_keyCount);
+
+ const_iterator end = other.end();
+ for (const_iterator iter = other.begin(); iter != end; ++iter) {
+ ASSERT(canInsert());
+ reinsert(*iter);
+ iter->key->ref();
+ Heap::writeBarrier(owner, iter->specificValue.get());
+ }
+
+ // Copy the m_deletedOffsets vector.
+ Vector<unsigned>* otherDeletedOffsets = other.m_deletedOffsets.get();
+ if (otherDeletedOffsets)
+ m_deletedOffsets = adoptPtr(new Vector<unsigned>(*otherDeletedOffsets));
+}
+
+inline PropertyTable::~PropertyTable()
+{
+ iterator end = this->end();
+ for (iterator iter = begin(); iter != end; ++iter)
+ iter->key->deref();
+
+ fastFree(m_index);
+}
+
+inline PropertyTable::iterator PropertyTable::begin()
+{
+ return iterator(skipDeletedEntries(table()));
+}
+
+inline PropertyTable::iterator PropertyTable::end()
+{
+ return iterator(table() + usedCount());
+}
+
+inline PropertyTable::const_iterator PropertyTable::begin() const
+{
+ return const_iterator(skipDeletedEntries(table()));
+}
+
+inline PropertyTable::const_iterator PropertyTable::end() const
+{
+ return const_iterator(table() + usedCount());
+}
+
+inline PropertyTable::find_iterator PropertyTable::find(const KeyType& key)
+{
+ ASSERT(key);
+ unsigned hash = key->existingHash();
+ unsigned step = 0;
+
+#if DUMP_PROPERTYMAP_STATS
+ ++numProbes;
+#endif
+
+ while (true) {
+ unsigned entryIndex = m_index[hash & m_indexMask];
+ if (entryIndex == EmptyEntryIndex)
+ return std::make_pair((ValueType*)0, hash & m_indexMask);
+ if (key == table()[entryIndex - 1].key)
+ return std::make_pair(&table()[entryIndex - 1], hash & m_indexMask);
+
+#if DUMP_PROPERTYMAP_STATS
+ ++numCollisions;
+#endif
+
+ if (!step)
+ step =WTF::doubleHash(key->existingHash()) | 1;
+ hash += step;
+
+#if DUMP_PROPERTYMAP_STATS
+ ++numRehashes;
+#endif
+ }
+}
+
+inline std::pair<PropertyTable::find_iterator, bool> PropertyTable::add(const ValueType& entry)
+{
+ // Look for a value with a matching key already in the array.
+ find_iterator iter = find(entry.key);
+ if (iter.first)
+ return std::make_pair(iter, false);
+
+ // Ref the key
+ entry.key->ref();
+
+ // ensure capacity is available.
+ if (!canInsert()) {
+ rehash(m_keyCount + 1);
+ iter = find(entry.key);
+ ASSERT(!iter.first);
+ }
+
+ // Allocate a slot in the hashtable, and set the index to reference this.
+ unsigned entryIndex = usedCount() + 1;
+ m_index[iter.second] = entryIndex;
+ iter.first = &table()[entryIndex - 1];
+ *iter.first = entry;
+
+ ++m_keyCount;
+ return std::make_pair(iter, true);
+}
+
+inline void PropertyTable::remove(const find_iterator& iter)
+{
+ // Removing a key that doesn't exist does nothing!
+ if (!iter.first)
+ return;
+
+#if DUMP_PROPERTYMAP_STATS
+ ++numRemoves;
+#endif
+
+ // Replace this one element with the deleted sentinel. Also clear out
+ // the entry so we can iterate all the entries as needed.
+ m_index[iter.second] = deletedEntryIndex();
+ iter.first->key->deref();
+ iter.first->key = PROPERTY_MAP_DELETED_ENTRY_KEY;
+
+ ASSERT(m_keyCount >= 1);
+ --m_keyCount;
+ ++m_deletedCount;
+
+ if (m_deletedCount * 4 >= m_indexSize)
+ rehash(m_keyCount);
+}
+
+inline void PropertyTable::remove(const KeyType& key)
+{
+ remove(find(key));
+}
+
+// returns the number of values in the hashtable.
+inline unsigned PropertyTable::size() const
+{
+ return m_keyCount;
+}
+
+inline bool PropertyTable::isEmpty() const
+{
+ return !m_keyCount;
+}
+
+inline unsigned PropertyTable::propertyStorageSize() const
+{
+ return size() + (m_deletedOffsets ? m_deletedOffsets->size() : 0);
+}
+
+inline void PropertyTable::clearDeletedOffsets()
+{
+ m_deletedOffsets.clear();
+}
+
+inline bool PropertyTable::hasDeletedOffset()
+{
+ return m_deletedOffsets && !m_deletedOffsets->isEmpty();
+}
+
+inline unsigned PropertyTable::getDeletedOffset()
+{
+ unsigned offset = m_deletedOffsets->last();
+ m_deletedOffsets->removeLast();
+ return offset;
+}
+
+inline void PropertyTable::addDeletedOffset(unsigned offset)
+{
+ if (!m_deletedOffsets)
+ m_deletedOffsets = adoptPtr(new Vector<unsigned>);
+ m_deletedOffsets->append(offset);
+}
+
+inline PassOwnPtr<PropertyTable> PropertyTable::copy(JSGlobalData& globalData, JSCell* owner, unsigned newCapacity)
+{
+ ASSERT(newCapacity >= m_keyCount);
+
+ // Fast case; if the new table will be the same m_indexSize as this one, we can memcpy it,
+ // save rehashing all keys.
+ if (sizeForCapacity(newCapacity) == m_indexSize)
+ return adoptPtr(new PropertyTable(globalData, owner, *this));
+ return adoptPtr(new PropertyTable(globalData, owner, newCapacity, *this));
+}
+
+#ifndef NDEBUG
+inline size_t PropertyTable::sizeInMemory()
+{
+ size_t result = sizeof(PropertyTable) + dataSize();
+ if (m_deletedOffsets)
+ result += (m_deletedOffsets->capacity() * sizeof(unsigned));
+ return result;
+}
+#endif
+
+inline void PropertyTable::reinsert(const ValueType& entry)
+{
+ // Used to insert a value known not to be in the table, and where
+ // we know capacity to be available.
+ ASSERT(canInsert());
+ find_iterator iter = find(entry.key);
+ ASSERT(!iter.first);
+
+ unsigned entryIndex = usedCount() + 1;
+ m_index[iter.second] = entryIndex;
+ table()[entryIndex - 1] = entry;
+
+ ++m_keyCount;
+}
+
+inline void PropertyTable::rehash(unsigned newCapacity)
+{
+ unsigned* oldEntryIndices = m_index;
+ iterator iter = this->begin();
+ iterator end = this->end();
+
+ m_indexSize = sizeForCapacity(newCapacity);
+ m_indexMask = m_indexSize - 1;
+ m_keyCount = 0;
+ m_deletedCount = 0;
+ m_index = static_cast<unsigned*>(fastZeroedMalloc(dataSize()));
+
+ for (; iter != end; ++iter) {
+ ASSERT(canInsert());
+ reinsert(*iter);
+ }
+
+ fastFree(oldEntryIndices);
+}
+
+inline unsigned PropertyTable::tableCapacity() const { return m_indexSize >> 1; }
+
+inline unsigned PropertyTable::deletedEntryIndex() const { return tableCapacity() + 1; }
+
+template<typename T>
+inline T* PropertyTable::skipDeletedEntries(T* valuePtr)
+{
+ while (valuePtr->key == PROPERTY_MAP_DELETED_ENTRY_KEY)
+ ++valuePtr;
+ return valuePtr;
+}
+
+inline PropertyTable::ValueType* PropertyTable::table()
+{
+ // The table of values lies after the hash index.
+ return reinterpret_cast<ValueType*>(m_index + m_indexSize);
+}
+
+inline const PropertyTable::ValueType* PropertyTable::table() const
+{
+ // The table of values lies after the hash index.
+ return reinterpret_cast<const ValueType*>(m_index + m_indexSize);
+}
+
+inline unsigned PropertyTable::usedCount() const
+{
+ // Total number of used entries in the values array - by either valid entries, or deleted ones.
+ return m_keyCount + m_deletedCount;
+}
+
+inline size_t PropertyTable::dataSize()
+{
+ // The size in bytes of data needed for by the table.
+ return m_indexSize * sizeof(unsigned) + ((tableCapacity()) + 1) * sizeof(ValueType);
+}
+
+inline unsigned PropertyTable::sizeForCapacity(unsigned capacity)
+{
+ if (capacity < 8)
+ return MinimumTableSize;
+ return nextPowerOf2(capacity + 1) * 2;
+}
+
+inline bool PropertyTable::canInsert()
+{
+ return usedCount() < tableCapacity();
+}
+
} // namespace JSC
#endif // PropertyMapHashTable_h
#include "config.h"
#include "PropertyNameArray.h"
+#include "JSObject.h"
+#include "ScopeChain.h"
#include "Structure.h"
#include "StructureChain.h"
static const size_t setThreshold = 20;
-void PropertyNameArray::add(UString::Rep* identifier)
+void PropertyNameArray::add(StringImpl* identifier)
{
- ASSERT(identifier == UString::null().rep() || identifier == UString::Rep::empty() || identifier->isIdentifier());
+ ASSERT(!identifier || identifier == StringImpl::empty() || identifier->isIdentifier());
size_t size = m_data->propertyNameVector().size();
if (size < setThreshold) {
for (size_t i = 0; i < size; ++i) {
- if (identifier == m_data->propertyNameVector()[i].ustring().rep())
+ if (identifier == m_data->propertyNameVector()[i].impl())
return;
}
} else {
if (m_set.isEmpty()) {
for (size_t i = 0; i < size; ++i)
- m_set.add(m_data->propertyNameVector()[i].ustring().rep());
+ m_set.add(m_data->propertyNameVector()[i].impl());
}
if (!m_set.add(identifier).second)
return;
JSGlobalData* globalData() { return m_globalData; }
- void add(const Identifier& identifier) { add(identifier.ustring().rep()); }
- void add(UString::Rep*);
- void addKnownUnique(UString::Rep* identifier) { m_data->propertyNameVector().append(Identifier(m_globalData, identifier)); }
+ void add(const Identifier& identifier) { add(identifier.impl()); }
+ void add(StringImpl*);
+ void addKnownUnique(StringImpl* identifier) { m_data->propertyNameVector().append(Identifier(m_globalData, identifier)); }
Identifier& operator[](unsigned i) { return m_data->propertyNameVector()[i]; }
const Identifier& operator[](unsigned i) const { return m_data->propertyNameVector()[i]; }
const_iterator end() const { return m_data->propertyNameVector().end(); }
private:
- typedef HashSet<UString::Rep*, PtrHash<UString::Rep*> > IdentifierSet;
+ typedef HashSet<StringImpl*, PtrHash<StringImpl*> > IdentifierSet;
RefPtr<PropertyNameArrayData> m_data;
IdentifierSet m_set;
CallData callData;
CallType callType = m_data.getterFunc->getCallData(callData);
- if (callType == CallTypeHost)
- return callData.native.function(exec, m_data.getterFunc, thisValue(), exec->emptyList());
- ASSERT(callType == CallTypeJS);
- // FIXME: Can this be done more efficiently using the callData?
- return asFunction(m_data.getterFunc)->call(exec, thisValue(), exec->emptyList());
+ return call(exec, m_data.getterFunc, callType, callData, thisValue(), exec->emptyList());
}
} // namespace JSC
class ExecState;
class JSObject;
-#define JSC_VALUE_SLOT_MARKER 0
-#define JSC_REGISTER_SLOT_MARKER reinterpret_cast<GetValueFunc>(1)
+#define JSC_VALUE_MARKER 0
#define INDEX_GETTER_MARKER reinterpret_cast<GetValueFunc>(2)
#define GETTER_FUNCTION_MARKER reinterpret_cast<GetValueFunc>(3)
JSValue getValue(ExecState* exec, const Identifier& propertyName) const
{
- if (m_getValue == JSC_VALUE_SLOT_MARKER)
- return *m_data.valueSlot;
- if (m_getValue == JSC_REGISTER_SLOT_MARKER)
- return (*m_data.registerSlot).jsValue();
+ if (m_getValue == JSC_VALUE_MARKER)
+ return m_value;
if (m_getValue == INDEX_GETTER_MARKER)
return m_getIndexValue(exec, slotBase(), index());
if (m_getValue == GETTER_FUNCTION_MARKER)
JSValue getValue(ExecState* exec, unsigned propertyName) const
{
- if (m_getValue == JSC_VALUE_SLOT_MARKER)
- return *m_data.valueSlot;
- if (m_getValue == JSC_REGISTER_SLOT_MARKER)
- return (*m_data.registerSlot).jsValue();
+ if (m_getValue == JSC_VALUE_MARKER)
+ return m_value;
if (m_getValue == INDEX_GETTER_MARKER)
return m_getIndexValue(exec, m_slotBase, m_data.index);
if (m_getValue == GETTER_FUNCTION_MARKER)
return m_offset;
}
- void setValueSlot(JSValue* valueSlot)
+ void setValue(JSValue slotBase, JSValue value)
{
- ASSERT(valueSlot);
- clearBase();
+ ASSERT(value);
clearOffset();
- m_getValue = JSC_VALUE_SLOT_MARKER;
- m_data.valueSlot = valueSlot;
- }
-
- void setValueSlot(JSValue slotBase, JSValue* valueSlot)
- {
- ASSERT(valueSlot);
- m_getValue = JSC_VALUE_SLOT_MARKER;
+ m_getValue = JSC_VALUE_MARKER;
m_slotBase = slotBase;
- m_data.valueSlot = valueSlot;
+ m_value = value;
}
- void setValueSlot(JSValue slotBase, JSValue* valueSlot, size_t offset)
+ void setValue(JSValue slotBase, JSValue value, size_t offset)
{
- ASSERT(valueSlot);
- m_getValue = JSC_VALUE_SLOT_MARKER;
+ ASSERT(value);
+ m_getValue = JSC_VALUE_MARKER;
m_slotBase = slotBase;
- m_data.valueSlot = valueSlot;
+ m_value = value;
m_offset = offset;
m_cachedPropertyType = Value;
}
-
+
void setValue(JSValue value)
{
ASSERT(value);
clearBase();
clearOffset();
- m_getValue = JSC_VALUE_SLOT_MARKER;
+ m_getValue = JSC_VALUE_MARKER;
m_value = value;
- m_data.valueSlot = &m_value;
- }
-
- void setRegisterSlot(Register* registerSlot)
- {
- ASSERT(registerSlot);
- clearBase();
- clearOffset();
- m_getValue = JSC_REGISTER_SLOT_MARKER;
- m_data.registerSlot = registerSlot;
}
void setCustom(JSValue slotBase, GetValueFunc getValue)
JSValue m_slotBase;
union {
JSObject* getterFunc;
- JSValue* valueSlot;
- Register* registerSlot;
unsigned index;
} m_data;
#ifndef Protect_h
#define Protect_h
-#include "Collector.h"
+#include "Heap.h"
#include "JSValue.h"
namespace JSC {
inline void gcProtect(JSValue value)
{
if (value && value.isCell())
- gcProtect(asCell(value));
+ gcProtect(value.asCell());
}
inline void gcUnprotect(JSValue value)
{
if (value && value.isCell())
- gcUnprotect(asCell(value));
+ gcUnprotect(value.asCell());
}
- // FIXME: Share more code with RefPtr template? The only differences are the ref/deref operation
- // and the implicit conversion to raw pointer
- template <class T> class ProtectedPtr {
- public:
- ProtectedPtr() : m_ptr(0) {}
- ProtectedPtr(T* ptr);
- ProtectedPtr(const ProtectedPtr&);
- ~ProtectedPtr();
-
- template <class U> ProtectedPtr(const ProtectedPtr<U>&);
-
- T* get() const { return m_ptr; }
- operator T*() const { return m_ptr; }
- operator JSValue() const { return JSValue(m_ptr); }
- T* operator->() const { return m_ptr; }
-
- operator bool() const { return m_ptr; }
- bool operator!() const { return !m_ptr; }
-
- ProtectedPtr& operator=(const ProtectedPtr&);
- ProtectedPtr& operator=(T*);
-
- private:
- T* m_ptr;
- };
-
- class ProtectedJSValue {
- public:
- ProtectedJSValue() {}
- ProtectedJSValue(JSValue value);
- ProtectedJSValue(const ProtectedJSValue&);
- ~ProtectedJSValue();
-
- template <class U> ProtectedJSValue(const ProtectedPtr<U>&);
-
- JSValue get() const { return m_value; }
- operator JSValue() const { return m_value; }
- JSValue operator->() const { return m_value; }
-
- operator bool() const { return m_value; }
- bool operator!() const { return !m_value; }
-
- ProtectedJSValue& operator=(const ProtectedJSValue&);
- ProtectedJSValue& operator=(JSValue);
-
- private:
- JSValue m_value;
- };
-
- template <class T> inline ProtectedPtr<T>::ProtectedPtr(T* ptr)
- : m_ptr(ptr)
- {
- gcProtectNullTolerant(m_ptr);
- }
-
- template <class T> inline ProtectedPtr<T>::ProtectedPtr(const ProtectedPtr& o)
- : m_ptr(o.get())
- {
- gcProtectNullTolerant(m_ptr);
- }
-
- template <class T> inline ProtectedPtr<T>::~ProtectedPtr()
- {
- gcUnprotectNullTolerant(m_ptr);
- }
-
- template <class T> template <class U> inline ProtectedPtr<T>::ProtectedPtr(const ProtectedPtr<U>& o)
- : m_ptr(o.get())
- {
- gcProtectNullTolerant(m_ptr);
- }
-
- template <class T> inline ProtectedPtr<T>& ProtectedPtr<T>::operator=(const ProtectedPtr<T>& o)
- {
- T* optr = o.m_ptr;
- gcProtectNullTolerant(optr);
- gcUnprotectNullTolerant(m_ptr);
- m_ptr = optr;
- return *this;
- }
-
- template <class T> inline ProtectedPtr<T>& ProtectedPtr<T>::operator=(T* optr)
- {
- gcProtectNullTolerant(optr);
- gcUnprotectNullTolerant(m_ptr);
- m_ptr = optr;
- return *this;
- }
-
- inline ProtectedJSValue::ProtectedJSValue(JSValue value)
- : m_value(value)
- {
- gcProtect(m_value);
- }
-
- inline ProtectedJSValue::ProtectedJSValue(const ProtectedJSValue& o)
- : m_value(o.get())
- {
- gcProtect(m_value);
- }
-
- inline ProtectedJSValue::~ProtectedJSValue()
- {
- gcUnprotect(m_value);
- }
-
- template <class U> ProtectedJSValue::ProtectedJSValue(const ProtectedPtr<U>& o)
- : m_value(o.get())
- {
- gcProtect(m_value);
- }
-
- inline ProtectedJSValue& ProtectedJSValue::operator=(const ProtectedJSValue& o)
- {
- JSValue ovalue = o.m_value;
- gcProtect(ovalue);
- gcUnprotect(m_value);
- m_value = ovalue;
- return *this;
- }
-
- inline ProtectedJSValue& ProtectedJSValue::operator=(JSValue ovalue)
- {
- gcProtect(ovalue);
- gcUnprotect(m_value);
- m_value = ovalue;
- return *this;
- }
-
- template <class T> inline bool operator==(const ProtectedPtr<T>& a, const ProtectedPtr<T>& b) { return a.get() == b.get(); }
- template <class T> inline bool operator==(const ProtectedPtr<T>& a, const T* b) { return a.get() == b; }
- template <class T> inline bool operator==(const T* a, const ProtectedPtr<T>& b) { return a == b.get(); }
-
- template <class T> inline bool operator!=(const ProtectedPtr<T>& a, const ProtectedPtr<T>& b) { return a.get() != b.get(); }
- template <class T> inline bool operator!=(const ProtectedPtr<T>& a, const T* b) { return a.get() != b; }
- template <class T> inline bool operator!=(const T* a, const ProtectedPtr<T>& b) { return a != b.get(); }
-
- inline bool operator==(const ProtectedJSValue& a, const ProtectedJSValue& b) { return a.get() == b.get(); }
- inline bool operator==(const ProtectedJSValue& a, const JSValue b) { return a.get() == b; }
- template <class T> inline bool operator==(const ProtectedJSValue& a, const ProtectedPtr<T>& b) { return a.get() == JSValue(b.get()); }
- inline bool operator==(const JSValue a, const ProtectedJSValue& b) { return a == b.get(); }
- template <class T> inline bool operator==(const ProtectedPtr<T>& a, const ProtectedJSValue& b) { return JSValue(a.get()) == b.get(); }
-
- inline bool operator!=(const ProtectedJSValue& a, const ProtectedJSValue& b) { return a.get() != b.get(); }
- inline bool operator!=(const ProtectedJSValue& a, const JSValue b) { return a.get() != b; }
- template <class T> inline bool operator!=(const ProtectedJSValue& a, const ProtectedPtr<T>& b) { return a.get() != JSValue(b.get()); }
- inline bool operator!=(const JSValue a, const ProtectedJSValue& b) { return a != b.get(); }
- template <class T> inline bool operator!=(const ProtectedPtr<T>& a, const ProtectedJSValue& b) { return JSValue(a.get()) != b.get(); }
-
} // namespace JSC
#endif // Protect_h
+++ /dev/null
-/*
- * Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
- * Copyright (C) 2001 Peter Kelly (pmk@post.com)
- * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
- * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
- * Copyright (C) 2007 Maks Orlovich
- *
- * 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 "PrototypeFunction.h"
-
-#include "JSGlobalObject.h"
-#include <wtf/Assertions.h>
-
-namespace JSC {
-
-ASSERT_CLASS_FITS_IN_CELL(PrototypeFunction);
-
-PrototypeFunction::PrototypeFunction(ExecState* exec, int length, const Identifier& name, NativeFunction function)
- : InternalFunction(&exec->globalData(), exec->lexicalGlobalObject()->prototypeFunctionStructure(), name)
- , m_function(function)
-{
- ASSERT_ARG(function, function);
- putDirect(exec->propertyNames().length, jsNumber(exec, length), DontDelete | ReadOnly | DontEnum);
-}
-
-PrototypeFunction::PrototypeFunction(ExecState* exec, NonNullPassRefPtr<Structure> prototypeFunctionStructure, int length, const Identifier& name, NativeFunction function)
- : InternalFunction(&exec->globalData(), prototypeFunctionStructure, name)
- , m_function(function)
-{
- ASSERT_ARG(function, function);
- putDirect(exec->propertyNames().length, jsNumber(exec, length), DontDelete | ReadOnly | DontEnum);
-}
-
-CallType PrototypeFunction::getCallData(CallData& callData)
-{
- callData.native.function = m_function;
- return CallTypeHost;
-}
-
-} // namespace JSC
+++ /dev/null
-/*
- * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2003, 2006, 2007, 2008 Apple Inc. All rights reserved.
- * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
- * Copyright (C) 2007 Maks Orlovich
- *
- * 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.
- *
- */
-
-#ifndef PrototypeFunction_h
-#define PrototypeFunction_h
-
-#include "InternalFunction.h"
-#include "CallData.h"
-
-namespace JSC {
-
- class PrototypeFunction : public InternalFunction {
- public:
- PrototypeFunction(ExecState*, int length, const Identifier&, NativeFunction);
- PrototypeFunction(ExecState*, NonNullPassRefPtr<Structure>, int length, const Identifier&, NativeFunction);
-
- private:
- virtual CallType getCallData(CallData&);
-
- const NativeFunction m_function;
- };
-
-} // namespace JSC
-
-#endif // PrototypeFunction_h
public:
enum Type { Uncachable, ExistingProperty, NewProperty };
- PutPropertySlot()
+ PutPropertySlot(bool isStrictMode = false)
: m_type(Uncachable)
, m_base(0)
+ , m_isStrictMode(isStrictMode)
{
}
Type type() const { return m_type; }
JSObject* base() const { return m_base; }
+ bool isStrictMode() const { return m_isStrictMode; }
bool isCacheable() const { return m_type != Uncachable; }
size_t cachedOffset() const {
ASSERT(isCacheable());
return m_offset;
}
+
private:
Type m_type;
JSObject* m_base;
size_t m_offset;
+ bool m_isStrictMode;
};
} // namespace JSC
* Copyright (C) 1999-2001, 2004 Harri Porten (porten@kde.org)
* Copyright (c) 2007, 2008 Apple Inc. All rights reserved.
* Copyright (C) 2009 Torch Mobile, Inc.
+ * Copyright (C) 2010 Peter Varga (pvarga@inf.u-szeged.hu), University of Szeged
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
#include "config.h"
#include "RegExp.h"
+
#include "Lexer.h"
+#include "RegExpCache.h"
+#include "yarr/Yarr.h"
+#include "yarr/YarrJIT.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wtf/Assertions.h>
#include <wtf/OwnArrayPtr.h>
-
-#if ENABLE(YARR)
-
-#include "yarr/RegexCompiler.h"
-#if ENABLE(YARR_JIT)
-#include "yarr/RegexJIT.h"
-#else
-#include "yarr/RegexInterpreter.h"
-#endif
-
-#else
-
-#include <pcre/pcre.h>
-
-#endif
-
namespace JSC {
-inline RegExp::RegExp(JSGlobalData* globalData, const UString& pattern)
- : m_pattern(pattern)
- , m_flagBits(0)
- , m_constructionError(0)
- , m_numSubpatterns(0)
- , m_lastMatchStart(-1)
+const ClassInfo RegExp::s_info = { "RegExp", 0, 0, 0 };
+
+RegExpFlags regExpFlags(const UString& string)
{
- compile(globalData);
-}
+ RegExpFlags flags = NoFlags;
+
+ for (unsigned i = 0; i < string.length(); ++i) {
+ switch (string.characters()[i]) {
+ case 'g':
+ if (flags & FlagGlobal)
+ return InvalidFlags;
+ flags = static_cast<RegExpFlags>(flags | FlagGlobal);
+ break;
+
+ case 'i':
+ if (flags & FlagIgnoreCase)
+ return InvalidFlags;
+ flags = static_cast<RegExpFlags>(flags | FlagIgnoreCase);
+ break;
+
+ case 'm':
+ if (flags & FlagMultiline)
+ return InvalidFlags;
+ flags = static_cast<RegExpFlags>(flags | FlagMultiline);
+ break;
+
+ default:
+ return InvalidFlags;
+ }
+ }
-inline RegExp::RegExp(JSGlobalData* globalData, const UString& pattern, const UString& flags)
- : m_pattern(pattern)
- , m_flagBits(0)
+ return flags;
+}
+
+struct RegExpRepresentation {
+#if ENABLE(YARR_JIT)
+ Yarr::YarrCodeBlock m_regExpJITCode;
+#endif
+ OwnPtr<Yarr::BytecodePattern> m_regExpBytecode;
+};
+
+RegExp::RegExp(JSGlobalData* globalData, const UString& patternString, RegExpFlags flags)
+ : JSCell(*globalData, globalData->regExpStructure.get())
+ , m_state(NotCompiled)
+ , m_patternString(patternString)
+ , m_flags(flags)
, m_constructionError(0)
, m_numSubpatterns(0)
- , m_lastMatchStart(-1)
+#if ENABLE(REGEXP_TRACING)
+ , m_rtMatchCallCount(0)
+ , m_rtMatchFoundCount(0)
+#endif
{
- // NOTE: The global flag is handled on a case-by-case basis by functions like
- // String::match and RegExpObject::match.
- if (flags.find('g') != UString::NotFound)
- m_flagBits |= Global;
- if (flags.find('i') != UString::NotFound)
- m_flagBits |= IgnoreCase;
- if (flags.find('m') != UString::NotFound)
- m_flagBits |= Multiline;
-
- compile(globalData);
+ Yarr::YarrPattern pattern(m_patternString, ignoreCase(), multiline(), &m_constructionError);
+ if (m_constructionError)
+ m_state = ParseError;
+ else
+ m_numSubpatterns = pattern.m_numSubpatterns;
}
-#if !ENABLE(YARR)
RegExp::~RegExp()
{
- jsRegExpFree(m_regExp);
}
-#endif
-PassRefPtr<RegExp> RegExp::create(JSGlobalData* globalData, const UString& pattern)
+RegExp* RegExp::create(JSGlobalData* globalData, const UString& patternString, RegExpFlags flags)
{
- return adoptRef(new RegExp(globalData, pattern));
+ return globalData->regExpCache()->lookupOrCreate(patternString, flags);
}
-PassRefPtr<RegExp> RegExp::create(JSGlobalData* globalData, const UString& pattern, const UString& flags)
+void RegExp::compile(JSGlobalData* globalData)
{
- return adoptRef(new RegExp(globalData, pattern, flags));
-}
+ ASSERT(m_state == NotCompiled);
+ m_representation = adoptPtr(new RegExpRepresentation);
+ m_state = Compiling;
+ Yarr::YarrPattern pattern(m_patternString, ignoreCase(), multiline(), &m_constructionError);
+ if (m_constructionError) {
+ ASSERT_NOT_REACHED();
+ m_state = ParseError;
+ return;
+ }
-#if ENABLE(YARR)
+ globalData->regExpCache()->addToStrongCache(this);
+
+ ASSERT(m_numSubpatterns == pattern.m_numSubpatterns);
-void RegExp::compile(JSGlobalData* globalData)
-{
#if ENABLE(YARR_JIT)
- Yarr::jitCompileRegex(globalData, m_regExpJITCode, m_pattern, m_numSubpatterns, m_constructionError, ignoreCase(), multiline());
+ if (!pattern.m_containsBackreferences && globalData->canUseJIT()) {
+ Yarr::jitCompile(pattern, globalData, m_representation->m_regExpJITCode);
+#if ENABLE(YARR_JIT_DEBUG)
+ if (!m_representation->m_regExpJITCode.isFallBack())
+ m_state = JITCode;
+ else
+ m_state = ByteCode;
#else
- UNUSED_PARAM(globalData);
- m_regExpBytecode.set(Yarr::byteCompileRegex(m_pattern, m_numSubpatterns, m_constructionError, ignoreCase(), multiline()));
+ if (!m_representation->m_regExpJITCode.isFallBack()) {
+ m_state = JITCode;
+ return;
+ }
+#endif
+ }
#endif
+
+ m_representation->m_regExpBytecode = Yarr::byteCompile(pattern, &globalData->m_regExpAllocator);
+
+ m_state = ByteCode;
}
-int RegExp::match(const UString& s, int startOffset, Vector<int, 32>* ovector)
+int RegExp::match(JSGlobalData& globalData, const UString& s, int startOffset, Vector<int, 32>* ovector)
{
if (startOffset < 0)
startOffset = 0;
- if (ovector)
- ovector->clear();
- if (static_cast<unsigned>(startOffset) > s.size() || s.isNull()) {
- m_lastMatchString = UString();
- m_lastMatchStart = -1;
- m_lastOVector.shrink(0);
+#if ENABLE(REGEXP_TRACING)
+ m_rtMatchCallCount++;
+#endif
+
+ if (static_cast<unsigned>(startOffset) > s.length() || s.isNull())
return -1;
- }
-
- // Perform check to see if this match call is the same as the last match invocation
- // and if it is return the prior result.
- if ((startOffset == m_lastMatchStart) && (s.rep() == m_lastMatchString.rep())) {
- if (ovector)
- *ovector = m_lastOVector;
-
- if (m_lastOVector.isEmpty())
- return -1;
-
- return m_lastOVector.at(0);
- }
-#if ENABLE(YARR_JIT)
- if (!!m_regExpJITCode) {
-#else
- if (m_regExpBytecode) {
-#endif
- int offsetVectorSize = (m_numSubpatterns + 1) * 3; // FIXME: should be 2 - but adding temporary fallback to pcre.
+ if (m_state != ParseError) {
+ compileIfNecessary(globalData);
+
+ int offsetVectorSize = (m_numSubpatterns + 1) * 2;
int* offsetVector;
Vector<int, 32> nonReturnedOvector;
if (ovector) {
}
ASSERT(offsetVector);
- for (int j = 0; j < offsetVectorSize; ++j)
+ // Initialize offsetVector with the return value (index 0) and the
+ // first subpattern start indicies (even index values) set to -1.
+ // No need to init the subpattern end indicies.
+ for (unsigned j = 0, i = 0; i < m_numSubpatterns + 1; j += 2, i++)
offsetVector[j] = -1;
-
+ int result;
#if ENABLE(YARR_JIT)
- int result = Yarr::executeRegex(m_regExpJITCode, s.data(), startOffset, s.size(), offsetVector, offsetVectorSize);
-#else
- int result = Yarr::interpretRegex(m_regExpBytecode.get(), s.data(), startOffset, s.size(), offsetVector);
+ if (m_state == JITCode) {
+ result = Yarr::execute(m_representation->m_regExpJITCode, s.characters(), startOffset, s.length(), offsetVector);
+#if ENABLE(YARR_JIT_DEBUG)
+ matchCompareWithInterpreter(s, startOffset, offsetVector, result);
#endif
-
- if (result < 0) {
-#ifndef NDEBUG
- // TODO: define up a symbol, rather than magic -1
- if (result != -1)
- fprintf(stderr, "jsRegExpExecute failed with result %d\n", result);
+ } else
#endif
- if (ovector)
- ovector->clear();
- }
-
- m_lastMatchString = s;
- m_lastMatchStart = startOffset;
+ result = Yarr::interpret(m_representation->m_regExpBytecode.get(), s.characters(), startOffset, s.length(), offsetVector);
+ ASSERT(result >= -1);
- if (ovector)
- m_lastOVector = *ovector;
- else
- m_lastOVector = nonReturnedOvector;
+#if ENABLE(REGEXP_TRACING)
+ if (result != -1)
+ m_rtMatchFoundCount++;
+#endif
return result;
}
- m_lastMatchString = UString();
- m_lastMatchStart = -1;
- m_lastOVector.shrink(0);
-
return -1;
}
-#else
-
-void RegExp::compile(JSGlobalData*)
+void RegExp::invalidateCode()
{
- m_regExp = 0;
- JSRegExpIgnoreCaseOption ignoreCaseOption = ignoreCase() ? JSRegExpIgnoreCase : JSRegExpDoNotIgnoreCase;
- JSRegExpMultilineOption multilineOption = multiline() ? JSRegExpMultiline : JSRegExpSingleLine;
- m_regExp = jsRegExpCompile(reinterpret_cast<const UChar*>(m_pattern.data()), m_pattern.size(), ignoreCaseOption, multilineOption, &m_numSubpatterns, &m_constructionError);
+ if (!m_representation || m_state == Compiling)
+ return;
+ m_state = NotCompiled;
+ m_representation.clear();
}
-int RegExp::match(const UString& s, int startOffset, Vector<int, 32>* ovector)
+#if ENABLE(YARR_JIT_DEBUG)
+void RegExp::matchCompareWithInterpreter(const UString& s, int startOffset, int* offsetVector, int jitResult)
{
- if (startOffset < 0)
- startOffset = 0;
- if (ovector)
- ovector->clear();
-
- if (static_cast<unsigned>(startOffset) > s.size() || s.isNull())
- return -1;
-
- if (m_regExp) {
- // Set up the offset vector for the result.
- // First 2/3 used for result, the last third used by PCRE.
- int* offsetVector;
- int offsetVectorSize;
- int fixedSizeOffsetVector[3];
- if (!ovector) {
- offsetVectorSize = 3;
- offsetVector = fixedSizeOffsetVector;
+ int offsetVectorSize = (m_numSubpatterns + 1) * 2;
+ Vector<int, 32> interpreterOvector;
+ interpreterOvector.resize(offsetVectorSize);
+ int* interpreterOffsetVector = interpreterOvector.data();
+ int interpreterResult = 0;
+ int differences = 0;
+
+ // Initialize interpreterOffsetVector with the return value (index 0) and the
+ // first subpattern start indicies (even index values) set to -1.
+ // No need to init the subpattern end indicies.
+ for (unsigned j = 0, i = 0; i < m_numSubpatterns + 1; j += 2, i++)
+ interpreterOffsetVector[j] = -1;
+
+ interpreterResult = Yarr::interpret(m_representation->m_regExpBytecode.get(), s.characters(), startOffset, s.length(), interpreterOffsetVector);
+
+ if (jitResult != interpreterResult)
+ differences++;
+
+ for (unsigned j = 2, i = 0; i < m_numSubpatterns; j +=2, i++)
+ if ((offsetVector[j] != interpreterOffsetVector[j])
+ || ((offsetVector[j] >= 0) && (offsetVector[j+1] != interpreterOffsetVector[j+1])))
+ differences++;
+
+ if (differences) {
+ fprintf(stderr, "RegExp Discrepency for /%s/\n string input ", pattern().utf8().data());
+ unsigned segmentLen = s.length() - static_cast<unsigned>(startOffset);
+
+ fprintf(stderr, (segmentLen < 150) ? "\"%s\"\n" : "\"%148s...\"\n", s.utf8().data() + startOffset);
+
+ if (jitResult != interpreterResult) {
+ fprintf(stderr, " JIT result = %d, blah interpreted result = %d\n", jitResult, interpreterResult);
+ differences--;
} else {
- offsetVectorSize = (m_numSubpatterns + 1) * 3;
- ovector->resize(offsetVectorSize);
- offsetVector = ovector->data();
+ fprintf(stderr, " Correct result = %d\n", jitResult);
}
- int numMatches = jsRegExpExecute(m_regExp, reinterpret_cast<const UChar*>(s.data()), s.size(), startOffset, offsetVector, offsetVectorSize);
-
- if (numMatches < 0) {
-#ifndef NDEBUG
- if (numMatches != JSRegExpErrorNoMatch)
- fprintf(stderr, "jsRegExpExecute failed with result %d\n", numMatches);
-#endif
- if (ovector)
- ovector->clear();
- return -1;
+ if (differences) {
+ for (unsigned j = 2, i = 0; i < m_numSubpatterns; j +=2, i++) {
+ if (offsetVector[j] != interpreterOffsetVector[j])
+ fprintf(stderr, " JIT offset[%d] = %d, interpreted offset[%d] = %d\n", j, offsetVector[j], j, interpreterOffsetVector[j]);
+ if ((offsetVector[j] >= 0) && (offsetVector[j+1] != interpreterOffsetVector[j+1]))
+ fprintf(stderr, " JIT offset[%d] = %d, interpreted offset[%d] = %d\n", j+1, offsetVector[j+1], j+1, interpreterOffsetVector[j+1]);
+ }
}
-
- return offsetVector[0];
}
-
- return -1;
}
+#endif
+
+#if ENABLE(REGEXP_TRACING)
+ void RegExp::printTraceData()
+ {
+ char formattedPattern[41];
+ char rawPattern[41];
+
+ strncpy(rawPattern, pattern().utf8().data(), 40);
+ rawPattern[40]= '\0';
+ int pattLen = strlen(rawPattern);
+
+ snprintf(formattedPattern, 41, (pattLen <= 38) ? "/%.38s/" : "/%.36s...", rawPattern);
+
+#if ENABLE(YARR_JIT)
+ Yarr::YarrCodeBlock& codeBlock = m_representation->m_regExpJITCode;
+
+ const size_t jitAddrSize = 20;
+ char jitAddr[jitAddrSize];
+ if (m_state == JITCode)
+ snprintf(jitAddr, jitAddrSize, "fallback");
+ else
+ snprintf(jitAddr, jitAddrSize, "0x%014lx", reinterpret_cast<unsigned long int>(codeBlock.getAddr()));
+#else
+ const char* jitAddr = "JIT Off";
#endif
+ printf("%-40.40s %16.16s %10d %10d\n", formattedPattern, jitAddr, m_rtMatchCallCount, m_rtMatchFoundCount);
+ }
+#endif
+
} // namespace JSC
#include "UString.h"
#include "ExecutableAllocator.h"
+#include "Structure.h"
+#include "RegExpKey.h"
#include <wtf/Forward.h>
#include <wtf/RefCounted.h>
-#include "yarr/RegexJIT.h"
-#include "yarr/RegexInterpreter.h"
-
-struct JSRegExp;
namespace JSC {
+ struct RegExpRepresentation;
class JSGlobalData;
- class RegExp : public RefCounted<RegExp> {
+ RegExpFlags regExpFlags(const UString&);
+
+ class RegExp : public JSCell {
public:
- static PassRefPtr<RegExp> create(JSGlobalData* globalData, const UString& pattern);
- static PassRefPtr<RegExp> create(JSGlobalData* globalData, const UString& pattern, const UString& flags);
-#if !ENABLE(YARR)
+ static RegExp* create(JSGlobalData*, const UString& pattern, RegExpFlags);
~RegExp();
-#endif
- bool global() const { return m_flagBits & Global; }
- bool ignoreCase() const { return m_flagBits & IgnoreCase; }
- bool multiline() const { return m_flagBits & Multiline; }
+ bool global() const { return m_flags & FlagGlobal; }
+ bool ignoreCase() const { return m_flags & FlagIgnoreCase; }
+ bool multiline() const { return m_flags & FlagMultiline; }
- const UString& pattern() const { return m_pattern; }
+ const UString& pattern() const { return m_patternString; }
- bool isValid() const { return !m_constructionError; }
+ bool isValid() const { return !m_constructionError && m_flags != InvalidFlags; }
const char* errorMessage() const { return m_constructionError; }
- int match(const UString&, int startOffset, Vector<int, 32>* ovector = 0);
+ int match(JSGlobalData&, const UString&, int startOffset, Vector<int, 32>* ovector = 0);
unsigned numSubpatterns() const { return m_numSubpatterns; }
+ bool hasCode()
+ {
+ return m_representation;
+ }
+
+ void invalidateCode();
+
+#if ENABLE(REGEXP_TRACING)
+ void printTraceData();
+#endif
+
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
+ {
+ return Structure::create(globalData, prototype, TypeInfo(LeafType, 0), 0, &s_info);
+ }
+
+ static JS_EXPORTDATA const ClassInfo s_info;
+
+ RegExpKey key() { return RegExpKey(m_flags, m_patternString); }
+
private:
- RegExp(JSGlobalData* globalData, const UString& pattern);
- RegExp(JSGlobalData* globalData, const UString& pattern, const UString& flags);
+ friend class RegExpCache;
+ RegExp(JSGlobalData* globalData, const UString& pattern, RegExpFlags);
- void compile(JSGlobalData*);
+ enum RegExpState {
+ ParseError,
+ JITCode,
+ ByteCode,
+ NotCompiled,
+ Compiling
+ } m_state;
- enum FlagBits { Global = 1, IgnoreCase = 2, Multiline = 4 };
+ void compile(JSGlobalData*);
+ void compileIfNecessary(JSGlobalData& globalData)
+ {
+ if (m_representation)
+ return;
+ compile(&globalData);
+ }
+
+#if ENABLE(YARR_JIT_DEBUG)
+ void matchCompareWithInterpreter(const UString&, int startOffset, int* offsetVector, int jitResult);
+#endif
- UString m_pattern; // FIXME: Just decompile m_regExp instead of storing this.
- int m_flagBits;
+ UString m_patternString;
+ RegExpFlags m_flags;
const char* m_constructionError;
unsigned m_numSubpatterns;
- UString m_lastMatchString;
- int m_lastMatchStart;
- Vector<int, 32> m_lastOVector;
-
-#if ENABLE(YARR_JIT)
- Yarr::RegexCodeBlock m_regExpJITCode;
-#elif ENABLE(YARR)
- OwnPtr<Yarr::BytecodePattern> m_regExpBytecode;
-#else
- JSRegExp* m_regExp;
+#if ENABLE(REGEXP_TRACING)
+ unsigned m_rtMatchCallCount;
+ unsigned m_rtMatchFoundCount;
#endif
+
+ OwnPtr<RegExpRepresentation> m_representation;
};
} // namespace JSC
#include "config.h"
#include "RegExpCache.h"
+#include "RegExpObject.h"
namespace JSC {
-PassRefPtr<RegExp> RegExpCache::lookupOrCreate(const UString& patternString, const UString& flags)
+RegExp* RegExpCache::lookupOrCreate(const UString& patternString, RegExpFlags flags)
{
- if (isCacheable(patternString)) {
- pair<HashMap<RegExpKey, RefPtr<RegExp> >::iterator, bool> result = m_cacheMap.add(RegExpKey(flags, patternString), 0);
- if (!result.second)
- return result.first->second;
- }
- return create(patternString, flags);
+ RegExpKey key(flags, patternString);
+ RegExpCacheMap::iterator result = m_weakCache.find(key);
+ if (result != m_weakCache.end())
+ return result->second.get();
+ RegExp* regExp = new (m_globalData) RegExp(m_globalData, patternString, flags);
+#if ENABLE(REGEXP_TRACING)
+ m_globalData->addRegExpToTrace(regExp);
+#endif
+ // We need to do a second lookup to add the RegExp as
+ // allocating it may have caused a gc cycle, which in
+ // turn may have removed items from the cache.
+ m_weakCache.add(key, Weak<RegExp>(*m_globalData, regExp, this));
+ return regExp;
}
-PassRefPtr<RegExp> RegExpCache::create(const UString& patternString, const UString& flags)
+RegExpCache::RegExpCache(JSGlobalData* globalData)
+ : m_nextEntryInStrongCache(0)
+ , m_globalData(globalData)
{
- RefPtr<RegExp> regExp;
-
- if (!flags.isNull())
- regExp = RegExp::create(m_globalData, patternString, flags);
- else
- regExp = RegExp::create(m_globalData, patternString);
-
- if (patternString.size() >= maxCacheablePatternLength)
- return regExp;
+}
- ++m_nextKeyToEvict;
- if (m_nextKeyToEvict == maxCacheableEntries) {
- m_nextKeyToEvict = 0;
- m_isFull = true;
- }
- if (m_isFull)
- m_cacheMap.remove(RegExpKey(patternKeyArray[m_nextKeyToEvict].flagsValue, patternKeyArray[m_nextKeyToEvict].pattern));
+void RegExpCache::finalize(Handle<Unknown> handle, void*)
+{
+ RegExp* regExp = static_cast<RegExp*>(handle.get().asCell());
+ m_weakCache.remove(regExp->key());
+ regExp->invalidateCode();
+}
- RegExpKey key = RegExpKey(flags, patternString);
- m_cacheMap.set(key, regExp);
- patternKeyArray[m_nextKeyToEvict].flagsValue = key.flagsValue;
- patternKeyArray[m_nextKeyToEvict].pattern = patternString.rep();
- return regExp;
+void RegExpCache::addToStrongCache(RegExp* regExp)
+{
+ UString pattern = regExp->pattern();
+ if (pattern.length() > maxStrongCacheablePatternLength)
+ return;
+ m_strongCache[m_nextEntryInStrongCache].set(*m_globalData, regExp);
+ m_nextEntryInStrongCache++;
+ if (m_nextEntryInStrongCache == maxStrongCacheableEntries)
+ m_nextEntryInStrongCache = 0;
}
-RegExpCache::RegExpCache(JSGlobalData* globalData)
- : m_globalData(globalData)
- , m_nextKeyToEvict(-1)
- , m_isFull(false)
+void RegExpCache::invalidateCode()
{
+ for (int i = 0; i < maxStrongCacheableEntries; i++)
+ m_strongCache[i].clear();
+ m_nextEntryInStrongCache = 0;
+ RegExpCacheMap::iterator end = m_weakCache.end();
+ for (RegExpCacheMap::iterator ptr = m_weakCache.begin(); ptr != end; ++ptr)
+ ptr->second->invalidateCode();
}
}
#include "RegExp.h"
#include "RegExpKey.h"
+#include "Strong.h"
#include "UString.h"
+#include "Weak.h"
+#include <wtf/FixedArray.h>
+#include <wtf/HashMap.h>
#ifndef RegExpCache_h
#define RegExpCache_h
namespace JSC {
-class RegExpCache {
+class RegExpCache : private WeakHandleOwner {
+friend class RegExp;
+typedef HashMap<RegExpKey, Weak<RegExp> > RegExpCacheMap;
+
public:
- PassRefPtr<RegExp> lookupOrCreate(const UString& patternString, const UString& flags);
- PassRefPtr<RegExp> create(const UString& patternString, const UString& flags);
RegExpCache(JSGlobalData* globalData);
-
- static bool isCacheable(const UString& patternString) { return patternString.size() < maxCacheablePatternLength; }
+ void invalidateCode();
private:
- static const unsigned maxCacheablePatternLength = 256;
- static const int maxCacheableEntries = 32;
+
+ static const unsigned maxStrongCacheablePatternLength = 256;
+
+ static const int maxStrongCacheableEntries = 32;
+
+ virtual void finalize(Handle<Unknown>, void* context);
- typedef HashMap<RegExpKey, RefPtr<RegExp> > RegExpCacheMap;
- RegExpKey patternKeyArray[maxCacheableEntries];
- RegExpCacheMap m_cacheMap;
+ RegExp* lookupOrCreate(const UString& patternString, RegExpFlags);
+ void addToStrongCache(RegExp*);
+ RegExpCacheMap m_weakCache; // Holds all regular expressions currently live.
+ int m_nextEntryInStrongCache;
+ WTF::FixedArray<Strong<RegExp>, maxStrongCacheableEntries> m_strongCache; // Holds a select few regular expressions that have compiled and executed
JSGlobalData* m_globalData;
- int m_nextKeyToEvict;
- bool m_isFull;
};
} // namespace JSC
#include "ArrayPrototype.h"
#include "Error.h"
+#include "ExceptionHelpers.h"
#include "JSArray.h"
#include "JSFunction.h"
#include "JSString.h"
#include "RegExpPrototype.h"
#include "RegExp.h"
#include "RegExpCache.h"
+#include "UStringConcatenate.h"
+#include <wtf/PassOwnPtr.h>
+
+#include <wtf/PassOwnPtr.h>
namespace JSC {
ASSERT_CLASS_FITS_IN_CELL(RegExpConstructor);
-const ClassInfo RegExpConstructor::info = { "Function", &InternalFunction::info, 0, ExecState::regExpConstructorTable };
+const ClassInfo RegExpConstructor::s_info = { "Function", &InternalFunction::s_info, 0, ExecState::regExpConstructorTable };
/* Source for RegExpConstructor.lut.h
@begin regExpConstructorTable
@end
*/
-RegExpConstructor::RegExpConstructor(ExecState* exec, NonNullPassRefPtr<Structure> structure, RegExpPrototype* regExpPrototype)
- : InternalFunction(&exec->globalData(), structure, Identifier(exec, "RegExp"))
- , d(new RegExpConstructorPrivate)
+RegExpConstructor::RegExpConstructor(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, RegExpPrototype* regExpPrototype)
+ : InternalFunction(&exec->globalData(), globalObject, structure, Identifier(exec, "RegExp"))
+ , d(adoptPtr(new RegExpConstructorPrivate))
{
+ ASSERT(inherits(&s_info));
+
// ECMA 15.10.5.1 RegExp.prototype
- putDirectWithoutTransition(exec->propertyNames().prototype, regExpPrototype, DontEnum | DontDelete | ReadOnly);
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().prototype, regExpPrototype, DontEnum | DontDelete | ReadOnly);
// no. of arguments for constructor
- putDirectWithoutTransition(exec->propertyNames().length, jsNumber(exec, 2), ReadOnly | DontDelete | DontEnum);
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(2), ReadOnly | DontDelete | DontEnum);
}
RegExpMatchesArray::RegExpMatchesArray(ExecState* exec, RegExpConstructorPrivate* data)
- : JSArray(exec->lexicalGlobalObject()->regExpMatchesArrayStructure(), data->lastNumSubPatterns + 1)
+ : JSArray(exec->globalData(), exec->lexicalGlobalObject()->regExpMatchesArrayStructure(), data->lastNumSubPatterns + 1, CreateInitialized)
{
RegExpConstructorPrivate* d = new RegExpConstructorPrivate;
d->input = data->lastInput;
}
PutPropertySlot slot;
- JSArray::put(exec, exec->propertyNames().index, jsNumber(exec, d->lastOvector()[0]), slot);
+ JSArray::put(exec, exec->propertyNames().index, jsNumber(d->lastOvector()[0]), slot);
JSArray::put(exec, exec->propertyNames().input, jsString(exec, d->input), slot);
delete d;
JSValue RegExpConstructor::getRightContext(ExecState* exec) const
{
if (!d->lastOvector().isEmpty())
- return jsSubstring(exec, d->lastInput, d->lastOvector()[1], d->lastInput.size() - d->lastOvector()[1]);
+ return jsSubstring(exec, d->lastInput, d->lastOvector()[1], d->lastInput.length() - d->lastOvector()[1]);
return jsEmptyString(exec);
}
{
asRegExpConstructor(baseObject)->setMultiline(value.toBoolean(exec));
}
-
+
// ECMA 15.10.4
-JSObject* constructRegExp(ExecState* exec, const ArgList& args)
+JSObject* constructRegExp(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args)
{
JSValue arg0 = args.at(0);
JSValue arg1 = args.at(1);
- if (arg0.inherits(&RegExpObject::info)) {
+ if (arg0.inherits(&RegExpObject::s_info)) {
if (!arg1.isUndefined())
- return throwError(exec, TypeError, "Cannot supply flags when constructing one RegExp from another.");
+ return throwError(exec, createTypeError(exec, "Cannot supply flags when constructing one RegExp from another."));
return asObject(arg0);
}
UString pattern = arg0.isUndefined() ? UString("") : arg0.toString(exec);
- UString flags = arg1.isUndefined() ? UString("") : arg1.toString(exec);
+ if (exec->hadException())
+ return 0;
+
+ RegExpFlags flags = NoFlags;
+ if (!arg1.isUndefined()) {
+ flags = regExpFlags(arg1.toString(exec));
+ if (exec->hadException())
+ return 0;
+ if (flags == InvalidFlags)
+ return throwError(exec, createSyntaxError(exec, "Invalid flags supplied to RegExp constructor."));
+ }
- RefPtr<RegExp> regExp = exec->globalData().regExpCache()->lookupOrCreate(pattern, flags);
+ RegExp* regExp = RegExp::create(&exec->globalData(), pattern, flags);
if (!regExp->isValid())
- return throwError(exec, SyntaxError, makeString("Invalid regular expression: ", regExp->errorMessage()));
- return new (exec) RegExpObject(exec->lexicalGlobalObject()->regExpStructure(), regExp.release());
+ return throwError(exec, createSyntaxError(exec, regExp->errorMessage()));
+ return new (exec) RegExpObject(exec->lexicalGlobalObject(), globalObject->regExpStructure(), regExp);
}
-static JSObject* constructWithRegExpConstructor(ExecState* exec, JSObject*, const ArgList& args)
+static EncodedJSValue JSC_HOST_CALL constructWithRegExpConstructor(ExecState* exec)
{
- return constructRegExp(exec, args);
+ ArgList args(exec);
+ return JSValue::encode(constructRegExp(exec, asInternalFunction(exec->callee())->globalObject(), args));
}
ConstructType RegExpConstructor::getConstructData(ConstructData& constructData)
}
// ECMA 15.10.3
-static JSValue JSC_HOST_CALL callRegExpConstructor(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+static EncodedJSValue JSC_HOST_CALL callRegExpConstructor(ExecState* exec)
{
- return constructRegExp(exec, args);
+ ArgList args(exec);
+ return JSValue::encode(constructRegExp(exec, asInternalFunction(exec->callee())->globalObject(), args));
}
CallType RegExpConstructor::getCallData(CallData& callData)
class RegExpPrototype;
struct RegExpConstructorPrivate;
- struct RegExpConstructorPrivate : FastAllocBase {
+ struct RegExpConstructorPrivate {
+ WTF_MAKE_FAST_ALLOCATED;
+ public:
// Global search cache / settings
RegExpConstructorPrivate()
: lastNumSubPatterns(0)
class RegExpConstructor : public InternalFunction {
public:
- RegExpConstructor(ExecState*, NonNullPassRefPtr<Structure>, RegExpPrototype*);
+ RegExpConstructor(ExecState*, JSGlobalObject*, Structure*, RegExpPrototype*);
- static PassRefPtr<Structure> createStructure(JSValue prototype)
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
+ return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
}
virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
- static const ClassInfo info;
+ static const ClassInfo s_info;
- void performMatch(RegExp*, const UString&, int startOffset, int& position, int& length, int** ovector = 0);
+ void performMatch(JSGlobalData&, RegExp*, const UString&, int startOffset, int& position, int& length, int** ovector = 0);
JSObject* arrayOfMatches(ExecState*) const;
void setInput(const UString&);
virtual ConstructType getConstructData(ConstructData&);
virtual CallType getCallData(CallData&);
- virtual const ClassInfo* classInfo() const { return &info; }
-
OwnPtr<RegExpConstructorPrivate> d;
};
RegExpConstructor* asRegExpConstructor(JSValue);
- JSObject* constructRegExp(ExecState*, const ArgList&);
+ JSObject* constructRegExp(ExecState*, JSGlobalObject*, const ArgList&);
inline RegExpConstructor* asRegExpConstructor(JSValue value)
{
- ASSERT(asObject(value)->inherits(&RegExpConstructor::info));
+ ASSERT(asObject(value)->inherits(&RegExpConstructor::s_info));
return static_cast<RegExpConstructor*>(asObject(value));
}
expression matching through the performMatch function. We use cached results to calculate,
e.g., RegExp.lastMatch and RegExp.leftParen.
*/
- inline void RegExpConstructor::performMatch(RegExp* r, const UString& s, int startOffset, int& position, int& length, int** ovector)
+ ALWAYS_INLINE void RegExpConstructor::performMatch(JSGlobalData& globalData, RegExp* r, const UString& s, int startOffset, int& position, int& length, int** ovector)
{
- position = r->match(s, startOffset, &d->tempOvector());
+ position = r->match(globalData, s, startOffset, &d->tempOvector());
if (ovector)
*ovector = d->tempOvector().data();
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "UString.h"
-
#ifndef RegExpKey_h
#define RegExpKey_h
+#include "UString.h"
+#include <wtf/text/StringHash.h>
+
namespace JSC {
+enum RegExpFlags {
+ NoFlags = 0,
+ FlagGlobal = 1,
+ FlagIgnoreCase = 2,
+ FlagMultiline = 4,
+ InvalidFlags = 8,
+ DeletedValueFlags = -1
+};
+
struct RegExpKey {
- int flagsValue;
- RefPtr<UString::Rep> pattern;
+ RegExpFlags flagsValue;
+ RefPtr<StringImpl> pattern;
RegExpKey()
- : flagsValue(0)
+ : flagsValue(NoFlags)
{
}
- RegExpKey(int flags)
+ RegExpKey(RegExpFlags flags)
: flagsValue(flags)
{
}
- RegExpKey(int flags, const UString& pattern)
+ RegExpKey(RegExpFlags flags, const UString& pattern)
: flagsValue(flags)
- , pattern(pattern.rep())
+ , pattern(pattern.impl())
{
}
- RegExpKey(int flags, const PassRefPtr<UString::Rep> pattern)
+ RegExpKey(RegExpFlags flags, const PassRefPtr<StringImpl> pattern)
: flagsValue(flags)
, pattern(pattern)
{
}
- RegExpKey(const UString& flags, const UString& pattern)
- : pattern(pattern.rep())
- {
- flagsValue = getFlagsValue(flags);
- }
-
- int getFlagsValue(const UString flags)
+ RegExpKey(RegExpFlags flags, const RefPtr<StringImpl>& pattern)
+ : flagsValue(flags)
+ , pattern(pattern)
{
- flagsValue = 0;
- if (flags.find('g') != UString::NotFound)
- flagsValue += 4;
- if (flags.find('i') != UString::NotFound)
- flagsValue += 2;
- if (flags.find('m') != UString::NotFound)
- flagsValue += 1;
- return flagsValue;
}
};
-} // namespace JSC
-
-namespace WTF {
-template<typename T> struct DefaultHash;
-template<typename T> struct RegExpHash;
-inline bool operator==(const JSC::RegExpKey& a, const JSC::RegExpKey& b)
+inline bool operator==(const RegExpKey& a, const RegExpKey& b)
{
if (a.flagsValue != b.flagsValue)
return false;
return equal(a.pattern.get(), b.pattern.get());
}
+} // namespace JSC
+
+namespace WTF {
+template<typename T> struct DefaultHash;
+template<typename T> struct RegExpHash;
+
template<> struct RegExpHash<JSC::RegExpKey> {
static unsigned hash(const JSC::RegExpKey& key) { return key.pattern->hash(); }
static bool equal(const JSC::RegExpKey& a, const JSC::RegExpKey& b) { return a == b; }
};
template<> struct HashTraits<JSC::RegExpKey> : GenericHashTraits<JSC::RegExpKey> {
- static void constructDeletedValue(JSC::RegExpKey& slot) { slot.flagsValue = -1; }
- static bool isDeletedValue(const JSC::RegExpKey& value) { return value.flagsValue == -1; }
+ static void constructDeletedValue(JSC::RegExpKey& slot) { slot.flagsValue = JSC::DeletedValueFlags; }
+ static bool isDeletedValue(const JSC::RegExpKey& value) { return value.flagsValue == JSC::DeletedValueFlags; }
};
} // namespace WTF
#include "RegExpObject.h"
#include "Error.h"
+#include "ExceptionHelpers.h"
#include "JSArray.h"
#include "JSGlobalObject.h"
#include "JSString.h"
#include "Lookup.h"
#include "RegExpConstructor.h"
#include "RegExpPrototype.h"
+#include "UStringConcatenate.h"
+#include <wtf/PassOwnPtr.h>
+
+#include <wtf/PassOwnPtr.h>
namespace JSC {
ASSERT_CLASS_FITS_IN_CELL(RegExpObject);
-const ClassInfo RegExpObject::info = { "RegExp", 0, 0, ExecState::regExpTable };
+const ClassInfo RegExpObject::s_info = { "RegExp", &JSObjectWithGlobalObject::s_info, 0, ExecState::regExpTable };
/* Source for RegExpObject.lut.h
@begin regExpTable
@end
*/
-RegExpObject::RegExpObject(NonNullPassRefPtr<Structure> structure, NonNullPassRefPtr<RegExp> regExp)
- : JSObject(structure)
- , d(new RegExpObjectData(regExp, 0))
+RegExpObject::RegExpObject(JSGlobalObject* globalObject, Structure* structure, RegExp* regExp)
+ : JSObjectWithGlobalObject(globalObject, structure)
+ , d(adoptPtr(new RegExpObjectData(globalObject->globalData(), this, regExp)))
{
+ ASSERT(inherits(&s_info));
}
RegExpObject::~RegExpObject()
{
}
+void RegExpObject::visitChildren(SlotVisitor& visitor)
+{
+ ASSERT_GC_OBJECT_INHERITS(this, &s_info);
+ COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
+ ASSERT(structure()->typeInfo().overridesVisitChildren());
+ Base::visitChildren(visitor);
+ if (d->regExp)
+ visitor.append(&d->regExp);
+ if (UNLIKELY(!d->lastIndex.get().isInt32()))
+ visitor.append(&d->lastIndex);
+}
+
bool RegExpObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
{
return getStaticValueSlot<RegExpObject, JSObject>(exec, ExecState::regExpTable(exec), this, propertyName, slot);
return jsString(exec, asRegExpObject(slotBase)->regExp()->pattern());
}
-JSValue regExpObjectLastIndex(ExecState* exec, JSValue slotBase, const Identifier&)
+JSValue regExpObjectLastIndex(ExecState*, JSValue slotBase, const Identifier&)
{
- return jsNumber(exec, asRegExpObject(slotBase)->lastIndex());
+ return asRegExpObject(slotBase)->getLastIndex();
}
void RegExpObject::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
void setRegExpObjectLastIndex(ExecState* exec, JSObject* baseObject, JSValue value)
{
- asRegExpObject(baseObject)->setLastIndex(value.toInteger(exec));
+ asRegExpObject(baseObject)->setLastIndex(exec->globalData(), value);
}
-JSValue RegExpObject::test(ExecState* exec, const ArgList& args)
+JSValue RegExpObject::test(ExecState* exec)
{
- return jsBoolean(match(exec, args));
+ return jsBoolean(match(exec));
}
-JSValue RegExpObject::exec(ExecState* exec, const ArgList& args)
+JSValue RegExpObject::exec(ExecState* exec)
{
- if (match(exec, args))
+ if (match(exec))
return exec->lexicalGlobalObject()->regExpConstructor()->arrayOfMatches(exec);
return jsNull();
}
-static JSValue JSC_HOST_CALL callRegExpObject(ExecState* exec, JSObject* function, JSValue, const ArgList& args)
-{
- return asRegExpObject(function)->exec(exec, args);
-}
-
-CallType RegExpObject::getCallData(CallData& callData)
-{
- callData.native.function = callRegExpObject;
- return CallTypeHost;
-}
-
// Shared implementation used by test and exec.
-bool RegExpObject::match(ExecState* exec, const ArgList& args)
+bool RegExpObject::match(ExecState* exec)
{
RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
-
- UString input = args.isEmpty() ? regExpConstructor->input() : args.at(0).toString(exec);
- if (input.isNull()) {
- throwError(exec, GeneralError, makeString("No input to ", toString(exec), "."));
- return false;
- }
-
+ UString input = exec->argument(0).toString(exec);
+ JSGlobalData* globalData = &exec->globalData();
if (!regExp()->global()) {
int position;
int length;
- regExpConstructor->performMatch(d->regExp.get(), input, 0, position, length);
+ regExpConstructor->performMatch(*globalData, d->regExp.get(), input, 0, position, length);
return position >= 0;
}
- if (d->lastIndex < 0 || d->lastIndex > input.size()) {
- d->lastIndex = 0;
- return false;
+ JSValue jsLastIndex = getLastIndex();
+ unsigned lastIndex;
+ if (LIKELY(jsLastIndex.isUInt32())) {
+ lastIndex = jsLastIndex.asUInt32();
+ if (lastIndex > input.length()) {
+ setLastIndex(0);
+ return false;
+ }
+ } else {
+ double doubleLastIndex = jsLastIndex.toInteger(exec);
+ if (doubleLastIndex < 0 || doubleLastIndex > input.length()) {
+ setLastIndex(0);
+ return false;
+ }
+ lastIndex = static_cast<unsigned>(doubleLastIndex);
}
int position;
int length = 0;
- regExpConstructor->performMatch(d->regExp.get(), input, static_cast<int>(d->lastIndex), position, length);
+ regExpConstructor->performMatch(*globalData, d->regExp.get(), input, lastIndex, position, length);
if (position < 0) {
- d->lastIndex = 0;
+ setLastIndex(0);
return false;
}
- d->lastIndex = position + length;
+ setLastIndex(position + length);
return true;
}
#ifndef RegExpObject_h
#define RegExpObject_h
-#include "JSObject.h"
+#include "JSObjectWithGlobalObject.h"
#include "RegExp.h"
namespace JSC {
-
- class RegExpObject : public JSObject {
+
+ class RegExpObject : public JSObjectWithGlobalObject {
public:
- RegExpObject(NonNullPassRefPtr<Structure>, NonNullPassRefPtr<RegExp>);
+ typedef JSObjectWithGlobalObject Base;
+
+ RegExpObject(JSGlobalObject*, Structure*, RegExp*);
virtual ~RegExpObject();
- void setRegExp(PassRefPtr<RegExp> r) { d->regExp = r; }
+ void setRegExp(JSGlobalData& globalData, RegExp* r) { d->regExp.set(globalData, this, r); }
RegExp* regExp() const { return d->regExp.get(); }
- void setLastIndex(double lastIndex) { d->lastIndex = lastIndex; }
- double lastIndex() const { return d->lastIndex; }
+ void setLastIndex(size_t lastIndex)
+ {
+ d->lastIndex.setWithoutWriteBarrier(jsNumber(lastIndex));
+ }
+ void setLastIndex(JSGlobalData& globalData, JSValue lastIndex)
+ {
+ d->lastIndex.set(globalData, this, lastIndex);
+ }
+ JSValue getLastIndex() const
+ {
+ return d->lastIndex.get();
+ }
- JSValue test(ExecState*, const ArgList&);
- JSValue exec(ExecState*, const ArgList&);
+ JSValue test(ExecState*);
+ JSValue exec(ExecState*);
virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
- virtual const ClassInfo* classInfo() const { return &info; }
- static const ClassInfo info;
+ static JS_EXPORTDATA const ClassInfo s_info;
- static PassRefPtr<Structure> createStructure(JSValue prototype)
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
+ return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
}
protected:
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | JSObject::StructureFlags;
+ static const unsigned StructureFlags = OverridesVisitChildren | OverridesGetOwnPropertySlot | JSObjectWithGlobalObject::StructureFlags;
private:
- bool match(ExecState*, const ArgList&);
+ virtual void visitChildren(SlotVisitor&);
- virtual CallType getCallData(CallData&);
+ bool match(ExecState*);
- struct RegExpObjectData : FastAllocBase {
- RegExpObjectData(NonNullPassRefPtr<RegExp> regExp, double lastIndex)
- : regExp(regExp)
- , lastIndex(lastIndex)
+ struct RegExpObjectData {
+ WTF_MAKE_FAST_ALLOCATED;
+ public:
+ RegExpObjectData(JSGlobalData& globalData, RegExpObject* owner, RegExp* regExp)
+ : regExp(globalData, owner, regExp)
{
+ lastIndex.setWithoutWriteBarrier(jsNumber(0));
}
- RefPtr<RegExp> regExp;
- double lastIndex;
+ WriteBarrier<RegExp> regExp;
+ WriteBarrier<Unknown> lastIndex;
};
-
+#if COMPILER(MSVC)
+ friend void WTF::deleteOwnedPtr<RegExpObjectData>(RegExpObjectData*);
+#endif
OwnPtr<RegExpObjectData> d;
};
inline RegExpObject* asRegExpObject(JSValue value)
{
- ASSERT(asObject(value)->inherits(&RegExpObject::info));
+ ASSERT(asObject(value)->inherits(&RegExpObject::s_info));
return static_cast<RegExpObject*>(asObject(value));
}
#include "JSStringBuilder.h"
#include "JSValue.h"
#include "ObjectPrototype.h"
-#include "PrototypeFunction.h"
#include "RegExpObject.h"
#include "RegExp.h"
#include "RegExpCache.h"
+#include "StringRecursionChecker.h"
+#include "UStringConcatenate.h"
namespace JSC {
-ASSERT_CLASS_FITS_IN_CELL(RegExpPrototype);
+static EncodedJSValue JSC_HOST_CALL regExpProtoFuncTest(ExecState*);
+static EncodedJSValue JSC_HOST_CALL regExpProtoFuncExec(ExecState*);
+static EncodedJSValue JSC_HOST_CALL regExpProtoFuncCompile(ExecState*);
+static EncodedJSValue JSC_HOST_CALL regExpProtoFuncToString(ExecState*);
+
+}
-static JSValue JSC_HOST_CALL regExpProtoFuncTest(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL regExpProtoFuncExec(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL regExpProtoFuncCompile(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL regExpProtoFuncToString(ExecState*, JSObject*, JSValue, const ArgList&);
+#include "RegExpPrototype.lut.h"
+
+namespace JSC {
-// ECMA 15.10.5
+const ClassInfo RegExpPrototype::s_info = { "RegExp", &RegExpObject::s_info, 0, ExecState::regExpPrototypeTable };
-const ClassInfo RegExpPrototype::info = { "RegExpPrototype", 0, 0, 0 };
+/* Source for RegExpPrototype.lut.h
+@begin regExpPrototypeTable
+ compile regExpProtoFuncCompile DontEnum|Function 2
+ exec regExpProtoFuncExec DontEnum|Function 1
+ test regExpProtoFuncTest DontEnum|Function 1
+ toString regExpProtoFuncToString DontEnum|Function 0
+@end
+*/
-RegExpPrototype::RegExpPrototype(ExecState* exec, NonNullPassRefPtr<Structure> structure, Structure* prototypeFunctionStructure)
- : JSObject(structure)
+ASSERT_CLASS_FITS_IN_CELL(RegExpPrototype);
+
+RegExpPrototype::RegExpPrototype(ExecState*, JSGlobalObject* globalObject, Structure* structure, RegExp* regExp)
+ : RegExpObject(globalObject, structure, regExp)
{
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 0, exec->propertyNames().compile, regExpProtoFuncCompile), DontEnum);
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 0, exec->propertyNames().exec, regExpProtoFuncExec), DontEnum);
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 0, exec->propertyNames().test, regExpProtoFuncTest), DontEnum);
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 0, exec->propertyNames().toString, regExpProtoFuncToString), DontEnum);
+}
+
+bool RegExpPrototype::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot &slot)
+{
+ return getStaticFunctionSlot<RegExpObject>(exec, ExecState::regExpPrototypeTable(exec), this, propertyName, slot);
+}
+
+bool RegExpPrototype::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ return getStaticFunctionDescriptor<RegExpObject>(exec, ExecState::regExpPrototypeTable(exec), this, propertyName, descriptor);
}
// ------------------------------ Functions ---------------------------
-
-JSValue JSC_HOST_CALL regExpProtoFuncTest(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+
+EncodedJSValue JSC_HOST_CALL regExpProtoFuncTest(ExecState* exec)
{
- if (!thisValue.inherits(&RegExpObject::info))
- return throwError(exec, TypeError);
- return asRegExpObject(thisValue)->test(exec, args);
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&RegExpObject::s_info))
+ return throwVMTypeError(exec);
+ return JSValue::encode(asRegExpObject(thisValue)->test(exec));
}
-JSValue JSC_HOST_CALL regExpProtoFuncExec(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL regExpProtoFuncExec(ExecState* exec)
{
- if (!thisValue.inherits(&RegExpObject::info))
- return throwError(exec, TypeError);
- return asRegExpObject(thisValue)->exec(exec, args);
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&RegExpObject::s_info))
+ return throwVMTypeError(exec);
+ return JSValue::encode(asRegExpObject(thisValue)->exec(exec));
}
-JSValue JSC_HOST_CALL regExpProtoFuncCompile(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL regExpProtoFuncCompile(ExecState* exec)
{
- if (!thisValue.inherits(&RegExpObject::info))
- return throwError(exec, TypeError);
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&RegExpObject::s_info))
+ return throwVMTypeError(exec);
- RefPtr<RegExp> regExp;
- JSValue arg0 = args.at(0);
- JSValue arg1 = args.at(1);
+ RegExp* regExp;
+ JSValue arg0 = exec->argument(0);
+ JSValue arg1 = exec->argument(1);
- if (arg0.inherits(&RegExpObject::info)) {
+ if (arg0.inherits(&RegExpObject::s_info)) {
if (!arg1.isUndefined())
- return throwError(exec, TypeError, "Cannot supply flags when constructing one RegExp from another.");
+ return throwVMError(exec, createTypeError(exec, "Cannot supply flags when constructing one RegExp from another."));
regExp = asRegExpObject(arg0)->regExp();
} else {
- UString pattern = args.isEmpty() ? UString("") : arg0.toString(exec);
- UString flags = arg1.isUndefined() ? UString("") : arg1.toString(exec);
- regExp = exec->globalData().regExpCache()->lookupOrCreate(pattern, flags);
+ UString pattern = !exec->argumentCount() ? UString("") : arg0.toString(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ RegExpFlags flags = NoFlags;
+ if (!arg1.isUndefined()) {
+ flags = regExpFlags(arg1.toString(exec));
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ if (flags == InvalidFlags)
+ return throwVMError(exec, createSyntaxError(exec, "Invalid flags supplied to RegExp constructor."));
+ }
+ regExp = RegExp::create(&exec->globalData(), pattern, flags);
}
if (!regExp->isValid())
- return throwError(exec, SyntaxError, makeString("Invalid regular expression: ", regExp->errorMessage()));
+ return throwVMError(exec, createSyntaxError(exec, regExp->errorMessage()));
- asRegExpObject(thisValue)->setRegExp(regExp.release());
+ asRegExpObject(thisValue)->setRegExp(exec->globalData(), regExp);
asRegExpObject(thisValue)->setLastIndex(0);
- return jsUndefined();
+ return JSValue::encode(jsUndefined());
}
-JSValue JSC_HOST_CALL regExpProtoFuncToString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL regExpProtoFuncToString(ExecState* exec)
{
- if (!thisValue.inherits(&RegExpObject::info)) {
- if (thisValue.inherits(&RegExpPrototype::info))
- return jsNontrivialString(exec, "//");
- return throwError(exec, TypeError);
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&RegExpObject::s_info)) {
+ if (thisValue.inherits(&RegExpPrototype::s_info))
+ return JSValue::encode(jsNontrivialString(exec, "//"));
+ return throwVMTypeError(exec);
}
+ RegExpObject* thisObject = asRegExpObject(thisValue);
+
+ StringRecursionChecker checker(exec, thisObject);
+ if (EncodedJSValue earlyReturnValue = checker.earlyReturnValue())
+ return earlyReturnValue;
+
char postfix[5] = { '/', 0, 0, 0, 0 };
int index = 1;
- if (asRegExpObject(thisValue)->get(exec, exec->propertyNames().global).toBoolean(exec))
+ if (thisObject->get(exec, exec->propertyNames().global).toBoolean(exec))
postfix[index++] = 'g';
- if (asRegExpObject(thisValue)->get(exec, exec->propertyNames().ignoreCase).toBoolean(exec))
+ if (thisObject->get(exec, exec->propertyNames().ignoreCase).toBoolean(exec))
postfix[index++] = 'i';
- if (asRegExpObject(thisValue)->get(exec, exec->propertyNames().multiline).toBoolean(exec))
+ if (thisObject->get(exec, exec->propertyNames().multiline).toBoolean(exec))
postfix[index] = 'm';
- UString source = asRegExpObject(thisValue)->get(exec, exec->propertyNames().source).toString(exec);
+ UString source = thisObject->get(exec, exec->propertyNames().source).toString(exec);
// If source is empty, use "/(?:)/" to avoid colliding with comment syntax
- return jsMakeNontrivialString(exec, "/", source.size() ? source : UString("(?:)"), postfix);
+ return JSValue::encode(jsMakeNontrivialString(exec, "/", source.length() ? source : UString("(?:)"), postfix));
}
} // namespace JSC
#ifndef RegExpPrototype_h
#define RegExpPrototype_h
+#include "RegExpObject.h"
#include "JSObject.h"
namespace JSC {
- class RegExpPrototype : public JSObject {
+ class RegExpPrototype : public RegExpObject {
public:
- RegExpPrototype(ExecState*, NonNullPassRefPtr<Structure>, Structure* prototypeFunctionStructure);
+ RegExpPrototype(ExecState*, JSGlobalObject*, Structure*, RegExp*);
- virtual const ClassInfo* classInfo() const { return &info; }
- static const ClassInfo info;
+ static const ClassInfo s_info;
+
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
+ {
+ return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
+ }
+
+ protected:
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | RegExpObject::StructureFlags;
+
+ private:
+ virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
+ virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
};
} // namespace JSC
else
nextRope->deref();
} else
- static_cast<UStringImpl*>(fiber)->deref();
+ static_cast<StringImpl*>(fiber)->deref();
}
}
#ifndef RopeImpl_h
#define RopeImpl_h
-#include "UStringImpl.h"
+#include <wtf/text/StringImpl.h>
namespace JSC {
class RopeImpl : public StringImplBase {
public:
// A RopeImpl is composed from a set of smaller strings called Fibers.
- // Each Fiber in a rope is either UStringImpl or another RopeImpl.
+ // Each Fiber in a rope is either StringImpl or another RopeImpl.
typedef StringImplBase* Fiber;
// Creates a RopeImpl comprising of 'fiberCount' Fibers.
if (isRope(fiber))
static_cast<RopeImpl*>(fiber)->deref();
else
- static_cast<UStringImpl*>(fiber)->deref();
+ static_cast<StringImpl*>(fiber)->deref();
}
void initializeFiber(unsigned &index, Fiber fiber)
#ifndef NDEBUG
-void ScopeChainNode::print() const
+void ScopeChainNode::print()
{
ScopeChainIterator scopeEnd = end();
for (ScopeChainIterator scopeIter = begin(); scopeIter != scopeEnd; ++scopeIter) {
- JSObject* o = *scopeIter;
+ JSObject* o = scopeIter->get();
PropertyNameArray propertyNames(globalObject->globalExec());
o->getPropertyNames(globalObject->globalExec(), propertyNames);
PropertyNameArray::const_iterator propEnd = propertyNames.end();
fprintf(stderr, "----- [scope %p] -----\n", o);
for (PropertyNameArray::const_iterator propIter = propertyNames.begin(); propIter != propEnd; propIter++) {
Identifier name = *propIter;
- fprintf(stderr, "%s, ", name.ascii());
+ fprintf(stderr, "%s, ", name.ustring().utf8().data());
}
fprintf(stderr, "\n");
}
#endif
-int ScopeChain::localDepth() const
+const ClassInfo ScopeChainNode::s_info = { "ScopeChainNode", 0, 0, 0 };
+
+int ScopeChainNode::localDepth()
{
int scopeDepth = 0;
ScopeChainIterator iter = this->begin();
ScopeChainIterator end = this->end();
- while (!(*iter)->inherits(&JSActivation::info)) {
+ while (!(*iter)->inherits(&JSActivation::s_info)) {
++iter;
if (iter == end)
break;
return scopeDepth;
}
+void ScopeChainNode::visitChildren(SlotVisitor& visitor)
+{
+ ASSERT_GC_OBJECT_INHERITS(this, &s_info);
+ COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
+ ASSERT(structure()->typeInfo().overridesVisitChildren());
+ if (next)
+ visitor.append(&next);
+ visitor.append(&object);
+ visitor.append(&globalObject);
+ visitor.append(&globalThis);
+}
+
} // namespace JSC
#ifndef ScopeChain_h
#define ScopeChain_h
-#include "FastAllocBase.h"
+#include "JSCell.h"
+#include "Structure.h"
+#include <wtf/FastAllocBase.h>
namespace JSC {
class JSObject;
class MarkStack;
class ScopeChainIterator;
+ typedef MarkStack SlotVisitor;
- class ScopeChainNode : public FastAllocBase {
+ class ScopeChainNode : public JSCell {
public:
ScopeChainNode(ScopeChainNode* next, JSObject* object, JSGlobalData* globalData, JSGlobalObject* globalObject, JSObject* globalThis)
- : next(next)
- , object(object)
+ : JSCell(*globalData, globalData->scopeChainNodeStructure.get())
, globalData(globalData)
- , globalObject(globalObject)
- , globalThis(globalThis)
- , refCount(1)
+ , next(*globalData, this, next, WriteBarrier<ScopeChainNode>::MayBeNull)
+ , object(*globalData, this, object)
+ , globalObject(*globalData, this, globalObject)
+ , globalThis(*globalData, this, globalThis)
{
ASSERT(globalData);
ASSERT(globalObject);
}
-#ifndef NDEBUG
- // Due to the number of subtle and timing dependent bugs that have occurred due
- // to deleted but still "valid" ScopeChainNodes we now deliberately clobber the
- // contents in debug builds.
- ~ScopeChainNode()
- {
- next = 0;
- object = 0;
- globalData = 0;
- globalObject = 0;
- globalThis = 0;
- }
-#endif
- ScopeChainNode* next;
- JSObject* object;
JSGlobalData* globalData;
- JSGlobalObject* globalObject;
- JSObject* globalThis;
- int refCount;
-
- void deref() { ASSERT(refCount); if (--refCount == 0) { release();} }
- void ref() { ASSERT(refCount); ++refCount; }
- void release();
-
- // Before calling "push" on a bare ScopeChainNode, a client should
- // logically "copy" the node. Later, the client can "deref" the head
- // of its chain of ScopeChainNodes to reclaim all the nodes it added
- // after the logical copy, leaving nodes added before the logical copy
- // (nodes shared with other clients) untouched.
- ScopeChainNode* copy()
- {
- ref();
- return this;
- }
+ WriteBarrier<ScopeChainNode> next;
+ WriteBarrier<JSObject> object;
+ WriteBarrier<JSGlobalObject> globalObject;
+ WriteBarrier<JSObject> globalThis;
ScopeChainNode* push(JSObject*);
ScopeChainNode* pop();
- ScopeChainIterator begin() const;
- ScopeChainIterator end() const;
+ ScopeChainIterator begin();
+ ScopeChainIterator end();
+
+ int localDepth();
#ifndef NDEBUG
- void print() const;
+ void print();
#endif
+
+ static Structure* createStructure(JSGlobalData& globalData, JSValue proto) { return Structure::create(globalData, proto, TypeInfo(CompoundType, StructureFlags), AnonymousSlotCount, &s_info); }
+ virtual void visitChildren(SlotVisitor&);
+ static JS_EXPORTDATA const ClassInfo s_info;
+
+ private:
+ static const unsigned StructureFlags = OverridesVisitChildren;
};
inline ScopeChainNode* ScopeChainNode::push(JSObject* o)
{
ASSERT(o);
- return new ScopeChainNode(this, o, globalData, globalObject, globalThis);
+ return new (globalData) ScopeChainNode(this, o, globalData, globalObject.get(), globalThis.get());
}
inline ScopeChainNode* ScopeChainNode::pop()
{
ASSERT(next);
- ScopeChainNode* result = next;
-
- if (--refCount != 0)
- ++result->refCount;
- else
- delete this;
-
- return result;
- }
-
- inline void ScopeChainNode::release()
- {
- // This function is only called by deref(),
- // Deref ensures these conditions are true.
- ASSERT(refCount == 0);
- ScopeChainNode* n = this;
- do {
- ScopeChainNode* next = n->next;
- delete n;
- n = next;
- } while (n && --n->refCount == 0);
+ return next.get();
}
class ScopeChainIterator {
public:
- ScopeChainIterator(const ScopeChainNode* node)
+ ScopeChainIterator(ScopeChainNode* node)
: m_node(node)
{
}
- JSObject* const & operator*() const { return m_node->object; }
- JSObject* const * operator->() const { return &(operator*()); }
+ WriteBarrier<JSObject> const & operator*() const { return m_node->object; }
+ WriteBarrier<JSObject> const * operator->() const { return &(operator*()); }
- ScopeChainIterator& operator++() { m_node = m_node->next; return *this; }
+ ScopeChainIterator& operator++() { m_node = m_node->next.get(); return *this; }
// postfix ++ intentionally omitted
bool operator!=(const ScopeChainIterator& other) const { return m_node != other.m_node; }
private:
- const ScopeChainNode* m_node;
+ ScopeChainNode* m_node;
};
- inline ScopeChainIterator ScopeChainNode::begin() const
+ inline ScopeChainIterator ScopeChainNode::begin()
{
return ScopeChainIterator(this);
}
- inline ScopeChainIterator ScopeChainNode::end() const
+ inline ScopeChainIterator ScopeChainNode::end()
{
return ScopeChainIterator(0);
}
- class NoScopeChain {};
-
- class ScopeChain {
- friend class JIT;
- public:
- ScopeChain(NoScopeChain)
- : m_node(0)
- {
- }
-
- ScopeChain(JSObject* o, JSGlobalData* globalData, JSGlobalObject* globalObject, JSObject* globalThis)
- : m_node(new ScopeChainNode(0, o, globalData, globalObject, globalThis))
- {
- }
-
- ScopeChain(const ScopeChain& c)
- : m_node(c.m_node->copy())
- {
- }
-
- ScopeChain& operator=(const ScopeChain& c);
-
- explicit ScopeChain(ScopeChainNode* node)
- : m_node(node->copy())
- {
- }
-
- ~ScopeChain()
- {
- if (m_node)
- m_node->deref();
-#ifndef NDEBUG
- m_node = 0;
-#endif
- }
-
- void swap(ScopeChain&);
-
- ScopeChainNode* node() const { return m_node; }
-
- JSObject* top() const { return m_node->object; }
-
- ScopeChainIterator begin() const { return m_node->begin(); }
- ScopeChainIterator end() const { return m_node->end(); }
-
- void push(JSObject* o) { m_node = m_node->push(o); }
-
- void pop() { m_node = m_node->pop(); }
- void clear() { m_node->deref(); m_node = 0; }
-
- JSGlobalObject* globalObject() const { return m_node->globalObject; }
-
- void markAggregate(MarkStack&) const;
-
- // Caution: this should only be used if the codeblock this is being used
- // with needs a full scope chain, otherwise this returns the depth of
- // the preceeding call frame
- //
- // Returns the depth of the current call frame's scope chain
- int localDepth() const;
-
-#ifndef NDEBUG
- void print() const { m_node->print(); }
-#endif
-
- private:
- ScopeChainNode* m_node;
- };
-
- inline void ScopeChain::swap(ScopeChain& o)
+ ALWAYS_INLINE JSGlobalData& ExecState::globalData() const
{
- ScopeChainNode* tmp = m_node;
- m_node = o.m_node;
- o.m_node = tmp;
+ ASSERT(scopeChain()->globalData);
+ return *scopeChain()->globalData;
}
- inline ScopeChain& ScopeChain::operator=(const ScopeChain& c)
+ ALWAYS_INLINE JSGlobalObject* ExecState::lexicalGlobalObject() const
+ {
+ return scopeChain()->globalObject.get();
+ }
+
+ ALWAYS_INLINE JSObject* ExecState::globalThisValue() const
+ {
+ return scopeChain()->globalThis.get();
+ }
+
+ ALWAYS_INLINE ScopeChainNode* Register::scopeChain() const
+ {
+ return static_cast<ScopeChainNode*>(jsValue().asCell());
+ }
+
+ ALWAYS_INLINE Register& Register::operator=(ScopeChainNode* scopeChain)
{
- ScopeChain tmp(c);
- swap(tmp);
+ *this = JSValue(scopeChain);
return *this;
}
namespace JSC {
- inline void ScopeChain::markAggregate(MarkStack& markStack) const
- {
- for (ScopeChainNode* n = m_node; n; n = n->next)
- markStack.append(n->object);
- }
-
} // namespace JSC
#endif // ScopeChainMark_h
/*
- * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2008, 2010 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
#include "JSGlobalObject.h"
#include "JSString.h"
-
#include <wtf/Noncopyable.h>
+#include <wtf/PassOwnPtr.h>
namespace JSC {
-static const unsigned numCharactersToStore = 0x100;
-static inline bool isMarked(JSString* string)
+static inline bool isMarked(JSCell* string)
{
- return string && Heap::isCellMarked(string);
+ return string && Heap::isMarked(string);
}
-class SmallStringsStorage : public Noncopyable {
+class SmallStringsStorage {
+ WTF_MAKE_NONCOPYABLE(SmallStringsStorage); WTF_MAKE_FAST_ALLOCATED;
public:
SmallStringsStorage();
- UString::Rep* rep(unsigned char character) { return m_reps[character].get(); }
+ StringImpl* rep(unsigned char character)
+ {
+ return m_reps[character].get();
+ }
private:
- RefPtr<UString::Rep> m_reps[numCharactersToStore];
+ static const unsigned singleCharacterStringCount = maxSingleCharacterString + 1;
+
+ RefPtr<StringImpl> m_reps[singleCharacterStringCount];
};
SmallStringsStorage::SmallStringsStorage()
{
UChar* characterBuffer = 0;
- RefPtr<UStringImpl> baseString = UStringImpl::createUninitialized(numCharactersToStore, characterBuffer);
- for (unsigned i = 0; i < numCharactersToStore; ++i) {
+ RefPtr<StringImpl> baseString = StringImpl::createUninitialized(singleCharacterStringCount, characterBuffer);
+ for (unsigned i = 0; i < singleCharacterStringCount; ++i) {
characterBuffer[i] = i;
- m_reps[i] = UStringImpl::create(baseString, i, 1);
+ m_reps[i] = StringImpl::create(baseString, i, 1);
}
}
SmallStrings::SmallStrings()
{
- COMPILE_ASSERT(numCharactersToStore == sizeof(m_singleCharacterStrings) / sizeof(m_singleCharacterStrings[0]), IsNumCharactersConstInSyncWithClassUsage);
+ COMPILE_ASSERT(singleCharacterStringCount == sizeof(m_singleCharacterStrings) / sizeof(m_singleCharacterStrings[0]), IsNumCharactersConstInSyncWithClassUsage);
clear();
}
{
}
-void SmallStrings::markChildren(MarkStack& markStack)
+void SmallStrings::visitChildren(HeapRootVisitor& heapRootMarker)
{
/*
Our hypothesis is that small strings are very common. So, we cache them
*/
bool isAnyStringMarked = isMarked(m_emptyString);
- for (unsigned i = 0; i < numCharactersToStore && !isAnyStringMarked; ++i)
+ for (unsigned i = 0; i < singleCharacterStringCount && !isAnyStringMarked; ++i)
isAnyStringMarked = isMarked(m_singleCharacterStrings[i]);
if (!isAnyStringMarked) {
}
if (m_emptyString)
- markStack.append(m_emptyString);
- for (unsigned i = 0; i < numCharactersToStore; ++i) {
+ heapRootMarker.mark(&m_emptyString);
+ for (unsigned i = 0; i < singleCharacterStringCount; ++i) {
if (m_singleCharacterStrings[i])
- markStack.append(m_singleCharacterStrings[i]);
+ heapRootMarker.mark(&m_singleCharacterStrings[i]);
}
}
void SmallStrings::clear()
{
m_emptyString = 0;
- for (unsigned i = 0; i < numCharactersToStore; ++i)
+ for (unsigned i = 0; i < singleCharacterStringCount; ++i)
m_singleCharacterStrings[i] = 0;
}
unsigned count = 0;
if (m_emptyString)
++count;
- for (unsigned i = 0; i < numCharactersToStore; ++i) {
+ for (unsigned i = 0; i < singleCharacterStringCount; ++i) {
if (m_singleCharacterStrings[i])
++count;
}
void SmallStrings::createSingleCharacterString(JSGlobalData* globalData, unsigned char character)
{
if (!m_storage)
- m_storage.set(new SmallStringsStorage);
+ m_storage = adoptPtr(new SmallStringsStorage);
ASSERT(!m_singleCharacterStrings[character]);
- m_singleCharacterStrings[character] = new (globalData) JSString(globalData, m_storage->rep(character), JSString::HasOtherOwner);
+ m_singleCharacterStrings[character] = new (globalData) JSString(globalData, PassRefPtr<StringImpl>(m_storage->rep(character)), JSString::HasOtherOwner);
}
-UString::Rep* SmallStrings::singleCharacterStringRep(unsigned char character)
+StringImpl* SmallStrings::singleCharacterStringRep(unsigned char character)
{
if (!m_storage)
- m_storage.set(new SmallStringsStorage);
+ m_storage = adoptPtr(new SmallStringsStorage);
return m_storage->rep(character);
}
#define SmallStrings_h
#include "UString.h"
+#include <wtf/FixedArray.h>
#include <wtf/OwnPtr.h>
namespace JSC {
+ class HeapRootVisitor;
class JSGlobalData;
class JSString;
class MarkStack;
class SmallStringsStorage;
+ typedef MarkStack SlotVisitor;
- class SmallStrings : public Noncopyable {
+ static const unsigned maxSingleCharacterString = 0xFF;
+
+ class SmallStrings {
+ WTF_MAKE_NONCOPYABLE(SmallStrings);
public:
SmallStrings();
~SmallStrings();
createEmptyString(globalData);
return m_emptyString;
}
+
JSString* singleCharacterString(JSGlobalData* globalData, unsigned char character)
{
if (!m_singleCharacterStrings[character])
return m_singleCharacterStrings[character];
}
- UString::Rep* singleCharacterStringRep(unsigned char character);
+ StringImpl* singleCharacterStringRep(unsigned char character);
- void markChildren(MarkStack&);
+ void visitChildren(HeapRootVisitor&);
void clear();
unsigned count() const;
-#if ENABLE(JIT)
- JSString** singleCharacterStrings() { return m_singleCharacterStrings; }
-#endif
+
+ JSString** singleCharacterStrings() { return &m_singleCharacterStrings[0]; }
+
private:
+ static const unsigned singleCharacterStringCount = maxSingleCharacterString + 1;
+
void createEmptyString(JSGlobalData*);
void createSingleCharacterString(JSGlobalData*, unsigned char);
JSString* m_emptyString;
- JSString* m_singleCharacterStrings[0x100];
+ JSString* m_singleCharacterStrings[singleCharacterStringCount];
OwnPtr<SmallStringsStorage> m_storage;
};
--- /dev/null
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "StrictEvalActivation.h"
+
+namespace JSC {
+
+StrictEvalActivation::StrictEvalActivation(ExecState* exec)
+ : JSNonFinalObject(exec->globalData(), exec->globalData().strictEvalActivationStructure.get())
+{
+}
+
+bool StrictEvalActivation::deleteProperty(ExecState*, const Identifier&)
+{
+ return false;
+}
+
+JSObject* StrictEvalActivation::toThisObject(ExecState* exec) const
+{
+ return exec->globalThisValue();
+}
+
+JSValue StrictEvalActivation::toStrictThisObject(ExecState*) const
+{
+ return jsNull();
+}
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef StrictEvalActivation_h
+#define StrictEvalActivation_h
+
+#include "JSObject.h"
+
+namespace JSC {
+
+class StrictEvalActivation : public JSNonFinalObject {
+public:
+ StrictEvalActivation(ExecState*);
+ virtual bool deleteProperty(ExecState*, const Identifier&);
+ virtual JSObject* toThisObject(ExecState*) const;
+ virtual JSValue toStrictThisObject(ExecState*) const;
+};
+
+} // namespace JSC
+
+#endif // StrictEvalActivation_h
+++ /dev/null
-/*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef StringBuilder_h
-#define StringBuilder_h
-
-#include <wtf/Vector.h>
-
-namespace JSC {
-
-class StringBuilder {
-public:
- void append(const UChar u)
- {
- buffer.append(u);
- }
-
- void append(const char* str)
- {
- append(str, strlen(str));
- }
-
- void append(const char* str, size_t len)
- {
- reserveCapacity(buffer.size() + len);
- for (size_t i = 0; i < len; i++)
- buffer.append(static_cast<unsigned char>(str[i]));
- }
-
- void append(const UChar* str, size_t len)
- {
- buffer.append(str, len);
- }
-
- void append(const UString& str)
- {
- buffer.append(str.data(), str.size());
- }
-
- bool isEmpty() { return buffer.isEmpty(); }
- void reserveCapacity(size_t newCapacity)
- {
- if (newCapacity < buffer.capacity())
- return;
- buffer.reserveCapacity(std::max(newCapacity, buffer.capacity() + buffer.capacity() / 4 + 1));
- }
- void resize(size_t size) { buffer.resize(size); }
- size_t size() const { return buffer.size(); }
-
- UChar operator[](size_t i) const { return buffer.at(i); }
-
- UString build()
- {
- buffer.shrinkToFit();
- ASSERT(buffer.data() || !buffer.size());
- return UString::adopt(buffer);
- }
-
-protected:
- Vector<UChar, 64> buffer;
-};
-
-}
-
-#endif
#include "config.h"
#include "StringConstructor.h"
+#include "Executable.h"
+#include "JITCode.h"
#include "JSFunction.h"
#include "JSGlobalObject.h"
-#include "PrototypeFunction.h"
#include "StringPrototype.h"
namespace JSC {
-static NEVER_INLINE JSValue stringFromCharCodeSlowCase(ExecState* exec, const ArgList& args)
+static EncodedJSValue JSC_HOST_CALL stringFromCharCode(ExecState*);
+
+}
+
+#include "StringConstructor.lut.h"
+
+namespace JSC {
+
+const ClassInfo StringConstructor::s_info = { "Function", &InternalFunction::s_info, 0, ExecState::stringConstructorTable };
+
+/* Source for StringConstructor.lut.h
+@begin stringConstructorTable
+ fromCharCode stringFromCharCode DontEnum|Function 1
+@end
+*/
+
+ASSERT_CLASS_FITS_IN_CELL(StringConstructor);
+
+StringConstructor::StringConstructor(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, StringPrototype* stringPrototype)
+ : InternalFunction(&exec->globalData(), globalObject, structure, Identifier(exec, stringPrototype->classInfo()->className))
{
- unsigned length = args.size();
- UChar* buf;
- PassRefPtr<UStringImpl> impl = UStringImpl::createUninitialized(length, buf);
- for (unsigned i = 0; i < length; ++i)
- buf[i] = static_cast<UChar>(args.at(i).toUInt32(exec));
- return jsString(exec, impl);
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().prototype, stringPrototype, ReadOnly | DontEnum | DontDelete);
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(1), ReadOnly | DontEnum | DontDelete);
}
-static JSValue JSC_HOST_CALL stringFromCharCode(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+bool StringConstructor::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot &slot)
{
- if (LIKELY(args.size() == 1))
- return jsSingleCharacterString(exec, args.at(0).toUInt32(exec));
- return stringFromCharCodeSlowCase(exec, args);
+ return getStaticFunctionSlot<InternalFunction>(exec, ExecState::stringConstructorTable(exec), this, propertyName, slot);
}
-ASSERT_CLASS_FITS_IN_CELL(StringConstructor);
+bool StringConstructor::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ return getStaticFunctionDescriptor<InternalFunction>(exec, ExecState::stringConstructorTable(exec), this, propertyName, descriptor);
+}
+
+// ------------------------------ Functions --------------------------------
+
+static NEVER_INLINE JSValue stringFromCharCodeSlowCase(ExecState* exec)
+{
+ unsigned length = exec->argumentCount();
+ UChar* buf;
+ PassRefPtr<StringImpl> impl = StringImpl::createUninitialized(length, buf);
+ for (unsigned i = 0; i < length; ++i)
+ buf[i] = static_cast<UChar>(exec->argument(i).toUInt32(exec));
+ return jsString(exec, impl);
+}
-StringConstructor::StringConstructor(ExecState* exec, NonNullPassRefPtr<Structure> structure, Structure* prototypeFunctionStructure, StringPrototype* stringPrototype)
- : InternalFunction(&exec->globalData(), structure, Identifier(exec, stringPrototype->classInfo()->className))
+static EncodedJSValue JSC_HOST_CALL stringFromCharCode(ExecState* exec)
{
- // ECMA 15.5.3.1 String.prototype
- putDirectWithoutTransition(exec->propertyNames().prototype, stringPrototype, ReadOnly | DontEnum | DontDelete);
-
- // ECMA 15.5.3.2 fromCharCode()
-#if ENABLE(JIT) && ENABLE(JIT_OPTIMIZE_NATIVE_CALL)
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().fromCharCode, exec->globalData().getThunk(fromCharCodeThunkGenerator), stringFromCharCode), DontEnum);
-#else
- putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().fromCharCode, stringFromCharCode), DontEnum);
-#endif
- // no. of arguments for constructor
- putDirectWithoutTransition(exec->propertyNames().length, jsNumber(exec, 1), ReadOnly | DontEnum | DontDelete);
+ if (LIKELY(exec->argumentCount() == 1))
+ return JSValue::encode(jsSingleCharacterString(exec, exec->argument(0).toUInt32(exec)));
+ return JSValue::encode(stringFromCharCodeSlowCase(exec));
}
-// ECMA 15.5.2
-static JSObject* constructWithStringConstructor(ExecState* exec, JSObject*, const ArgList& args)
+static EncodedJSValue JSC_HOST_CALL constructWithStringConstructor(ExecState* exec)
{
- if (args.isEmpty())
- return new (exec) StringObject(exec, exec->lexicalGlobalObject()->stringObjectStructure());
- return new (exec) StringObject(exec, exec->lexicalGlobalObject()->stringObjectStructure(), args.at(0).toString(exec));
+ JSGlobalObject* globalObject = asInternalFunction(exec->callee())->globalObject();
+ if (!exec->argumentCount())
+ return JSValue::encode(new (exec) StringObject(exec, globalObject->stringObjectStructure()));
+ return JSValue::encode(new (exec) StringObject(exec, globalObject->stringObjectStructure(), exec->argument(0).toString(exec)));
}
ConstructType StringConstructor::getConstructData(ConstructData& constructData)
return ConstructTypeHost;
}
-// ECMA 15.5.1
-static JSValue JSC_HOST_CALL callStringConstructor(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+static EncodedJSValue JSC_HOST_CALL callStringConstructor(ExecState* exec)
{
- if (args.isEmpty())
- return jsEmptyString(exec);
- return jsString(exec, args.at(0).toString(exec));
+ if (!exec->argumentCount())
+ return JSValue::encode(jsEmptyString(exec));
+ return JSValue::encode(jsString(exec, exec->argument(0).toString(exec)));
}
CallType StringConstructor::getCallData(CallData& callData)
class StringConstructor : public InternalFunction {
public:
- StringConstructor(ExecState*, NonNullPassRefPtr<Structure>, Structure* prototypeFunctionStructure, StringPrototype*);
+ StringConstructor(ExecState*, JSGlobalObject*, Structure*, StringPrototype*);
+ static const ClassInfo s_info;
+
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
+ {
+ return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
+ }
+
+ protected:
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InternalFunction::StructureFlags;
+
+ private:
virtual ConstructType getConstructData(ConstructData&);
virtual CallType getCallData(CallData&);
+
+ virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
+ virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
};
} // namespace JSC
ASSERT_CLASS_FITS_IN_CELL(StringObject);
-const ClassInfo StringObject::info = { "String", 0, 0, 0 };
+const ClassInfo StringObject::s_info = { "String", &JSWrapperObject::s_info, 0, 0 };
-StringObject::StringObject(ExecState* exec, NonNullPassRefPtr<Structure> structure)
- : JSWrapperObject(structure)
+StringObject::StringObject(ExecState* exec, Structure* structure)
+ : JSWrapperObject(exec->globalData(), structure)
{
- setInternalValue(jsEmptyString(exec));
+ ASSERT(inherits(&s_info));
+ setInternalValue(exec->globalData(), jsEmptyString(exec));
}
-StringObject::StringObject(NonNullPassRefPtr<Structure> structure, JSString* string)
- : JSWrapperObject(structure)
+StringObject::StringObject(JSGlobalData& globalData, Structure* structure, JSString* string)
+ : JSWrapperObject(globalData, structure)
{
- setInternalValue(string);
+ ASSERT(inherits(&s_info));
+ setInternalValue(globalData, string);
}
-StringObject::StringObject(ExecState* exec, NonNullPassRefPtr<Structure> structure, const UString& string)
- : JSWrapperObject(structure)
+StringObject::StringObject(ExecState* exec, Structure* structure, const UString& string)
+ : JSWrapperObject(exec->globalData(), structure)
{
- setInternalValue(jsString(exec, string));
+ ASSERT(inherits(&s_info));
+ setInternalValue(exec->globalData(), jsString(exec, string));
}
bool StringObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
if (propertyName == exec->propertyNames().length)
return false;
bool isStrictUInt32;
- unsigned i = propertyName.toStrictUInt32(&isStrictUInt32);
+ unsigned i = propertyName.toUInt32(isStrictUInt32);
if (isStrictUInt32 && internalValue()->canGetIndex(i))
return false;
return JSObject::deleteProperty(exec, propertyName);
{
int size = internalValue()->length();
for (int i = 0; i < size; ++i)
- propertyNames.add(Identifier(exec, UString::from(i)));
+ propertyNames.add(Identifier(exec, UString::number(i)));
if (mode == IncludeDontEnumProperties)
propertyNames.add(exec->propertyNames().length);
return JSObject::getOwnPropertyNames(exec, propertyNames, mode);
class StringObject : public JSWrapperObject {
public:
- StringObject(ExecState*, NonNullPassRefPtr<Structure>);
- StringObject(ExecState*, NonNullPassRefPtr<Structure>, const UString&);
+ StringObject(ExecState*, Structure*);
+ StringObject(ExecState*, Structure*, const UString&);
- static StringObject* create(ExecState*, JSString*);
+ static StringObject* create(ExecState*, JSGlobalObject*, JSString*);
virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties);
- virtual const ClassInfo* classInfo() const { return &info; }
- static const JS_EXPORTDATA ClassInfo info;
+ static const JS_EXPORTDATA ClassInfo s_info;
JSString* internalValue() const { return asString(JSWrapperObject::internalValue());}
- static PassRefPtr<Structure> createStructure(JSValue prototype)
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
+ return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
}
protected:
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesMarkChildren | OverridesGetPropertyNames | JSWrapperObject::StructureFlags;
- StringObject(NonNullPassRefPtr<Structure>, JSString*);
- };
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesGetPropertyNames | JSWrapperObject::StructureFlags;
+ StringObject(JSGlobalData&, Structure*, JSString*);
+ };
StringObject* asStringObject(JSValue);
inline StringObject* asStringObject(JSValue value)
{
- ASSERT(asObject(value)->inherits(&StringObject::info));
+ ASSERT(asObject(value)->inherits(&StringObject::s_info));
return static_cast<StringObject*>(asObject(value));
}
static StringObjectThatMasqueradesAsUndefined* create(ExecState* exec, const UString& string)
{
return new (exec) StringObjectThatMasqueradesAsUndefined(exec,
- createStructure(exec->lexicalGlobalObject()->stringPrototype()), string);
+ createStructure(exec->globalData(), exec->lexicalGlobalObject()->stringPrototype()), string);
}
private:
- StringObjectThatMasqueradesAsUndefined(ExecState* exec, NonNullPassRefPtr<Structure> structure, const UString& string)
+ StringObjectThatMasqueradesAsUndefined(ExecState* exec, Structure* structure, const UString& string)
: StringObject(exec, structure, string)
{
}
- static PassRefPtr<Structure> createStructure(JSValue proto)
+ static Structure* createStructure(JSGlobalData& globalData, JSValue proto)
{
- return Structure::create(proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
+ return Structure::create(globalData, proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
}
static const unsigned StructureFlags = OverridesGetOwnPropertySlot | MasqueradesAsUndefined | OverridesGetPropertyNames | StringObject::StructureFlags;
ASSERT_CLASS_FITS_IN_CELL(StringPrototype);
-static JSValue JSC_HOST_CALL stringProtoFuncToString(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL stringProtoFuncCharAt(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL stringProtoFuncCharCodeAt(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL stringProtoFuncConcat(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL stringProtoFuncLastIndexOf(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL stringProtoFuncSlice(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL stringProtoFuncSubstr(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL stringProtoFuncSubstring(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL stringProtoFuncToLowerCase(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL stringProtoFuncToUpperCase(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL stringProtoFuncLocaleCompare(ExecState*, JSObject*, JSValue, const ArgList&);
-
-static JSValue JSC_HOST_CALL stringProtoFuncBig(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL stringProtoFuncSmall(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL stringProtoFuncBlink(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL stringProtoFuncBold(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL stringProtoFuncFixed(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL stringProtoFuncItalics(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL stringProtoFuncStrike(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL stringProtoFuncSub(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL stringProtoFuncSup(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL stringProtoFuncFontcolor(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL stringProtoFuncAnchor(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL stringProtoFuncLink(ExecState*, JSObject*, JSValue, const ArgList&);
-
-static JSValue JSC_HOST_CALL stringProtoFuncTrim(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL stringProtoFuncTrimLeft(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL stringProtoFuncTrimRight(ExecState*, JSObject*, JSValue, const ArgList&);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncToString(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncCharAt(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncCharCodeAt(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncConcat(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncLastIndexOf(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncSlice(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstr(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstring(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncToLowerCase(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncToUpperCase(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncLocaleCompare(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncBig(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncSmall(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncBlink(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncBold(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncFixed(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncItalics(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncStrike(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncSub(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncSup(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncFontcolor(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncAnchor(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncLink(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncTrim(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimLeft(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimRight(ExecState*);
}
namespace JSC {
-const ClassInfo StringPrototype::info = { "String", &StringObject::info, 0, ExecState::stringTable };
+const ClassInfo StringPrototype::s_info = { "String", &StringObject::s_info, 0, ExecState::stringTable };
/* Source for StringPrototype.lut.h
@begin stringTable 26
*/
// ECMA 15.5.4
-StringPrototype::StringPrototype(ExecState* exec, NonNullPassRefPtr<Structure> structure)
+StringPrototype::StringPrototype(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
: StringObject(exec, structure)
{
+ ASSERT(inherits(&s_info));
+
+ putAnonymousValue(exec->globalData(), 0, globalObject);
// The constructor will be added later, after StringConstructor has been built
- putDirectWithoutTransition(exec->propertyNames().length, jsNumber(exec, 0), DontDelete | ReadOnly | DontEnum);
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(0), DontDelete | ReadOnly | DontEnum);
}
bool StringPrototype::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot &slot)
// ------------------------------ Functions --------------------------
-static NEVER_INLINE UString substituteBackreferencesSlow(const UString& replacement, const UString& source, const int* ovector, RegExp* reg, unsigned i)
+static NEVER_INLINE UString substituteBackreferencesSlow(const UString& replacement, const UString& source, const int* ovector, RegExp* reg, size_t i)
{
Vector<UChar> substitutedReplacement;
int offset = 0;
do {
- if (i + 1 == replacement.size())
+ if (i + 1 == replacement.length())
break;
UChar ref = replacement[i + 1];
if (ref == '$') {
// "$$" -> "$"
++i;
- substitutedReplacement.append(replacement.data() + offset, i - offset);
+ substitutedReplacement.append(replacement.characters() + offset, i - offset);
offset = i + 1;
continue;
}
backrefLength = ovector[0];
} else if (ref == '\'') {
backrefStart = ovector[1];
- backrefLength = source.size() - backrefStart;
+ backrefLength = source.length() - backrefStart;
} else if (reg && ref >= '0' && ref <= '9') {
// 1- and 2-digit back references are allowed
unsigned backrefIndex = ref - '0';
if (backrefIndex > reg->numSubpatterns())
continue;
- if (replacement.size() > i + 2) {
+ if (replacement.length() > i + 2) {
ref = replacement[i + 2];
if (ref >= '0' && ref <= '9') {
backrefIndex = 10 * backrefIndex + ref - '0';
continue;
if (i - offset)
- substitutedReplacement.append(replacement.data() + offset, i - offset);
+ substitutedReplacement.append(replacement.characters() + offset, i - offset);
i += 1 + advance;
offset = i + 1;
- substitutedReplacement.append(source.data() + backrefStart, backrefLength);
- } while ((i = replacement.find('$', i + 1)) != UString::NotFound);
+ if (backrefStart >= 0)
+ substitutedReplacement.append(source.characters() + backrefStart, backrefLength);
+ } while ((i = replacement.find('$', i + 1)) != notFound);
- if (replacement.size() - offset)
- substitutedReplacement.append(replacement.data() + offset, replacement.size() - offset);
+ if (replacement.length() - offset)
+ substitutedReplacement.append(replacement.characters() + offset, replacement.length() - offset);
substitutedReplacement.shrinkToFit();
return UString::adopt(substitutedReplacement);
static inline UString substituteBackreferences(const UString& replacement, const UString& source, const int* ovector, RegExp* reg)
{
- unsigned i = replacement.find('$', 0);
- if (UNLIKELY(i != UString::NotFound))
+ size_t i = replacement.find('$', 0);
+ if (UNLIKELY(i != notFound))
return substituteBackreferencesSlow(replacement, source, ovector, reg, i);
return replacement;
}
static inline int localeCompare(const UString& a, const UString& b)
{
- return Collator::userDefault()->collate(reinterpret_cast<const ::UChar*>(a.data()), a.size(), reinterpret_cast<const ::UChar*>(b.data()), b.size());
+ return Collator::userDefault()->collate(reinterpret_cast<const ::UChar*>(a.characters()), a.length(), reinterpret_cast<const ::UChar*>(b.characters()), b.length());
}
struct StringRange {
int length;
};
-JSValue jsSpliceSubstringsWithSeparators(ExecState* exec, JSString* sourceVal, const UString& source, const StringRange* substringRanges, int rangeCount, const UString* separators, int separatorCount);
-JSValue jsSpliceSubstringsWithSeparators(ExecState* exec, JSString* sourceVal, const UString& source, const StringRange* substringRanges, int rangeCount, const UString* separators, int separatorCount)
+static ALWAYS_INLINE JSValue jsSpliceSubstringsWithSeparators(ExecState* exec, JSString* sourceVal, const UString& source, const StringRange* substringRanges, int rangeCount, const UString* separators, int separatorCount)
{
if (rangeCount == 1 && separatorCount == 0) {
- int sourceSize = source.size();
+ int sourceSize = source.length();
int position = substringRanges[0].position;
int length = substringRanges[0].length;
if (position <= 0 && length >= sourceSize)
return sourceVal;
// We could call UString::substr, but this would result in redundant checks
- return jsString(exec, UStringImpl::create(source.rep(), max(0, position), min(sourceSize, length)));
+ return jsString(exec, StringImpl::create(source.impl(), max(0, position), min(sourceSize, length)));
}
int totalLength = 0;
for (int i = 0; i < rangeCount; i++)
totalLength += substringRanges[i].length;
for (int i = 0; i < separatorCount; i++)
- totalLength += separators[i].size();
+ totalLength += separators[i].length();
if (totalLength == 0)
return jsString(exec, "");
UChar* buffer;
- PassRefPtr<UStringImpl> impl = UStringImpl::tryCreateUninitialized(totalLength, buffer);
+ PassRefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(totalLength, buffer);
if (!impl)
return throwOutOfMemoryError(exec);
int bufferPos = 0;
for (int i = 0; i < maxCount; i++) {
if (i < rangeCount) {
- UStringImpl::copyChars(buffer + bufferPos, source.data() + substringRanges[i].position, substringRanges[i].length);
- bufferPos += substringRanges[i].length;
+ if (int srcLen = substringRanges[i].length) {
+ StringImpl::copyChars(buffer + bufferPos, source.characters() + substringRanges[i].position, srcLen);
+ bufferPos += srcLen;
+ }
}
if (i < separatorCount) {
- UStringImpl::copyChars(buffer + bufferPos, separators[i].data(), separators[i].size());
- bufferPos += separators[i].size();
+ if (int sepLen = separators[i].length()) {
+ StringImpl::copyChars(buffer + bufferPos, separators[i].characters(), sepLen);
+ bufferPos += sepLen;
+ }
}
}
return jsString(exec, impl);
}
-JSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec)
{
+ JSValue thisValue = exec->hostThisValue();
JSString* sourceVal = thisValue.toThisJSString(exec);
- JSValue pattern = args.at(0);
- JSValue replacement = args.at(1);
+ JSValue pattern = exec->argument(0);
+ JSValue replacement = exec->argument(1);
+ JSGlobalData* globalData = &exec->globalData();
UString replacementString;
CallData callData;
- CallType callType = replacement.getCallData(callData);
+ CallType callType = getCallData(replacement, callData);
if (callType == CallTypeNone)
replacementString = replacement.toString(exec);
- if (pattern.inherits(&RegExpObject::info)) {
+ if (pattern.inherits(&RegExpObject::s_info)) {
const UString& source = sourceVal->value(exec);
+ unsigned sourceLen = source.length();
if (exec->hadException())
- return JSValue();
+ return JSValue::encode(JSValue());
RegExp* reg = asRegExpObject(pattern)->regExp();
bool global = reg->global();
// reg->numSubpatterns() + 1 for pattern args, + 2 for match start and sourceValue
int argCount = reg->numSubpatterns() + 1 + 2;
JSFunction* func = asFunction(replacement);
- CachedCall cachedCall(exec, func, argCount, exec->exceptionSlot());
+ CachedCall cachedCall(exec, func, argCount);
if (exec->hadException())
- return jsNull();
+ return JSValue::encode(jsNull());
while (true) {
int matchIndex;
int matchLen = 0;
int* ovector;
- regExpConstructor->performMatch(reg, source, startPosition, matchIndex, matchLen, &ovector);
+ regExpConstructor->performMatch(*globalData, reg, source, startPosition, matchIndex, matchLen, &ovector);
if (matchIndex < 0)
break;
-
+
sourceRanges.append(StringRange(lastIndex, matchIndex - lastIndex));
int completeMatchStart = ovector[0];
cachedCall.setArgument(i, jsSubstring(exec, source, matchStart, matchLen));
}
- cachedCall.setArgument(i++, jsNumber(exec, completeMatchStart));
+ cachedCall.setArgument(i++, jsNumber(completeMatchStart));
cachedCall.setArgument(i++, sourceVal);
-
+
cachedCall.setThis(exec->globalThisValue());
JSValue result = cachedCall.call();
- replacements.append(result.toString(cachedCall.newCallFrame(exec)));
+ if (LIKELY(result.isString()))
+ replacements.append(asString(result)->value(exec));
+ else
+ replacements.append(result.toString(cachedCall.newCallFrame(exec)));
if (exec->hadException())
break;
// special case of empty match
if (matchLen == 0) {
startPosition++;
- if (startPosition > source.size())
+ if (startPosition > sourceLen)
break;
}
- }
+ }
} else {
do {
int matchIndex;
int matchLen = 0;
int* ovector;
- regExpConstructor->performMatch(reg, source, startPosition, matchIndex, matchLen, &ovector);
+ regExpConstructor->performMatch(*globalData, reg, source, startPosition, matchIndex, matchLen, &ovector);
if (matchIndex < 0)
break;
- sourceRanges.append(StringRange(lastIndex, matchIndex - lastIndex));
-
if (callType != CallTypeNone) {
+ sourceRanges.append(StringRange(lastIndex, matchIndex - lastIndex));
+
int completeMatchStart = ovector[0];
MarkedArgumentBuffer args;
for (unsigned i = 0; i < reg->numSubpatterns() + 1; ++i) {
int matchStart = ovector[i * 2];
int matchLen = ovector[i * 2 + 1] - matchStart;
-
+
if (matchStart < 0)
args.append(jsUndefined());
else
args.append(jsSubstring(exec, source, matchStart, matchLen));
}
- args.append(jsNumber(exec, completeMatchStart));
+ args.append(jsNumber(completeMatchStart));
args.append(sourceVal);
replacements.append(call(exec, replacement, callType, callData, exec->globalThisValue(), args).toString(exec));
if (exec->hadException())
break;
- } else
- replacements.append(substituteBackreferences(replacementString, source, ovector, reg));
+ } else {
+ int replLen = replacementString.length();
+ if (lastIndex < matchIndex || replLen) {
+ sourceRanges.append(StringRange(lastIndex, matchIndex - lastIndex));
+
+ if (replLen)
+ replacements.append(substituteBackreferences(replacementString, source, ovector, reg));
+ else
+ replacements.append(UString());
+ }
+ }
lastIndex = matchIndex + matchLen;
startPosition = lastIndex;
// special case of empty match
if (matchLen == 0) {
startPosition++;
- if (startPosition > source.size())
+ if (startPosition > sourceLen)
break;
}
} while (global);
}
if (!lastIndex && replacements.isEmpty())
- return sourceVal;
+ return JSValue::encode(sourceVal);
- if (static_cast<unsigned>(lastIndex) < source.size())
- sourceRanges.append(StringRange(lastIndex, source.size() - lastIndex));
+ if (static_cast<unsigned>(lastIndex) < sourceLen)
+ sourceRanges.append(StringRange(lastIndex, sourceLen - lastIndex));
- return jsSpliceSubstringsWithSeparators(exec, sourceVal, source, sourceRanges.data(), sourceRanges.size(), replacements.data(), replacements.size());
+ return JSValue::encode(jsSpliceSubstringsWithSeparators(exec, sourceVal, source, sourceRanges.data(), sourceRanges.size(), replacements.data(), replacements.size()));
}
// Not a regular expression, so treat the pattern as a string.
UString patternString = pattern.toString(exec);
- if (patternString.size() == 1 && callType == CallTypeNone)
- return sourceVal->replaceCharacter(exec, patternString[0], replacementString);
-
+ // Special case for single character patterns without back reference replacement
+ if (patternString.length() == 1 && callType == CallTypeNone && replacementString.find('$', 0) == notFound)
+ return JSValue::encode(sourceVal->replaceCharacter(exec, patternString[0], replacementString));
+
const UString& source = sourceVal->value(exec);
- unsigned matchPos = source.find(patternString);
+ size_t matchPos = source.find(patternString);
- if (matchPos == UString::NotFound)
- return sourceVal;
+ if (matchPos == notFound)
+ return JSValue::encode(sourceVal);
- int matchLen = patternString.size();
+ int matchLen = patternString.length();
if (callType != CallTypeNone) {
MarkedArgumentBuffer args;
args.append(jsSubstring(exec, source, matchPos, matchLen));
- args.append(jsNumber(exec, matchPos));
+ args.append(jsNumber(matchPos));
args.append(sourceVal);
replacementString = call(exec, replacement, callType, callData, exec->globalThisValue(), args).toString(exec);
size_t matchEnd = matchPos + matchLen;
int ovector[2] = { matchPos, matchEnd };
- return jsString(exec, source.substr(0, matchPos), substituteBackreferences(replacementString, source, ovector, 0), source.substr(matchEnd));
+ return JSValue::encode(jsString(exec, source.substringSharingImpl(0, matchPos), substituteBackreferences(replacementString, source, ovector, 0), source.substringSharingImpl(matchEnd)));
}
-JSValue JSC_HOST_CALL stringProtoFuncToString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL stringProtoFuncToString(ExecState* exec)
{
+ JSValue thisValue = exec->hostThisValue();
// Also used for valueOf.
if (thisValue.isString())
- return thisValue;
+ return JSValue::encode(thisValue);
- if (thisValue.inherits(&StringObject::info))
- return asStringObject(thisValue)->internalValue();
+ if (thisValue.inherits(&StringObject::s_info))
+ return JSValue::encode(asStringObject(thisValue)->internalValue());
- return throwError(exec, TypeError);
+ return throwVMTypeError(exec);
}
-JSValue JSC_HOST_CALL stringProtoFuncCharAt(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL stringProtoFuncCharAt(ExecState* exec)
{
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwVMTypeError(exec);
UString s = thisValue.toThisString(exec);
- unsigned len = s.size();
- JSValue a0 = args.at(0);
+ unsigned len = s.length();
+ JSValue a0 = exec->argument(0);
if (a0.isUInt32()) {
uint32_t i = a0.asUInt32();
if (i < len)
- return jsSingleCharacterSubstring(exec, s, i);
- return jsEmptyString(exec);
+ return JSValue::encode(jsSingleCharacterSubstring(exec, s, i));
+ return JSValue::encode(jsEmptyString(exec));
}
double dpos = a0.toInteger(exec);
if (dpos >= 0 && dpos < len)
- return jsSingleCharacterSubstring(exec, s, static_cast<unsigned>(dpos));
- return jsEmptyString(exec);
+ return JSValue::encode(jsSingleCharacterSubstring(exec, s, static_cast<unsigned>(dpos)));
+ return JSValue::encode(jsEmptyString(exec));
}
-JSValue JSC_HOST_CALL stringProtoFuncCharCodeAt(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL stringProtoFuncCharCodeAt(ExecState* exec)
{
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwVMTypeError(exec);
UString s = thisValue.toThisString(exec);
- unsigned len = s.size();
- JSValue a0 = args.at(0);
+ unsigned len = s.length();
+ JSValue a0 = exec->argument(0);
if (a0.isUInt32()) {
uint32_t i = a0.asUInt32();
if (i < len)
- return jsNumber(exec, s.data()[i]);
- return jsNaN(exec);
+ return JSValue::encode(jsNumber(s.characters()[i]));
+ return JSValue::encode(jsNaN());
}
double dpos = a0.toInteger(exec);
if (dpos >= 0 && dpos < len)
- return jsNumber(exec, s[static_cast<int>(dpos)]);
- return jsNaN(exec);
+ return JSValue::encode(jsNumber(s[static_cast<int>(dpos)]));
+ return JSValue::encode(jsNaN());
}
-JSValue JSC_HOST_CALL stringProtoFuncConcat(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL stringProtoFuncConcat(ExecState* exec)
{
- if (thisValue.isString() && (args.size() == 1)) {
- JSValue v = args.at(0);
- return v.isString()
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isString() && (exec->argumentCount() == 1)) {
+ JSValue v = exec->argument(0);
+ return JSValue::encode(v.isString()
? jsString(exec, asString(thisValue), asString(v))
- : jsString(exec, asString(thisValue), v.toString(exec));
+ : jsString(exec, asString(thisValue), v.toString(exec)));
}
-
- return jsString(exec, thisValue, args);
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwVMTypeError(exec);
+ return JSValue::encode(jsString(exec, thisValue));
}
-JSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState* exec)
{
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwVMTypeError(exec);
UString s = thisValue.toThisString(exec);
- int len = s.size();
+ int len = s.length();
- JSValue a0 = args.at(0);
- JSValue a1 = args.at(1);
+ JSValue a0 = exec->argument(0);
+ JSValue a1 = exec->argument(1);
UString u2 = a0.toString(exec);
int pos;
if (a1.isUndefined())
pos = static_cast<int>(dpos);
}
- unsigned result = s.find(u2, pos);
- if (result == UString::NotFound)
- return jsNumber(exec, -1);
- return jsNumber(exec, result);
+ size_t result = s.find(u2, pos);
+ if (result == notFound)
+ return JSValue::encode(jsNumber(-1));
+ return JSValue::encode(jsNumber(result));
}
-JSValue JSC_HOST_CALL stringProtoFuncLastIndexOf(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL stringProtoFuncLastIndexOf(ExecState* exec)
{
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwVMTypeError(exec);
UString s = thisValue.toThisString(exec);
- int len = s.size();
+ int len = s.length();
- JSValue a0 = args.at(0);
- JSValue a1 = args.at(1);
+ JSValue a0 = exec->argument(0);
+ JSValue a1 = exec->argument(1);
UString u2 = a0.toString(exec);
double dpos = a1.toIntegerPreserveNaN(exec);
dpos = len;
#endif
- unsigned result = s.rfind(u2, static_cast<unsigned>(dpos));
- if (result == UString::NotFound)
- return jsNumber(exec, -1);
- return jsNumber(exec, result);
+ size_t result = s.reverseFind(u2, static_cast<unsigned>(dpos));
+ if (result == notFound)
+ return JSValue::encode(jsNumber(-1));
+ return JSValue::encode(jsNumber(result));
}
-JSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec)
{
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwVMTypeError(exec);
UString s = thisValue.toThisString(exec);
+ JSGlobalData* globalData = &exec->globalData();
- JSValue a0 = args.at(0);
+ JSValue a0 = exec->argument(0);
- UString u = s;
- RefPtr<RegExp> reg;
- RegExpObject* imp = 0;
- if (a0.inherits(&RegExpObject::info))
+ RegExp* reg;
+ if (a0.inherits(&RegExpObject::s_info))
reg = asRegExpObject(a0)->regExp();
else {
/*
* If regexp is not an object whose [[Class]] property is "RegExp", it is
* replaced with the result of the expression new RegExp(regexp).
*/
- reg = exec->globalData().regExpCache()->lookupOrCreate(a0.toString(exec), UString::null());
+ reg = RegExp::create(&exec->globalData(), a0.toString(exec), NoFlags);
}
RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
int pos;
int matchLength = 0;
- regExpConstructor->performMatch(reg.get(), u, 0, pos, matchLength);
+ regExpConstructor->performMatch(*globalData, reg, s, 0, pos, matchLength);
if (!(reg->global())) {
// case without 'g' flag is handled like RegExp.prototype.exec
if (pos < 0)
- return jsNull();
- return regExpConstructor->arrayOfMatches(exec);
+ return JSValue::encode(jsNull());
+ return JSValue::encode(regExpConstructor->arrayOfMatches(exec));
}
// return array of matches
MarkedArgumentBuffer list;
- int lastIndex = 0;
while (pos >= 0) {
- list.append(jsSubstring(exec, u, pos, matchLength));
- lastIndex = pos;
+ list.append(jsSubstring(exec, s, pos, matchLength));
pos += matchLength == 0 ? 1 : matchLength;
- regExpConstructor->performMatch(reg.get(), u, pos, pos, matchLength);
+ regExpConstructor->performMatch(*globalData, reg, s, pos, pos, matchLength);
}
- if (imp)
- imp->setLastIndex(lastIndex);
if (list.isEmpty()) {
// if there are no matches at all, it's important to return
// Null instead of an empty array, because this matches
// other browsers and because Null is a false value.
- return jsNull();
+ return JSValue::encode(jsNull());
}
- return constructArray(exec, list);
+ return JSValue::encode(constructArray(exec, list));
}
-JSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState* exec)
{
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwVMTypeError(exec);
UString s = thisValue.toThisString(exec);
+ JSGlobalData* globalData = &exec->globalData();
- JSValue a0 = args.at(0);
+ JSValue a0 = exec->argument(0);
- UString u = s;
- RefPtr<RegExp> reg;
- if (a0.inherits(&RegExpObject::info))
+ RegExp* reg;
+ if (a0.inherits(&RegExpObject::s_info))
reg = asRegExpObject(a0)->regExp();
else {
/*
* If regexp is not an object whose [[Class]] property is "RegExp", it is
* replaced with the result of the expression new RegExp(regexp).
*/
- reg = exec->globalData().regExpCache()->lookupOrCreate(a0.toString(exec), UString::null());
+ reg = RegExp::create(&exec->globalData(), a0.toString(exec), NoFlags);
}
RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
int pos;
int matchLength = 0;
- regExpConstructor->performMatch(reg.get(), u, 0, pos, matchLength);
- return jsNumber(exec, pos);
+ regExpConstructor->performMatch(*globalData, reg, s, 0, pos, matchLength);
+ return JSValue::encode(jsNumber(pos));
}
-JSValue JSC_HOST_CALL stringProtoFuncSlice(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL stringProtoFuncSlice(ExecState* exec)
{
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwVMTypeError(exec);
UString s = thisValue.toThisString(exec);
- int len = s.size();
+ int len = s.length();
- JSValue a0 = args.at(0);
- JSValue a1 = args.at(1);
+ JSValue a0 = exec->argument(0);
+ JSValue a1 = exec->argument(1);
// The arg processing is very much like ArrayProtoFunc::Slice
double start = a0.toInteger(exec);
from = 0;
if (to > len)
to = len;
- return jsSubstring(exec, s, static_cast<unsigned>(from), static_cast<unsigned>(to) - static_cast<unsigned>(from));
+ return JSValue::encode(jsSubstring(exec, s, static_cast<unsigned>(from), static_cast<unsigned>(to) - static_cast<unsigned>(from)));
}
- return jsEmptyString(exec);
+ return JSValue::encode(jsEmptyString(exec));
}
-JSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec)
{
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwVMTypeError(exec);
UString s = thisValue.toThisString(exec);
+ JSGlobalData* globalData = &exec->globalData();
- JSValue a0 = args.at(0);
- JSValue a1 = args.at(1);
+ JSValue a0 = exec->argument(0);
+ JSValue a1 = exec->argument(1);
JSArray* result = constructEmptyArray(exec);
unsigned i = 0;
unsigned p0 = 0;
unsigned limit = a1.isUndefined() ? 0xFFFFFFFFU : a1.toUInt32(exec);
- if (a0.inherits(&RegExpObject::info)) {
+ if (a0.inherits(&RegExpObject::s_info)) {
RegExp* reg = asRegExpObject(a0)->regExp();
- if (s.isEmpty() && reg->match(s, 0) >= 0) {
+ if (s.isEmpty() && reg->match(*globalData, s, 0) >= 0) {
// empty string matched by regexp -> empty array
- return result;
+ return JSValue::encode(result);
}
unsigned pos = 0;
- while (i != limit && pos < s.size()) {
+ while (i != limit && pos < s.length()) {
Vector<int, 32> ovector;
- int mpos = reg->match(s, pos, &ovector);
+ int mpos = reg->match(*globalData, s, pos, &ovector);
if (mpos < 0)
break;
int mlen = ovector[1] - ovector[0];
if (u2.isEmpty()) {
if (s.isEmpty()) {
// empty separator matches empty string -> empty array
- return result;
+ return JSValue::encode(result);
}
- while (i != limit && p0 < s.size() - 1)
+ while (i != limit && p0 < s.length() - 1)
result->put(exec, i++, jsSingleCharacterSubstring(exec, s, p0++));
} else {
- unsigned pos;
-
- while (i != limit && (pos = s.find(u2, p0)) != UString::NotFound) {
+ size_t pos;
+ while (i != limit && (pos = s.find(u2, p0)) != notFound) {
result->put(exec, i++, jsSubstring(exec, s, p0, pos - p0));
- p0 = pos + u2.size();
+ p0 = pos + u2.length();
}
}
}
// add remaining string
if (i != limit)
- result->put(exec, i++, jsSubstring(exec, s, p0, s.size() - p0));
+ result->put(exec, i++, jsSubstring(exec, s, p0, s.length() - p0));
- return result;
+ return JSValue::encode(result);
}
-JSValue JSC_HOST_CALL stringProtoFuncSubstr(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
-{
- int len;
+EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstr(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwVMTypeError(exec);
+ unsigned len;
JSString* jsString = 0;
UString uString;
if (thisValue.isString()) {
len = jsString->length();
} else {
uString = thisValue.toThisObject(exec)->toString(exec);
- len = uString.size();
+ len = uString.length();
}
- JSValue a0 = args.at(0);
- JSValue a1 = args.at(1);
+ JSValue a0 = exec->argument(0);
+ JSValue a1 = exec->argument(1);
double start = a0.toInteger(exec);
double length = a1.isUndefined() ? len : a1.toInteger(exec);
if (start >= len || length <= 0)
- return jsEmptyString(exec);
+ return JSValue::encode(jsEmptyString(exec));
if (start < 0) {
start += len;
if (start < 0)
}
if (start + length > len)
length = len - start;
-
unsigned substringStart = static_cast<unsigned>(start);
unsigned substringLength = static_cast<unsigned>(length);
if (jsString)
- return jsSubstring(exec, jsString, substringStart, substringLength);
- return jsSubstring(exec, uString, substringStart, substringLength);
+ return JSValue::encode(jsSubstring(exec, jsString, substringStart, substringLength));
+ return JSValue::encode(jsSubstring(exec, uString, substringStart, substringLength));
}
-JSValue JSC_HOST_CALL stringProtoFuncSubstring(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstring(ExecState* exec)
{
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwVMTypeError(exec);
int len;
JSString* jsString = 0;
UString uString;
len = jsString->length();
} else {
uString = thisValue.toThisObject(exec)->toString(exec);
- len = uString.size();
+ len = uString.length();
}
- JSValue a0 = args.at(0);
- JSValue a1 = args.at(1);
+ JSValue a0 = exec->argument(0);
+ JSValue a1 = exec->argument(1);
double start = a0.toNumber(exec);
- double end = a1.toNumber(exec);
- if (isnan(start))
- start = 0;
- if (isnan(end))
- end = 0;
- if (start < 0)
+ double end;
+ if (!(start >= 0)) // check for negative values or NaN
start = 0;
- if (end < 0)
- end = 0;
- if (start > len)
+ else if (start > len)
start = len;
- if (end > len)
- end = len;
if (a1.isUndefined())
end = len;
+ else {
+ end = a1.toNumber(exec);
+ if (!(end >= 0)) // check for negative values or NaN
+ end = 0;
+ else if (end > len)
+ end = len;
+ }
if (start > end) {
double temp = end;
end = start;
unsigned substringStart = static_cast<unsigned>(start);
unsigned substringLength = static_cast<unsigned>(end) - substringStart;
if (jsString)
- return jsSubstring(exec, jsString, substringStart, substringLength);
- return jsSubstring(exec, uString, substringStart, substringLength);
+ return JSValue::encode(jsSubstring(exec, jsString, substringStart, substringLength));
+ return JSValue::encode(jsSubstring(exec, uString, substringStart, substringLength));
}
-JSValue JSC_HOST_CALL stringProtoFuncToLowerCase(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL stringProtoFuncToLowerCase(ExecState* exec)
{
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwVMTypeError(exec);
JSString* sVal = thisValue.toThisJSString(exec);
const UString& s = sVal->value(exec);
- int sSize = s.size();
+ int sSize = s.length();
if (!sSize)
- return sVal;
+ return JSValue::encode(sVal);
- const UChar* sData = s.data();
+ const UChar* sData = s.characters();
Vector<UChar> buffer(sSize);
UChar ored = 0;
buffer[i] = toASCIILower(c);
}
if (!(ored & ~0x7f))
- return jsString(exec, UString::adopt(buffer));
+ return JSValue::encode(jsString(exec, UString::adopt(buffer)));
bool error;
int length = Unicode::toLower(buffer.data(), sSize, sData, sSize, &error);
buffer.resize(length);
length = Unicode::toLower(buffer.data(), length, sData, sSize, &error);
if (error)
- return sVal;
+ return JSValue::encode(sVal);
}
if (length == sSize) {
if (memcmp(buffer.data(), sData, length * sizeof(UChar)) == 0)
- return sVal;
+ return JSValue::encode(sVal);
} else
buffer.resize(length);
- return jsString(exec, UString::adopt(buffer));
+ return JSValue::encode(jsString(exec, UString::adopt(buffer)));
}
-JSValue JSC_HOST_CALL stringProtoFuncToUpperCase(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL stringProtoFuncToUpperCase(ExecState* exec)
{
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwVMTypeError(exec);
JSString* sVal = thisValue.toThisJSString(exec);
const UString& s = sVal->value(exec);
- int sSize = s.size();
+ int sSize = s.length();
if (!sSize)
- return sVal;
+ return JSValue::encode(sVal);
- const UChar* sData = s.data();
+ const UChar* sData = s.characters();
Vector<UChar> buffer(sSize);
UChar ored = 0;
buffer[i] = toASCIIUpper(c);
}
if (!(ored & ~0x7f))
- return jsString(exec, UString::adopt(buffer));
+ return JSValue::encode(jsString(exec, UString::adopt(buffer)));
bool error;
int length = Unicode::toUpper(buffer.data(), sSize, sData, sSize, &error);
buffer.resize(length);
length = Unicode::toUpper(buffer.data(), length, sData, sSize, &error);
if (error)
- return sVal;
+ return JSValue::encode(sVal);
}
if (length == sSize) {
if (memcmp(buffer.data(), sData, length * sizeof(UChar)) == 0)
- return sVal;
+ return JSValue::encode(sVal);
} else
buffer.resize(length);
- return jsString(exec, UString::adopt(buffer));
+ return JSValue::encode(jsString(exec, UString::adopt(buffer)));
}
-JSValue JSC_HOST_CALL stringProtoFuncLocaleCompare(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL stringProtoFuncLocaleCompare(ExecState* exec)
{
- if (args.size() < 1)
- return jsNumber(exec, 0);
+ if (exec->argumentCount() < 1)
+ return JSValue::encode(jsNumber(0));
+
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwVMTypeError(exec);
UString s = thisValue.toThisString(exec);
- JSValue a0 = args.at(0);
- return jsNumber(exec, localeCompare(s, a0.toString(exec)));
+ JSValue a0 = exec->argument(0);
+ return JSValue::encode(jsNumber(localeCompare(s, a0.toString(exec))));
}
-JSValue JSC_HOST_CALL stringProtoFuncBig(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL stringProtoFuncBig(ExecState* exec)
{
+ JSValue thisValue = exec->hostThisValue();
UString s = thisValue.toThisString(exec);
- return jsMakeNontrivialString(exec, "<big>", s, "</big>");
+ return JSValue::encode(jsMakeNontrivialString(exec, "<big>", s, "</big>"));
}
-JSValue JSC_HOST_CALL stringProtoFuncSmall(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL stringProtoFuncSmall(ExecState* exec)
{
+ JSValue thisValue = exec->hostThisValue();
UString s = thisValue.toThisString(exec);
- return jsMakeNontrivialString(exec, "<small>", s, "</small>");
+ return JSValue::encode(jsMakeNontrivialString(exec, "<small>", s, "</small>"));
}
-JSValue JSC_HOST_CALL stringProtoFuncBlink(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL stringProtoFuncBlink(ExecState* exec)
{
+ JSValue thisValue = exec->hostThisValue();
UString s = thisValue.toThisString(exec);
- return jsMakeNontrivialString(exec, "<blink>", s, "</blink>");
+ return JSValue::encode(jsMakeNontrivialString(exec, "<blink>", s, "</blink>"));
}
-JSValue JSC_HOST_CALL stringProtoFuncBold(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL stringProtoFuncBold(ExecState* exec)
{
+ JSValue thisValue = exec->hostThisValue();
UString s = thisValue.toThisString(exec);
- return jsMakeNontrivialString(exec, "<b>", s, "</b>");
+ return JSValue::encode(jsMakeNontrivialString(exec, "<b>", s, "</b>"));
}
-JSValue JSC_HOST_CALL stringProtoFuncFixed(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL stringProtoFuncFixed(ExecState* exec)
{
+ JSValue thisValue = exec->hostThisValue();
UString s = thisValue.toThisString(exec);
- return jsMakeNontrivialString(exec, "<tt>", s, "</tt>");
+ return JSValue::encode(jsMakeNontrivialString(exec, "<tt>", s, "</tt>"));
}
-JSValue JSC_HOST_CALL stringProtoFuncItalics(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL stringProtoFuncItalics(ExecState* exec)
{
+ JSValue thisValue = exec->hostThisValue();
UString s = thisValue.toThisString(exec);
- return jsMakeNontrivialString(exec, "<i>", s, "</i>");
+ return JSValue::encode(jsMakeNontrivialString(exec, "<i>", s, "</i>"));
}
-JSValue JSC_HOST_CALL stringProtoFuncStrike(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL stringProtoFuncStrike(ExecState* exec)
{
+ JSValue thisValue = exec->hostThisValue();
UString s = thisValue.toThisString(exec);
- return jsMakeNontrivialString(exec, "<strike>", s, "</strike>");
+ return JSValue::encode(jsMakeNontrivialString(exec, "<strike>", s, "</strike>"));
}
-JSValue JSC_HOST_CALL stringProtoFuncSub(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL stringProtoFuncSub(ExecState* exec)
{
+ JSValue thisValue = exec->hostThisValue();
UString s = thisValue.toThisString(exec);
- return jsMakeNontrivialString(exec, "<sub>", s, "</sub>");
+ return JSValue::encode(jsMakeNontrivialString(exec, "<sub>", s, "</sub>"));
}
-JSValue JSC_HOST_CALL stringProtoFuncSup(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL stringProtoFuncSup(ExecState* exec)
{
+ JSValue thisValue = exec->hostThisValue();
UString s = thisValue.toThisString(exec);
- return jsMakeNontrivialString(exec, "<sup>", s, "</sup>");
+ return JSValue::encode(jsMakeNontrivialString(exec, "<sup>", s, "</sup>"));
}
-JSValue JSC_HOST_CALL stringProtoFuncFontcolor(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL stringProtoFuncFontcolor(ExecState* exec)
{
+ JSValue thisValue = exec->hostThisValue();
UString s = thisValue.toThisString(exec);
- JSValue a0 = args.at(0);
- return jsMakeNontrivialString(exec, "<font color=\"", a0.toString(exec), "\">", s, "</font>");
+ JSValue a0 = exec->argument(0);
+ return JSValue::encode(jsMakeNontrivialString(exec, "<font color=\"", a0.toString(exec), "\">", s, "</font>"));
}
-JSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState* exec)
{
+ JSValue thisValue = exec->hostThisValue();
UString s = thisValue.toThisString(exec);
- JSValue a0 = args.at(0);
+ JSValue a0 = exec->argument(0);
uint32_t smallInteger;
if (a0.getUInt32(smallInteger) && smallInteger <= 9) {
- unsigned stringSize = s.size();
+ unsigned stringSize = s.length();
unsigned bufferSize = 22 + stringSize;
UChar* buffer;
- PassRefPtr<UStringImpl> impl = UStringImpl::tryCreateUninitialized(bufferSize, buffer);
+ PassRefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(bufferSize, buffer);
if (!impl)
- return jsUndefined();
+ return JSValue::encode(jsUndefined());
buffer[0] = '<';
buffer[1] = 'f';
buffer[2] = 'o';
buffer[12] = '0' + smallInteger;
buffer[13] = '"';
buffer[14] = '>';
- memcpy(&buffer[15], s.data(), stringSize * sizeof(UChar));
+ memcpy(&buffer[15], s.characters(), stringSize * sizeof(UChar));
buffer[15 + stringSize] = '<';
buffer[16 + stringSize] = '/';
buffer[17 + stringSize] = 'f';
buffer[19 + stringSize] = 'n';
buffer[20 + stringSize] = 't';
buffer[21 + stringSize] = '>';
- return jsNontrivialString(exec, impl);
+ return JSValue::encode(jsNontrivialString(exec, impl));
}
- return jsMakeNontrivialString(exec, "<font size=\"", a0.toString(exec), "\">", s, "</font>");
+ return JSValue::encode(jsMakeNontrivialString(exec, "<font size=\"", a0.toString(exec), "\">", s, "</font>"));
}
-JSValue JSC_HOST_CALL stringProtoFuncAnchor(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL stringProtoFuncAnchor(ExecState* exec)
{
+ JSValue thisValue = exec->hostThisValue();
UString s = thisValue.toThisString(exec);
- JSValue a0 = args.at(0);
- return jsMakeNontrivialString(exec, "<a name=\"", a0.toString(exec), "\">", s, "</a>");
+ JSValue a0 = exec->argument(0);
+ return JSValue::encode(jsMakeNontrivialString(exec, "<a name=\"", a0.toString(exec), "\">", s, "</a>"));
}
-JSValue JSC_HOST_CALL stringProtoFuncLink(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL stringProtoFuncLink(ExecState* exec)
{
+ JSValue thisValue = exec->hostThisValue();
UString s = thisValue.toThisString(exec);
- JSValue a0 = args.at(0);
+ JSValue a0 = exec->argument(0);
UString linkText = a0.toString(exec);
- unsigned linkTextSize = linkText.size();
- unsigned stringSize = s.size();
+ unsigned linkTextSize = linkText.length();
+ unsigned stringSize = s.length();
unsigned bufferSize = 15 + linkTextSize + stringSize;
UChar* buffer;
- PassRefPtr<UStringImpl> impl = UStringImpl::tryCreateUninitialized(bufferSize, buffer);
+ PassRefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(bufferSize, buffer);
if (!impl)
- return jsUndefined();
+ return JSValue::encode(jsUndefined());
buffer[0] = '<';
buffer[1] = 'a';
buffer[2] = ' ';
buffer[6] = 'f';
buffer[7] = '=';
buffer[8] = '"';
- memcpy(&buffer[9], linkText.data(), linkTextSize * sizeof(UChar));
+ memcpy(&buffer[9], linkText.characters(), linkTextSize * sizeof(UChar));
buffer[9 + linkTextSize] = '"';
buffer[10 + linkTextSize] = '>';
- memcpy(&buffer[11 + linkTextSize], s.data(), stringSize * sizeof(UChar));
+ memcpy(&buffer[11 + linkTextSize], s.characters(), stringSize * sizeof(UChar));
buffer[11 + linkTextSize + stringSize] = '<';
buffer[12 + linkTextSize + stringSize] = '/';
buffer[13 + linkTextSize + stringSize] = 'a';
buffer[14 + linkTextSize + stringSize] = '>';
- return jsNontrivialString(exec, impl);
+ return JSValue::encode(jsNontrivialString(exec, impl));
}
enum {
static inline JSValue trimString(ExecState* exec, JSValue thisValue, int trimKind)
{
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwTypeError(exec);
UString str = thisValue.toThisString(exec);
unsigned left = 0;
if (trimKind & TrimLeft) {
- while (left < str.size() && isTrimWhitespace(str[left]))
+ while (left < str.length() && isTrimWhitespace(str[left]))
left++;
}
- unsigned right = str.size();
+ unsigned right = str.length();
if (trimKind & TrimRight) {
while (right > left && isTrimWhitespace(str[right - 1]))
right--;
}
// Don't gc allocate a new string if we don't have to.
- if (left == 0 && right == str.size() && thisValue.isString())
+ if (left == 0 && right == str.length() && thisValue.isString())
return thisValue;
- return jsString(exec, str.substr(left, right - left));
+ return jsString(exec, str.substringSharingImpl(left, right - left));
}
-JSValue JSC_HOST_CALL stringProtoFuncTrim(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL stringProtoFuncTrim(ExecState* exec)
{
- return trimString(exec, thisValue, TrimLeft | TrimRight);
+ JSValue thisValue = exec->hostThisValue();
+ return JSValue::encode(trimString(exec, thisValue, TrimLeft | TrimRight));
}
-JSValue JSC_HOST_CALL stringProtoFuncTrimLeft(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimLeft(ExecState* exec)
{
- return trimString(exec, thisValue, TrimLeft);
+ JSValue thisValue = exec->hostThisValue();
+ return JSValue::encode(trimString(exec, thisValue, TrimLeft));
}
-JSValue JSC_HOST_CALL stringProtoFuncTrimRight(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimRight(ExecState* exec)
{
- return trimString(exec, thisValue, TrimRight);
+ JSValue thisValue = exec->hostThisValue();
+ return JSValue::encode(trimString(exec, thisValue, TrimRight));
}
class StringPrototype : public StringObject {
public:
- StringPrototype(ExecState*, NonNullPassRefPtr<Structure>);
+ StringPrototype(ExecState*, JSGlobalObject*, Structure*);
virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
- virtual const ClassInfo* classInfo() const { return &info; }
- static const ClassInfo info;
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
+ {
+ return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
+ }
+
+ static const ClassInfo s_info;
+
+ protected:
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | StringObject::StructureFlags;
+
+ COMPILE_ASSERT(!StringObject::AnonymousSlotCount, StringPrototype_stomps_on_your_anonymous_slot);
+ static const unsigned AnonymousSlotCount = 1;
};
} // namespace JSC
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "config.h"
+#include "StringRecursionChecker.h"
+
+#include "Error.h"
+#include "ExceptionHelpers.h"
+
+namespace JSC {
+
+EncodedJSValue StringRecursionChecker::throwStackOverflowError()
+{
+ return throwVMError(m_exec, createStackOverflowError(m_exec));
+}
+
+EncodedJSValue StringRecursionChecker::emptyString()
+{
+ return JSValue::encode(jsEmptyString(m_exec));
+}
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef StringRecursionChecker_h
+#define StringRecursionChecker_h
+
+#include "Interpreter.h"
+
+namespace JSC {
+
+class StringRecursionChecker {
+ WTF_MAKE_NONCOPYABLE(StringRecursionChecker);
+
+public:
+ StringRecursionChecker(ExecState*, JSObject* thisObject);
+ ~StringRecursionChecker();
+
+ EncodedJSValue earlyReturnValue() const; // 0 if everything is OK, value to return for failure cases
+
+private:
+ EncodedJSValue throwStackOverflowError();
+ EncodedJSValue emptyString();
+ EncodedJSValue performCheck();
+
+ ExecState* m_exec;
+ JSObject* m_thisObject;
+ EncodedJSValue m_earlyReturnValue;
+};
+
+inline EncodedJSValue StringRecursionChecker::performCheck()
+{
+ int size = m_exec->globalData().stringRecursionCheckVisitedObjects.size();
+ if (size >= MaxSmallThreadReentryDepth && size >= m_exec->globalData().maxReentryDepth)
+ return throwStackOverflowError();
+ bool alreadyVisited = !m_exec->globalData().stringRecursionCheckVisitedObjects.add(m_thisObject).second;
+ if (alreadyVisited)
+ return emptyString(); // Return empty string to avoid infinite recursion.
+ return 0; // Indicate success.
+}
+
+inline StringRecursionChecker::StringRecursionChecker(ExecState* exec, JSObject* thisObject)
+ : m_exec(exec)
+ , m_thisObject(thisObject)
+ , m_earlyReturnValue(performCheck())
+{
+}
+
+inline EncodedJSValue StringRecursionChecker::earlyReturnValue() const
+{
+ return m_earlyReturnValue;
+}
+
+inline StringRecursionChecker::~StringRecursionChecker()
+{
+ if (m_earlyReturnValue)
+ return;
+ ASSERT(m_exec->globalData().stringRecursionCheckVisitedObjects.contains(m_thisObject));
+ m_exec->globalData().stringRecursionCheckVisitedObjects.remove(m_thisObject);
+}
+
+}
+
+#endif
using namespace std;
using namespace WTF;
-namespace JSC {
-
-// Choose a number for the following so that most property maps are smaller,
-// but it's not going to blow out the stack to allocate this number of pointers.
-static const int smallMapThreshold = 1024;
-
-// The point at which the function call overhead of the qsort implementation
-// becomes small compared to the inefficiency of insertion sort.
-static const unsigned tinyMapThreshold = 20;
-
-static const unsigned newTableSize = 16;
+#if DUMP_PROPERTYMAP_STATS
-#ifndef NDEBUG
-static WTF::RefCountedLeakCounter structureCounter("Structure");
+int numProbes;
+int numCollisions;
+int numRehashes;
+int numRemoves;
-#if ENABLE(JSC_MULTIPLE_THREADS)
-static Mutex& ignoreSetMutex = *(new Mutex);
#endif
-static bool shouldIgnoreLeaks;
-static HashSet<Structure*>& ignoreSet = *(new HashSet<Structure*>);
-#endif
+namespace JSC {
#if DUMP_STRUCTURE_ID_STATISTICS
static HashSet<Structure*>& liveStructureSet = *(new HashSet<Structure*>);
#endif
-static int comparePropertyMapEntryIndices(const void* a, const void* b);
-
-inline void Structure::setTransitionTable(TransitionTable* table)
-{
- ASSERT(m_isUsingSingleSlot);
-#ifndef NDEBUG
- setSingleTransition(0);
-#endif
- m_isUsingSingleSlot = false;
- m_transitions.m_table = table;
- // This implicitly clears the flag that indicates we're using a single transition
- ASSERT(!m_isUsingSingleSlot);
-}
-
-// The contains and get methods accept imprecise matches, so if an unspecialised transition exists
-// for the given key they will consider that transition to be a match. If a specialised transition
-// exists and it matches the provided specificValue, get will return the specific transition.
-inline bool Structure::transitionTableContains(const StructureTransitionTableHash::Key& key, JSCell* specificValue)
-{
- if (m_isUsingSingleSlot) {
- Structure* existingTransition = singleTransition();
- return existingTransition && existingTransition->m_nameInPrevious.get() == key.first
- && existingTransition->m_attributesInPrevious == key.second
- && (existingTransition->m_specificValueInPrevious == specificValue || existingTransition->m_specificValueInPrevious == 0);
- }
- TransitionTable::iterator find = transitionTable()->find(key);
- if (find == transitionTable()->end())
- return false;
-
- return find->second.first || find->second.second->transitionedFor(specificValue);
-}
-
-inline Structure* Structure::transitionTableGet(const StructureTransitionTableHash::Key& key, JSCell* specificValue) const
+bool StructureTransitionTable::contains(StringImpl* rep, unsigned attributes) const
{
- if (m_isUsingSingleSlot) {
- Structure* existingTransition = singleTransition();
- if (existingTransition && existingTransition->m_nameInPrevious.get() == key.first
- && existingTransition->m_attributesInPrevious == key.second
- && (existingTransition->m_specificValueInPrevious == specificValue || existingTransition->m_specificValueInPrevious == 0))
- return existingTransition;
- return 0;
+ if (isUsingSingleSlot()) {
+ Structure* transition = singleTransition();
+ return transition && transition->m_nameInPrevious == rep && transition->m_attributesInPrevious == attributes;
}
-
- Transition transition = transitionTable()->get(key);
- if (transition.second && transition.second->transitionedFor(specificValue))
- return transition.second;
- return transition.first;
+ return map()->contains(make_pair(rep, attributes));
}
-inline bool Structure::transitionTableHasTransition(const StructureTransitionTableHash::Key& key) const
+inline Structure* StructureTransitionTable::get(StringImpl* rep, unsigned attributes) const
{
- if (m_isUsingSingleSlot) {
+ if (isUsingSingleSlot()) {
Structure* transition = singleTransition();
- return transition && transition->m_nameInPrevious == key.first
- && transition->m_attributesInPrevious == key.second;
+ return (transition && transition->m_nameInPrevious == rep && transition->m_attributesInPrevious == attributes) ? transition : 0;
}
- return transitionTable()->contains(key);
+ return map()->get(make_pair(rep, attributes));
}
-inline void Structure::transitionTableRemove(const StructureTransitionTableHash::Key& key, JSCell* specificValue)
+inline void StructureTransitionTable::remove(Structure* structure)
{
- if (m_isUsingSingleSlot) {
- ASSERT(transitionTableContains(key, specificValue));
- setSingleTransition(0);
- return;
+ if (isUsingSingleSlot()) {
+ // If more than one transition had been added, then we wouldn't be in
+ // single slot mode (even despecifying a from a specific value triggers
+ // map mode).
+ // As such, the passed structure *must* be the existing transition.
+ ASSERT(singleTransition() == structure);
+ clearSingleTransition();
+ } else {
+ // Check whether a mapping exists for structure's key, and whether the
+ // entry is structure (the latter check may fail if we initially had a
+ // transition with a specific value, and this has been despecified).
+
+ // Newer versions of the STL have an std::make_pair function that takes rvalue references.
+ // When either of the parameters are bitfields, the C++ compiler will try to bind them as lvalues, which is invalid. To work around this, use unary "+" to make the parameter an rvalue.
+ // See https://bugs.webkit.org/show_bug.cgi?id=59261 for more details
+ TransitionMap::iterator entry = map()->find(make_pair(structure->m_nameInPrevious, +structure->m_attributesInPrevious));
+ if (entry != map()->end() && structure == entry.get().second)
+ map()->remove(entry);
}
- TransitionTable::iterator find = transitionTable()->find(key);
- if (!specificValue)
- find->second.first = 0;
- else
- find->second.second = 0;
- if (!find->second.first && !find->second.second)
- transitionTable()->remove(find);
}
-inline void Structure::transitionTableAdd(const StructureTransitionTableHash::Key& key, Structure* structure, JSCell* specificValue)
+inline void StructureTransitionTable::add(JSGlobalData& globalData, Structure* structure)
{
- if (m_isUsingSingleSlot) {
- if (!singleTransition()) {
- setSingleTransition(structure);
+ if (isUsingSingleSlot()) {
+ Structure* existingTransition = singleTransition();
+
+ // This handles the first transition being added.
+ if (!existingTransition) {
+ setSingleTransition(globalData, structure);
return;
}
- Structure* existingTransition = singleTransition();
- TransitionTable* transitionTable = new TransitionTable;
- setTransitionTable(transitionTable);
- if (existingTransition)
- transitionTableAdd(std::make_pair(existingTransition->m_nameInPrevious.get(), existingTransition->m_attributesInPrevious), existingTransition, existingTransition->m_specificValueInPrevious);
+
+ // This handles the second transition being added
+ // (or the first transition being despecified!)
+ setMap(new TransitionMap());
+ add(globalData, existingTransition);
}
- if (!specificValue) {
- TransitionTable::iterator find = transitionTable()->find(key);
- if (find == transitionTable()->end())
- transitionTable()->add(key, Transition(structure, static_cast<Structure*>(0)));
- else
- find->second.first = structure;
- } else {
- // If we're adding a transition to a specific value, then there cannot be
- // an existing transition
- ASSERT(!transitionTable()->contains(key));
- transitionTable()->add(key, Transition(static_cast<Structure*>(0), structure));
+
+ // Add the structure to the map.
+
+ // Newer versions of the STL have an std::make_pair function that takes rvalue references.
+ // When either of the parameters are bitfields, the C++ compiler will try to bind them as lvalues, which is invalid. To work around this, use unary "+" to make the parameter an rvalue.
+ // See https://bugs.webkit.org/show_bug.cgi?id=59261 for more details
+ std::pair<TransitionMap::iterator, bool> result = map()->add(globalData, make_pair(structure->m_nameInPrevious, +structure->m_attributesInPrevious), structure);
+ if (!result.second) {
+ // There already is an entry! - we should only hit this when despecifying.
+ ASSERT(result.first.get().second->m_specificValueInPrevious);
+ ASSERT(!structure->m_specificValueInPrevious);
+ map()->set(result.first, structure);
}
}
HashSet<Structure*>::const_iterator end = liveStructureSet.end();
for (HashSet<Structure*>::const_iterator it = liveStructureSet.begin(); it != end; ++it) {
Structure* structure = *it;
- if (structure->m_usingSingleTransitionSlot) {
- if (!structure->m_transitions.singleTransition)
+
+ switch (structure->m_transitionTable.size()) {
+ case 0:
++numberLeaf;
- else
- ++numberUsingSingleSlot;
+ if (!structure->m_previous)
+ ++numberSingletons;
+ break;
- if (!structure->m_previous && !structure->m_transitions.singleTransition)
- ++numberSingletons;
+ case 1:
+ ++numberUsingSingleSlot;
+ break;
}
if (structure->m_propertyTable) {
++numberWithPropertyMaps;
- totalPropertyMapsSize += PropertyMapHashTable::allocationSize(structure->m_propertyTable->size);
- if (structure->m_propertyTable->deletedOffsets)
- totalPropertyMapsSize += (structure->m_propertyTable->deletedOffsets->capacity() * sizeof(unsigned));
+ totalPropertyMapsSize += structure->m_propertyTable->sizeInMemory();
}
}
#endif
}
-Structure::Structure(JSValue prototype, const TypeInfo& typeInfo, unsigned anonymousSlotCount)
- : m_typeInfo(typeInfo)
- , m_prototype(prototype)
- , m_specificValueInPrevious(0)
- , m_propertyTable(0)
- , m_propertyStorageCapacity(JSObject::inlineStorageCapacity)
+Structure::Structure(JSGlobalData& globalData, JSValue prototype, const TypeInfo& typeInfo, unsigned anonymousSlotCount, const ClassInfo* classInfo)
+ : JSCell(globalData, globalData.structureStructure.get())
+ , m_typeInfo(typeInfo)
+ , m_prototype(globalData, this, prototype)
+ , m_classInfo(classInfo)
+ , m_propertyStorageCapacity(typeInfo.isFinal() ? JSFinalObject_inlineStorageCapacity : JSNonFinalObject_inlineStorageCapacity)
, m_offset(noOffset)
, m_dictionaryKind(NoneDictionaryKind)
, m_isPinnedPropertyTable(false)
, m_hasGetterSetterProperties(false)
+ , m_hasNonEnumerableProperties(false)
, m_attributesInPrevious(0)
, m_specificFunctionThrashCount(0)
, m_anonymousSlotCount(anonymousSlotCount)
- , m_isUsingSingleSlot(true)
+ , m_preventExtensions(false)
+ , m_didTransition(false)
{
- m_transitions.m_singleTransition = 0;
-
ASSERT(m_prototype);
ASSERT(m_prototype.isObject() || m_prototype.isNull());
-
-#ifndef NDEBUG
-#if ENABLE(JSC_MULTIPLE_THREADS)
- MutexLocker protect(ignoreSetMutex);
-#endif
- if (shouldIgnoreLeaks)
- ignoreSet.add(this);
- else
- structureCounter.increment();
-#endif
-
-#if DUMP_STRUCTURE_ID_STATISTICS
- liveStructureSet.add(this);
-#endif
-}
-
-Structure::~Structure()
-{
- if (m_previous) {
- ASSERT(m_nameInPrevious);
- m_previous->transitionTableRemove(make_pair(m_nameInPrevious.get(), m_attributesInPrevious), m_specificValueInPrevious);
-
- }
- ASSERT(!m_enumerationCache.hasDeadObject());
-
- if (m_propertyTable) {
- unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount;
- for (unsigned i = 1; i <= entryCount; i++) {
- if (UString::Rep* key = m_propertyTable->entries()[i].key)
- key->deref();
- }
-
- delete m_propertyTable->deletedOffsets;
- fastFree(m_propertyTable);
- }
-
- if (!m_isUsingSingleSlot)
- delete transitionTable();
-
-#ifndef NDEBUG
-#if ENABLE(JSC_MULTIPLE_THREADS)
- MutexLocker protect(ignoreSetMutex);
-#endif
- HashSet<Structure*>::iterator it = ignoreSet.find(this);
- if (it != ignoreSet.end())
- ignoreSet.remove(it);
- else
- structureCounter.decrement();
-#endif
-
-#if DUMP_STRUCTURE_ID_STATISTICS
- liveStructureSet.remove(this);
-#endif
-}
-
-void Structure::startIgnoringLeaks()
-{
-#ifndef NDEBUG
- shouldIgnoreLeaks = true;
-#endif
}
-void Structure::stopIgnoringLeaks()
-{
-#ifndef NDEBUG
- shouldIgnoreLeaks = false;
-#endif
-}
+const ClassInfo Structure::s_info = { "Structure", 0, 0, 0 };
-static bool isPowerOf2(unsigned v)
+Structure::Structure(JSGlobalData& globalData)
+ : JSCell(globalData, this, CreatingEarlyCell)
+ , m_typeInfo(CompoundType, OverridesVisitChildren)
+ , m_prototype(globalData, this, jsNull())
+ , m_classInfo(&s_info)
+ , m_propertyStorageCapacity(0)
+ , m_offset(noOffset)
+ , m_dictionaryKind(NoneDictionaryKind)
+ , m_isPinnedPropertyTable(false)
+ , m_hasGetterSetterProperties(false)
+ , m_hasNonEnumerableProperties(false)
+ , m_attributesInPrevious(0)
+ , m_specificFunctionThrashCount(0)
+ , m_anonymousSlotCount(0)
+ , m_preventExtensions(false)
+ , m_didTransition(false)
{
- // Taken from http://www.cs.utk.edu/~vose/c-stuff/bithacks.html
-
- return !(v & (v - 1)) && v;
+ ASSERT(m_prototype);
+ ASSERT(m_prototype.isNull());
+ ASSERT(!globalData.structureStructure);
}
-static unsigned nextPowerOf2(unsigned v)
+Structure::Structure(JSGlobalData& globalData, const Structure* previous)
+ : JSCell(globalData, globalData.structureStructure.get())
+ , m_typeInfo(previous->typeInfo())
+ , m_prototype(globalData, this, previous->storedPrototype())
+ , m_classInfo(previous->m_classInfo)
+ , m_propertyStorageCapacity(previous->m_propertyStorageCapacity)
+ , m_offset(noOffset)
+ , m_dictionaryKind(NoneDictionaryKind)
+ , m_isPinnedPropertyTable(false)
+ , m_hasGetterSetterProperties(previous->m_hasGetterSetterProperties)
+ , m_hasNonEnumerableProperties(previous->m_hasNonEnumerableProperties)
+ , m_attributesInPrevious(0)
+ , m_specificFunctionThrashCount(previous->m_specificFunctionThrashCount)
+ , m_anonymousSlotCount(previous->anonymousSlotCount())
+ , m_preventExtensions(previous->m_preventExtensions)
+ , m_didTransition(true)
{
- // Taken from http://www.cs.utk.edu/~vose/c-stuff/bithacks.html
- // Devised by Sean Anderson, Sepember 14, 2001
-
- v--;
- v |= v >> 1;
- v |= v >> 2;
- v |= v >> 4;
- v |= v >> 8;
- v |= v >> 16;
- v++;
-
- return v;
+ ASSERT(m_prototype);
+ ASSERT(m_prototype.isObject() || m_prototype.isNull());
}
-static unsigned sizeForKeyCount(size_t keyCount)
+Structure::~Structure()
{
- if (keyCount == notFound)
- return newTableSize;
-
- if (keyCount < 8)
- return newTableSize;
-
- if (isPowerOf2(keyCount))
- return keyCount * 4;
-
- return nextPowerOf2(keyCount) * 2;
}
-void Structure::materializePropertyMap()
+void Structure::materializePropertyMap(JSGlobalData& globalData)
{
+ ASSERT(structure()->classInfo() == &s_info);
ASSERT(!m_propertyTable);
Vector<Structure*, 8> structures;
Structure* structure = this;
- // Search for the last Structure with a property table.
+ // Search for the last Structure with a property table.
while ((structure = structure->previousID())) {
if (structure->m_isPinnedPropertyTable) {
ASSERT(structure->m_propertyTable);
ASSERT(!structure->m_previous);
- m_propertyTable = structure->copyPropertyTable();
+ m_propertyTable = structure->m_propertyTable->copy(globalData, 0, m_offset + 1);
break;
}
}
if (!m_propertyTable)
- createPropertyMapHashTable(sizeForKeyCount(m_offset + 1));
- else {
- if (sizeForKeyCount(m_offset + 1) > m_propertyTable->size)
- rehashPropertyMapHashTable(sizeForKeyCount(m_offset + 1)); // This could be made more efficient by combining with the copy above.
- }
+ createPropertyMap(m_offset + 1);
for (ptrdiff_t i = structures.size() - 2; i >= 0; --i) {
structure = structures[i];
- structure->m_nameInPrevious->ref();
- PropertyMapEntry entry(structure->m_nameInPrevious.get(), m_anonymousSlotCount + structure->m_offset, structure->m_attributesInPrevious, structure->m_specificValueInPrevious, ++m_propertyTable->lastIndexUsed);
- insertIntoPropertyMapHashTable(entry);
+ PropertyMapEntry entry(globalData, this, structure->m_nameInPrevious.get(), m_anonymousSlotCount + structure->m_offset, structure->m_attributesInPrevious, structure->m_specificValueInPrevious.get());
+ m_propertyTable->add(entry);
}
}
void Structure::growPropertyStorageCapacity()
{
- if (m_propertyStorageCapacity == JSObject::inlineStorageCapacity)
- m_propertyStorageCapacity = JSObject::nonInlineBaseStorageCapacity;
+ if (isUsingInlineStorage())
+ m_propertyStorageCapacity = JSObject::baseExternalStorageCapacity;
else
m_propertyStorageCapacity *= 2;
}
-void Structure::despecifyDictionaryFunction(const Identifier& propertyName)
+void Structure::despecifyDictionaryFunction(JSGlobalData& globalData, const Identifier& propertyName)
{
- const UString::Rep* rep = propertyName._ustring.rep();
+ StringImpl* rep = propertyName.impl();
- materializePropertyMapIfNecessary();
+ materializePropertyMapIfNecessary(globalData);
ASSERT(isDictionary());
ASSERT(m_propertyTable);
- unsigned i = rep->existingHash();
-
-#if DUMP_PROPERTYMAP_STATS
- ++numProbes;
-#endif
-
- unsigned entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];
- ASSERT(entryIndex != emptyEntryIndex);
-
- if (rep == m_propertyTable->entries()[entryIndex - 1].key) {
- m_propertyTable->entries()[entryIndex - 1].specificValue = 0;
- return;
- }
-
-#if DUMP_PROPERTYMAP_STATS
- ++numCollisions;
-#endif
-
- unsigned k = 1 | doubleHash(rep->existingHash());
-
- while (1) {
- i += k;
-
-#if DUMP_PROPERTYMAP_STATS
- ++numRehashes;
-#endif
-
- entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];
- ASSERT(entryIndex != emptyEntryIndex);
-
- if (rep == m_propertyTable->entries()[entryIndex - 1].key) {
- m_propertyTable->entries()[entryIndex - 1].specificValue = 0;
- return;
- }
- }
+ PropertyMapEntry* entry = m_propertyTable->find(rep).first;
+ ASSERT(entry);
+ entry->specificValue.clear();
}
-PassRefPtr<Structure> Structure::addPropertyTransitionToExistingStructure(Structure* structure, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset)
+Structure* Structure::addPropertyTransitionToExistingStructure(Structure* structure, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset)
{
ASSERT(!structure->isDictionary());
ASSERT(structure->typeInfo().type() == ObjectType);
- if (Structure* existingTransition = structure->transitionTableGet(make_pair(propertyName.ustring().rep(), attributes), specificValue)) {
+ if (Structure* existingTransition = structure->m_transitionTable.get(propertyName.impl(), attributes)) {
+ JSCell* specificValueInPrevious = existingTransition->m_specificValueInPrevious.get();
+ if (specificValueInPrevious && specificValueInPrevious != specificValue)
+ return 0;
ASSERT(existingTransition->m_offset != noOffset);
offset = existingTransition->m_offset + existingTransition->m_anonymousSlotCount;
ASSERT(offset >= structure->m_anonymousSlotCount);
return 0;
}
-PassRefPtr<Structure> Structure::addPropertyTransition(Structure* structure, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset)
+Structure* Structure::addPropertyTransition(JSGlobalData& globalData, Structure* structure, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset)
{
+ // If we have a specific function, we may have got to this point if there is
+ // already a transition with the correct property name and attributes, but
+ // specialized to a different function. In this case we just want to give up
+ // and despecialize the transition.
+ // In this case we clear the value of specificFunction which will result
+ // in us adding a non-specific transition, and any subsequent lookup in
+ // Structure::addPropertyTransitionToExistingStructure will just use that.
+ if (specificValue && structure->m_transitionTable.contains(propertyName.impl(), attributes))
+ specificValue = 0;
+
ASSERT(!structure->isDictionary());
ASSERT(structure->typeInfo().type() == ObjectType);
ASSERT(!Structure::addPropertyTransitionToExistingStructure(structure, propertyName, attributes, specificValue, offset));
specificValue = 0;
if (structure->transitionCount() > s_maxTransitionLength) {
- RefPtr<Structure> transition = toCacheableDictionaryTransition(structure);
+ Structure* transition = toCacheableDictionaryTransition(globalData, structure);
ASSERT(structure != transition);
- offset = transition->put(propertyName, attributes, specificValue);
+ offset = transition->putSpecificValue(globalData, propertyName, attributes, specificValue);
ASSERT(offset >= structure->m_anonymousSlotCount);
ASSERT(structure->m_anonymousSlotCount == transition->m_anonymousSlotCount);
if (transition->propertyStorageSize() > transition->propertyStorageCapacity())
transition->growPropertyStorageCapacity();
- return transition.release();
+ return transition;
}
- RefPtr<Structure> transition = create(structure->m_prototype, structure->typeInfo(), structure->anonymousSlotCount());
+ Structure* transition = create(globalData, structure);
- transition->m_cachedPrototypeChain = structure->m_cachedPrototypeChain;
- transition->m_previous = structure;
- transition->m_nameInPrevious = propertyName.ustring().rep();
+ transition->m_cachedPrototypeChain.setMayBeNull(globalData, transition, structure->m_cachedPrototypeChain.get());
+ transition->m_previous.set(globalData, transition, structure);
+ transition->m_nameInPrevious = propertyName.impl();
transition->m_attributesInPrevious = attributes;
- transition->m_specificValueInPrevious = specificValue;
- transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity;
- transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties;
- transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties;
- transition->m_specificFunctionThrashCount = structure->m_specificFunctionThrashCount;
+ transition->m_specificValueInPrevious.setMayBeNull(globalData, transition, specificValue);
if (structure->m_propertyTable) {
if (structure->m_isPinnedPropertyTable)
- transition->m_propertyTable = structure->copyPropertyTable();
- else {
- transition->m_propertyTable = structure->m_propertyTable;
- structure->m_propertyTable = 0;
- }
+ transition->m_propertyTable = structure->m_propertyTable->copy(globalData, 0, structure->m_propertyTable->size() + 1);
+ else
+ transition->m_propertyTable = structure->m_propertyTable.release();
} else {
if (structure->m_previous)
- transition->materializePropertyMap();
+ transition->materializePropertyMap(globalData);
else
- transition->createPropertyMapHashTable();
+ transition->createPropertyMap();
}
- offset = transition->put(propertyName, attributes, specificValue);
+ offset = transition->putSpecificValue(globalData, propertyName, attributes, specificValue);
ASSERT(offset >= structure->m_anonymousSlotCount);
ASSERT(structure->m_anonymousSlotCount == transition->m_anonymousSlotCount);
if (transition->propertyStorageSize() > transition->propertyStorageCapacity())
transition->m_offset = offset - structure->m_anonymousSlotCount;
ASSERT(structure->anonymousSlotCount() == transition->anonymousSlotCount());
- structure->transitionTableAdd(make_pair(propertyName.ustring().rep(), attributes), transition.get(), specificValue);
- return transition.release();
+ structure->m_transitionTable.add(globalData, transition);
+ return transition;
}
-PassRefPtr<Structure> Structure::removePropertyTransition(Structure* structure, const Identifier& propertyName, size_t& offset)
+Structure* Structure::removePropertyTransition(JSGlobalData& globalData, Structure* structure, const Identifier& propertyName, size_t& offset)
{
ASSERT(!structure->isUncacheableDictionary());
- RefPtr<Structure> transition = toUncacheableDictionaryTransition(structure);
+ Structure* transition = toUncacheableDictionaryTransition(globalData, structure);
offset = transition->remove(propertyName);
ASSERT(offset >= structure->m_anonymousSlotCount);
ASSERT(structure->m_anonymousSlotCount == transition->m_anonymousSlotCount);
- return transition.release();
+ return transition;
}
-PassRefPtr<Structure> Structure::changePrototypeTransition(Structure* structure, JSValue prototype)
+Structure* Structure::changePrototypeTransition(JSGlobalData& globalData, Structure* structure, JSValue prototype)
{
- RefPtr<Structure> transition = create(prototype, structure->typeInfo(), structure->anonymousSlotCount());
+ Structure* transition = create(globalData, structure);
- transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity;
- transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties;
- transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties;
- transition->m_specificFunctionThrashCount = structure->m_specificFunctionThrashCount;
+ transition->m_prototype.set(globalData, transition, prototype);
// Don't set m_offset, as one can not transition to this.
- structure->materializePropertyMapIfNecessary();
- transition->m_propertyTable = structure->copyPropertyTable();
+ structure->materializePropertyMapIfNecessary(globalData);
+ transition->m_propertyTable = structure->copyPropertyTable(globalData, transition);
transition->m_isPinnedPropertyTable = true;
ASSERT(structure->anonymousSlotCount() == transition->anonymousSlotCount());
- return transition.release();
+ return transition;
}
-PassRefPtr<Structure> Structure::despecifyFunctionTransition(Structure* structure, const Identifier& replaceFunction)
+Structure* Structure::despecifyFunctionTransition(JSGlobalData& globalData, Structure* structure, const Identifier& replaceFunction)
{
ASSERT(structure->m_specificFunctionThrashCount < maxSpecificFunctionThrashCount);
- RefPtr<Structure> transition = create(structure->storedPrototype(), structure->typeInfo(), structure->anonymousSlotCount());
+ Structure* transition = create(globalData, structure);
- transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity;
- transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties;
- transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties;
- transition->m_specificFunctionThrashCount = structure->m_specificFunctionThrashCount + 1;
+ ++transition->m_specificFunctionThrashCount;
// Don't set m_offset, as one can not transition to this.
- structure->materializePropertyMapIfNecessary();
- transition->m_propertyTable = structure->copyPropertyTable();
+ structure->materializePropertyMapIfNecessary(globalData);
+ transition->m_propertyTable = structure->copyPropertyTable(globalData, transition);
transition->m_isPinnedPropertyTable = true;
if (transition->m_specificFunctionThrashCount == maxSpecificFunctionThrashCount)
- transition->despecifyAllFunctions();
+ transition->despecifyAllFunctions(globalData);
else {
- bool removed = transition->despecifyFunction(replaceFunction);
+ bool removed = transition->despecifyFunction(globalData, replaceFunction);
ASSERT_UNUSED(removed, removed);
}
ASSERT(structure->anonymousSlotCount() == transition->anonymousSlotCount());
- return transition.release();
+ return transition;
}
-PassRefPtr<Structure> Structure::getterSetterTransition(Structure* structure)
+Structure* Structure::getterSetterTransition(JSGlobalData& globalData, Structure* structure)
{
- RefPtr<Structure> transition = create(structure->storedPrototype(), structure->typeInfo(), structure->anonymousSlotCount());
- transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity;
- transition->m_hasGetterSetterProperties = transition->m_hasGetterSetterProperties;
- transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties;
- transition->m_specificFunctionThrashCount = structure->m_specificFunctionThrashCount;
+ Structure* transition = create(globalData, structure);
// Don't set m_offset, as one can not transition to this.
- structure->materializePropertyMapIfNecessary();
- transition->m_propertyTable = structure->copyPropertyTable();
+ structure->materializePropertyMapIfNecessary(globalData);
+ transition->m_propertyTable = structure->copyPropertyTable(globalData, transition);
transition->m_isPinnedPropertyTable = true;
ASSERT(structure->anonymousSlotCount() == transition->anonymousSlotCount());
- return transition.release();
+ return transition;
}
-PassRefPtr<Structure> Structure::toDictionaryTransition(Structure* structure, DictionaryKind kind)
+Structure* Structure::toDictionaryTransition(JSGlobalData& globalData, Structure* structure, DictionaryKind kind)
{
ASSERT(!structure->isUncacheableDictionary());
- RefPtr<Structure> transition = create(structure->m_prototype, structure->typeInfo(), structure->anonymousSlotCount());
+ Structure* transition = create(globalData, structure);
+
+ structure->materializePropertyMapIfNecessary(globalData);
+ transition->m_propertyTable = structure->copyPropertyTable(globalData, transition);
+ transition->m_isPinnedPropertyTable = true;
transition->m_dictionaryKind = kind;
- transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity;
- transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties;
- transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties;
- transition->m_specificFunctionThrashCount = structure->m_specificFunctionThrashCount;
- structure->materializePropertyMapIfNecessary();
- transition->m_propertyTable = structure->copyPropertyTable();
+ ASSERT(structure->anonymousSlotCount() == transition->anonymousSlotCount());
+ return transition;
+}
+
+Structure* Structure::toCacheableDictionaryTransition(JSGlobalData& globalData, Structure* structure)
+{
+ return toDictionaryTransition(globalData, structure, CachedDictionaryKind);
+}
+
+Structure* Structure::toUncacheableDictionaryTransition(JSGlobalData& globalData, Structure* structure)
+{
+ return toDictionaryTransition(globalData, structure, UncachedDictionaryKind);
+}
+
+// In future we may want to cache this transition.
+Structure* Structure::sealTransition(JSGlobalData& globalData, Structure* structure)
+{
+ Structure* transition = preventExtensionsTransition(globalData, structure);
+
+ if (transition->m_propertyTable) {
+ PropertyTable::iterator end = transition->m_propertyTable->end();
+ for (PropertyTable::iterator iter = transition->m_propertyTable->begin(); iter != end; ++iter)
+ iter->attributes |= DontDelete;
+ }
+
+ return transition;
+}
+
+// In future we may want to cache this transition.
+Structure* Structure::freezeTransition(JSGlobalData& globalData, Structure* structure)
+{
+ Structure* transition = preventExtensionsTransition(globalData, structure);
+
+ if (transition->m_propertyTable) {
+ PropertyTable::iterator end = transition->m_propertyTable->end();
+ for (PropertyTable::iterator iter = transition->m_propertyTable->begin(); iter != end; ++iter)
+ iter->attributes |= (DontDelete | ReadOnly);
+ }
+
+ return transition;
+}
+
+// In future we may want to cache this transition.
+Structure* Structure::preventExtensionsTransition(JSGlobalData& globalData, Structure* structure)
+{
+ Structure* transition = create(globalData, structure);
+
+ // Don't set m_offset, as one can not transition to this.
+
+ structure->materializePropertyMapIfNecessary(globalData);
+ transition->m_propertyTable = structure->copyPropertyTable(globalData, transition);
transition->m_isPinnedPropertyTable = true;
-
+ transition->m_preventExtensions = true;
+
ASSERT(structure->anonymousSlotCount() == transition->anonymousSlotCount());
- return transition.release();
+ return transition;
}
-PassRefPtr<Structure> Structure::toCacheableDictionaryTransition(Structure* structure)
+// In future we may want to cache this property.
+bool Structure::isSealed(JSGlobalData& globalData)
{
- return toDictionaryTransition(structure, CachedDictionaryKind);
+ if (isExtensible())
+ return false;
+
+ materializePropertyMapIfNecessary(globalData);
+ if (!m_propertyTable)
+ return true;
+
+ PropertyTable::iterator end = m_propertyTable->end();
+ for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter) {
+ if ((iter->attributes & DontDelete) != DontDelete)
+ return false;
+ }
+ return true;
}
-PassRefPtr<Structure> Structure::toUncacheableDictionaryTransition(Structure* structure)
+// In future we may want to cache this property.
+bool Structure::isFrozen(JSGlobalData& globalData)
{
- return toDictionaryTransition(structure, UncachedDictionaryKind);
+ if (isExtensible())
+ return false;
+
+ materializePropertyMapIfNecessary(globalData);
+ if (!m_propertyTable)
+ return true;
+
+ PropertyTable::iterator end = m_propertyTable->end();
+ for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter) {
+ if ((iter->attributes & (DontDelete | ReadOnly)) != (DontDelete | ReadOnly))
+ return false;
+ }
+ return true;
}
-PassRefPtr<Structure> Structure::flattenDictionaryStructure(JSObject* object)
+Structure* Structure::flattenDictionaryStructure(JSGlobalData& globalData, JSObject* object)
{
ASSERT(isDictionary());
if (isUncacheableDictionary()) {
ASSERT(m_propertyTable);
- Vector<PropertyMapEntry*> sortedPropertyEntries(m_propertyTable->keyCount);
- PropertyMapEntry** p = sortedPropertyEntries.data();
- unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount;
- for (unsigned i = 1; i <= entryCount; i++) {
- if (m_propertyTable->entries()[i].key)
- *p++ = &m_propertyTable->entries()[i];
- }
- size_t propertyCount = p - sortedPropertyEntries.data();
- qsort(sortedPropertyEntries.data(), propertyCount, sizeof(PropertyMapEntry*), comparePropertyMapEntryIndices);
- sortedPropertyEntries.resize(propertyCount);
- // We now have the properties currently defined on this object
- // in the order that they are expected to be in, but we need to
- // reorder the storage, so we have to copy the current values out
- Vector<JSValue> values(propertyCount);
unsigned anonymousSlotCount = m_anonymousSlotCount;
- for (unsigned i = 0; i < propertyCount; i++) {
- PropertyMapEntry* entry = sortedPropertyEntries[i];
- values[i] = object->getDirectOffset(entry->offset);
+ size_t propertyCount = m_propertyTable->size();
+ Vector<JSValue> values(propertyCount);
+
+ unsigned i = 0;
+ PropertyTable::iterator end = m_propertyTable->end();
+ for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter, ++i) {
+ values[i] = object->getDirectOffset(iter->offset);
// Update property table to have the new property offsets
- entry->offset = anonymousSlotCount + i;
- entry->index = i;
+ iter->offset = anonymousSlotCount + i;
}
// Copy the original property values into their final locations
for (unsigned i = 0; i < propertyCount; i++)
- object->putDirectOffset(anonymousSlotCount + i, values[i]);
+ object->putDirectOffset(globalData, anonymousSlotCount + i, values[i]);
- if (m_propertyTable->deletedOffsets) {
- delete m_propertyTable->deletedOffsets;
- m_propertyTable->deletedOffsets = 0;
- }
+ m_propertyTable->clearDeletedOffsets();
}
m_dictionaryKind = NoneDictionaryKind;
return this;
}
-size_t Structure::addPropertyWithoutTransition(const Identifier& propertyName, unsigned attributes, JSCell* specificValue)
+size_t Structure::addPropertyWithoutTransition(JSGlobalData& globalData, const Identifier& propertyName, unsigned attributes, JSCell* specificValue)
{
ASSERT(!m_enumerationCache);
if (m_specificFunctionThrashCount == maxSpecificFunctionThrashCount)
specificValue = 0;
- materializePropertyMapIfNecessary();
+ materializePropertyMapIfNecessary(globalData);
m_isPinnedPropertyTable = true;
- size_t offset = put(propertyName, attributes, specificValue);
+ size_t offset = putSpecificValue(globalData, propertyName, attributes, specificValue);
ASSERT(offset >= m_anonymousSlotCount);
if (propertyStorageSize() > propertyStorageCapacity())
growPropertyStorageCapacity();
return offset;
}
-size_t Structure::removePropertyWithoutTransition(const Identifier& propertyName)
+size_t Structure::removePropertyWithoutTransition(JSGlobalData& globalData, const Identifier& propertyName)
{
ASSERT(isUncacheableDictionary());
ASSERT(!m_enumerationCache);
- materializePropertyMapIfNecessary();
+ materializePropertyMapIfNecessary(globalData);
m_isPinnedPropertyTable = true;
size_t offset = remove(propertyName);
#if DUMP_PROPERTYMAP_STATS
-static int numProbes;
-static int numCollisions;
-static int numRehashes;
-static int numRemoves;
-
struct PropertyMapStatisticsExitLogger {
~PropertyMapStatisticsExitLogger();
};
#endif
-static const unsigned deletedSentinelIndex = 1;
-
#if !DO_PROPERTYMAP_CONSTENCY_CHECK
inline void Structure::checkConsistency()
#endif
-PropertyMapHashTable* Structure::copyPropertyTable()
+PassOwnPtr<PropertyTable> Structure::copyPropertyTable(JSGlobalData& globalData, Structure* owner)
{
- if (!m_propertyTable)
- return 0;
-
- size_t tableSize = PropertyMapHashTable::allocationSize(m_propertyTable->size);
- PropertyMapHashTable* newTable = static_cast<PropertyMapHashTable*>(fastMalloc(tableSize));
- memcpy(newTable, m_propertyTable, tableSize);
-
- unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount;
- for (unsigned i = 1; i <= entryCount; ++i) {
- if (UString::Rep* key = newTable->entries()[i].key)
- key->ref();
- }
-
- // Copy the deletedOffsets vector.
- if (m_propertyTable->deletedOffsets)
- newTable->deletedOffsets = new Vector<unsigned>(*m_propertyTable->deletedOffsets);
-
- return newTable;
+ return adoptPtr(m_propertyTable ? new PropertyTable(globalData, owner, *m_propertyTable) : 0);
}
-size_t Structure::get(const UString::Rep* rep, unsigned& attributes, JSCell*& specificValue)
+size_t Structure::get(JSGlobalData& globalData, StringImpl* propertyName, unsigned& attributes, JSCell*& specificValue)
{
- materializePropertyMapIfNecessary();
+ materializePropertyMapIfNecessary(globalData);
if (!m_propertyTable)
- return notFound;
-
- unsigned i = rep->existingHash();
-
-#if DUMP_PROPERTYMAP_STATS
- ++numProbes;
-#endif
-
- unsigned entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];
- if (entryIndex == emptyEntryIndex)
- return notFound;
-
- if (rep == m_propertyTable->entries()[entryIndex - 1].key) {
- attributes = m_propertyTable->entries()[entryIndex - 1].attributes;
- specificValue = m_propertyTable->entries()[entryIndex - 1].specificValue;
- ASSERT(m_propertyTable->entries()[entryIndex - 1].offset >= m_anonymousSlotCount);
- return m_propertyTable->entries()[entryIndex - 1].offset;
- }
-
-#if DUMP_PROPERTYMAP_STATS
- ++numCollisions;
-#endif
-
- unsigned k = 1 | doubleHash(rep->existingHash());
-
- while (1) {
- i += k;
+ return WTF::notFound;
-#if DUMP_PROPERTYMAP_STATS
- ++numRehashes;
-#endif
-
- entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];
- if (entryIndex == emptyEntryIndex)
- return notFound;
+ PropertyMapEntry* entry = m_propertyTable->find(propertyName).first;
+ if (!entry)
+ return WTF::notFound;
- if (rep == m_propertyTable->entries()[entryIndex - 1].key) {
- attributes = m_propertyTable->entries()[entryIndex - 1].attributes;
- specificValue = m_propertyTable->entries()[entryIndex - 1].specificValue;
- ASSERT(m_propertyTable->entries()[entryIndex - 1].offset >= m_anonymousSlotCount);
- return m_propertyTable->entries()[entryIndex - 1].offset;
- }
- }
+ attributes = entry->attributes;
+ specificValue = entry->specificValue.get();
+ ASSERT(entry->offset >= m_anonymousSlotCount);
+ return entry->offset;
}
-bool Structure::despecifyFunction(const Identifier& propertyName)
+bool Structure::despecifyFunction(JSGlobalData& globalData, const Identifier& propertyName)
{
- ASSERT(!propertyName.isNull());
-
- materializePropertyMapIfNecessary();
+ materializePropertyMapIfNecessary(globalData);
if (!m_propertyTable)
return false;
- UString::Rep* rep = propertyName._ustring.rep();
-
- unsigned i = rep->existingHash();
-
-#if DUMP_PROPERTYMAP_STATS
- ++numProbes;
-#endif
-
- unsigned entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];
- if (entryIndex == emptyEntryIndex)
+ ASSERT(!propertyName.isNull());
+ PropertyMapEntry* entry = m_propertyTable->find(propertyName.impl()).first;
+ if (!entry)
return false;
- if (rep == m_propertyTable->entries()[entryIndex - 1].key) {
- ASSERT(m_propertyTable->entries()[entryIndex - 1].specificValue);
- m_propertyTable->entries()[entryIndex - 1].specificValue = 0;
- return true;
- }
-
-#if DUMP_PROPERTYMAP_STATS
- ++numCollisions;
-#endif
-
- unsigned k = 1 | doubleHash(rep->existingHash());
-
- while (1) {
- i += k;
-
-#if DUMP_PROPERTYMAP_STATS
- ++numRehashes;
-#endif
-
- entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];
- if (entryIndex == emptyEntryIndex)
- return false;
-
- if (rep == m_propertyTable->entries()[entryIndex - 1].key) {
- ASSERT(m_propertyTable->entries()[entryIndex - 1].specificValue);
- m_propertyTable->entries()[entryIndex - 1].specificValue = 0;
- return true;
- }
- }
+ ASSERT(entry->specificValue);
+ entry->specificValue.clear();
+ return true;
}
-void Structure::despecifyAllFunctions()
+void Structure::despecifyAllFunctions(JSGlobalData& globalData)
{
- materializePropertyMapIfNecessary();
+ materializePropertyMapIfNecessary(globalData);
if (!m_propertyTable)
return;
-
- unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount;
- for (unsigned i = 1; i <= entryCount; ++i)
- m_propertyTable->entries()[i].specificValue = 0;
+
+ PropertyTable::iterator end = m_propertyTable->end();
+ for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter)
+ iter->specificValue.clear();
}
-size_t Structure::put(const Identifier& propertyName, unsigned attributes, JSCell* specificValue)
+size_t Structure::putSpecificValue(JSGlobalData& globalData, const Identifier& propertyName, unsigned attributes, JSCell* specificValue)
{
ASSERT(!propertyName.isNull());
- ASSERT(get(propertyName) == notFound);
+ ASSERT(get(globalData, propertyName) == notFound);
checkConsistency();
-
if (attributes & DontEnum)
m_hasNonEnumerableProperties = true;
- UString::Rep* rep = propertyName._ustring.rep();
+ StringImpl* rep = propertyName.impl();
if (!m_propertyTable)
- createPropertyMapHashTable();
-
- // FIXME: Consider a fast case for tables with no deleted sentinels.
-
- unsigned i = rep->existingHash();
- unsigned k = 0;
- bool foundDeletedElement = false;
- unsigned deletedElementIndex = 0; // initialize to make the compiler happy
-
-#if DUMP_PROPERTYMAP_STATS
- ++numProbes;
-#endif
-
- while (1) {
- unsigned entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];
- if (entryIndex == emptyEntryIndex)
- break;
-
- if (entryIndex == deletedSentinelIndex) {
- // If we find a deleted-element sentinel, remember it for use later.
- if (!foundDeletedElement) {
- foundDeletedElement = true;
- deletedElementIndex = i;
- }
- }
-
- if (k == 0) {
- k = 1 | doubleHash(rep->existingHash());
-#if DUMP_PROPERTYMAP_STATS
- ++numCollisions;
-#endif
- }
-
- i += k;
-
-#if DUMP_PROPERTYMAP_STATS
- ++numRehashes;
-#endif
- }
-
- // Figure out which entry to use.
- unsigned entryIndex = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount + 2;
- if (foundDeletedElement) {
- i = deletedElementIndex;
- --m_propertyTable->deletedSentinelCount;
-
- // Since we're not making the table bigger, we can't use the entry one past
- // the end that we were planning on using, so search backwards for the empty
- // slot that we can use. We know it will be there because we did at least one
- // deletion in the past that left an entry empty.
- while (m_propertyTable->entries()[--entryIndex - 1].key) { }
- }
-
- // Create a new hash table entry.
- m_propertyTable->entryIndices[i & m_propertyTable->sizeMask] = entryIndex;
-
- // Create a new hash table entry.
- rep->ref();
- m_propertyTable->entries()[entryIndex - 1].key = rep;
- m_propertyTable->entries()[entryIndex - 1].attributes = attributes;
- m_propertyTable->entries()[entryIndex - 1].specificValue = specificValue;
- m_propertyTable->entries()[entryIndex - 1].index = ++m_propertyTable->lastIndexUsed;
+ createPropertyMap();
unsigned newOffset;
- if (m_propertyTable->deletedOffsets && !m_propertyTable->deletedOffsets->isEmpty()) {
- newOffset = m_propertyTable->deletedOffsets->last();
- m_propertyTable->deletedOffsets->removeLast();
- } else
- newOffset = m_propertyTable->keyCount + m_anonymousSlotCount;
- m_propertyTable->entries()[entryIndex - 1].offset = newOffset;
-
+
+ if (m_propertyTable->hasDeletedOffset())
+ newOffset = m_propertyTable->getDeletedOffset();
+ else
+ newOffset = m_propertyTable->size() + m_anonymousSlotCount;
ASSERT(newOffset >= m_anonymousSlotCount);
- ++m_propertyTable->keyCount;
- if ((m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount) * 2 >= m_propertyTable->size)
- expandPropertyMapHashTable();
+ m_propertyTable->add(PropertyMapEntry(globalData, this, rep, newOffset, attributes, specificValue));
checkConsistency();
return newOffset;
}
-bool Structure::hasTransition(UString::Rep* rep, unsigned attributes)
-{
- return transitionTableHasTransition(make_pair(rep, attributes));
-}
-
size_t Structure::remove(const Identifier& propertyName)
{
ASSERT(!propertyName.isNull());
checkConsistency();
- UString::Rep* rep = propertyName._ustring.rep();
+ StringImpl* rep = propertyName.impl();
if (!m_propertyTable)
return notFound;
-#if DUMP_PROPERTYMAP_STATS
- ++numProbes;
- ++numRemoves;
-#endif
-
- // Find the thing to remove.
- unsigned i = rep->existingHash();
- unsigned k = 0;
- unsigned entryIndex;
- UString::Rep* key = 0;
- while (1) {
- entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];
- if (entryIndex == emptyEntryIndex)
- return notFound;
-
- key = m_propertyTable->entries()[entryIndex - 1].key;
- if (rep == key)
- break;
-
- if (k == 0) {
- k = 1 | doubleHash(rep->existingHash());
-#if DUMP_PROPERTYMAP_STATS
- ++numCollisions;
-#endif
- }
-
- i += k;
-
-#if DUMP_PROPERTYMAP_STATS
- ++numRehashes;
-#endif
- }
-
- // Replace this one element with the deleted sentinel. Also clear out
- // the entry so we can iterate all the entries as needed.
- m_propertyTable->entryIndices[i & m_propertyTable->sizeMask] = deletedSentinelIndex;
+ PropertyTable::find_iterator position = m_propertyTable->find(rep);
+ if (!position.first)
+ return notFound;
- size_t offset = m_propertyTable->entries()[entryIndex - 1].offset;
+ size_t offset = position.first->offset;
ASSERT(offset >= m_anonymousSlotCount);
- key->deref();
- m_propertyTable->entries()[entryIndex - 1].key = 0;
- m_propertyTable->entries()[entryIndex - 1].attributes = 0;
- m_propertyTable->entries()[entryIndex - 1].specificValue = 0;
- m_propertyTable->entries()[entryIndex - 1].offset = 0;
-
- if (!m_propertyTable->deletedOffsets)
- m_propertyTable->deletedOffsets = new Vector<unsigned>;
- m_propertyTable->deletedOffsets->append(offset);
-
- ASSERT(m_propertyTable->keyCount >= 1);
- --m_propertyTable->keyCount;
- ++m_propertyTable->deletedSentinelCount;
-
- if (m_propertyTable->deletedSentinelCount * 4 >= m_propertyTable->size)
- rehashPropertyMapHashTable();
+ m_propertyTable->remove(position);
+ m_propertyTable->addDeletedOffset(offset);
checkConsistency();
return offset;
}
-void Structure::insertIntoPropertyMapHashTable(const PropertyMapEntry& entry)
-{
- ASSERT(m_propertyTable);
- ASSERT(entry.offset >= m_anonymousSlotCount);
- unsigned i = entry.key->existingHash();
- unsigned k = 0;
-
-#if DUMP_PROPERTYMAP_STATS
- ++numProbes;
-#endif
-
- while (1) {
- unsigned entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];
- if (entryIndex == emptyEntryIndex)
- break;
-
- if (k == 0) {
- k = 1 | doubleHash(entry.key->existingHash());
-#if DUMP_PROPERTYMAP_STATS
- ++numCollisions;
-#endif
- }
-
- i += k;
-
-#if DUMP_PROPERTYMAP_STATS
- ++numRehashes;
-#endif
- }
-
- unsigned entryIndex = m_propertyTable->keyCount + 2;
- m_propertyTable->entryIndices[i & m_propertyTable->sizeMask] = entryIndex;
- m_propertyTable->entries()[entryIndex - 1] = entry;
-
- ++m_propertyTable->keyCount;
-}
-
-void Structure::createPropertyMapHashTable()
-{
- ASSERT(sizeForKeyCount(7) == newTableSize);
- createPropertyMapHashTable(newTableSize);
-}
-
-void Structure::createPropertyMapHashTable(unsigned newTableSize)
+void Structure::createPropertyMap(unsigned capacity)
{
ASSERT(!m_propertyTable);
- ASSERT(isPowerOf2(newTableSize));
checkConsistency();
-
- m_propertyTable = static_cast<PropertyMapHashTable*>(fastZeroedMalloc(PropertyMapHashTable::allocationSize(newTableSize)));
- m_propertyTable->size = newTableSize;
- m_propertyTable->sizeMask = newTableSize - 1;
-
+ m_propertyTable = adoptPtr(new PropertyTable(capacity));
checkConsistency();
}
-void Structure::expandPropertyMapHashTable()
-{
- ASSERT(m_propertyTable);
- rehashPropertyMapHashTable(m_propertyTable->size * 2);
-}
-
-void Structure::rehashPropertyMapHashTable()
-{
- ASSERT(m_propertyTable);
- ASSERT(m_propertyTable->size);
- rehashPropertyMapHashTable(m_propertyTable->size);
-}
-
-void Structure::rehashPropertyMapHashTable(unsigned newTableSize)
+void Structure::getPropertyNames(JSGlobalData& globalData, PropertyNameArray& propertyNames, EnumerationMode mode)
{
- ASSERT(m_propertyTable);
- ASSERT(isPowerOf2(newTableSize));
-
- checkConsistency();
-
- PropertyMapHashTable* oldTable = m_propertyTable;
+ materializePropertyMapIfNecessary(globalData);
+ if (!m_propertyTable)
+ return;
- m_propertyTable = static_cast<PropertyMapHashTable*>(fastZeroedMalloc(PropertyMapHashTable::allocationSize(newTableSize)));
- m_propertyTable->size = newTableSize;
- m_propertyTable->sizeMask = newTableSize - 1;
+ bool knownUnique = !propertyNames.size();
- unsigned lastIndexUsed = 0;
- unsigned entryCount = oldTable->keyCount + oldTable->deletedSentinelCount;
- for (unsigned i = 1; i <= entryCount; ++i) {
- if (oldTable->entries()[i].key) {
- lastIndexUsed = max(oldTable->entries()[i].index, lastIndexUsed);
- insertIntoPropertyMapHashTable(oldTable->entries()[i]);
+ PropertyTable::iterator end = m_propertyTable->end();
+ for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter) {
+ ASSERT(m_hasNonEnumerableProperties || !(iter->attributes & DontEnum));
+ if (!(iter->attributes & DontEnum) || (mode == IncludeDontEnumProperties)) {
+ if (knownUnique)
+ propertyNames.addKnownUnique(iter->key);
+ else
+ propertyNames.add(iter->key);
}
}
- m_propertyTable->lastIndexUsed = lastIndexUsed;
- m_propertyTable->deletedOffsets = oldTable->deletedOffsets;
-
- fastFree(oldTable);
-
- checkConsistency();
-}
-
-int comparePropertyMapEntryIndices(const void* a, const void* b)
-{
- unsigned ia = static_cast<PropertyMapEntry* const*>(a)[0]->index;
- unsigned ib = static_cast<PropertyMapEntry* const*>(b)[0]->index;
- if (ia < ib)
- return -1;
- if (ia > ib)
- return +1;
- return 0;
}
-void Structure::getPropertyNames(PropertyNameArray& propertyNames, EnumerationMode mode)
+void Structure::visitChildren(SlotVisitor& visitor)
{
- materializePropertyMapIfNecessary();
- if (!m_propertyTable)
- return;
-
- if (m_propertyTable->keyCount < tinyMapThreshold) {
- PropertyMapEntry* a[tinyMapThreshold];
- int i = 0;
- unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount;
- for (unsigned k = 1; k <= entryCount; k++) {
- ASSERT(m_hasNonEnumerableProperties || !(m_propertyTable->entries()[k].attributes & DontEnum));
- if (m_propertyTable->entries()[k].key && (!(m_propertyTable->entries()[k].attributes & DontEnum) || (mode == IncludeDontEnumProperties))) {
- PropertyMapEntry* value = &m_propertyTable->entries()[k];
- int j;
- for (j = i - 1; j >= 0 && a[j]->index > value->index; --j)
- a[j + 1] = a[j];
- a[j + 1] = value;
- ++i;
- }
- }
- if (!propertyNames.size()) {
- for (int k = 0; k < i; ++k)
- propertyNames.addKnownUnique(a[k]->key);
- } else {
- for (int k = 0; k < i; ++k)
- propertyNames.add(a[k]->key);
+ ASSERT_GC_OBJECT_INHERITS(this, &s_info);
+ ASSERT(structure()->typeInfo().overridesVisitChildren());
+ JSCell::visitChildren(visitor);
+ if (m_prototype)
+ visitor.append(&m_prototype);
+ if (m_cachedPrototypeChain)
+ visitor.append(&m_cachedPrototypeChain);
+ if (m_previous)
+ visitor.append(&m_previous);
+ if (m_specificValueInPrevious)
+ visitor.append(&m_specificValueInPrevious);
+ if (m_enumerationCache)
+ visitor.append(&m_enumerationCache);
+ if (m_propertyTable) {
+ PropertyTable::iterator end = m_propertyTable->end();
+ for (PropertyTable::iterator ptr = m_propertyTable->begin(); ptr != end; ++ptr) {
+ if (ptr->specificValue)
+ visitor.append(&ptr->specificValue);
}
-
- return;
- }
-
- // Allocate a buffer to use to sort the keys.
- Vector<PropertyMapEntry*, smallMapThreshold> sortedEnumerables(m_propertyTable->keyCount);
-
- // Get pointers to the enumerable entries in the buffer.
- PropertyMapEntry** p = sortedEnumerables.data();
- unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount;
- for (unsigned i = 1; i <= entryCount; i++) {
- if (m_propertyTable->entries()[i].key && (!(m_propertyTable->entries()[i].attributes & DontEnum) || (mode == IncludeDontEnumProperties)))
- *p++ = &m_propertyTable->entries()[i];
- }
-
- size_t enumerableCount = p - sortedEnumerables.data();
- // Sort the entries by index.
- qsort(sortedEnumerables.data(), enumerableCount, sizeof(PropertyMapEntry*), comparePropertyMapEntryIndices);
- sortedEnumerables.resize(enumerableCount);
-
- // Put the keys of the sorted entries into the list.
- if (!propertyNames.size()) {
- for (size_t i = 0; i < sortedEnumerables.size(); ++i)
- propertyNames.addKnownUnique(sortedEnumerables[i]->key);
- } else {
- for (size_t i = 0; i < sortedEnumerables.size(); ++i)
- propertyNames.add(sortedEnumerables[i]->key);
}
}
#if DO_PROPERTYMAP_CONSTENCY_CHECK
-void Structure::checkConsistency()
+void PropertyTable::checkConsistency()
{
- if (!m_propertyTable)
- return;
-
- ASSERT(m_propertyTable->size >= newTableSize);
- ASSERT(m_propertyTable->sizeMask);
- ASSERT(m_propertyTable->size == m_propertyTable->sizeMask + 1);
- ASSERT(!(m_propertyTable->size & m_propertyTable->sizeMask));
-
- ASSERT(m_propertyTable->keyCount <= m_propertyTable->size / 2);
- ASSERT(m_propertyTable->deletedSentinelCount <= m_propertyTable->size / 4);
+ ASSERT(m_indexSize >= PropertyTable::MinimumTableSize);
+ ASSERT(m_indexMask);
+ ASSERT(m_indexSize == m_indexMask + 1);
+ ASSERT(!(m_indexSize & m_indexMask));
- ASSERT(m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount <= m_propertyTable->size / 2);
+ ASSERT(m_keyCount <= m_indexSize / 2);
+ ASSERT(m_keyCount + m_deletedCount <= m_indexSize / 2);
+ ASSERT(m_deletedCount <= m_indexSize / 4);
unsigned indexCount = 0;
unsigned deletedIndexCount = 0;
- for (unsigned a = 0; a != m_propertyTable->size; ++a) {
- unsigned entryIndex = m_propertyTable->entryIndices[a];
- if (entryIndex == emptyEntryIndex)
+ for (unsigned a = 0; a != m_indexSize; ++a) {
+ unsigned entryIndex = m_index[a];
+ if (entryIndex == PropertyTable::EmptyEntryIndex)
continue;
- if (entryIndex == deletedSentinelIndex) {
+ if (entryIndex == deletedEntryIndex()) {
++deletedIndexCount;
continue;
}
- ASSERT(entryIndex > deletedSentinelIndex);
- ASSERT(entryIndex - 1 <= m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount);
+ ASSERT(entryIndex < deletedEntryIndex());
+ ASSERT(entryIndex - 1 <= usedCount());
++indexCount;
- for (unsigned b = a + 1; b != m_propertyTable->size; ++b)
- ASSERT(m_propertyTable->entryIndices[b] != entryIndex);
+ for (unsigned b = a + 1; b != m_indexSize; ++b)
+ ASSERT(m_index[b] != entryIndex);
}
- ASSERT(indexCount == m_propertyTable->keyCount);
- ASSERT(deletedIndexCount == m_propertyTable->deletedSentinelCount);
+ ASSERT(indexCount == m_keyCount);
+ ASSERT(deletedIndexCount == m_deletedCount);
- ASSERT(m_propertyTable->entries()[0].key == 0);
+ ASSERT(!table()[deletedEntryIndex() - 1].key);
unsigned nonEmptyEntryCount = 0;
- for (unsigned c = 1; c <= m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount; ++c) {
- ASSERT(m_hasNonEnumerableProperties || !(m_propertyTable->entries()[c].attributes & DontEnum));
- UString::Rep* rep = m_propertyTable->entries()[c].key;
- ASSERT(m_propertyTable->entries()[c].offset >= m_anonymousSlotCount);
- if (!rep)
+ for (unsigned c = 0; c < usedCount(); ++c) {
+ StringImpl* rep = table()[c].key;
+ if (rep == PROPERTY_MAP_DELETED_ENTRY_KEY)
continue;
++nonEmptyEntryCount;
unsigned i = rep->existingHash();
unsigned k = 0;
unsigned entryIndex;
while (1) {
- entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];
- ASSERT(entryIndex != emptyEntryIndex);
- if (rep == m_propertyTable->entries()[entryIndex - 1].key)
+ entryIndex = m_index[i & m_indexMask];
+ ASSERT(entryIndex != PropertyTable::EmptyEntryIndex);
+ if (rep == table()[entryIndex - 1].key)
break;
if (k == 0)
k = 1 | doubleHash(rep->existingHash());
ASSERT(entryIndex == c + 1);
}
- ASSERT(nonEmptyEntryCount == m_propertyTable->keyCount);
+ ASSERT(nonEmptyEntryCount == m_keyCount);
+}
+
+void Structure::checkConsistency()
+{
+ if (!m_propertyTable)
+ return;
+
+ if (!m_hasNonEnumerableProperties) {
+ PropertyTable::iterator end = m_propertyTable->end();
+ for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter) {
+ ASSERT(!(iter->attributes & DontEnum));
+ ASSERT(iter->offset >= m_anonymousSlotCount);
+ }
+ }
+
+ m_propertyTable->checkConsistency();
}
#endif // DO_PROPERTYMAP_CONSTENCY_CHECK
#define Structure_h
#include "Identifier.h"
+#include "JSCell.h"
#include "JSType.h"
#include "JSValue.h"
#include "PropertyMapHashTable.h"
#include "PropertyNameArray.h"
#include "Protect.h"
-#include "StructureChain.h"
#include "StructureTransitionTable.h"
#include "JSTypeInfo.h"
#include "UString.h"
-#include "WeakGCPtr.h"
+#include "Weak.h"
+#include <wtf/PassOwnPtr.h>
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
-#ifndef NDEBUG
-#define DUMP_PROPERTYMAP_STATS 0
-#else
-#define DUMP_PROPERTYMAP_STATS 0
-#endif
namespace JSC {
class MarkStack;
class PropertyNameArray;
class PropertyNameArrayData;
+ class StructureChain;
+ typedef MarkStack SlotVisitor;
+
+ struct ClassInfo;
enum EnumerationMode {
ExcludeDontEnumProperties,
IncludeDontEnumProperties
};
- class Structure : public RefCounted<Structure> {
+ class Structure : public JSCell {
public:
- friend class JIT;
friend class StructureTransitionTable;
- static PassRefPtr<Structure> create(JSValue prototype, const TypeInfo& typeInfo, unsigned anonymousSlotCount)
+ static Structure* create(JSGlobalData& globalData, JSValue prototype, const TypeInfo& typeInfo, unsigned anonymousSlotCount, const ClassInfo* classInfo)
{
- return adoptRef(new Structure(prototype, typeInfo, anonymousSlotCount));
+ ASSERT(globalData.structureStructure);
+ ASSERT(classInfo);
+ return new (&globalData) Structure(globalData, prototype, typeInfo, anonymousSlotCount, classInfo);
}
- static void startIgnoringLeaks();
- static void stopIgnoringLeaks();
-
static void dumpStatistics();
- static PassRefPtr<Structure> addPropertyTransition(Structure*, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset);
- static PassRefPtr<Structure> addPropertyTransitionToExistingStructure(Structure*, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset);
- static PassRefPtr<Structure> removePropertyTransition(Structure*, const Identifier& propertyName, size_t& offset);
- static PassRefPtr<Structure> changePrototypeTransition(Structure*, JSValue prototype);
- static PassRefPtr<Structure> despecifyFunctionTransition(Structure*, const Identifier&);
- static PassRefPtr<Structure> getterSetterTransition(Structure*);
- static PassRefPtr<Structure> toCacheableDictionaryTransition(Structure*);
- static PassRefPtr<Structure> toUncacheableDictionaryTransition(Structure*);
-
- PassRefPtr<Structure> flattenDictionaryStructure(JSObject*);
+ static Structure* addPropertyTransition(JSGlobalData&, Structure*, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset);
+ static Structure* addPropertyTransitionToExistingStructure(Structure*, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset);
+ static Structure* removePropertyTransition(JSGlobalData&, Structure*, const Identifier& propertyName, size_t& offset);
+ static Structure* changePrototypeTransition(JSGlobalData&, Structure*, JSValue prototype);
+ static Structure* despecifyFunctionTransition(JSGlobalData&, Structure*, const Identifier&);
+ static Structure* getterSetterTransition(JSGlobalData&, Structure*);
+ static Structure* toCacheableDictionaryTransition(JSGlobalData&, Structure*);
+ static Structure* toUncacheableDictionaryTransition(JSGlobalData&, Structure*);
+ static Structure* sealTransition(JSGlobalData&, Structure*);
+ static Structure* freezeTransition(JSGlobalData&, Structure*);
+ static Structure* preventExtensionsTransition(JSGlobalData&, Structure*);
+
+ bool isSealed(JSGlobalData&);
+ bool isFrozen(JSGlobalData&);
+ bool isExtensible() const { return !m_preventExtensions; }
+ bool didTransition() const { return m_didTransition; }
+
+ Structure* flattenDictionaryStructure(JSGlobalData&, JSObject*);
~Structure();
// These should be used with caution.
- size_t addPropertyWithoutTransition(const Identifier& propertyName, unsigned attributes, JSCell* specificValue);
- size_t removePropertyWithoutTransition(const Identifier& propertyName);
- void setPrototypeWithoutTransition(JSValue prototype) { m_prototype = prototype; }
+ size_t addPropertyWithoutTransition(JSGlobalData&, const Identifier& propertyName, unsigned attributes, JSCell* specificValue);
+ size_t removePropertyWithoutTransition(JSGlobalData&, const Identifier& propertyName);
+ void setPrototypeWithoutTransition(JSGlobalData& globalData, JSValue prototype) { m_prototype.set(globalData, this, prototype); }
bool isDictionary() const { return m_dictionaryKind != NoneDictionaryKind; }
bool isUncacheableDictionary() const { return m_dictionaryKind == UncachedDictionaryKind; }
- const TypeInfo& typeInfo() const { return m_typeInfo; }
+ const TypeInfo& typeInfo() const { ASSERT(structure()->classInfo() == &s_info); return m_typeInfo; }
- JSValue storedPrototype() const { return m_prototype; }
+ JSValue storedPrototype() const { return m_prototype.get(); }
JSValue prototypeForLookup(ExecState*) const;
StructureChain* prototypeChain(ExecState*) const;
+ void visitChildren(SlotVisitor&);
- Structure* previousID() const { return m_previous.get(); }
+ Structure* previousID() const { ASSERT(structure()->classInfo() == &s_info); return m_previous.get(); }
void growPropertyStorageCapacity();
- unsigned propertyStorageCapacity() const { return m_propertyStorageCapacity; }
- unsigned propertyStorageSize() const { return m_anonymousSlotCount + (m_propertyTable ? m_propertyTable->keyCount + (m_propertyTable->deletedOffsets ? m_propertyTable->deletedOffsets->size() : 0) : static_cast<unsigned>(m_offset + 1)); }
+ unsigned propertyStorageCapacity() const { ASSERT(structure()->classInfo() == &s_info); return m_propertyStorageCapacity; }
+ unsigned propertyStorageSize() const { ASSERT(structure()->classInfo() == &s_info); return m_anonymousSlotCount + (m_propertyTable ? m_propertyTable->propertyStorageSize() : static_cast<unsigned>(m_offset + 1)); }
bool isUsingInlineStorage() const;
- size_t get(const Identifier& propertyName);
- size_t get(const UString::Rep* rep, unsigned& attributes, JSCell*& specificValue);
- size_t get(const Identifier& propertyName, unsigned& attributes, JSCell*& specificValue)
+ size_t get(JSGlobalData&, const Identifier& propertyName);
+ size_t get(JSGlobalData&, StringImpl* propertyName, unsigned& attributes, JSCell*& specificValue);
+ size_t get(JSGlobalData& globalData, const Identifier& propertyName, unsigned& attributes, JSCell*& specificValue)
{
ASSERT(!propertyName.isNull());
- return get(propertyName.ustring().rep(), attributes, specificValue);
- }
- bool transitionedFor(const JSCell* specificValue)
- {
- return m_specificValueInPrevious == specificValue;
- }
- bool hasTransition(UString::Rep*, unsigned attributes);
- bool hasTransition(const Identifier& propertyName, unsigned attributes)
- {
- return hasTransition(propertyName._ustring.rep(), attributes);
+ ASSERT(structure()->classInfo() == &s_info);
+ return get(globalData, propertyName.impl(), attributes, specificValue);
}
bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties; }
bool hasAnonymousSlots() const { return !!m_anonymousSlotCount; }
unsigned anonymousSlotCount() const { return m_anonymousSlotCount; }
- bool isEmpty() const { return m_propertyTable ? !m_propertyTable->keyCount : m_offset == noOffset; }
+ bool isEmpty() const { return m_propertyTable ? m_propertyTable->isEmpty() : m_offset == noOffset; }
- void despecifyDictionaryFunction(const Identifier& propertyName);
+ void despecifyDictionaryFunction(JSGlobalData&, const Identifier& propertyName);
void disableSpecificFunctionTracking() { m_specificFunctionThrashCount = maxSpecificFunctionThrashCount; }
- void setEnumerationCache(JSPropertyNameIterator* enumerationCache); // Defined in JSPropertyNameIterator.h.
- void clearEnumerationCache(JSPropertyNameIterator* enumerationCache); // Defined in JSPropertyNameIterator.h.
+ void setEnumerationCache(JSGlobalData&, JSPropertyNameIterator* enumerationCache); // Defined in JSPropertyNameIterator.h.
JSPropertyNameIterator* enumerationCache(); // Defined in JSPropertyNameIterator.h.
- void getPropertyNames(PropertyNameArray&, EnumerationMode mode);
+ void getPropertyNames(JSGlobalData&, PropertyNameArray&, EnumerationMode mode);
+
+ const ClassInfo* classInfo() const { return m_classInfo; }
+
+ static ptrdiff_t prototypeOffset()
+ {
+ return OBJECT_OFFSETOF(Structure, m_prototype);
+ }
+
+ static ptrdiff_t typeInfoFlagsOffset()
+ {
+ return OBJECT_OFFSETOF(Structure, m_typeInfo) + TypeInfo::flagsOffset();
+ }
+
+ static ptrdiff_t typeInfoTypeOffset()
+ {
+ return OBJECT_OFFSETOF(Structure, m_typeInfo) + TypeInfo::typeOffset();
+ }
+
+ static Structure* createStructure(JSGlobalData& globalData)
+ {
+ ASSERT(!globalData.structureStructure);
+ return new (&globalData) Structure(globalData);
+ }
+ static JS_EXPORTDATA const ClassInfo s_info;
+
private:
+ Structure(JSGlobalData&, JSValue prototype, const TypeInfo&, unsigned anonymousSlotCount, const ClassInfo*);
+ Structure(JSGlobalData&);
+ Structure(JSGlobalData&, const Structure*);
- Structure(JSValue prototype, const TypeInfo&, unsigned anonymousSlotCount);
+ static Structure* create(JSGlobalData& globalData, const Structure* structure)
+ {
+ ASSERT(globalData.structureStructure);
+ return new (&globalData) Structure(globalData, structure);
+ }
typedef enum {
NoneDictionaryKind = 0,
CachedDictionaryKind = 1,
UncachedDictionaryKind = 2
} DictionaryKind;
- static PassRefPtr<Structure> toDictionaryTransition(Structure*, DictionaryKind);
+ static Structure* toDictionaryTransition(JSGlobalData&, Structure*, DictionaryKind);
- size_t put(const Identifier& propertyName, unsigned attributes, JSCell* specificValue);
+ size_t putSpecificValue(JSGlobalData&, const Identifier& propertyName, unsigned attributes, JSCell* specificValue);
size_t remove(const Identifier& propertyName);
- void expandPropertyMapHashTable();
- void rehashPropertyMapHashTable();
- void rehashPropertyMapHashTable(unsigned newTableSize);
- void createPropertyMapHashTable();
- void createPropertyMapHashTable(unsigned newTableSize);
- void insertIntoPropertyMapHashTable(const PropertyMapEntry&);
+ void createPropertyMap(unsigned keyCount = 0);
void checkConsistency();
- bool despecifyFunction(const Identifier&);
- void despecifyAllFunctions();
+ bool despecifyFunction(JSGlobalData&, const Identifier&);
+ void despecifyAllFunctions(JSGlobalData&);
- PropertyMapHashTable* copyPropertyTable();
- void materializePropertyMap();
- void materializePropertyMapIfNecessary()
+ PassOwnPtr<PropertyTable> copyPropertyTable(JSGlobalData&, Structure* owner);
+ void materializePropertyMap(JSGlobalData&);
+ void materializePropertyMapIfNecessary(JSGlobalData& globalData)
{
- if (m_propertyTable || !m_previous)
- return;
- materializePropertyMap();
+ ASSERT(structure()->classInfo() == &s_info);
+ if (!m_propertyTable && m_previous)
+ materializePropertyMap(globalData);
}
signed char transitionCount() const
return m_offset == noOffset ? 0 : m_offset + 1;
}
- typedef std::pair<Structure*, Structure*> Transition;
- typedef HashMap<StructureTransitionTableHash::Key, Transition, StructureTransitionTableHash, StructureTransitionTableHashTraits> TransitionTable;
-
- inline bool transitionTableContains(const StructureTransitionTableHash::Key& key, JSCell* specificValue);
- inline void transitionTableRemove(const StructureTransitionTableHash::Key& key, JSCell* specificValue);
- inline void transitionTableAdd(const StructureTransitionTableHash::Key& key, Structure* structure, JSCell* specificValue);
- inline bool transitionTableHasTransition(const StructureTransitionTableHash::Key& key) const;
- inline Structure* transitionTableGet(const StructureTransitionTableHash::Key& key, JSCell* specificValue) const;
-
- TransitionTable* transitionTable() const { ASSERT(!m_isUsingSingleSlot); return m_transitions.m_table; }
- inline void setTransitionTable(TransitionTable* table);
- Structure* singleTransition() const { ASSERT(m_isUsingSingleSlot); return m_transitions.m_singleTransition; }
- void setSingleTransition(Structure* structure) { ASSERT(m_isUsingSingleSlot); m_transitions.m_singleTransition = structure; }
-
bool isValid(ExecState*, StructureChain* cachedPrototypeChain) const;
- static const unsigned emptyEntryIndex = 0;
-
static const signed char s_maxTransitionLength = 64;
static const signed char noOffset = -1;
TypeInfo m_typeInfo;
- JSValue m_prototype;
- mutable RefPtr<StructureChain> m_cachedPrototypeChain;
+ WriteBarrier<Unknown> m_prototype;
+ mutable WriteBarrier<StructureChain> m_cachedPrototypeChain;
- RefPtr<Structure> m_previous;
- RefPtr<UString::Rep> m_nameInPrevious;
- JSCell* m_specificValueInPrevious;
+ WriteBarrier<Structure> m_previous;
+ RefPtr<StringImpl> m_nameInPrevious;
+ WriteBarrier<JSCell> m_specificValueInPrevious;
- // 'm_isUsingSingleSlot' indicates whether we are using the single transition optimisation.
- union {
- TransitionTable* m_table;
- Structure* m_singleTransition;
- } m_transitions;
+ const ClassInfo* m_classInfo;
- WeakGCPtr<JSPropertyNameIterator> m_enumerationCache;
+ StructureTransitionTable m_transitionTable;
- PropertyMapHashTable* m_propertyTable;
+ WriteBarrier<JSPropertyNameIterator> m_enumerationCache;
+
+ OwnPtr<PropertyTable> m_propertyTable;
uint32_t m_propertyStorageCapacity;
#endif
unsigned m_specificFunctionThrashCount : 2;
unsigned m_anonymousSlotCount : 5;
- unsigned m_isUsingSingleSlot : 1;
- // 4 free bits
+ unsigned m_preventExtensions : 1;
+ unsigned m_didTransition : 1;
+ // 3 free bits
};
- inline size_t Structure::get(const Identifier& propertyName)
+ inline size_t Structure::get(JSGlobalData& globalData, const Identifier& propertyName)
{
- ASSERT(!propertyName.isNull());
-
- materializePropertyMapIfNecessary();
+ ASSERT(structure()->classInfo() == &s_info);
+ materializePropertyMapIfNecessary(globalData);
if (!m_propertyTable)
- return WTF::notFound;
+ return notFound;
- UString::Rep* rep = propertyName._ustring.rep();
-
- unsigned i = rep->existingHash();
-
-#if DUMP_PROPERTYMAP_STATS
- ++numProbes;
-#endif
+ PropertyMapEntry* entry = m_propertyTable->find(propertyName.impl()).first;
+ ASSERT(!entry || entry->offset >= m_anonymousSlotCount);
+ return entry ? entry->offset : notFound;
+ }
- unsigned entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];
- if (entryIndex == emptyEntryIndex)
- return WTF::notFound;
+ inline bool JSCell::isObject() const
+ {
+ return m_structure->typeInfo().type() == ObjectType;
+ }
- if (rep == m_propertyTable->entries()[entryIndex - 1].key)
- return m_propertyTable->entries()[entryIndex - 1].offset;
+ inline bool JSCell::isString() const
+ {
+ return m_structure->typeInfo().type() == StringType;
+ }
-#if DUMP_PROPERTYMAP_STATS
- ++numCollisions;
+ inline const ClassInfo* JSCell::classInfo() const
+ {
+#if ENABLE(GC_VALIDATION)
+ return m_structure.unvalidatedGet()->classInfo();
+#else
+ return m_structure->classInfo();
#endif
+ }
- unsigned k = 1 | WTF::doubleHash(rep->existingHash());
-
- while (1) {
- i += k;
+ inline Structure* JSCell::createDummyStructure(JSGlobalData& globalData)
+ {
+ return Structure::create(globalData, jsNull(), TypeInfo(UnspecifiedType), AnonymousSlotCount, &s_dummyCellInfo);
+ }
-#if DUMP_PROPERTYMAP_STATS
- ++numRehashes;
-#endif
+ inline bool JSValue::needsThisConversion() const
+ {
+ if (UNLIKELY(!isCell()))
+ return true;
+ return asCell()->structure()->typeInfo().needsThisConversion();
+ }
- entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];
- if (entryIndex == emptyEntryIndex)
- return WTF::notFound;
+ ALWAYS_INLINE void MarkStack::internalAppend(JSCell* cell)
+ {
+ ASSERT(!m_isCheckingForDefaultMarkViolation);
+ ASSERT(cell);
+ if (Heap::testAndSetMarked(cell))
+ return;
+ if (cell->structure() && cell->structure()->typeInfo().type() >= CompoundType)
+ m_values.append(cell);
+ }
- if (rep == m_propertyTable->entries()[entryIndex - 1].key)
- return m_propertyTable->entries()[entryIndex - 1].offset;
- }
+ inline StructureTransitionTable::Hash::Key StructureTransitionTable::keyForWeakGCMapFinalizer(void*, Structure* structure)
+ {
+ // Newer versions of the STL have an std::make_pair function that takes rvalue references.
+ // When either of the parameters are bitfields, the C++ compiler will try to bind them as lvalues, which is invalid. To work around this, use unary "+" to make the parameter an rvalue.
+ // See https://bugs.webkit.org/show_bug.cgi?id=59261 for more details.
+ return Hash::Key(structure->m_nameInPrevious.get(), +structure->m_attributesInPrevious);
}
} // namespace JSC
#include <wtf/RefPtr.h>
namespace JSC {
+
+ClassInfo StructureChain::s_info = { "StructureChain", 0, 0, 0 };
-StructureChain::StructureChain(Structure* head)
+StructureChain::StructureChain(JSGlobalData& globalData, Structure* structure, Structure* head)
+ : JSCell(globalData, structure)
{
size_t size = 0;
for (Structure* current = head; current; current = current->storedPrototype().isNull() ? 0 : asObject(current->storedPrototype())->structure())
++size;
- m_vector.set(new RefPtr<Structure>[size + 1]);
+ m_vector = adoptArrayPtr(new WriteBarrier<Structure>[size + 1]);
size_t i = 0;
for (Structure* current = head; current; current = current->storedPrototype().isNull() ? 0 : asObject(current->storedPrototype())->structure())
- m_vector[i++] = current;
- m_vector[i] = 0;
+ m_vector[i++].set(globalData, this, current);
+ m_vector[i].clear();
+}
+
+StructureChain::~StructureChain()
+{
+}
+
+void StructureChain::visitChildren(SlotVisitor& visitor)
+{
+ ASSERT_GC_OBJECT_INHERITS(this, &s_info);
+ ASSERT(structure()->typeInfo().overridesVisitChildren());
+ size_t i = 0;
+ while (m_vector[i])
+ visitor.append(&m_vector[i++]);
}
} // namespace JSC
#ifndef StructureChain_h
#define StructureChain_h
+#include "JSCell.h"
+#include "Structure.h"
+
#include <wtf/OwnArrayPtr.h>
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
class Structure;
- class StructureChain : public RefCounted<StructureChain> {
+ class StructureChain : public JSCell {
friend class JIT;
public:
- static PassRefPtr<StructureChain> create(Structure* head) { return adoptRef(new StructureChain(head)); }
- RefPtr<Structure>* head() { return m_vector.get(); }
+ static StructureChain* create(JSGlobalData& globalData, Structure* head) { return new (&globalData) StructureChain(globalData, globalData.structureChainStructure.get(), head); }
+ WriteBarrier<Structure>* head() { return m_vector.get(); }
+ void visitChildren(SlotVisitor&);
- private:
- StructureChain(Structure* head);
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype) { return Structure::create(globalData, prototype, TypeInfo(CompoundType, OverridesVisitChildren), 0, &s_info); }
+
+ static ClassInfo s_info;
- OwnArrayPtr<RefPtr<Structure> > m_vector;
+ private:
+ StructureChain(JSGlobalData&, Structure*, Structure* head);
+ ~StructureChain();
+ OwnArrayPtr<WriteBarrier<Structure> > m_vector;
};
} // namespace JSC
#define StructureTransitionTable_h
#include "UString.h"
+#include "WeakGCMap.h"
#include <wtf/HashFunctions.h>
-#include <wtf/HashMap.h>
#include <wtf/HashTraits.h>
#include <wtf/OwnPtr.h>
#include <wtf/RefPtr.h>
namespace JSC {
- class Structure;
+class Structure;
- struct StructureTransitionTableHash {
- typedef std::pair<RefPtr<UString::Rep>, unsigned> Key;
+class StructureTransitionTable {
+ static const intptr_t UsingSingleSlotFlag = 1;
+
+ struct Hash {
+ typedef std::pair<RefPtr<StringImpl>, unsigned> Key;
static unsigned hash(const Key& p)
{
return p.first->existingHash();
static const bool safeToCompareToEmptyOrDeleted = true;
};
- struct StructureTransitionTableHashTraits {
- typedef WTF::HashTraits<RefPtr<UString::Rep> > FirstTraits;
+ struct HashTraits {
+ typedef WTF::HashTraits<RefPtr<StringImpl> > FirstTraits;
typedef WTF::GenericHashTraits<unsigned> SecondTraits;
typedef std::pair<FirstTraits::TraitType, SecondTraits::TraitType > TraitType;
static bool isDeletedValue(const TraitType& value) { return FirstTraits::isDeletedValue(value.first); }
};
+ struct WeakGCMapFinalizerCallback {
+ static void* finalizerContextFor(Hash::Key)
+ {
+ return 0;
+ }
+
+ static inline Hash::Key keyForFinalizer(void* context, Structure* structure)
+ {
+ return keyForWeakGCMapFinalizer(context, structure);
+ }
+ };
+
+ typedef WeakGCMap<Hash::Key, Structure, WeakGCMapFinalizerCallback, Hash, HashTraits> TransitionMap;
+
+ static Hash::Key keyForWeakGCMapFinalizer(void* context, Structure*);
+
+public:
+ StructureTransitionTable()
+ : m_data(UsingSingleSlotFlag)
+ {
+ }
+
+ ~StructureTransitionTable()
+ {
+ if (!isUsingSingleSlot())
+ delete map();
+ else
+ clearSingleTransition();
+ }
+
+ inline void add(JSGlobalData&, Structure*);
+ inline void remove(Structure*);
+ inline bool contains(StringImpl* rep, unsigned attributes) const;
+ inline Structure* get(StringImpl* rep, unsigned attributes) const;
+
+private:
+ bool isUsingSingleSlot() const
+ {
+ return m_data & UsingSingleSlotFlag;
+ }
+
+ TransitionMap* map() const
+ {
+ ASSERT(!isUsingSingleSlot());
+ return reinterpret_cast<TransitionMap*>(m_data);
+ }
+
+ HandleSlot slot() const
+ {
+ ASSERT(isUsingSingleSlot());
+ return reinterpret_cast<HandleSlot>(m_data & ~UsingSingleSlotFlag);
+ }
+
+ void setMap(TransitionMap* map)
+ {
+ ASSERT(isUsingSingleSlot());
+
+ if (HandleSlot slot = this->slot())
+ HandleHeap::heapFor(slot)->deallocate(slot);
+
+ // This implicitly clears the flag that indicates we're using a single transition
+ m_data = reinterpret_cast<intptr_t>(map);
+
+ ASSERT(!isUsingSingleSlot());
+ }
+
+ Structure* singleTransition() const
+ {
+ ASSERT(isUsingSingleSlot());
+ if (HandleSlot slot = this->slot()) {
+ if (*slot)
+ return reinterpret_cast<Structure*>(slot->asCell());
+ }
+ return 0;
+ }
+
+ void clearSingleTransition()
+ {
+ ASSERT(isUsingSingleSlot());
+ if (HandleSlot slot = this->slot())
+ HandleHeap::heapFor(slot)->deallocate(slot);
+ }
+
+ void setSingleTransition(JSGlobalData& globalData, Structure* structure)
+ {
+ ASSERT(isUsingSingleSlot());
+ HandleSlot slot = this->slot();
+ if (!slot) {
+ slot = globalData.allocateGlobalHandle();
+ HandleHeap::heapFor(slot)->makeWeak(slot, 0, 0);
+ m_data = reinterpret_cast<intptr_t>(slot) | UsingSingleSlotFlag;
+ }
+ HandleHeap::heapFor(slot)->writeBarrier(slot, reinterpret_cast<JSCell*>(structure));
+ *slot = reinterpret_cast<JSCell*>(structure);
+ }
+
+ intptr_t m_data;
+};
+
} // namespace JSC
#endif // StructureTransitionTable_h
static const bool needsDestruction = false;
};
- typedef HashMap<RefPtr<UString::Rep>, SymbolTableEntry, IdentifierRepHash, HashTraits<RefPtr<UString::Rep> >, SymbolTableIndexHashTraits> SymbolTable;
+ typedef HashMap<RefPtr<StringImpl>, SymbolTableEntry, IdentifierRepHash, HashTraits<RefPtr<StringImpl> >, SymbolTableIndexHashTraits> SymbolTable;
- class SharedSymbolTable : public SymbolTable, public RefCounted<SharedSymbolTable>
- {
+ class SharedSymbolTable : public SymbolTable, public RefCounted<SharedSymbolTable> {
+ WTF_MAKE_FAST_ALLOCATED;
+ public:
+ static PassRefPtr<SharedSymbolTable> create() { return adoptRef(new SharedSymbolTable); }
+ private:
+ SharedSymbolTable() { }
};
} // namespace JSC
return GETUPTIMEMS();
#else
// FIXME: We should return the time the current thread has spent executing.
- return currentTime() * 1000;
+
+ // use a relative time from first call in order to avoid an overflow
+ static double firstTime = currentTime();
+ return static_cast<unsigned> ((currentTime() - firstTime) * 1000);
#endif
}
TimeoutChecker();
void setTimeoutInterval(unsigned timeoutInterval) { m_timeoutInterval = timeoutInterval; }
+ unsigned timeoutInterval() const { return m_timeoutInterval; }
unsigned ticksUntilNextCheck() { return m_ticksUntilNextCheck; }
#include "UString.h"
#include "JSGlobalObjectFunctions.h"
-#include "Collector.h"
-#include "dtoa.h"
+#include "Heap.h"
#include "Identifier.h"
#include "Operations.h"
#include <ctype.h>
#include <limits.h>
#include <limits>
-#include <math.h>
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
#include <wtf/ASCIICType.h>
#include <wtf/Assertions.h>
+#include <wtf/DecimalNumber.h>
#include <wtf/MathExtras.h>
#include <wtf/StringExtras.h>
#include <wtf/Vector.h>
#include <wtf/unicode/UTF8.h>
-#include <wtf/StringExtras.h>
#if HAVE(STRINGS_H)
#include <strings.h>
extern const double NaN;
extern const double Inf;
-// The null string is immutable, except for refCount.
-UString* UString::s_nullUString;
+COMPILE_ASSERT(sizeof(UString) == sizeof(void*), UString_should_stay_small);
-void initializeUString()
+// Construct a string with UTF-16 data.
+UString::UString(const UChar* characters, unsigned length)
+ : m_impl(characters ? StringImpl::create(characters, length) : 0)
{
- // UStringImpl::empty() does not construct its static string in a threadsafe fashion,
- // so ensure it has been initialized from here.
- UStringImpl::empty();
-
- UString::s_nullUString = new UString;
}
-UString::UString(const char* c)
- : m_rep(Rep::create(c))
+// Construct a string with UTF-16 data, from a null-terminated source.
+UString::UString(const UChar* characters)
{
+ if (!characters)
+ return;
+
+ int length = 0;
+ while (characters[length] != UChar(0))
+ ++length;
+
+ m_impl = StringImpl::create(characters, length);
}
-UString::UString(const char* c, unsigned length)
- : m_rep(Rep::create(c, length))
+// Construct a string with latin1 data.
+UString::UString(const char* characters, unsigned length)
+ : m_impl(characters ? StringImpl::create(characters, length) : 0)
{
}
-UString::UString(const UChar* c, unsigned length)
- : m_rep(Rep::create(c, length))
+// Construct a string with latin1 data, from a null-terminated source.
+UString::UString(const char* characters)
+ : m_impl(characters ? StringImpl::create(characters) : 0)
{
}
-UString UString::from(int i)
+UString UString::number(int i)
{
UChar buf[1 + sizeof(i) * 3];
- UChar* end = buf + sizeof(buf) / sizeof(UChar);
+ UChar* end = buf + WTF_ARRAY_LENGTH(buf);
UChar* p = end;
if (i == 0)
return UString(p, static_cast<unsigned>(end - p));
}
-UString UString::from(long long i)
+UString UString::number(long long i)
{
UChar buf[1 + sizeof(i) * 3];
- UChar* end = buf + sizeof(buf) / sizeof(UChar);
+ UChar* end = buf + WTF_ARRAY_LENGTH(buf);
UChar* p = end;
if (i == 0)
*--p = '0';
else if (i == std::numeric_limits<long long>::min()) {
char minBuf[1 + sizeof(i) * 3];
+#if OS(WINDOWS)
+ snprintf(minBuf, sizeof(minBuf), "%I64d", std::numeric_limits<long long>::min());
+#else
snprintf(minBuf, sizeof(minBuf), "%lld", std::numeric_limits<long long>::min());
+#endif
return UString(minBuf);
} else {
bool negative = false;
return UString(p, static_cast<unsigned>(end - p));
}
-UString UString::from(unsigned u)
+UString UString::number(unsigned u)
{
UChar buf[sizeof(u) * 3];
- UChar* end = buf + sizeof(buf) / sizeof(UChar);
+ UChar* end = buf + WTF_ARRAY_LENGTH(buf);
UChar* p = end;
if (u == 0)
return UString(p, static_cast<unsigned>(end - p));
}
-UString UString::from(long l)
+UString UString::number(long l)
{
UChar buf[1 + sizeof(l) * 3];
- UChar* end = buf + sizeof(buf) / sizeof(UChar);
+ UChar* end = buf + WTF_ARRAY_LENGTH(buf);
UChar* p = end;
if (l == 0)
return UString(p, end - p);
}
-UString UString::from(double d)
+UString UString::number(double d)
{
- DtoaBuffer buffer;
- unsigned length;
- doubleToStringInJavaScriptFormat(d, buffer, &length);
+ NumberToStringBuffer buffer;
+ unsigned length = numberToString(d, buffer);
return UString(buffer, length);
}
-char* UString::ascii() const
-{
- static char* asciiBuffer = 0;
-
- unsigned length = size();
- unsigned neededSize = length + 1;
- delete[] asciiBuffer;
- asciiBuffer = new char[neededSize];
-
- const UChar* p = data();
- char* q = asciiBuffer;
- const UChar* limit = p + length;
- while (p != limit) {
- *q = static_cast<char>(p[0]);
- ++p;
- ++q;
- }
- *q = '\0';
-
- return asciiBuffer;
-}
-
-bool UString::is8Bit() const
-{
- const UChar* u = data();
- const UChar* limit = u + size();
- while (u < limit) {
- if (u[0] > 0xFF)
- return false;
- ++u;
- }
-
- return true;
-}
-
-UChar UString::operator[](unsigned pos) const
-{
- if (pos >= size())
- return '\0';
- return data()[pos];
-}
-
-double UString::toDouble(bool tolerateTrailingJunk, bool tolerateEmptyString) const
-{
- if (size() == 1) {
- UChar c = data()[0];
- if (isASCIIDigit(c))
- return c - '0';
- if (isASCIISpace(c) && tolerateEmptyString)
- return 0;
- return NaN;
- }
-
- // FIXME: If tolerateTrailingJunk is true, then we want to tolerate junk
- // after the number, even if it contains invalid UTF-16 sequences. So we
- // shouldn't use the UTF8String function, which returns null when it
- // encounters invalid UTF-16. Further, we have no need to convert the
- // non-ASCII characters to UTF-8, so the UTF8String does quite a bit of
- // unnecessary work.
- CString s = UTF8String();
- if (s.isNull())
- return NaN;
- const char* c = s.data();
-
- // skip leading white space
- while (isASCIISpace(*c))
- c++;
-
- // empty string ?
- if (*c == '\0')
- return tolerateEmptyString ? 0.0 : NaN;
-
- double d;
-
- // hex number ?
- if (*c == '0' && (*(c + 1) == 'x' || *(c + 1) == 'X')) {
- const char* firstDigitPosition = c + 2;
- c++;
- d = 0.0;
- while (*(++c)) {
- if (*c >= '0' && *c <= '9')
- d = d * 16.0 + *c - '0';
- else if ((*c >= 'A' && *c <= 'F') || (*c >= 'a' && *c <= 'f'))
- d = d * 16.0 + (*c & 0xdf) - 'A' + 10.0;
- else
- break;
- }
-
- if (d >= mantissaOverflowLowerBound)
- d = parseIntOverflow(firstDigitPosition, c - firstDigitPosition, 16);
- } else {
- // regular number ?
- char* end;
- d = WTF::strtod(c, &end);
- if ((d != 0.0 || end != c) && d != Inf && d != -Inf) {
- c = end;
- } else {
- double sign = 1.0;
-
- if (*c == '+')
- c++;
- else if (*c == '-') {
- sign = -1.0;
- c++;
- }
-
- // We used strtod() to do the conversion. However, strtod() handles
- // infinite values slightly differently than JavaScript in that it
- // converts the string "inf" with any capitalization to infinity,
- // whereas the ECMA spec requires that it be converted to NaN.
-
- if (c[0] == 'I' && c[1] == 'n' && c[2] == 'f' && c[3] == 'i' && c[4] == 'n' && c[5] == 'i' && c[6] == 't' && c[7] == 'y') {
- d = sign * Inf;
- c += 8;
- } else if ((d == Inf || d == -Inf) && *c != 'I' && *c != 'i')
- c = end;
- else
- return NaN;
- }
- }
-
- // allow trailing white space
- while (isASCIISpace(*c))
- c++;
- // don't allow anything after - unless tolerant=true
- // FIXME: If string contains a U+0000 character, then this check is incorrect.
- if (!tolerateTrailingJunk && *c != '\0')
- d = NaN;
-
- return d;
-}
-
-double UString::toDouble(bool tolerateTrailingJunk) const
-{
- return toDouble(tolerateTrailingJunk, true);
-}
-
-double UString::toDouble() const
+UString UString::substringSharingImpl(unsigned offset, unsigned length) const
{
- return toDouble(false, true);
-}
-
-uint32_t UString::toUInt32(bool* ok) const
-{
- double d = toDouble();
- bool b = true;
+ // FIXME: We used to check against a limit of Heap::minExtraCost / sizeof(UChar).
- if (d != static_cast<uint32_t>(d)) {
- b = false;
- d = 0;
- }
-
- if (ok)
- *ok = b;
-
- return static_cast<uint32_t>(d);
-}
+ unsigned stringLength = this->length();
+ offset = min(offset, stringLength);
+ length = min(length, stringLength - offset);
-uint32_t UString::toUInt32(bool* ok, bool tolerateEmptyString) const
-{
- double d = toDouble(false, tolerateEmptyString);
- bool b = true;
-
- if (d != static_cast<uint32_t>(d)) {
- b = false;
- d = 0;
- }
-
- if (ok)
- *ok = b;
-
- return static_cast<uint32_t>(d);
-}
-
-uint32_t UString::toStrictUInt32(bool* ok) const
-{
- if (ok)
- *ok = false;
-
- // Empty string is not OK.
- unsigned len = m_rep->length();
- if (len == 0)
- return 0;
- const UChar* p = m_rep->characters();
- unsigned short c = p[0];
-
- // If the first digit is 0, only 0 itself is OK.
- if (c == '0') {
- if (len == 1 && ok)
- *ok = true;
- return 0;
- }
-
- // Convert to UInt32, checking for overflow.
- uint32_t i = 0;
- while (1) {
- // Process character, turning it into a digit.
- if (c < '0' || c > '9')
- return 0;
- const unsigned d = c - '0';
-
- // Multiply by 10, checking for overflow out of 32 bits.
- if (i > 0xFFFFFFFFU / 10)
- return 0;
- i *= 10;
-
- // Add in the digit, checking for overflow out of 32 bits.
- const unsigned max = 0xFFFFFFFFU - d;
- if (i > max)
- return 0;
- i += d;
-
- // Handle end of string.
- if (--len == 0) {
- if (ok)
- *ok = true;
- return i;
- }
-
- // Get next character.
- c = *(++p);
- }
-}
-
-unsigned UString::find(const UString& f, unsigned pos) const
-{
- unsigned fsz = f.size();
-
- if (fsz == 1) {
- UChar ch = f[0];
- const UChar* end = data() + size();
- for (const UChar* c = data() + pos; c < end; c++) {
- if (*c == ch)
- return static_cast<unsigned>(c - data());
- }
- return NotFound;
- }
-
- unsigned sz = size();
- if (sz < fsz)
- return NotFound;
- if (fsz == 0)
- return pos;
- const UChar* end = data() + sz - fsz;
- unsigned fsizeminusone = (fsz - 1) * sizeof(UChar);
- const UChar* fdata = f.data();
- unsigned short fchar = fdata[0];
- ++fdata;
- for (const UChar* c = data() + pos; c <= end; c++) {
- if (c[0] == fchar && !memcmp(c + 1, fdata, fsizeminusone))
- return static_cast<unsigned>(c - data());
- }
-
- return NotFound;
-}
-
-unsigned UString::find(UChar ch, unsigned pos) const
-{
- const UChar* end = data() + size();
- for (const UChar* c = data() + pos; c < end; c++) {
- if (*c == ch)
- return static_cast<unsigned>(c - data());
- }
-
- return NotFound;
-}
-
-unsigned UString::rfind(const UString& f, unsigned pos) const
-{
- unsigned sz = size();
- unsigned fsz = f.size();
- if (sz < fsz)
- return NotFound;
- if (pos > sz - fsz)
- pos = sz - fsz;
- if (fsz == 0)
- return pos;
- unsigned fsizeminusone = (fsz - 1) * sizeof(UChar);
- const UChar* fdata = f.data();
- for (const UChar* c = data() + pos; c >= data(); c--) {
- if (*c == *fdata && !memcmp(c + 1, fdata + 1, fsizeminusone))
- return static_cast<unsigned>(c - data());
- }
-
- return NotFound;
-}
-
-unsigned UString::rfind(UChar ch, unsigned pos) const
-{
- if (isEmpty())
- return NotFound;
- if (pos + 1 >= size())
- pos = size() - 1;
- for (const UChar* c = data() + pos; c >= data(); c--) {
- if (*c == ch)
- return static_cast<unsigned>(c - data());
- }
-
- return NotFound;
-}
-
-UString UString::substr(unsigned pos, unsigned len) const
-{
- unsigned s = size();
-
- if (pos >= s)
- pos = s;
- unsigned limit = s - pos;
- if (len > limit)
- len = limit;
-
- if (pos == 0 && len == s)
+ if (!offset && length == stringLength)
return *this;
-
- return UString(Rep::create(m_rep, pos, len));
+ return UString(StringImpl::create(m_impl, offset, length));
}
bool operator==(const UString& s1, const char *s2)
if (s2 == 0)
return s1.isEmpty();
- const UChar* u = s1.data();
- const UChar* uend = u + s1.size();
+ const UChar* u = s1.characters();
+ const UChar* uend = u + s1.length();
while (u != uend && *s2) {
if (u[0] != (unsigned char)*s2)
return false;
bool operator<(const UString& s1, const UString& s2)
{
- const unsigned l1 = s1.size();
- const unsigned l2 = s2.size();
+ const unsigned l1 = s1.length();
+ const unsigned l2 = s2.length();
const unsigned lmin = l1 < l2 ? l1 : l2;
- const UChar* c1 = s1.data();
- const UChar* c2 = s2.data();
+ const UChar* c1 = s1.characters();
+ const UChar* c2 = s2.characters();
unsigned l = 0;
while (l < lmin && *c1 == *c2) {
c1++;
bool operator>(const UString& s1, const UString& s2)
{
- const unsigned l1 = s1.size();
- const unsigned l2 = s2.size();
+ const unsigned l1 = s1.length();
+ const unsigned l2 = s2.length();
const unsigned lmin = l1 < l2 ? l1 : l2;
- const UChar* c1 = s1.data();
- const UChar* c2 = s2.data();
+ const UChar* c1 = s1.characters();
+ const UChar* c2 = s2.characters();
unsigned l = 0;
while (l < lmin && *c1 == *c2) {
c1++;
return (l1 > l2);
}
-int compare(const UString& s1, const UString& s2)
+CString UString::ascii() const
{
- const unsigned l1 = s1.size();
- const unsigned l2 = s2.size();
- const unsigned lmin = l1 < l2 ? l1 : l2;
- const UChar* c1 = s1.data();
- const UChar* c2 = s2.data();
- unsigned l = 0;
- while (l < lmin && *c1 == *c2) {
- c1++;
- c2++;
- l++;
+ // Basic Latin1 (ISO) encoding - Unicode characters 0..255 are
+ // preserved, characters outside of this range are converted to '?'.
+
+ unsigned length = this->length();
+ const UChar* characters = this->characters();
+
+ char* characterBuffer;
+ CString result = CString::newUninitialized(length, characterBuffer);
+
+ for (unsigned i = 0; i < length; ++i) {
+ UChar ch = characters[i];
+ characterBuffer[i] = ch && (ch < 0x20 || ch >= 0x7f) ? '?' : ch;
}
- if (l < lmin)
- return (c1[0] > c2[0]) ? 1 : -1;
+ return result;
+}
- if (l1 == l2)
- return 0;
+CString UString::latin1() const
+{
+ // Basic Latin1 (ISO) encoding - Unicode characters 0..255 are
+ // preserved, characters outside of this range are converted to '?'.
+
+ unsigned length = this->length();
+ const UChar* characters = this->characters();
- return (l1 > l2) ? 1 : -1;
+ char* characterBuffer;
+ CString result = CString::newUninitialized(length, characterBuffer);
+
+ for (unsigned i = 0; i < length; ++i) {
+ UChar ch = characters[i];
+ characterBuffer[i] = ch > 0xff ? '?' : ch;
+ }
+
+ return result;
}
-CString UString::UTF8String(bool strict) const
+// Helper to write a three-byte UTF-8 code point to the buffer, caller must check room is available.
+static inline void putUTF8Triple(char*& buffer, UChar ch)
{
- // Allocate a buffer big enough to hold all the characters.
- const unsigned length = size();
+ ASSERT(ch >= 0x0800);
+ *buffer++ = static_cast<char>(((ch >> 12) & 0x0F) | 0xE0);
+ *buffer++ = static_cast<char>(((ch >> 6) & 0x3F) | 0x80);
+ *buffer++ = static_cast<char>((ch & 0x3F) | 0x80);
+}
+
+CString UString::utf8(bool strict) const
+{
+ unsigned length = this->length();
+ const UChar* characters = this->characters();
+
+ // Allocate a buffer big enough to hold all the characters
+ // (an individual UTF-16 UChar can only expand to 3 UTF-8 bytes).
+ // Optimization ideas, if we find this function is hot:
+ // * We could speculatively create a CStringBuffer to contain 'length'
+ // characters, and resize if necessary (i.e. if the buffer contains
+ // non-ascii characters). (Alternatively, scan the buffer first for
+ // ascii characters, so we know this will be sufficient).
+ // * We could allocate a CStringBuffer with an appropriate size to
+ // have a good chance of being able to write the string into the
+ // buffer without reallocing (say, 1.5 x length).
if (length > numeric_limits<unsigned>::max() / 3)
- return CString();
- Vector<char, 1024> buffer(length * 3);
-
- // Convert to runs of 8-bit characters.
- char* p = buffer.data();
- const UChar* d = reinterpret_cast<const UChar*>(&data()[0]);
- ConversionResult result = convertUTF16ToUTF8(&d, d + length, &p, p + buffer.size(), strict);
- if (result != conversionOK)
return CString();
+ Vector<char, 1024> bufferVector(length * 3);
+
+ char* buffer = bufferVector.data();
+ ConversionResult result = convertUTF16ToUTF8(&characters, characters + length, &buffer, buffer + bufferVector.size(), strict);
+ ASSERT(result != targetExhausted); // (length * 3) should be sufficient for any conversion
+
+ // Only produced from strict conversion.
+ if (result == sourceIllegal)
+ return CString();
+
+ // Check for an unconverted high surrogate.
+ if (result == sourceExhausted) {
+ if (strict)
+ return CString();
+ // This should be one unpaired high surrogate. Treat it the same
+ // was as an unpaired high surrogate would have been handled in
+ // the middle of a string with non-strict conversion - which is
+ // to say, simply encode it to UTF-8.
+ ASSERT((characters + 1) == (this->characters() + length));
+ ASSERT((*characters >= 0xD800) && (*characters <= 0xDBFF));
+ // There should be room left, since one UChar hasn't been converted.
+ ASSERT((buffer + 3) <= (buffer + bufferVector.size()));
+ putUTF8Triple(buffer, *characters);
+ }
- return CString(buffer.data(), p - buffer.data());
+ return CString(bufferVector.data(), buffer - bufferVector.data());
}
} // namespace JSC
/*
- * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
- * Copyright (C) 2009 Google Inc. All rights reserved.
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Google Inc. All rights reserved.
*
- * 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 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.
+ * 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.
+ * 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.
*
*/
#ifndef UString_h
#define UString_h
-#include "Collector.h"
-#include "UStringImpl.h"
-#include <stdint.h>
-#include <string.h>
-#include <wtf/Assertions.h>
-#include <wtf/CrossThreadRefCounted.h>
-#include <wtf/OwnFastMallocPtr.h>
-#include <wtf/PassRefPtr.h>
-#include <wtf/RefPtr.h>
-#include <wtf/Vector.h>
-#include <wtf/text/CString.h>
-#include <wtf/unicode/Unicode.h>
+#include <wtf/text/StringImpl.h>
namespace JSC {
- using WTF::PlacementNewAdoptType;
- using WTF::PlacementNewAdopt;
+class UString {
+public:
+ // Construct a null string, distinguishable from an empty string.
+ UString() { }
- class UString {
- friend class JIT;
+ // Construct a string with UTF-16 data.
+ UString(const UChar* characters, unsigned length);
- public:
- typedef UStringImpl Rep;
-
- public:
- UString() {}
- UString(const char*); // Constructor for null-terminated string.
- UString(const char*, unsigned length);
- UString(const UChar*, unsigned length);
- UString(const Vector<UChar>& buffer);
-
- UString(const UString& s)
- : m_rep(s.m_rep)
- {
- }
-
- // Special constructor for cases where we overwrite an object in place.
- UString(PlacementNewAdoptType)
- : m_rep(PlacementNewAdopt)
- {
- }
-
- template<size_t inlineCapacity>
- static PassRefPtr<UStringImpl> adopt(Vector<UChar, inlineCapacity>& vector)
- {
- return Rep::adopt(vector);
- }
-
- static UString from(int);
- static UString from(long long);
- static UString from(unsigned);
- static UString from(long);
- static UString from(double);
-
- // NOTE: This method should only be used for *debugging* purposes as it
- // is neither Unicode safe nor free from side effects nor thread-safe.
- char* ascii() const;
-
- /**
- * Convert the string to UTF-8, assuming it is UTF-16 encoded.
- * In non-strict mode, this function is tolerant of badly formed UTF-16, it
- * can create UTF-8 strings that are invalid because they have characters in
- * the range U+D800-U+DDFF, U+FFFE, or U+FFFF, but the UTF-8 string is
- * guaranteed to be otherwise valid.
- * In strict mode, error is returned as null CString.
- */
- CString UTF8String(bool strict = false) const;
-
- const UChar* data() const
- {
- if (!m_rep)
- return 0;
- return m_rep->characters();
- }
-
- unsigned size() const
- {
- if (!m_rep)
- return 0;
- return m_rep->length();
- }
-
- bool isNull() const { return !m_rep; }
- bool isEmpty() const { return !m_rep || !m_rep->length(); }
-
- bool is8Bit() const;
-
- UChar operator[](unsigned pos) const;
-
- double toDouble(bool tolerateTrailingJunk, bool tolerateEmptyString) const;
- double toDouble(bool tolerateTrailingJunk) const;
- double toDouble() const;
-
- uint32_t toUInt32(bool* ok = 0) const;
- uint32_t toUInt32(bool* ok, bool tolerateEmptyString) const;
- uint32_t toStrictUInt32(bool* ok = 0) const;
-
- unsigned toArrayIndex(bool* ok = 0) const;
-
- static const unsigned NotFound = 0xFFFFFFFFu;
- unsigned find(const UString& f, unsigned pos = 0) const;
- unsigned find(UChar, unsigned pos = 0) const;
- unsigned rfind(const UString& f, unsigned pos) const;
- unsigned rfind(UChar, unsigned pos) const;
-
- UString substr(unsigned pos = 0, unsigned len = 0xFFFFFFFF) const;
-
- static const UString& null() { return *s_nullUString; }
-
- Rep* rep() const { return m_rep.get(); }
-
- UString(PassRefPtr<Rep> r)
- : m_rep(r)
- {
- }
-
- size_t cost() const
- {
- if (!m_rep)
- return 0;
- return m_rep->cost();
- }
-
- private:
- RefPtr<Rep> m_rep;
-
- static UString* s_nullUString;
-
- friend void initializeUString();
- friend bool operator==(const UString&, const UString&);
- };
-
- ALWAYS_INLINE bool operator==(const UString& s1, const UString& s2)
- {
- UString::Rep* rep1 = s1.rep();
- UString::Rep* rep2 = s2.rep();
- unsigned size1 = 0;
- unsigned size2 = 0;
-
- if (rep1 == rep2) // If they're the same rep, they're equal.
- return true;
-
- if (rep1)
- size1 = rep1->length();
-
- if (rep2)
- size2 = rep2->length();
-
- if (size1 != size2) // If the lengths are not the same, we're done.
- return false;
-
- if (!size1)
- return true;
-
- // At this point we know
- // (a) that the strings are the same length and
- // (b) that they are greater than zero length.
- const UChar* d1 = rep1->characters();
- const UChar* d2 = rep2->characters();
-
- if (d1 == d2) // Check to see if the data pointers are the same.
- return true;
-
- // Do quick checks for sizes 1 and 2.
- switch (size1) {
- case 1:
- return d1[0] == d2[0];
- case 2:
- return (d1[0] == d2[0]) & (d1[1] == d2[1]);
- default:
- return memcmp(d1, d2, size1 * sizeof(UChar)) == 0;
- }
- }
+ // Construct a string with UTF-16 data, from a null-terminated source.
+ UString(const UChar*);
+ // Construct a string with latin1 data.
+ UString(const char* characters, unsigned length);
- inline bool operator!=(const UString& s1, const UString& s2)
- {
- return !JSC::operator==(s1, s2);
- }
+ // Construct a string with latin1 data, from a null-terminated source.
+ UString(const char* characters);
- bool operator<(const UString& s1, const UString& s2);
- bool operator>(const UString& s1, const UString& s2);
+ // Construct a string referencing an existing StringImpl.
+ UString(StringImpl* impl) : m_impl(impl) { }
+ UString(PassRefPtr<StringImpl> impl) : m_impl(impl) { }
+ UString(RefPtr<StringImpl> impl) : m_impl(impl) { }
- bool operator==(const UString& s1, const char* s2);
+ // Inline the destructor.
+ ALWAYS_INLINE ~UString() { }
- inline bool operator!=(const UString& s1, const char* s2)
- {
- return !JSC::operator==(s1, s2);
- }
+ void swap(UString& o) { m_impl.swap(o.m_impl); }
- inline bool operator==(const char *s1, const UString& s2)
- {
- return operator==(s2, s1);
- }
+ template<size_t inlineCapacity>
+ static UString adopt(Vector<UChar, inlineCapacity>& vector) { return StringImpl::adopt(vector); }
- inline bool operator!=(const char *s1, const UString& s2)
- {
- return !JSC::operator==(s1, s2);
- }
+ bool isNull() const { return !m_impl; }
+ bool isEmpty() const { return !m_impl || !m_impl->length(); }
- int compare(const UString&, const UString&);
+ StringImpl* impl() const { return m_impl.get(); }
- // Rule from ECMA 15.2 about what an array index is.
- // Must exactly match string form of an unsigned integer, and be less than 2^32 - 1.
- inline unsigned UString::toArrayIndex(bool* ok) const
+ unsigned length() const
{
- unsigned i = toStrictUInt32(ok);
- if (ok && i >= 0xFFFFFFFFU)
- *ok = false;
- return i;
- }
-
- // We'd rather not do shared substring append for small strings, since
- // this runs too much risk of a tiny initial string holding down a
- // huge buffer.
- static const unsigned minShareSize = Heap::minExtraCost / sizeof(UChar);
-
- struct IdentifierRepHash : PtrHash<RefPtr<JSC::UString::Rep> > {
- static unsigned hash(const RefPtr<JSC::UString::Rep>& key) { return key->existingHash(); }
- static unsigned hash(JSC::UString::Rep* key) { return key->existingHash(); }
- };
-
- void initializeUString();
-
- template<typename StringType>
- class StringTypeAdapter {
- };
-
- template<>
- class StringTypeAdapter<char*> {
- public:
- StringTypeAdapter<char*>(char* buffer)
- : m_buffer((unsigned char*)buffer)
- , m_length(strlen(buffer))
- {
- }
-
- unsigned length() { return m_length; }
-
- void writeTo(UChar* destination)
- {
- for (unsigned i = 0; i < m_length; ++i)
- destination[i] = m_buffer[i];
- }
-
- private:
- const unsigned char* m_buffer;
- unsigned m_length;
- };
-
- template<>
- class StringTypeAdapter<const char*> {
- public:
- StringTypeAdapter<const char*>(const char* buffer)
- : m_buffer((unsigned char*)buffer)
- , m_length(strlen(buffer))
- {
- }
-
- unsigned length() { return m_length; }
-
- void writeTo(UChar* destination)
- {
- for (unsigned i = 0; i < m_length; ++i)
- destination[i] = m_buffer[i];
- }
-
- private:
- const unsigned char* m_buffer;
- unsigned m_length;
- };
-
- template<>
- class StringTypeAdapter<UString> {
- public:
- StringTypeAdapter<UString>(UString& string)
- : m_data(string.data())
- , m_length(string.size())
- {
- }
-
- unsigned length() { return m_length; }
-
- void writeTo(UChar* destination)
- {
- for (unsigned i = 0; i < m_length; ++i)
- destination[i] = m_data[i];
- }
-
- private:
- const UChar* m_data;
- unsigned m_length;
- };
-
- inline void sumWithOverflow(unsigned& total, unsigned addend, bool& overflow)
- {
- unsigned oldTotal = total;
- total = oldTotal + addend;
- if (total < oldTotal)
- overflow = true;
- }
-
- template<typename StringType1, typename StringType2>
- PassRefPtr<UStringImpl> tryMakeString(StringType1 string1, StringType2 string2)
- {
- StringTypeAdapter<StringType1> adapter1(string1);
- StringTypeAdapter<StringType2> adapter2(string2);
-
- UChar* buffer;
- bool overflow = false;
- unsigned length = adapter1.length();
- sumWithOverflow(length, adapter2.length(), overflow);
- if (overflow)
- return 0;
- PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer);
- if (!resultImpl)
+ if (!m_impl)
return 0;
-
- UChar* result = buffer;
- adapter1.writeTo(result);
- result += adapter1.length();
- adapter2.writeTo(result);
-
- return resultImpl;
+ return m_impl->length();
}
- template<typename StringType1, typename StringType2, typename StringType3>
- PassRefPtr<UStringImpl> tryMakeString(StringType1 string1, StringType2 string2, StringType3 string3)
+ const UChar* characters() const
{
- StringTypeAdapter<StringType1> adapter1(string1);
- StringTypeAdapter<StringType2> adapter2(string2);
- StringTypeAdapter<StringType3> adapter3(string3);
-
- UChar* buffer = 0;
- bool overflow = false;
- unsigned length = adapter1.length();
- sumWithOverflow(length, adapter2.length(), overflow);
- sumWithOverflow(length, adapter3.length(), overflow);
- if (overflow)
+ if (!m_impl)
return 0;
- PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer);
- if (!resultImpl)
- return 0;
-
- UChar* result = buffer;
- adapter1.writeTo(result);
- result += adapter1.length();
- adapter2.writeTo(result);
- result += adapter2.length();
- adapter3.writeTo(result);
-
- return resultImpl;
+ return m_impl->characters();
}
- template<typename StringType1, typename StringType2, typename StringType3, typename StringType4>
- PassRefPtr<UStringImpl> tryMakeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4)
+ CString ascii() const;
+ CString latin1() const;
+ CString utf8(bool strict = false) const;
+
+ UChar operator[](unsigned index) const
{
- StringTypeAdapter<StringType1> adapter1(string1);
- StringTypeAdapter<StringType2> adapter2(string2);
- StringTypeAdapter<StringType3> adapter3(string3);
- StringTypeAdapter<StringType4> adapter4(string4);
-
- UChar* buffer;
- bool overflow = false;
- unsigned length = adapter1.length();
- sumWithOverflow(length, adapter2.length(), overflow);
- sumWithOverflow(length, adapter3.length(), overflow);
- sumWithOverflow(length, adapter4.length(), overflow);
- if (overflow)
+ if (!m_impl || index >= m_impl->length())
return 0;
- PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer);
- if (!resultImpl)
- return 0;
-
- UChar* result = buffer;
- adapter1.writeTo(result);
- result += adapter1.length();
- adapter2.writeTo(result);
- result += adapter2.length();
- adapter3.writeTo(result);
- result += adapter3.length();
- adapter4.writeTo(result);
+ return m_impl->characters()[index];
+ }
- return resultImpl;
+ static UString number(int);
+ static UString number(unsigned);
+ static UString number(long);
+ static UString number(long long);
+ static UString number(double);
+
+ // Find a single character or string, also with match function & latin1 forms.
+ size_t find(UChar c, unsigned start = 0) const
+ { return m_impl ? m_impl->find(c, start) : notFound; }
+ size_t find(const UString& str, unsigned start = 0) const
+ { return m_impl ? m_impl->find(str.impl(), start) : notFound; }
+ size_t find(const char* str, unsigned start = 0) const
+ { return m_impl ? m_impl->find(str, start) : notFound; }
+
+ // Find the last instance of a single character or string.
+ size_t reverseFind(UChar c, unsigned start = UINT_MAX) const
+ { return m_impl ? m_impl->reverseFind(c, start) : notFound; }
+ size_t reverseFind(const UString& str, unsigned start = UINT_MAX) const
+ { return m_impl ? m_impl->reverseFind(str.impl(), start) : notFound; }
+
+ UString substringSharingImpl(unsigned pos, unsigned len = UINT_MAX) const;
+
+private:
+ RefPtr<StringImpl> m_impl;
+};
+
+ALWAYS_INLINE bool operator==(const UString& s1, const UString& s2)
+{
+ StringImpl* rep1 = s1.impl();
+ StringImpl* rep2 = s2.impl();
+ unsigned size1 = 0;
+ unsigned size2 = 0;
+
+ if (rep1 == rep2) // If they're the same rep, they're equal.
+ return true;
+
+ if (rep1)
+ size1 = rep1->length();
+
+ if (rep2)
+ size2 = rep2->length();
+
+ if (size1 != size2) // If the lengths are not the same, we're done.
+ return false;
+
+ if (!size1)
+ return true;
+
+ // At this point we know
+ // (a) that the strings are the same length and
+ // (b) that they are greater than zero length.
+ const UChar* d1 = rep1->characters();
+ const UChar* d2 = rep2->characters();
+
+ if (d1 == d2) // Check to see if the data pointers are the same.
+ return true;
+
+ // Do quick checks for sizes 1 and 2.
+ switch (size1) {
+ case 1:
+ return d1[0] == d2[0];
+ case 2:
+ return (d1[0] == d2[0]) & (d1[1] == d2[1]);
+ default:
+ return memcmp(d1, d2, size1 * sizeof(UChar)) == 0;
}
+}
- template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5>
- PassRefPtr<UStringImpl> tryMakeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5)
- {
- StringTypeAdapter<StringType1> adapter1(string1);
- StringTypeAdapter<StringType2> adapter2(string2);
- StringTypeAdapter<StringType3> adapter3(string3);
- StringTypeAdapter<StringType4> adapter4(string4);
- StringTypeAdapter<StringType5> adapter5(string5);
-
- UChar* buffer;
- bool overflow = false;
- unsigned length = adapter1.length();
- sumWithOverflow(length, adapter2.length(), overflow);
- sumWithOverflow(length, adapter3.length(), overflow);
- sumWithOverflow(length, adapter4.length(), overflow);
- sumWithOverflow(length, adapter5.length(), overflow);
- if (overflow)
- return 0;
- PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer);
- if (!resultImpl)
- return 0;
- UChar* result = buffer;
- adapter1.writeTo(result);
- result += adapter1.length();
- adapter2.writeTo(result);
- result += adapter2.length();
- adapter3.writeTo(result);
- result += adapter3.length();
- adapter4.writeTo(result);
- result += adapter4.length();
- adapter5.writeTo(result);
-
- return resultImpl;
- }
+inline bool operator!=(const UString& s1, const UString& s2)
+{
+ return !JSC::operator==(s1, s2);
+}
- template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6>
- PassRefPtr<UStringImpl> tryMakeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6)
- {
- StringTypeAdapter<StringType1> adapter1(string1);
- StringTypeAdapter<StringType2> adapter2(string2);
- StringTypeAdapter<StringType3> adapter3(string3);
- StringTypeAdapter<StringType4> adapter4(string4);
- StringTypeAdapter<StringType5> adapter5(string5);
- StringTypeAdapter<StringType6> adapter6(string6);
-
- UChar* buffer;
- bool overflow = false;
- unsigned length = adapter1.length();
- sumWithOverflow(length, adapter2.length(), overflow);
- sumWithOverflow(length, adapter3.length(), overflow);
- sumWithOverflow(length, adapter4.length(), overflow);
- sumWithOverflow(length, adapter5.length(), overflow);
- sumWithOverflow(length, adapter6.length(), overflow);
- if (overflow)
- return 0;
- PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer);
- if (!resultImpl)
- return 0;
+bool operator<(const UString& s1, const UString& s2);
+bool operator>(const UString& s1, const UString& s2);
- UChar* result = buffer;
- adapter1.writeTo(result);
- result += adapter1.length();
- adapter2.writeTo(result);
- result += adapter2.length();
- adapter3.writeTo(result);
- result += adapter3.length();
- adapter4.writeTo(result);
- result += adapter4.length();
- adapter5.writeTo(result);
- result += adapter5.length();
- adapter6.writeTo(result);
-
- return resultImpl;
- }
+bool operator==(const UString& s1, const char* s2);
- template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7>
- PassRefPtr<UStringImpl> tryMakeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7)
- {
- StringTypeAdapter<StringType1> adapter1(string1);
- StringTypeAdapter<StringType2> adapter2(string2);
- StringTypeAdapter<StringType3> adapter3(string3);
- StringTypeAdapter<StringType4> adapter4(string4);
- StringTypeAdapter<StringType5> adapter5(string5);
- StringTypeAdapter<StringType6> adapter6(string6);
- StringTypeAdapter<StringType7> adapter7(string7);
-
- UChar* buffer;
- bool overflow = false;
- unsigned length = adapter1.length();
- sumWithOverflow(length, adapter2.length(), overflow);
- sumWithOverflow(length, adapter3.length(), overflow);
- sumWithOverflow(length, adapter4.length(), overflow);
- sumWithOverflow(length, adapter5.length(), overflow);
- sumWithOverflow(length, adapter6.length(), overflow);
- sumWithOverflow(length, adapter7.length(), overflow);
- if (overflow)
- return 0;
- PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer);
- if (!resultImpl)
- return 0;
+inline bool operator!=(const UString& s1, const char* s2)
+{
+ return !JSC::operator==(s1, s2);
+}
- UChar* result = buffer;
- adapter1.writeTo(result);
- result += adapter1.length();
- adapter2.writeTo(result);
- result += adapter2.length();
- adapter3.writeTo(result);
- result += adapter3.length();
- adapter4.writeTo(result);
- result += adapter4.length();
- adapter5.writeTo(result);
- result += adapter5.length();
- adapter6.writeTo(result);
- result += adapter6.length();
- adapter7.writeTo(result);
-
- return resultImpl;
- }
+inline bool operator==(const char *s1, const UString& s2)
+{
+ return operator==(s2, s1);
+}
- template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7, typename StringType8>
- PassRefPtr<UStringImpl> tryMakeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7, StringType8 string8)
- {
- StringTypeAdapter<StringType1> adapter1(string1);
- StringTypeAdapter<StringType2> adapter2(string2);
- StringTypeAdapter<StringType3> adapter3(string3);
- StringTypeAdapter<StringType4> adapter4(string4);
- StringTypeAdapter<StringType5> adapter5(string5);
- StringTypeAdapter<StringType6> adapter6(string6);
- StringTypeAdapter<StringType7> adapter7(string7);
- StringTypeAdapter<StringType8> adapter8(string8);
-
- UChar* buffer;
- bool overflow = false;
- unsigned length = adapter1.length();
- sumWithOverflow(length, adapter2.length(), overflow);
- sumWithOverflow(length, adapter3.length(), overflow);
- sumWithOverflow(length, adapter4.length(), overflow);
- sumWithOverflow(length, adapter5.length(), overflow);
- sumWithOverflow(length, adapter6.length(), overflow);
- sumWithOverflow(length, adapter7.length(), overflow);
- sumWithOverflow(length, adapter8.length(), overflow);
- if (overflow)
- return 0;
- PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer);
- if (!resultImpl)
- return 0;
+inline bool operator!=(const char *s1, const UString& s2)
+{
+ return !JSC::operator==(s1, s2);
+}
- UChar* result = buffer;
- adapter1.writeTo(result);
- result += adapter1.length();
- adapter2.writeTo(result);
- result += adapter2.length();
- adapter3.writeTo(result);
- result += adapter3.length();
- adapter4.writeTo(result);
- result += adapter4.length();
- adapter5.writeTo(result);
- result += adapter5.length();
- adapter6.writeTo(result);
- result += adapter6.length();
- adapter7.writeTo(result);
- result += adapter7.length();
- adapter8.writeTo(result);
-
- return resultImpl;
- }
+inline int codePointCompare(const UString& s1, const UString& s2)
+{
+ return codePointCompare(s1.impl(), s2.impl());
+}
- template<typename StringType1, typename StringType2>
- UString makeString(StringType1 string1, StringType2 string2)
+struct UStringHash {
+ static unsigned hash(StringImpl* key) { return key->hash(); }
+ static bool equal(const StringImpl* a, const StringImpl* b)
{
- PassRefPtr<UStringImpl> resultImpl = tryMakeString(string1, string2);
- if (!resultImpl)
- CRASH();
- return resultImpl;
- }
+ if (a == b)
+ return true;
+ if (!a || !b)
+ return false;
- template<typename StringType1, typename StringType2, typename StringType3>
- UString makeString(StringType1 string1, StringType2 string2, StringType3 string3)
- {
- PassRefPtr<UStringImpl> resultImpl = tryMakeString(string1, string2, string3);
- if (!resultImpl)
- CRASH();
- return resultImpl;
- }
+ unsigned aLength = a->length();
+ unsigned bLength = b->length();
+ if (aLength != bLength)
+ return false;
- template<typename StringType1, typename StringType2, typename StringType3, typename StringType4>
- UString makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4)
- {
- PassRefPtr<UStringImpl> resultImpl = tryMakeString(string1, string2, string3, string4);
- if (!resultImpl)
- CRASH();
- return resultImpl;
- }
+ // FIXME: perhaps we should have a more abstract macro that indicates when
+ // going 4 bytes at a time is unsafe
+#if CPU(ARM) || CPU(SH4) || CPU(MIPS)
+ const UChar* aChars = a->characters();
+ const UChar* bChars = b->characters();
+ for (unsigned i = 0; i != aLength; ++i) {
+ if (*aChars++ != *bChars++)
+ return false;
+ }
+ return true;
+#else
+ /* Do it 4-bytes-at-a-time on architectures where it's safe */
+ const uint32_t* aChars = reinterpret_cast<const uint32_t*>(a->characters());
+ const uint32_t* bChars = reinterpret_cast<const uint32_t*>(b->characters());
+
+ unsigned halfLength = aLength >> 1;
+ for (unsigned i = 0; i != halfLength; ++i)
+ if (*aChars++ != *bChars++)
+ return false;
+
+ if (aLength & 1 && *reinterpret_cast<const uint16_t*>(aChars) != *reinterpret_cast<const uint16_t*>(bChars))
+ return false;
- template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5>
- UString makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5)
- {
- PassRefPtr<UStringImpl> resultImpl = tryMakeString(string1, string2, string3, string4, string5);
- if (!resultImpl)
- CRASH();
- return resultImpl;
+ return true;
+#endif
}
- template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6>
- UString makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6)
+ static unsigned hash(const RefPtr<StringImpl>& key) { return key->hash(); }
+ static bool equal(const RefPtr<StringImpl>& a, const RefPtr<StringImpl>& b)
{
- PassRefPtr<UStringImpl> resultImpl = tryMakeString(string1, string2, string3, string4, string5, string6);
- if (!resultImpl)
- CRASH();
- return resultImpl;
+ return equal(a.get(), b.get());
}
- template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7>
- UString makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7)
+ static unsigned hash(const UString& key) { return key.impl()->hash(); }
+ static bool equal(const UString& a, const UString& b)
{
- PassRefPtr<UStringImpl> resultImpl = tryMakeString(string1, string2, string3, string4, string5, string6, string7);
- if (!resultImpl)
- CRASH();
- return resultImpl;
+ return equal(a.impl(), b.impl());
}
- template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7, typename StringType8>
- UString makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7, StringType8 string8)
- {
- PassRefPtr<UStringImpl> resultImpl = tryMakeString(string1, string2, string3, string4, string5, string6, string7, string8);
- if (!resultImpl)
- CRASH();
- return resultImpl;
- }
+ static const bool safeToCompareToEmptyOrDeleted = false;
+};
} // namespace JSC
namespace WTF {
- template<typename T> struct DefaultHash;
- template<typename T> struct StrHash;
-
- template<> struct StrHash<JSC::UString::Rep*> {
- static unsigned hash(const JSC::UString::Rep* key) { return key->hash(); }
- static bool equal(const JSC::UString::Rep* a, const JSC::UString::Rep* b) { return ::equal(a, b); }
- static const bool safeToCompareToEmptyOrDeleted = false;
- };
-
- template<> struct StrHash<RefPtr<JSC::UString::Rep> > : public StrHash<JSC::UString::Rep*> {
- using StrHash<JSC::UString::Rep*>::hash;
- static unsigned hash(const RefPtr<JSC::UString::Rep>& key) { return key->hash(); }
- using StrHash<JSC::UString::Rep*>::equal;
- static bool equal(const RefPtr<JSC::UString::Rep>& a, const RefPtr<JSC::UString::Rep>& b) { return ::equal(a.get(), b.get()); }
- static bool equal(const JSC::UString::Rep* a, const RefPtr<JSC::UString::Rep>& b) { return ::equal(a, b.get()); }
- static bool equal(const RefPtr<JSC::UString::Rep>& a, const JSC::UString::Rep* b) { return ::equal(a.get(), b); }
+// UStringHash is the default hash for UString
+template<typename T> struct DefaultHash;
+template<> struct DefaultHash<JSC::UString> {
+ typedef JSC::UStringHash Hash;
+};
- static const bool safeToCompareToEmptyOrDeleted = false;
- };
+template <> struct VectorTraits<JSC::UString> : SimpleClassVectorTraits { };
- template <> struct VectorTraits<JSC::UString> : SimpleClassVectorTraits
- {
- static const bool canInitializeWithMemset = true;
- };
-
} // namespace WTF
#endif
+
--- /dev/null
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UStringBuilder_h
+#define UStringBuilder_h
+
+#include <wtf/text/StringBuilder.h>
+
+namespace JSC {
+
+class UStringBuilder : public StringBuilder {
+public:
+ using StringBuilder::append;
+ void append(const UString& str) { append(String(str.impl())); }
+
+ UString toUString() { return toString().impl(); }
+};
+
+} // namespace JSC
+
+#endif // UStringBuilder_h
--- /dev/null
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UStringConcatenate_h
+#define UStringConcatenate_h
+
+#include "UString.h"
+#include <wtf/text/StringConcatenate.h>
+
+namespace WTF {
+
+template<>
+class StringTypeAdapter<JSC::UString> {
+public:
+ StringTypeAdapter<JSC::UString>(JSC::UString& string)
+ : m_data(string.characters())
+ , m_length(string.length())
+ {
+ }
+
+ unsigned length() { return m_length; }
+
+ void writeTo(UChar* destination)
+ {
+ for (unsigned i = 0; i < m_length; ++i)
+ destination[i] = m_data[i];
+ }
+
+private:
+ const UChar* m_data;
+ unsigned m_length;
+};
+
+}; // namespace WTF
+
+namespace JSC {
+
+template<typename StringType1, typename StringType2>
+UString makeUString(StringType1 string1, StringType2 string2)
+{
+ PassRefPtr<StringImpl> resultImpl = WTF::tryMakeString(string1, string2);
+ if (!resultImpl)
+ CRASH();
+ return resultImpl;
+}
+
+template<typename StringType1, typename StringType2, typename StringType3>
+UString makeUString(StringType1 string1, StringType2 string2, StringType3 string3)
+{
+ PassRefPtr<StringImpl> resultImpl = WTF::tryMakeString(string1, string2, string3);
+ if (!resultImpl)
+ CRASH();
+ return resultImpl;
+}
+
+template<typename StringType1, typename StringType2, typename StringType3, typename StringType4>
+UString makeUString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4)
+{
+ PassRefPtr<StringImpl> resultImpl = WTF::tryMakeString(string1, string2, string3, string4);
+ if (!resultImpl)
+ CRASH();
+ return resultImpl;
+}
+
+template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5>
+UString makeUString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5)
+{
+ PassRefPtr<StringImpl> resultImpl = WTF::tryMakeString(string1, string2, string3, string4, string5);
+ if (!resultImpl)
+ CRASH();
+ return resultImpl;
+}
+
+template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6>
+UString makeUString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6)
+{
+ PassRefPtr<StringImpl> resultImpl = WTF::tryMakeString(string1, string2, string3, string4, string5, string6);
+ if (!resultImpl)
+ CRASH();
+ return resultImpl;
+}
+
+template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7>
+UString makeUString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7)
+{
+ PassRefPtr<StringImpl> resultImpl = WTF::tryMakeString(string1, string2, string3, string4, string5, string6, string7);
+ if (!resultImpl)
+ CRASH();
+ return resultImpl;
+}
+
+template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7, typename StringType8>
+UString makeUString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7, StringType8 string8)
+{
+ PassRefPtr<StringImpl> resultImpl = WTF::tryMakeString(string1, string2, string3, string4, string5, string6, string7, string8);
+ if (!resultImpl)
+ CRASH();
+ return resultImpl;
+}
+
+} // namespace JSC
+
+#endif
+++ /dev/null
-/*
- * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
- * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
- * Copyright (C) 2009 Google Inc. All rights reserved.
- *
- * 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.
- *
- */
-
-#ifndef UStringImpl_h
-#define UStringImpl_h
-
-// FIXME: Remove this redundant name!
-#include <wtf/text/StringImpl.h>
-namespace JSC { typedef WebCore::StringImpl UStringImpl; }
-
-#endif
#ifndef WeakGCMap_h
#define WeakGCMap_h
-#include "Collector.h"
+#include "Handle.h"
+#include "JSGlobalData.h"
#include <wtf/HashMap.h>
namespace JSC {
-class JSCell;
+// A HashMap for GC'd values that removes entries when the associated value
+// dies.
+template <typename KeyType, typename MappedType> struct DefaultWeakGCMapFinalizerCallback {
+ static void* finalizerContextFor(KeyType key)
+ {
+ return reinterpret_cast<void*>(key);
+ }
+
+ static KeyType keyForFinalizer(void* context, typename HandleTypes<MappedType>::ExternalType)
+ {
+ return reinterpret_cast<KeyType>(context);
+ }
+};
-// A HashMap whose get() function returns emptyValue() for cells awaiting destruction.
-template<typename KeyType, typename MappedType>
-class WeakGCMap : public FastAllocBase {
- /*
- Invariants:
- * A value enters the WeakGCMap marked. (Guaranteed by set().)
- * A value that becomes unmarked leaves the WeakGCMap before being recycled. (Guaranteed by the value's destructor removing it from the WeakGCMap.)
- * A value that becomes unmarked leaves the WeakGCMap before becoming marked again. (Guaranteed by all destructors running before the mark phase begins.)
- * During the mark phase, all values in the WeakGCMap are valid. (Guaranteed by all destructors running before the mark phase begins.)
- */
+template<typename KeyType, typename MappedType, typename FinalizerCallback = DefaultWeakGCMapFinalizerCallback<KeyType, MappedType>, typename HashArg = typename DefaultHash<KeyType>::Hash, typename KeyTraitsArg = HashTraits<KeyType> >
+class WeakGCMap : private WeakHandleOwner {
+ WTF_MAKE_FAST_ALLOCATED;
+ WTF_MAKE_NONCOPYABLE(WeakGCMap);
+
+ typedef HashMap<KeyType, HandleSlot, HashArg, KeyTraitsArg> MapType;
+ typedef typename HandleTypes<MappedType>::ExternalType ExternalType;
+ typedef typename MapType::iterator map_iterator;
public:
- typedef typename HashMap<KeyType, MappedType>::iterator iterator;
- typedef typename HashMap<KeyType, MappedType>::const_iterator const_iterator;
-
+
+ struct iterator {
+ friend class WeakGCMap;
+ iterator(map_iterator iter)
+ : m_iterator(iter)
+ {
+ }
+
+ std::pair<KeyType, ExternalType> get() const { return std::make_pair(m_iterator->first, HandleTypes<MappedType>::getFromSlot(m_iterator->second)); }
+ std::pair<KeyType, HandleSlot> getSlot() const { return *m_iterator; }
+
+ iterator& operator++() { ++m_iterator; return *this; }
+
+ // postfix ++ intentionally omitted
+
+ // Comparison.
+ bool operator==(const iterator& other) const { return m_iterator == other.m_iterator; }
+ bool operator!=(const iterator& other) const { return m_iterator != other.m_iterator; }
+
+ private:
+ map_iterator m_iterator;
+ };
+
+ WeakGCMap()
+ {
+ }
+
bool isEmpty() { return m_map.isEmpty(); }
+ void clear()
+ {
+ map_iterator end = m_map.end();
+ for (map_iterator ptr = m_map.begin(); ptr != end; ++ptr)
+ HandleHeap::heapFor(ptr->second)->deallocate(ptr->second);
+ m_map.clear();
+ }
- MappedType get(const KeyType& key) const;
- pair<iterator, bool> set(const KeyType&, const MappedType&);
- MappedType take(const KeyType& key);
+ bool contains(const KeyType& key) const
+ {
+ return m_map.contains(key);
+ }
- // These unchecked functions provide access to a value even if the value's
- // mark bit is not set. This is used, among other things, to retrieve values
- // during the GC mark phase, which begins by clearing all mark bits.
+ iterator find(const KeyType& key)
+ {
+ return m_map.find(key);
+ }
- MappedType uncheckedGet(const KeyType& key) const { return m_map.get(key); }
- bool uncheckedRemove(const KeyType&, const MappedType&);
+ void remove(iterator iter)
+ {
+ ASSERT(iter.m_iterator != m_map.end());
+ HandleSlot slot = iter.m_iterator->second;
+ ASSERT(slot);
+ HandleHeap::heapFor(slot)->deallocate(slot);
+ m_map.remove(iter.m_iterator);
+ }
- iterator uncheckedBegin() { return m_map.begin(); }
- iterator uncheckedEnd() { return m_map.end(); }
+ ExternalType get(const KeyType& key) const
+ {
+ return HandleTypes<MappedType>::getFromSlot(m_map.get(key));
+ }
- const_iterator uncheckedBegin() const { return m_map.begin(); }
- const_iterator uncheckedEnd() const { return m_map.end(); }
+ HandleSlot getSlot(const KeyType& key) const
+ {
+ return m_map.get(key);
+ }
-private:
- HashMap<KeyType, MappedType> m_map;
-};
+ pair<iterator, bool> add(JSGlobalData& globalData, const KeyType& key, ExternalType value)
+ {
+ pair<typename MapType::iterator, bool> iter = m_map.add(key, 0);
+ if (iter.second) {
+ HandleSlot slot = globalData.allocateGlobalHandle();
+ iter.first->second = slot;
+ HandleHeap::heapFor(slot)->makeWeak(slot, this, FinalizerCallback::finalizerContextFor(key));
+ HandleHeap::heapFor(slot)->writeBarrier(slot, value);
+ *slot = value;
+ }
+ return iter;
+ }
+
+ void set(iterator iter, ExternalType value)
+ {
+ HandleSlot slot = iter.m_iterator->second;
+ ASSERT(slot);
+ HandleHeap::heapFor(slot)->writeBarrier(slot, value);
+ *slot = value;
+ }
-template<typename KeyType, typename MappedType>
-inline MappedType WeakGCMap<KeyType, MappedType>::get(const KeyType& key) const
-{
- MappedType result = m_map.get(key);
- if (result == HashTraits<MappedType>::emptyValue())
- return result;
- if (!Heap::isCellMarked(result))
- return HashTraits<MappedType>::emptyValue();
- return result;
-}
-
-template<typename KeyType, typename MappedType>
-MappedType WeakGCMap<KeyType, MappedType>::take(const KeyType& key)
-{
- MappedType result = m_map.take(key);
- if (result == HashTraits<MappedType>::emptyValue())
+ void set(JSGlobalData& globalData, const KeyType& key, ExternalType value)
+ {
+ pair<typename MapType::iterator, bool> iter = m_map.add(key, 0);
+ HandleSlot slot = iter.first->second;
+ if (iter.second) {
+ slot = globalData.allocateGlobalHandle();
+ HandleHeap::heapFor(slot)->makeWeak(slot, this, key);
+ iter.first->second = slot;
+ }
+ HandleHeap::heapFor(slot)->writeBarrier(slot, value);
+ *slot = value;
+ }
+
+ ExternalType take(const KeyType& key)
+ {
+ HandleSlot slot = m_map.take(key);
+ if (!slot)
+ return HashTraits<ExternalType>::emptyValue();
+ ExternalType result = HandleTypes<MappedType>::getFromSlot(slot);
+ HandleHeap::heapFor(slot)->deallocate(slot);
return result;
- if (!Heap::isCellMarked(result))
- return HashTraits<MappedType>::emptyValue();
- return result;
-}
-
-template<typename KeyType, typename MappedType>
-pair<typename HashMap<KeyType, MappedType>::iterator, bool> WeakGCMap<KeyType, MappedType>::set(const KeyType& key, const MappedType& value)
-{
- Heap::markCell(value); // If value is newly allocated, it's not marked, so mark it now.
- pair<iterator, bool> result = m_map.add(key, value);
- if (!result.second) { // pre-existing entry
- result.second = !Heap::isCellMarked(result.first->second);
- result.first->second = value;
}
- return result;
-}
-
-template<typename KeyType, typename MappedType>
-bool WeakGCMap<KeyType, MappedType>::uncheckedRemove(const KeyType& key, const MappedType& value)
-{
- iterator it = m_map.find(key);
- if (it == m_map.end())
- return false;
- if (it->second != value)
- return false;
- m_map.remove(it);
- return true;
-}
+
+ size_t size() { return m_map.size(); }
+
+ iterator begin() { return iterator(m_map.begin()); }
+ iterator end() { return iterator(m_map.end()); }
+
+ ~WeakGCMap()
+ {
+ clear();
+ }
+
+private:
+ virtual void finalize(Handle<Unknown> handle, void* context)
+ {
+ HandleSlot slot = m_map.take(FinalizerCallback::keyForFinalizer(context, HandleTypes<MappedType>::getFromSlot(handle.slot())));
+ ASSERT(slot);
+ HandleHeap::heapFor(slot)->deallocate(slot);
+ }
+
+ MapType m_map;
+};
} // namespace JSC
+++ /dev/null
-/*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef WeakGCPtr_h
-#define WeakGCPtr_h
-
-#include "Collector.h"
-#include <wtf/Noncopyable.h>
-
-namespace JSC {
-
-// A smart pointer whose get() function returns 0 for cells awaiting destruction.
-template <typename T> class WeakGCPtr : Noncopyable {
-public:
- WeakGCPtr() : m_ptr(0) { }
- WeakGCPtr(T* ptr) { assign(ptr); }
-
- T* get() const
- {
- if (!m_ptr || !Heap::isCellMarked(m_ptr))
- return 0;
- return m_ptr;
- }
-
- bool clear(JSCell* ptr)
- {
- if (ptr == m_ptr) {
- m_ptr = 0;
- return true;
- }
- return false;
- }
-
- T& operator*() const { return *get(); }
- T* operator->() const { return get(); }
-
- bool operator!() const { return !get(); }
-
- // This conversion operator allows implicit conversion to bool but not to other integer types.
-#if COMPILER(WINSCW)
- operator bool() const { return m_ptr; }
-#else
- typedef T* WeakGCPtr::*UnspecifiedBoolType;
- operator UnspecifiedBoolType() const { return get() ? &WeakGCPtr::m_ptr : 0; }
-#endif
-
- WeakGCPtr& operator=(T*);
-
-#if !ASSERT_DISABLED
- bool hasDeadObject() const { return !!m_ptr; }
-#endif
-
-private:
- void assign(T* ptr)
- {
- ASSERT(ptr);
- Heap::markCell(ptr);
- m_ptr = ptr;
- }
-
- T* m_ptr;
-};
-
-template <typename T> inline WeakGCPtr<T>& WeakGCPtr<T>::operator=(T* optr)
-{
- assign(optr);
- return *this;
-}
-
-template <typename T, typename U> inline bool operator==(const WeakGCPtr<T>& a, const WeakGCPtr<U>& b)
-{
- return a.get() == b.get();
-}
-
-template <typename T, typename U> inline bool operator==(const WeakGCPtr<T>& a, U* b)
-{
- return a.get() == b;
-}
-
-template <typename T, typename U> inline bool operator==(T* a, const WeakGCPtr<U>& b)
-{
- return a == b.get();
-}
-
-template <typename T, typename U> inline bool operator!=(const WeakGCPtr<T>& a, const WeakGCPtr<U>& b)
-{
- return a.get() != b.get();
-}
-
-template <typename T, typename U> inline bool operator!=(const WeakGCPtr<T>& a, U* b)
-{
- return a.get() != b;
-}
-
-template <typename T, typename U> inline bool operator!=(T* a, const WeakGCPtr<U>& b)
-{
- return a != b.get();
-}
-
-template <typename T, typename U> inline WeakGCPtr<T> static_pointer_cast(const WeakGCPtr<U>& p)
-{
- return WeakGCPtr<T>(static_cast<T*>(p.get()));
-}
-
-template <typename T, typename U> inline WeakGCPtr<T> const_pointer_cast(const WeakGCPtr<U>& p)
-{
- return WeakGCPtr<T>(const_cast<T*>(p.get()));
-}
-
-template <typename T> inline T* getPtr(const WeakGCPtr<T>& p)
-{
- return p.get();
-}
-
-} // namespace JSC
-
-#endif // WeakGCPtr_h
return advance() / (UINT_MAX + 1.0);
}
+ unsigned getUint32()
+ {
+ return advance();
+ }
+
private:
unsigned advance()
{
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WriteBarrier_h
+#define WriteBarrier_h
+
+#include "HandleTypes.h"
+#include "Heap.h"
+#include "TypeTraits.h"
+
+namespace JSC {
+
+class JSCell;
+class JSGlobalData;
+class JSGlobalObject;
+
+template<class T> class WriteBarrierBase;
+template<> class WriteBarrierBase<JSValue>;
+
+void slowValidateCell(JSCell*);
+void slowValidateCell(JSGlobalObject*);
+
+#if ENABLE(GC_VALIDATION)
+template<class T> inline void validateCell(T cell)
+{
+ ASSERT_GC_OBJECT_INHERITS(cell, &WTF::RemovePointer<T>::Type::s_info);
+}
+
+template<> inline void validateCell<JSCell*>(JSCell* cell)
+{
+ slowValidateCell(cell);
+}
+
+template<> inline void validateCell<JSGlobalObject*>(JSGlobalObject* globalObject)
+{
+ slowValidateCell(globalObject);
+}
+#else
+template<class T> inline void validateCell(T)
+{
+}
+#endif
+
+// We have a separate base class with no constructors for use in Unions.
+template <typename T> class WriteBarrierBase {
+public:
+ void set(JSGlobalData& globalData, const JSCell* owner, T* value)
+ {
+ ASSERT(value);
+ validateCell(value);
+ setEarlyValue(globalData, owner, value);
+ }
+
+ void setMayBeNull(JSGlobalData& globalData, const JSCell* owner, T* value)
+ {
+ if (value)
+ validateCell(value);
+ setEarlyValue(globalData, owner, value);
+ }
+
+ // Should only be used by JSCell during early initialisation
+ // when some basic types aren't yet completely instantiated
+ void setEarlyValue(JSGlobalData&, const JSCell* owner, T* value)
+ {
+ this->m_cell = reinterpret_cast<JSCell*>(value);
+ Heap::writeBarrier(owner, this->m_cell);
+#if ENABLE(JSC_ZOMBIES)
+ ASSERT(!isZombie(owner));
+ ASSERT(!isZombie(m_cell));
+#endif
+ }
+
+ T* get() const
+ {
+ if (m_cell)
+ validateCell(m_cell);
+ return reinterpret_cast<T*>(m_cell);
+ }
+
+ T* operator*() const
+ {
+ ASSERT(m_cell);
+#if ENABLE(JSC_ZOMBIES)
+ ASSERT(!isZombie(m_cell));
+#endif
+ validateCell<T>(static_cast<T*>(m_cell));
+ return static_cast<T*>(m_cell);
+ }
+
+ T* operator->() const
+ {
+ ASSERT(m_cell);
+ validateCell(static_cast<T*>(m_cell));
+ return static_cast<T*>(m_cell);
+ }
+
+ void clear() { m_cell = 0; }
+
+ JSCell** slot() { return &m_cell; }
+
+ typedef T* (WriteBarrierBase::*UnspecifiedBoolType);
+ operator UnspecifiedBoolType*() const { return m_cell ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; }
+
+ bool operator!() const { return !m_cell; }
+
+ void setWithoutWriteBarrier(T* value)
+ {
+ this->m_cell = reinterpret_cast<JSCell*>(value);
+#if ENABLE(JSC_ZOMBIES)
+ ASSERT(!m_cell || !isZombie(m_cell));
+#endif
+ }
+
+#if ENABLE(GC_VALIDATION)
+ T* unvalidatedGet() const { return reinterpret_cast<T*>(m_cell); }
+#endif
+
+private:
+ JSCell* m_cell;
+};
+
+template <> class WriteBarrierBase<Unknown> {
+public:
+ void set(JSGlobalData&, const JSCell* owner, JSValue value)
+ {
+#if ENABLE(JSC_ZOMBIES)
+ ASSERT(!isZombie(owner));
+ ASSERT(!value.isZombie());
+#endif
+ m_value = JSValue::encode(value);
+ Heap::writeBarrier(owner, value);
+ }
+
+ void setWithoutWriteBarrier(JSValue value)
+ {
+#if ENABLE(JSC_ZOMBIES)
+ ASSERT(!value.isZombie());
+#endif
+ m_value = JSValue::encode(value);
+ }
+
+ JSValue get() const
+ {
+ return JSValue::decode(m_value);
+ }
+ void clear() { m_value = JSValue::encode(JSValue()); }
+ void setUndefined() { m_value = JSValue::encode(jsUndefined()); }
+ bool isNumber() const { return get().isNumber(); }
+ bool isObject() const { return get().isObject(); }
+ bool isNull() const { return get().isNull(); }
+ bool isGetterSetter() const { return get().isGetterSetter(); }
+
+ JSValue* slot()
+ {
+ union {
+ EncodedJSValue* v;
+ JSValue* slot;
+ } u;
+ u.v = &m_value;
+ return u.slot;
+ }
+
+ typedef JSValue (WriteBarrierBase::*UnspecifiedBoolType);
+ operator UnspecifiedBoolType*() const { return get() ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; }
+ bool operator!() const { return !get(); }
+
+private:
+ EncodedJSValue m_value;
+};
+
+template <typename T> class WriteBarrier : public WriteBarrierBase<T> {
+public:
+ WriteBarrier()
+ {
+ this->setWithoutWriteBarrier(0);
+ }
+
+ WriteBarrier(JSGlobalData& globalData, const JSCell* owner, T* value)
+ {
+ this->set(globalData, owner, value);
+ }
+
+ enum MayBeNullTag { MayBeNull };
+ WriteBarrier(JSGlobalData& globalData, const JSCell* owner, T* value, MayBeNullTag)
+ {
+ this->setMayBeNull(globalData, owner, value);
+ }
+};
+
+template <> class WriteBarrier<Unknown> : public WriteBarrierBase<Unknown> {
+public:
+ WriteBarrier()
+ {
+ this->setWithoutWriteBarrier(JSValue());
+ }
+
+ WriteBarrier(JSGlobalData& globalData, const JSCell* owner, JSValue value)
+ {
+ this->set(globalData, owner, value);
+ }
+};
+
+template <typename U, typename V> inline bool operator==(const WriteBarrierBase<U>& lhs, const WriteBarrierBase<V>& rhs)
+{
+ return lhs.get() == rhs.get();
+}
+
+// MarkStack functions
+
+template<typename T> inline void MarkStack::append(WriteBarrierBase<T>* slot)
+{
+ internalAppend(*slot->slot());
+}
+
+inline void MarkStack::appendValues(WriteBarrierBase<Unknown>* barriers, size_t count, MarkSetProperties properties)
+{
+ JSValue* values = barriers->slot();
+#if ENABLE(GC_VALIDATION)
+ validateSet(values, count);
+#endif
+ if (count)
+ m_markSets.append(MarkSet(values, values + count, properties));
+}
+
+} // namespace JSC
+
+#endif // WriteBarrier_h
--- /dev/null
+SET(JSC_HEADERS
+)
+
+SET(JSC_SOURCES
+ ../jsc.cpp
+)
+
+SET(JSC_LIBRARIES
+ ${JavaScriptCore_LIBRARY_NAME}
+)
+
+INCLUDE_IF_EXISTS(${JAVASCRIPTCORE_DIR}/shell/CMakeLists${PORT}.txt)
+
+WEBKIT_WRAP_SOURCELIST(${JSC_SOURCES})
+INCLUDE_DIRECTORIES(./ ${JavaScriptCore_INCLUDE_DIRECTORIES})
+ADD_EXECUTABLE(${JSC_EXECUTABLE_NAME} ${JSC_HEADERS} ${JSC_SOURCES})
+TARGET_LINK_LIBRARIES(${JSC_EXECUTABLE_NAME} ${JSC_LIBRARIES})
+
+IF (JSC_LINK_FLAGS)
+ ADD_TARGET_PROPERTIES(${JSC_EXECUTABLE_NAME} LINK_FLAGS "${JSC_LINK_FLAGS}")
+ENDIF ()
+
+IF (SHARED_CORE)
+ SET_TARGET_PROPERTIES(${JSC_EXECUTABLE_NAME} PROPERTIES VERSION ${PROJECT_VERSION})
+ENDIF ()
--- /dev/null
+LIST(APPEND JSC_LIBRARIES
+ ${Glib_LIBRARIES}
+ ${ECORE_LIBRARIES}
+)
+
+LIST(APPEND JSC_LINK_FLAGS
+ ${ECORE_LDFLAGS}
+)
--- /dev/null
+LIST(APPEND JSC_SOURCES
+ ../os-win32/WinMain.cpp
+)
<p class='results_summary'>
Test List: All tests<br>
Skip List: ecma/Date/15.9.2.1.js, ecma/Date/15.9.2.2-1.js, ecma/Date/15.9.2.2-2.js, ecma/Date/15.9.2.2-3.js, ecma/Date/15.9.2.2-4.js, ecma/Date/15.9.2.2-5.js, ecma/Date/15.9.2.2-6.js, ecma_3/Date/15.9.5.7.js<br>
-1127 test(s) selected, 1119 test(s) completed, 49 failures reported (4.37% failed)<br>
-Engine command line: "/Volumes/Big/ggaren/build/Debug/jsc" <br>
-OS type: Darwin il0301a-dhcp53.apple.com 9.7.0 Darwin Kernel Version 9.7.0: Tue Mar 31 22:52:17 PDT 2009; root:xnu-1228.12.14~1/RELEASE_I386 i386<br>
-Testcase execution time: 3 minutes, 18 seconds.<br>
-Tests completed on Tue Apr 21 12:56:28 2009.<br><br>
+1127 test(s) selected, 1119 test(s) completed, 51 failures reported (4.55% failed)<br>
+Engine command line: "/Volumes/BigData/git/WebKit/WebKitBuild/Debug/jsc" <br>
+OS type: Darwin 10.6.0 Darwin Kernel Version 10.6.0: Wed Nov 10 18:13:17 PST 2010; root:xnu-1504.9.26~3/RELEASE_I386 i386<br>
+Testcase execution time: 1 minutes, 3 seconds.<br>
+Tests completed on Wed Jan 19 13:26:57 2011.<br><br>
[ <a href='#fail_detail'>Failure Details</a> | <a href='#retest_list'>Retest List</a> | <a href='menu.html'>Test Selection Page</a> ]<br>
<hr>
<a name='fail_detail'></a>
Failure messages were:<br>
- "-0x123456789abcde8" = NaN FAILED! expected: 81985529216486880<br>
- "-0x123456789abcde8" = NaN FAILED! expected: 81985529216486880<br>
--"\u20001234\u2001" = NaN FAILED! expected: -1234<br>
</tt><br>
<a name='failure2'></a><dd><b>Testcase <a target='other_window' href='./ecma_2/Exceptions/function-001.js'>ecma_2/Exceptions/function-001.js</a> failed</b> <a href='http://bugzilla.mozilla.org/show_bug.cgi?id=10278' target='other_window'>Bug Number 10278</a><br>
[ <a href='#failure1'>Previous Failure</a> | <a href='#failure3'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
Failure messages were:<br>
eval("function f(){}function g(){}") (threw no exception thrown = fail FAILED! expected: pass<br>
</tt><br>
-<a name='failure3'></a><dd><b>Testcase <a target='other_window' href='./ecma_3/FunExpr/fe-001.js'>ecma_3/FunExpr/fe-001.js</a> failed</b> <br>
+<a name='failure3'></a><dd><b>Testcase <a target='other_window' href='./ecma_2/RegExp/regress-001.js'>ecma_2/RegExp/regress-001.js</a> failed</b> <a href='http://bugzilla.mozilla.org/show_bug.cgi?id=http://bugzilla.mozilla.org/show_bug.cgi?id=2157' target='other_window'>Bug Number http://bugzilla.mozilla.org/show_bug.cgi?id=2157</a><br>
[ <a href='#failure2'>Previous Failure</a> | <a href='#failure4'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<tt>Expected exit code 0, got 3<br>
+Testcase terminated with signal 0<br>
+Complete testcase output was:<br>
+RegExp/hex-001.js JS regexp anchoring on empty match bug<br>
+BUGNUMBER: http://bugzilla.mozilla.org/show_bug.cgi?id=2157<br>
+</tt><br>
+<a name='failure4'></a><dd><b>Testcase <a target='other_window' href='./ecma_3/FunExpr/fe-001.js'>ecma_3/FunExpr/fe-001.js</a> failed</b> <br>
+ [ <a href='#failure3'>Previous Failure</a> | <a href='#failure5'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt>STATUS: Function Expression Statements basic test.<br>
Failure messages were:<br>
FAILED!: [reported from test()] Both functions were defined.<br>
FAILED!: [reported from test()] Expected value '1', Actual value '0'<br>
FAILED!: [reported from test()] <br>
</tt><br>
-<a name='failure4'></a><dd><b>Testcase <a target='other_window' href='./ecma_3/RegExp/15.10.2-1.js'>ecma_3/RegExp/15.10.2-1.js</a> failed</b> <a href='http://bugzilla.mozilla.org/show_bug.cgi?id=(none)' target='other_window'>Bug Number (none)</a><br>
- [ <a href='#failure3'>Previous Failure</a> | <a href='#failure5'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
-<tt>STATUS: RegExp conformance test<br>
-Failure messages were:<br>
-FAILED!: [reported from test()] Section 7 of test -<br>
-FAILED!: [reported from test()] regexp = /(z)((a+)?(b+)?(c))*/<br>
-FAILED!: [reported from test()] string = 'zaacbbbcac'<br>
-FAILED!: [reported from test()] ERROR !!! regexp failed to give expected match array:<br>
-FAILED!: [reported from test()] Expect: ["zaacbbbcac", "z", "ac", "a", , "c"]<br>
-FAILED!: [reported from test()] Actual: ["zaacbbbcac", "z", "ac", "a", "bbb", "c"]<br>
-FAILED!: [reported from test()] <br>
-FAILED!: [reported from test()] Section 8 of test -<br>
-FAILED!: [reported from test()] regexp = /(a*)*/<br>
-FAILED!: [reported from test()] string = 'b'<br>
-FAILED!: [reported from test()] ERROR !!! regexp failed to give expected match array:<br>
-FAILED!: [reported from test()] Expect: ["", , ]<br>
-FAILED!: [reported from test()] Actual: ["", ""]<br>
-FAILED!: [reported from test()] <br>
-FAILED!: [reported from test()] Section 12 of test -<br>
-FAILED!: [reported from test()] regexp = /(.*?)a(?!(a+)b\2c)\2(.*)/<br>
-FAILED!: [reported from test()] string = 'baaabaac'<br>
-FAILED!: [reported from test()] ERROR !!! regexp failed to give expected match array:<br>
-FAILED!: [reported from test()] Expect: ["baaabaac", "ba", , "abaac"]<br>
-FAILED!: [reported from test()] Actual: ["baaabaac", "ba", "aa", "abaac"]<br>
-FAILED!: [reported from test()] <br>
-</tt><br>
-<a name='failure5'></a><dd><b>Testcase <a target='other_window' href='./ecma_3/RegExp/perlstress-001.js'>ecma_3/RegExp/perlstress-001.js</a> failed</b> <a href='http://bugzilla.mozilla.org/show_bug.cgi?id=85721' target='other_window'>Bug Number 85721</a><br>
+<a name='failure5'></a><dd><b>Testcase <a target='other_window' href='./ecma_3/Statements/regress-194364.js'>ecma_3/Statements/regress-194364.js</a> failed</b> <br>
[ <a href='#failure4'>Previous Failure</a> | <a href='#failure6'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
-<tt>STATUS: Testing regular expression edge cases<br>
-Failure messages were:<br>
-FAILED!: [reported from test()] Section 218 of test -<br>
-FAILED!: [reported from test()] regexp = /((foo)|(bar))*/<br>
-FAILED!: [reported from test()] string = 'foobar'<br>
-FAILED!: [reported from test()] ERROR !!! regexp failed to give expected match array:<br>
-FAILED!: [reported from test()] Expect: ["foobar", "bar", , "bar"]<br>
-FAILED!: [reported from test()] Actual: ["foobar", "bar", "foo", "bar"]<br>
-FAILED!: [reported from test()] <br>
-FAILED!: [reported from test()] Section 234 of test -<br>
-FAILED!: [reported from test()] regexp = /(?:(f)(o)(o)|(b)(a)(r))*/<br>
-FAILED!: [reported from test()] string = 'foobar'<br>
-FAILED!: [reported from test()] ERROR !!! regexp failed to give expected match array:<br>
-FAILED!: [reported from test()] Expect: ["foobar", , , , "b", "a", "r"]<br>
-FAILED!: [reported from test()] Actual: ["foobar", "f", "o", "o", "b", "a", "r"]<br>
-FAILED!: [reported from test()] <br>
-FAILED!: [reported from test()] Section 241 of test -<br>
-FAILED!: [reported from test()] regexp = /^(?:b|a(?=(.)))*\1/<br>
-FAILED!: [reported from test()] string = 'abc'<br>
-FAILED!: [reported from test()] ERROR !!! regexp failed to give expected match array:<br>
-FAILED!: [reported from test()] Expect: ["ab", , ]<br>
-FAILED!: [reported from test()] Actual: ["ab", "b"]<br>
-FAILED!: [reported from test()] <br>
-FAILED!: [reported from test()] Section 412 of test -<br>
-FAILED!: [reported from test()] regexp = /^(a(b)?)+$/<br>
-FAILED!: [reported from test()] string = 'aba'<br>
-FAILED!: [reported from test()] ERROR !!! regexp failed to give expected match array:<br>
-FAILED!: [reported from test()] Expect: ["aba", "a", , ]<br>
-FAILED!: [reported from test()] Actual: ["aba", "a", "b"]<br>
-FAILED!: [reported from test()] <br>
-FAILED!: [reported from test()] Section 413 of test -<br>
-FAILED!: [reported from test()] regexp = /^(aa(bb)?)+$/<br>
-FAILED!: [reported from test()] string = 'aabbaa'<br>
-FAILED!: [reported from test()] ERROR !!! regexp failed to give expected match array:<br>
-FAILED!: [reported from test()] Expect: ["aabbaa", "aa", , ]<br>
-FAILED!: [reported from test()] Actual: ["aabbaa", "aa", "bb"]<br>
-FAILED!: [reported from test()] <br>
-</tt><br>
-<a name='failure6'></a><dd><b>Testcase <a target='other_window' href='./ecma_3/RegExp/regress-209919.js'>ecma_3/RegExp/regress-209919.js</a> failed</b> <a href='http://bugzilla.mozilla.org/show_bug.cgi?id=209919' target='other_window'>Bug Number 209919</a><br>
- [ <a href='#failure5'>Previous Failure</a> | <a href='#failure7'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
-<tt>STATUS: Testing regexp submatches with quantifiers<br>
-Failure messages were:<br>
-FAILED!: [reported from test()] Section 1 of test -<br>
-FAILED!: [reported from test()] regexp = /(a|b*)*/<br>
-FAILED!: [reported from test()] string = 'a'<br>
-FAILED!: [reported from test()] ERROR !!! regexp failed to give expected match array:<br>
-FAILED!: [reported from test()] Expect: ["a", "a"]<br>
-FAILED!: [reported from test()] Actual: ["a", ""]<br>
-FAILED!: [reported from test()] <br>
-FAILED!: [reported from test()] Section 3 of test -<br>
-FAILED!: [reported from test()] regexp = /(b*)*/<br>
-FAILED!: [reported from test()] string = 'a'<br>
-FAILED!: [reported from test()] ERROR !!! regexp failed to give expected match array:<br>
-FAILED!: [reported from test()] Expect: ["", , ]<br>
-FAILED!: [reported from test()] Actual: ["", ""]<br>
-FAILED!: [reported from test()] <br>
-FAILED!: [reported from test()] Section 5 of test -<br>
-FAILED!: [reported from test()] regexp = /^\-?(\d{1,}|\.{0,})*(\,\d{1,})?$/<br>
-FAILED!: [reported from test()] string = '100.00'<br>
-FAILED!: [reported from test()] ERROR !!! regexp failed to give expected match array:<br>
-FAILED!: [reported from test()] Expect: ["100.00", "00", , ]<br>
-FAILED!: [reported from test()] Actual: ["100.00", "", , ]<br>
-FAILED!: [reported from test()] <br>
-FAILED!: [reported from test()] Section 6 of test -<br>
-FAILED!: [reported from test()] regexp = /^\-?(\d{1,}|\.{0,})*(\,\d{1,})?$/<br>
-FAILED!: [reported from test()] string = '100,00'<br>
-FAILED!: [reported from test()] ERROR !!! regexp failed to give expected match array:<br>
-FAILED!: [reported from test()] Expect: ["100,00", "100", ",00"]<br>
-FAILED!: [reported from test()] Actual: ["100,00", "", ",00"]<br>
-FAILED!: [reported from test()] <br>
-FAILED!: [reported from test()] Section 7 of test -<br>
-FAILED!: [reported from test()] regexp = /^\-?(\d{1,}|\.{0,})*(\,\d{1,})?$/<br>
-FAILED!: [reported from test()] string = '1.000,00'<br>
-FAILED!: [reported from test()] ERROR !!! regexp failed to give expected match array:<br>
-FAILED!: [reported from test()] Expect: ["1.000,00", "000", ",00"]<br>
-FAILED!: [reported from test()] Actual: ["1.000,00", "", ",00"]<br>
-FAILED!: [reported from test()] <br>
-</tt><br>
-<a name='failure7'></a><dd><b>Testcase <a target='other_window' href='./ecma_3/Statements/regress-194364.js'>ecma_3/Statements/regress-194364.js</a> failed</b> <br>
- [ <a href='#failure6'>Previous Failure</a> | <a href='#failure8'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt>Expected exit code 0, got 3<br>
Testcase terminated with signal 0<br>
Complete testcase output was:<br>
Testcase produced no output!</tt><br>
-<a name='failure8'></a><dd><b>Testcase <a target='other_window' href='./ecma_3/Unicode/uc-001.js'>ecma_3/Unicode/uc-001.js</a> failed</b> <a href='http://bugzilla.mozilla.org/show_bug.cgi?id=23610' target='other_window'>Bug Number 23610</a><br>
- [ <a href='#failure7'>Previous Failure</a> | <a href='#failure9'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<a name='failure6'></a><dd><b>Testcase <a target='other_window' href='./ecma_3/Unicode/uc-001.js'>ecma_3/Unicode/uc-001.js</a> failed</b> <a href='http://bugzilla.mozilla.org/show_bug.cgi?id=23610' target='other_window'>Bug Number 23610</a><br>
+ [ <a href='#failure5'>Previous Failure</a> | <a href='#failure7'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt>STATUS: Unicode format-control character (Category Cf) test.<br>
Failure messages were:<br>
FAILED!: [reported from test()] Unicode format-control character test (Category Cf.)<br>
FAILED!: [reported from test()] Expected value 'no error', Actual value 'no‎ error'<br>
FAILED!: [reported from test()] <br>
</tt><br>
-<a name='failure9'></a><dd><b>Testcase <a target='other_window' href='./js1_2/Objects/toString-001.js'>js1_2/Objects/toString-001.js</a> failed</b> <br>
- [ <a href='#failure8'>Previous Failure</a> | <a href='#failure10'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
-<tt><br>
-Failure messages were:<br>
-var o = new Object(); o.toString() = [object Object] FAILED! expected: {}<br>
-o = {}; o.toString() = [object Object] FAILED! expected: {}<br>
-o = { name:"object", length:0, value:"hello" }; o.toString() = false FAILED! expected: true<br>
+<a name='failure7'></a><dd><b>Testcase <a target='other_window' href='./js1_2/Objects/toString-001.js'>js1_2/Objects/toString-001.js</a> failed</b> <br>
+ [ <a href='#failure6'>Previous Failure</a> | <a href='#failure8'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<tt>Expected exit code 0, got 3<br>
+Testcase terminated with signal 0<br>
+Complete testcase output was:<br>
+JS1_2 Object.toString()<br>
</tt><br>
-<a name='failure10'></a><dd><b>Testcase <a target='other_window' href='./js1_2/function/Function_object.js'>js1_2/function/Function_object.js</a> failed</b> <br>
- [ <a href='#failure9'>Previous Failure</a> | <a href='#failure11'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<a name='failure8'></a><dd><b>Testcase <a target='other_window' href='./js1_2/function/Function_object.js'>js1_2/function/Function_object.js</a> failed</b> <br>
+ [ <a href='#failure7'>Previous Failure</a> | <a href='#failure9'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt><br>
Failure messages were:<br>
f.arity = undefined FAILED! expected: 3<br>
} FAILED! expected: <br>
</tt><br>
-<a name='failure11'></a><dd><b>Testcase <a target='other_window' href='./js1_2/function/function-001-n.js'>js1_2/function/function-001-n.js</a> failed</b> <br>
- [ <a href='#failure10'>Previous Failure</a> | <a href='#failure12'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<a name='failure9'></a><dd><b>Testcase <a target='other_window' href='./js1_2/function/function-001-n.js'>js1_2/function/function-001-n.js</a> failed</b> <br>
+ [ <a href='#failure8'>Previous Failure</a> | <a href='#failure10'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt>Expected exit code 3, got 0<br>
Testcase terminated with signal 0<br>
Complete testcase output was:<br>
function-001.js functions not separated by semicolons are errors in version 120 and higher<br>
eval("function f(){}function g(){}") = undefined FAILED! expected: error<br>
</tt><br>
-<a name='failure12'></a><dd><b>Testcase <a target='other_window' href='./js1_2/function/tostring-1.js'>js1_2/function/tostring-1.js</a> failed</b> <br>
- [ <a href='#failure11'>Previous Failure</a> | <a href='#failure13'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<a name='failure10'></a><dd><b>Testcase <a target='other_window' href='./js1_2/function/regexparg-1.js'>js1_2/function/regexparg-1.js</a> failed</b> <br>
+ [ <a href='#failure9'>Previous Failure</a> | <a href='#failure11'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<tt>Expected exit code 0, got 3<br>
+Testcase terminated with signal 0<br>
+Complete testcase output was:<br>
+JS_1.2 The variable statment<br>
+</tt><br>
+<a name='failure11'></a><dd><b>Testcase <a target='other_window' href='./js1_2/function/tostring-1.js'>js1_2/function/tostring-1.js</a> failed</b> <br>
+ [ <a href='#failure10'>Previous Failure</a> | <a href='#failure12'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt><br>
Failure messages were:<br>
} FAILED! expected: <br>
} FAILED! expected: <br>
} FAILED! expected: <br>
</tt><br>
-<a name='failure13'></a><dd><b>Testcase <a target='other_window' href='./js1_2/function/tostring-2.js'>js1_2/function/tostring-2.js</a> failed</b> <br>
- [ <a href='#failure12'>Previous Failure</a> | <a href='#failure14'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<a name='failure12'></a><dd><b>Testcase <a target='other_window' href='./js1_2/function/tostring-2.js'>js1_2/function/tostring-2.js</a> failed</b> <br>
+ [ <a href='#failure11'>Previous Failure</a> | <a href='#failure13'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt><br>
Failure messages were:<br>
} FAILED! expected: <br>
} FAILED! expected: <br>
} FAILED! expected: <br>
</tt><br>
-<a name='failure14'></a><dd><b>Testcase <a target='other_window' href='./js1_2/operator/equality.js'>js1_2/operator/equality.js</a> failed</b> <br>
- [ <a href='#failure13'>Previous Failure</a> | <a href='#failure15'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<a name='failure13'></a><dd><b>Testcase <a target='other_window' href='./js1_2/operator/equality.js'>js1_2/operator/equality.js</a> failed</b> <br>
+ [ <a href='#failure12'>Previous Failure</a> | <a href='#failure14'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt><br>
Failure messages were:<br>
(new String('x') == 'x') = true FAILED! expected: false<br>
('x' == new String('x')) = true FAILED! expected: false<br>
</tt><br>
-<a name='failure15'></a><dd><b>Testcase <a target='other_window' href='./js1_2/regexp/RegExp_lastIndex.js'>js1_2/regexp/RegExp_lastIndex.js</a> failed</b> <br>
- [ <a href='#failure14'>Previous Failure</a> | <a href='#failure16'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<a name='failure14'></a><dd><b>Testcase <a target='other_window' href='./js1_2/regexp/RegExp_lastIndex.js'>js1_2/regexp/RegExp_lastIndex.js</a> failed</b> <br>
+ [ <a href='#failure13'>Previous Failure</a> | <a href='#failure15'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt><br>
Failure messages were:<br>
re=/x./g; re.lastIndex=4; re.exec('xyabcdxa') = xa FAILED! expected: ["xa"]<br>
re.exec('xyabcdef') = xy FAILED! expected: ["xy"]<br>
</tt><br>
-<a name='failure16'></a><dd><b>Testcase <a target='other_window' href='./js1_2/regexp/RegExp_multiline.js'>js1_2/regexp/RegExp_multiline.js</a> failed</b> <br>
- [ <a href='#failure15'>Previous Failure</a> | <a href='#failure17'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<a name='failure15'></a><dd><b>Testcase <a target='other_window' href='./js1_2/regexp/RegExp_multiline.js'>js1_2/regexp/RegExp_multiline.js</a> failed</b> <br>
+ [ <a href='#failure14'>Previous Failure</a> | <a href='#failure16'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt><br>
Failure messages were:<br>
(multiline == true) '123\n456'.match(/^4../) = null FAILED! expected: 456<br>
(multiline == true) 'a11\na22\na23\na24'.match(/a..$/g) = a24 FAILED! expected: a11,a22,a23,a24<br>
(multiline == true) 'a11\na22\na23\na24'.match(new RegExp('a..$','g')) = a24 FAILED! expected: a11,a22,a23,a24<br>
</tt><br>
-<a name='failure17'></a><dd><b>Testcase <a target='other_window' href='./js1_2/regexp/RegExp_multiline_as_array.js'>js1_2/regexp/RegExp_multiline_as_array.js</a> failed</b> <br>
- [ <a href='#failure16'>Previous Failure</a> | <a href='#failure18'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<a name='failure16'></a><dd><b>Testcase <a target='other_window' href='./js1_2/regexp/RegExp_multiline_as_array.js'>js1_2/regexp/RegExp_multiline_as_array.js</a> failed</b> <br>
+ [ <a href='#failure15'>Previous Failure</a> | <a href='#failure17'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt><br>
Failure messages were:<br>
(['$*'] == true) '123\n456'.match(/^4../) = null FAILED! expected: 456<br>
(['$*'] == true) 'a11\na22\na23\na24'.match(/a..$/g) = a24 FAILED! expected: a11,a22,a23,a24<br>
(['$*'] == true) 'a11\na22\na23\na24'.match(new RegExp('a..$','g')) = a24 FAILED! expected: a11,a22,a23,a24<br>
</tt><br>
-<a name='failure18'></a><dd><b>Testcase <a target='other_window' href='./js1_2/regexp/beginLine.js'>js1_2/regexp/beginLine.js</a> failed</b> <br>
- [ <a href='#failure17'>Previous Failure</a> | <a href='#failure19'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<a name='failure17'></a><dd><b>Testcase <a target='other_window' href='./js1_2/regexp/beginLine.js'>js1_2/regexp/beginLine.js</a> failed</b> <br>
+ [ <a href='#failure16'>Previous Failure</a> | <a href='#failure18'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt><br>
Failure messages were:<br>
123xyz'.match(new RegExp('^\d+')) = null FAILED! expected: 123<br>
</tt><br>
-<a name='failure19'></a><dd><b>Testcase <a target='other_window' href='./js1_2/regexp/endLine.js'>js1_2/regexp/endLine.js</a> failed</b> <br>
- [ <a href='#failure18'>Previous Failure</a> | <a href='#failure20'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<a name='failure18'></a><dd><b>Testcase <a target='other_window' href='./js1_2/regexp/endLine.js'>js1_2/regexp/endLine.js</a> failed</b> <br>
+ [ <a href='#failure17'>Previous Failure</a> | <a href='#failure19'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt><br>
Failure messages were:<br>
xyz'.match(new RegExp('\d+$')) = null FAILED! expected: 890<br>
</tt><br>
-<a name='failure20'></a><dd><b>Testcase <a target='other_window' href='./js1_2/regexp/string_split.js'>js1_2/regexp/string_split.js</a> failed</b> <br>
+<a name='failure19'></a><dd><b>Testcase <a target='other_window' href='./js1_2/regexp/regress-6359.js'>js1_2/regexp/regress-6359.js</a> failed</b> <a href='http://bugzilla.mozilla.org/show_bug.cgi?id=http://bugzilla.mozilla.org/show_bug.cgi?id=6359' target='other_window'>Bug Number http://bugzilla.mozilla.org/show_bug.cgi?id=6359</a><br>
+ [ <a href='#failure18'>Previous Failure</a> | <a href='#failure20'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<tt>Expected exit code 0, got 3<br>
+Testcase terminated with signal 0<br>
+Complete testcase output was:<br>
+BUGNUMBER: http://bugzilla.mozilla.org/show_bug.cgi?id=6359<br>
+</tt><br>
+<a name='failure20'></a><dd><b>Testcase <a target='other_window' href='./js1_2/regexp/regress-9141.js'>js1_2/regexp/regress-9141.js</a> failed</b> <a href='http://bugzilla.mozilla.org/show_bug.cgi?id=http://bugzilla.mozilla.org/show_bug.cgi?id=9141' target='other_window'>Bug Number http://bugzilla.mozilla.org/show_bug.cgi?id=9141</a><br>
[ <a href='#failure19'>Previous Failure</a> | <a href='#failure21'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<tt>Expected exit code 0, got 3<br>
+Testcase terminated with signal 0<br>
+Complete testcase output was:<br>
+BUGNUMBER: http://bugzilla.mozilla.org/show_bug.cgi?id=9141<br>
+</tt><br>
+<a name='failure21'></a><dd><b>Testcase <a target='other_window' href='./js1_2/regexp/simple_form.js'>js1_2/regexp/simple_form.js</a> failed</b> <br>
+ [ <a href='#failure20'>Previous Failure</a> | <a href='#failure22'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<tt>Expected exit code 0, got 3<br>
+Testcase terminated with signal 0<br>
+Complete testcase output was:<br>
+Executing script: simple_form.js<br>
+As described in Netscape doc "Whats new in JavaScript 1.2" RegExp: simple form<br>
+</tt><br>
+<a name='failure22'></a><dd><b>Testcase <a target='other_window' href='./js1_2/regexp/string_split.js'>js1_2/regexp/string_split.js</a> failed</b> <br>
+ [ <a href='#failure21'>Previous Failure</a> | <a href='#failure23'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt><br>
Failure messages were:<br>
'abc'.split(/[a-z]/) = ,,, FAILED! expected: ,,<br>
'abc'.split(new RegExp('[a-z]')) = ,,, FAILED! expected: ,,<br>
'abc'.split(new RegExp('[a-z]')) = ,,, FAILED! expected: ,,<br>
</tt><br>
-<a name='failure21'></a><dd><b>Testcase <a target='other_window' href='./js1_2/version120/boolean-001.js'>js1_2/version120/boolean-001.js</a> failed</b> <br>
- [ <a href='#failure20'>Previous Failure</a> | <a href='#failure22'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<a name='failure23'></a><dd><b>Testcase <a target='other_window' href='./js1_2/version120/boolean-001.js'>js1_2/version120/boolean-001.js</a> failed</b> <br>
+ [ <a href='#failure22'>Previous Failure</a> | <a href='#failure24'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt><br>
Failure messages were:<br>
new Boolean(false) = true FAILED! expected: false<br>
</tt><br>
-<a name='failure22'></a><dd><b>Testcase <a target='other_window' href='./js1_2/version120/regress-99663.js'>js1_2/version120/regress-99663.js</a> failed</b> <br>
- [ <a href='#failure21'>Previous Failure</a> | <a href='#failure23'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<a name='failure24'></a><dd><b>Testcase <a target='other_window' href='./js1_2/version120/regress-99663.js'>js1_2/version120/regress-99663.js</a> failed</b> <br>
+ [ <a href='#failure23'>Previous Failure</a> | <a href='#failure25'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt>STATUS: Regression test for Bugzilla bug 99663<br>
Failure messages were:<br>
Section 1 of test - got Error: Can't find variable: it FAILED! expected: a "read-only" error<br>
Section 2 of test - got Error: Can't find variable: it FAILED! expected: a "read-only" error<br>
Section 3 of test - got Error: Can't find variable: it FAILED! expected: a "read-only" error<br>
</tt><br>
-<a name='failure23'></a><dd><b>Testcase <a target='other_window' href='./js1_3/Script/function-001-n.js'>js1_3/Script/function-001-n.js</a> failed</b> <a href='http://bugzilla.mozilla.org/show_bug.cgi?id=10278' target='other_window'>Bug Number 10278</a><br>
- [ <a href='#failure22'>Previous Failure</a> | <a href='#failure24'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<a name='failure25'></a><dd><b>Testcase <a target='other_window' href='./js1_3/Script/function-001-n.js'>js1_3/Script/function-001-n.js</a> failed</b> <a href='http://bugzilla.mozilla.org/show_bug.cgi?id=10278' target='other_window'>Bug Number 10278</a><br>
+ [ <a href='#failure24'>Previous Failure</a> | <a href='#failure26'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt>Expected exit code 3, got 0<br>
Testcase terminated with signal 0<br>
Complete testcase output was:<br>
function-001.js functions not separated by semicolons are errors in version 120 and higher<br>
eval("function f(){}function g(){}") = undefined FAILED! expected: error<br>
</tt><br>
-<a name='failure24'></a><dd><b>Testcase <a target='other_window' href='./js1_3/Script/script-001.js'>js1_3/Script/script-001.js</a> failed</b> <br>
- [ <a href='#failure23'>Previous Failure</a> | <a href='#failure25'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<a name='failure26'></a><dd><b>Testcase <a target='other_window' href='./js1_3/Script/script-001.js'>js1_3/Script/script-001.js</a> failed</b> <br>
+ [ <a href='#failure25'>Previous Failure</a> | <a href='#failure27'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt>Expected exit code 0, got 3<br>
Testcase terminated with signal 0<br>
Complete testcase output was:<br>
script-001 NativeScript<br>
</tt><br>
-<a name='failure25'></a><dd><b>Testcase <a target='other_window' href='./js1_3/regress/function-001-n.js'>js1_3/regress/function-001-n.js</a> failed</b> <a href='http://bugzilla.mozilla.org/show_bug.cgi?id=10278' target='other_window'>Bug Number 10278</a><br>
- [ <a href='#failure24'>Previous Failure</a> | <a href='#failure26'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<a name='failure27'></a><dd><b>Testcase <a target='other_window' href='./js1_3/regress/function-001-n.js'>js1_3/regress/function-001-n.js</a> failed</b> <a href='http://bugzilla.mozilla.org/show_bug.cgi?id=10278' target='other_window'>Bug Number 10278</a><br>
+ [ <a href='#failure26'>Previous Failure</a> | <a href='#failure28'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt>Expected exit code 3, got 0<br>
Testcase terminated with signal 0<br>
Complete testcase output was:<br>
function-001.js functions not separated by semicolons are errors in version 120 and higher<br>
eval("function f(){}function g(){}") = undefined FAILED! expected: error<br>
</tt><br>
-<a name='failure26'></a><dd><b>Testcase <a target='other_window' href='./js1_5/Exceptions/catchguard-001.js'>js1_5/Exceptions/catchguard-001.js</a> failed</b> <br>
- [ <a href='#failure25'>Previous Failure</a> | <a href='#failure27'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<a name='failure28'></a><dd><b>Testcase <a target='other_window' href='./js1_5/Exceptions/catchguard-001.js'>js1_5/Exceptions/catchguard-001.js</a> failed</b> <br>
+ [ <a href='#failure27'>Previous Failure</a> | <a href='#failure29'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt>Expected exit code 0, got 3<br>
Testcase terminated with signal 0<br>
Complete testcase output was:<br>
Testcase produced no output!</tt><br>
-<a name='failure27'></a><dd><b>Testcase <a target='other_window' href='./js1_5/Exceptions/catchguard-002.js'>js1_5/Exceptions/catchguard-002.js</a> failed</b> <br>
- [ <a href='#failure26'>Previous Failure</a> | <a href='#failure28'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<a name='failure29'></a><dd><b>Testcase <a target='other_window' href='./js1_5/Exceptions/catchguard-002.js'>js1_5/Exceptions/catchguard-002.js</a> failed</b> <br>
+ [ <a href='#failure28'>Previous Failure</a> | <a href='#failure30'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt>Expected exit code 0, got 3<br>
Testcase terminated with signal 0<br>
Complete testcase output was:<br>
Testcase produced no output!</tt><br>
-<a name='failure28'></a><dd><b>Testcase <a target='other_window' href='./js1_5/Exceptions/catchguard-003.js'>js1_5/Exceptions/catchguard-003.js</a> failed</b> <br>
- [ <a href='#failure27'>Previous Failure</a> | <a href='#failure29'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<a name='failure30'></a><dd><b>Testcase <a target='other_window' href='./js1_5/Exceptions/catchguard-003.js'>js1_5/Exceptions/catchguard-003.js</a> failed</b> <br>
+ [ <a href='#failure29'>Previous Failure</a> | <a href='#failure31'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt>Expected exit code 0, got 3<br>
Testcase terminated with signal 0<br>
Complete testcase output was:<br>
Testcase produced no output!</tt><br>
-<a name='failure29'></a><dd><b>Testcase <a target='other_window' href='./js1_5/Exceptions/errstack-001.js'>js1_5/Exceptions/errstack-001.js</a> failed</b> <br>
- [ <a href='#failure28'>Previous Failure</a> | <a href='#failure30'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<a name='failure31'></a><dd><b>Testcase <a target='other_window' href='./js1_5/Exceptions/errstack-001.js'>js1_5/Exceptions/errstack-001.js</a> failed</b> <br>
+ [ <a href='#failure30'>Previous Failure</a> | <a href='#failure32'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt>Expected exit code 0, got 3<br>
Testcase terminated with signal 0<br>
Complete testcase output was:<br>
Testcase produced no output!</tt><br>
-<a name='failure30'></a><dd><b>Testcase <a target='other_window' href='./js1_5/Exceptions/regress-50447.js'>js1_5/Exceptions/regress-50447.js</a> failed</b> <a href='http://bugzilla.mozilla.org/show_bug.cgi?id=50447' target='other_window'>Bug Number 50447</a><br>
- [ <a href='#failure29'>Previous Failure</a> | <a href='#failure31'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<a name='failure32'></a><dd><b>Testcase <a target='other_window' href='./js1_5/Exceptions/regress-50447.js'>js1_5/Exceptions/regress-50447.js</a> failed</b> <a href='http://bugzilla.mozilla.org/show_bug.cgi?id=50447' target='other_window'>Bug Number 50447</a><br>
+ [ <a href='#failure31'>Previous Failure</a> | <a href='#failure33'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt>Expected exit code 0, got 3<br>
Testcase terminated with signal 0<br>
Complete testcase output was:<br>
BUGNUMBER: 50447<br>
STATUS: Test (non-ECMA) Error object properties fileName, lineNumber<br>
</tt><br>
-<a name='failure31'></a><dd><b>Testcase <a target='other_window' href='./js1_5/GetSet/getset-001.js'>js1_5/GetSet/getset-001.js</a> failed</b> <br>
- [ <a href='#failure30'>Previous Failure</a> | <a href='#failure32'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<a name='failure33'></a><dd><b>Testcase <a target='other_window' href='./js1_5/GetSet/getset-001.js'>js1_5/GetSet/getset-001.js</a> failed</b> <br>
+ [ <a href='#failure32'>Previous Failure</a> | <a href='#failure34'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt>Expected exit code 0, got 3<br>
Testcase terminated with signal 0<br>
Complete testcase output was:<br>
Testcase produced no output!</tt><br>
-<a name='failure32'></a><dd><b>Testcase <a target='other_window' href='./js1_5/GetSet/getset-002.js'>js1_5/GetSet/getset-002.js</a> failed</b> <br>
- [ <a href='#failure31'>Previous Failure</a> | <a href='#failure33'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<a name='failure34'></a><dd><b>Testcase <a target='other_window' href='./js1_5/GetSet/getset-002.js'>js1_5/GetSet/getset-002.js</a> failed</b> <br>
+ [ <a href='#failure33'>Previous Failure</a> | <a href='#failure35'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt>Expected exit code 0, got 3<br>
Testcase terminated with signal 0<br>
Complete testcase output was:<br>
Testcase produced no output!</tt><br>
-<a name='failure33'></a><dd><b>Testcase <a target='other_window' href='./js1_5/GetSet/getset-003.js'>js1_5/GetSet/getset-003.js</a> failed</b> <br>
- [ <a href='#failure32'>Previous Failure</a> | <a href='#failure34'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<a name='failure35'></a><dd><b>Testcase <a target='other_window' href='./js1_5/GetSet/getset-003.js'>js1_5/GetSet/getset-003.js</a> failed</b> <br>
+ [ <a href='#failure34'>Previous Failure</a> | <a href='#failure36'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt>Expected exit code 0, got 3<br>
Testcase terminated with signal 0<br>
Complete testcase output was:<br>
Testcase produced no output!</tt><br>
-<a name='failure34'></a><dd><b>Testcase <a target='other_window' href='./js1_5/Object/regress-90596-001.js'>js1_5/Object/regress-90596-001.js</a> failed</b> <br>
- [ <a href='#failure33'>Previous Failure</a> | <a href='#failure35'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<a name='failure36'></a><dd><b>Testcase <a target='other_window' href='./js1_5/Object/regress-90596-001.js'>js1_5/Object/regress-90596-001.js</a> failed</b> <br>
+ [ <a href='#failure35'>Previous Failure</a> | <a href='#failure37'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt>Expected exit code 0, got 3<br>
Testcase terminated with signal 0<br>
Complete testcase output was:<br>
Testcase produced no output!</tt><br>
-<a name='failure35'></a><dd><b>Testcase <a target='other_window' href='./js1_5/Object/regress-90596-002.js'>js1_5/Object/regress-90596-002.js</a> failed</b> <br>
- [ <a href='#failure34'>Previous Failure</a> | <a href='#failure36'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<a name='failure37'></a><dd><b>Testcase <a target='other_window' href='./js1_5/Object/regress-90596-002.js'>js1_5/Object/regress-90596-002.js</a> failed</b> <br>
+ [ <a href='#failure36'>Previous Failure</a> | <a href='#failure38'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt>Expected exit code 0, got 3<br>
Testcase terminated with signal 0<br>
Complete testcase output was:<br>
Testcase produced no output!</tt><br>
-<a name='failure36'></a><dd><b>Testcase <a target='other_window' href='./js1_5/Object/regress-96284-001.js'>js1_5/Object/regress-96284-001.js</a> failed</b> <br>
- [ <a href='#failure35'>Previous Failure</a> | <a href='#failure37'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<a name='failure38'></a><dd><b>Testcase <a target='other_window' href='./js1_5/Object/regress-96284-001.js'>js1_5/Object/regress-96284-001.js</a> failed</b> <br>
+ [ <a href='#failure37'>Previous Failure</a> | <a href='#failure39'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt>Expected exit code 0, got 3<br>
Testcase terminated with signal 0<br>
Complete testcase output was:<br>
Testcase produced no output!</tt><br>
-<a name='failure37'></a><dd><b>Testcase <a target='other_window' href='./js1_5/Object/regress-96284-002.js'>js1_5/Object/regress-96284-002.js</a> failed</b> <br>
- [ <a href='#failure36'>Previous Failure</a> | <a href='#failure38'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<a name='failure39'></a><dd><b>Testcase <a target='other_window' href='./js1_5/Object/regress-96284-002.js'>js1_5/Object/regress-96284-002.js</a> failed</b> <br>
+ [ <a href='#failure38'>Previous Failure</a> | <a href='#failure40'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt>Expected exit code 0, got 3<br>
Testcase terminated with signal 0<br>
Complete testcase output was:<br>
Testcase produced no output!</tt><br>
-<a name='failure38'></a><dd><b>Testcase <a target='other_window' href='./js1_5/Regress/regress-44009.js'>js1_5/Regress/regress-44009.js</a> failed</b> <a href='http://bugzilla.mozilla.org/show_bug.cgi?id=44009' target='other_window'>Bug Number 44009</a><br>
- [ <a href='#failure37'>Previous Failure</a> | <a href='#failure39'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<a name='failure40'></a><dd><b>Testcase <a target='other_window' href='./js1_5/Regress/regress-44009.js'>js1_5/Regress/regress-44009.js</a> failed</b> <a href='http://bugzilla.mozilla.org/show_bug.cgi?id=44009' target='other_window'>Bug Number 44009</a><br>
+ [ <a href='#failure39'>Previous Failure</a> | <a href='#failure41'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt>Expected exit code 0, got 3<br>
Testcase terminated with signal 0<br>
Complete testcase output was:<br>
BUGNUMBER: 44009<br>
STATUS: Testing that we don't crash on obj.toSource()<br>
</tt><br>
-<a name='failure39'></a><dd><b>Testcase <a target='other_window' href='./js1_5/Regress/regress-103602.js'>js1_5/Regress/regress-103602.js</a> failed</b> <a href='http://bugzilla.mozilla.org/show_bug.cgi?id=103602' target='other_window'>Bug Number 103602</a><br>
- [ <a href='#failure38'>Previous Failure</a> | <a href='#failure40'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<a name='failure41'></a><dd><b>Testcase <a target='other_window' href='./js1_5/Regress/regress-103602.js'>js1_5/Regress/regress-103602.js</a> failed</b> <a href='http://bugzilla.mozilla.org/show_bug.cgi?id=103602' target='other_window'>Bug Number 103602</a><br>
+ [ <a href='#failure40'>Previous Failure</a> | <a href='#failure42'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt>STATUS: Reassignment to a const is NOT an error per ECMA<br>
Failure messages were:<br>
FAILED!: [reported from test()] Section 1 of test -<br>
FAILED!: [reported from test()] Expected value '1', Actual value '2'<br>
FAILED!: [reported from test()] <br>
</tt><br>
-<a name='failure40'></a><dd><b>Testcase <a target='other_window' href='./js1_5/Regress/regress-104077.js'>js1_5/Regress/regress-104077.js</a> failed</b> <br>
- [ <a href='#failure39'>Previous Failure</a> | <a href='#failure41'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<a name='failure42'></a><dd><b>Testcase <a target='other_window' href='./js1_5/Regress/regress-104077.js'>js1_5/Regress/regress-104077.js</a> failed</b> <br>
+ [ <a href='#failure41'>Previous Failure</a> | <a href='#failure43'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt>Expected exit code 0, got 3<br>
Testcase terminated with signal 0<br>
Complete testcase output was:<br>
Testcase produced no output!</tt><br>
-<a name='failure41'></a><dd><b>Testcase <a target='other_window' href='./js1_5/Regress/regress-127557.js'>js1_5/Regress/regress-127557.js</a> failed</b> <br>
- [ <a href='#failure40'>Previous Failure</a> | <a href='#failure42'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<a name='failure43'></a><dd><b>Testcase <a target='other_window' href='./js1_5/Regress/regress-127557.js'>js1_5/Regress/regress-127557.js</a> failed</b> <br>
+ [ <a href='#failure42'>Previous Failure</a> | <a href='#failure44'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt>Expected exit code 0, got 3<br>
Testcase terminated with signal 0<br>
Complete testcase output was:<br>
Testcase produced no output!</tt><br>
-<a name='failure42'></a><dd><b>Testcase <a target='other_window' href='./js1_5/Regress/regress-172699.js'>js1_5/Regress/regress-172699.js</a> failed</b> <br>
- [ <a href='#failure41'>Previous Failure</a> | <a href='#failure43'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<a name='failure44'></a><dd><b>Testcase <a target='other_window' href='./js1_5/Regress/regress-172699.js'>js1_5/Regress/regress-172699.js</a> failed</b> <br>
+ [ <a href='#failure43'>Previous Failure</a> | <a href='#failure45'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt>Expected exit code 0, got 3<br>
Testcase terminated with signal 0<br>
Complete testcase output was:<br>
Testcase produced no output!</tt><br>
-<a name='failure43'></a><dd><b>Testcase <a target='other_window' href='./js1_5/Regress/regress-179524.js'>js1_5/Regress/regress-179524.js</a> failed</b> <a href='http://bugzilla.mozilla.org/show_bug.cgi?id=179524' target='other_window'>Bug Number 179524</a><br>
- [ <a href='#failure42'>Previous Failure</a> | <a href='#failure44'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<a name='failure45'></a><dd><b>Testcase <a target='other_window' href='./js1_5/Regress/regress-179524.js'>js1_5/Regress/regress-179524.js</a> failed</b> <a href='http://bugzilla.mozilla.org/show_bug.cgi?id=179524' target='other_window'>Bug Number 179524</a><br>
+ [ <a href='#failure44'>Previous Failure</a> | <a href='#failure46'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt>STATUS: Don't crash on extraneous arguments to str.match(), etc.<br>
Failure messages were:<br>
FAILED!: [reported from test()] Section 14 of test -<br>
FAILED!: [reported from test()] Expected value 'SHOULD HAVE FALLEN INTO CATCH-BLOCK!', Actual value 'ABC Zbc'<br>
FAILED!: [reported from test()] <br>
</tt><br>
-<a name='failure44'></a><dd><b>Testcase <a target='other_window' href='./js1_5/Scope/regress-220584.js'>js1_5/Scope/regress-220584.js</a> failed</b> <br>
- [ <a href='#failure43'>Previous Failure</a> | <a href='#failure45'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<a name='failure46'></a><dd><b>Testcase <a target='other_window' href='./js1_5/Scope/regress-220584.js'>js1_5/Scope/regress-220584.js</a> failed</b> <br>
+ [ <a href='#failure45'>Previous Failure</a> | <a href='#failure47'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt>Expected exit code 0, got 3<br>
Testcase terminated with signal 0<br>
Complete testcase output was:<br>
Testcase produced no output!</tt><br>
-<a name='failure45'></a><dd><b>Testcase <a target='other_window' href='./js1_5/Scope/scope-001.js'>js1_5/Scope/scope-001.js</a> failed</b> <a href='http://bugzilla.mozilla.org/show_bug.cgi?id=53268' target='other_window'>Bug Number 53268</a><br>
- [ <a href='#failure44'>Previous Failure</a> | <a href='#failure46'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<a name='failure47'></a><dd><b>Testcase <a target='other_window' href='./js1_5/Scope/scope-001.js'>js1_5/Scope/scope-001.js</a> failed</b> <a href='http://bugzilla.mozilla.org/show_bug.cgi?id=53268' target='other_window'>Bug Number 53268</a><br>
+ [ <a href='#failure46'>Previous Failure</a> | <a href='#failure48'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt>STATUS: Testing scope after changing obj.__proto__<br>
Failure messages were:<br>
FAILED!: [reported from test()] Step 1: setting obj.__proto__ = global object<br>
FAILED!: [reported from test()] Expected value 'undefined', Actual value '1'<br>
FAILED!: [reported from test()] <br>
</tt><br>
-<a name='failure46'></a><dd><b>Testcase <a target='other_window' href='./js1_6/Regress/regress-301574.js'>js1_6/Regress/regress-301574.js</a> failed</b> <a href='http://bugzilla.mozilla.org/show_bug.cgi?id=301574' target='other_window'>Bug Number 301574</a><br>
- [ <a href='#failure45'>Previous Failure</a> | <a href='#failure47'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<a name='failure48'></a><dd><b>Testcase <a target='other_window' href='./js1_6/Regress/regress-301574.js'>js1_6/Regress/regress-301574.js</a> failed</b> <a href='http://bugzilla.mozilla.org/show_bug.cgi?id=301574' target='other_window'>Bug Number 301574</a><br>
+ [ <a href='#failure47'>Previous Failure</a> | <a href='#failure49'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt>STATUS: E4X should be enabled even when e4x=1 not specified<br>
Failure messages were:<br>
FAILED!: E4X should be enabled even when e4x=1 not specified: XML()<br>
FAILED!: Expected value 'No error', Actual value 'error: ReferenceError: Can't find variable: XML'<br>
FAILED!: <br>
</tt><br>
-<a name='failure47'></a><dd><b>Testcase <a target='other_window' href='./js1_6/Regress/regress-309242.js'>js1_6/Regress/regress-309242.js</a> failed</b> <br>
- [ <a href='#failure46'>Previous Failure</a> | <a href='#failure48'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<a name='failure49'></a><dd><b>Testcase <a target='other_window' href='./js1_6/Regress/regress-309242.js'>js1_6/Regress/regress-309242.js</a> failed</b> <br>
+ [ <a href='#failure48'>Previous Failure</a> | <a href='#failure50'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt>Expected exit code 0, got 3<br>
Testcase terminated with signal 0<br>
Complete testcase output was:<br>
Testcase produced no output!</tt><br>
-<a name='failure48'></a><dd><b>Testcase <a target='other_window' href='./js1_6/Regress/regress-314887.js'>js1_6/Regress/regress-314887.js</a> failed</b> <br>
- [ <a href='#failure47'>Previous Failure</a> | <a href='#failure49'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<a name='failure50'></a><dd><b>Testcase <a target='other_window' href='./js1_6/Regress/regress-314887.js'>js1_6/Regress/regress-314887.js</a> failed</b> <br>
+ [ <a href='#failure49'>Previous Failure</a> | <a href='#failure51'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt>Expected exit code 0, got 3<br>
Testcase terminated with signal 0<br>
Complete testcase output was:<br>
Testcase produced no output!</tt><br>
-<a name='failure49'></a><dd><b>Testcase <a target='other_window' href='./js1_6/String/regress-306591.js'>js1_6/String/regress-306591.js</a> failed</b> <a href='http://bugzilla.mozilla.org/show_bug.cgi?id=306591' target='other_window'>Bug Number 306591</a><br>
- [ <a href='#failure48'>Previous Failure</a> | <a href='#failure50'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
+<a name='failure51'></a><dd><b>Testcase <a target='other_window' href='./js1_6/String/regress-306591.js'>js1_6/String/regress-306591.js</a> failed</b> <a href='http://bugzilla.mozilla.org/show_bug.cgi?id=306591' target='other_window'>Bug Number 306591</a><br>
+ [ <a href='#failure50'>Previous Failure</a> | <a href='#failure52'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br>
<tt>Expected exit code 0, got 3<br>
Testcase terminated with signal 0<br>
Complete testcase output was:<br>
<pre>
<a name='retest_list'></a>
<h2>Retest List</h2><br>
-# Retest List, squirrelfish, generated Tue Apr 21 12:56:28 2009.
+# Retest List, squirrelfish, generated Wed Jan 19 13:26:57 2011.
# Original test base was: All tests.
-# 1119 of 1127 test(s) were completed, 49 failures reported.
+# 1119 of 1127 test(s) were completed, 51 failures reported.
ecma/TypeConversion/9.3.1-3.js
ecma_2/Exceptions/function-001.js
+ecma_2/RegExp/regress-001.js
ecma_3/FunExpr/fe-001.js
-ecma_3/RegExp/15.10.2-1.js
-ecma_3/RegExp/perlstress-001.js
-ecma_3/RegExp/regress-209919.js
ecma_3/Statements/regress-194364.js
ecma_3/Unicode/uc-001.js
js1_2/Objects/toString-001.js
js1_2/function/Function_object.js
js1_2/function/function-001-n.js
+js1_2/function/regexparg-1.js
js1_2/function/tostring-1.js
js1_2/function/tostring-2.js
js1_2/operator/equality.js
js1_2/regexp/RegExp_multiline_as_array.js
js1_2/regexp/beginLine.js
js1_2/regexp/endLine.js
+js1_2/regexp/regress-6359.js
+js1_2/regexp/regress-9141.js
+js1_2/regexp/simple_form.js
js1_2/regexp/string_split.js
js1_2/version120/boolean-001.js
js1_2/version120/regress-99663.js
testcases[count++] = new TestCase ( SECTION, "RegExp.input = 'abcd12357efg'; /\\d+/.exec('2345')",
String(["2345"]), String(/\d+/.exec('2345')));
- // RegExp.input = "abcd12357efg"; /\d+/.exec()
+ // RegExp.input = "abcd12357efg"; /\d+/.exec(RegExp.input)
RegExp.input = "abcd12357efg";
- testcases[count++] = new TestCase ( SECTION, "RegExp.input = 'abcd12357efg'; /\\d+/.exec()",
- String(["12357"]), String(/\d+/.exec()));
+ testcases[count++] = new TestCase ( SECTION, "RegExp.input = 'abcd12357efg'; /\\d+/.exec(RegExp.input)",
+ String(["12357"]), String(/\d+/.exec(RegExp.input)));
- // RegExp.input = "abcd12357efg"; /[h-z]+/.exec()
+ // RegExp.input = "abcd12357efg"; /[h-z]+/.exec(RegExp.input)
RegExp.input = "abcd12357efg";
- testcases[count++] = new TestCase ( SECTION, "RegExp.input = 'abcd12357efg'; /[h-z]+/.exec()",
- null, /[h-z]+/.exec());
+ testcases[count++] = new TestCase ( SECTION, "RegExp.input = 'abcd12357efg'; /[h-z]+/.exec(RegExp.input)",
+ null, /[h-z]+/.exec(RegExp.input));
// RegExp.input = "abcd12357efg"; /\d+/.test('2345')
RegExp.input = "abcd12357efg";
testcases[count++] = new TestCase ( SECTION, "RegExp.input = 'abcd12357efg'; /\\d+/.test('2345')",
true, /\d+/.test('2345'));
- // RegExp.input = "abcd12357efg"; /\d+/.test()
+ // RegExp.input = "abcd12357efg"; /\d+/.test(RegExp.input)
RegExp.input = "abcd12357efg";
- testcases[count++] = new TestCase ( SECTION, "RegExp.input = 'abcd12357efg'; /\\d+/.test()",
- true, /\d+/.test());
+ testcases[count++] = new TestCase ( SECTION, "RegExp.input = 'abcd12357efg'; /\\d+/.test(RegExp.input)",
+ true, /\d+/.test(RegExp.input));
- // RegExp.input = "abcd12357efg"; (new RegExp('d+')).test()
+ // RegExp.input = "abcd12357efg"; (new RegExp('d+')).test(RegExp.input)
RegExp.input = "abcd12357efg";
- testcases[count++] = new TestCase ( SECTION, "RegExp.input = 'abcd12357efg'; (new RegExp('d+')).test()",
- true, (new RegExp('d+')).test());
+ testcases[count++] = new TestCase ( SECTION, "RegExp.input = 'abcd12357efg'; (new RegExp('d+')).test(RegExp.input)",
+ true, (new RegExp('d+')).test(RegExp.input));
- // RegExp.input = "abcd12357efg"; /[h-z]+/.test()
+ // RegExp.input = "abcd12357efg"; /[h-z]+/.test(RegExp.input)
RegExp.input = "abcd12357efg";
- testcases[count++] = new TestCase ( SECTION, "RegExp.input = 'abcd12357efg'; /[h-z]+/.test()",
- false, /[h-z]+/.test());
+ testcases[count++] = new TestCase ( SECTION, "RegExp.input = 'abcd12357efg'; /[h-z]+/.test(RegExp.input)",
+ false, /[h-z]+/.test(RegExp.input));
- // RegExp.input = "abcd12357efg"; (new RegExp('[h-z]+')).test()
+ // RegExp.input = "abcd12357efg"; (new RegExp('[h-z]+')).test(RegExp.input)
RegExp.input = "abcd12357efg";
- testcases[count++] = new TestCase ( SECTION, "RegExp.input = 'abcd12357efg'; (new RegExp('[h-z]+')).test()",
- false, (new RegExp('[h-z]+')).test());
+ testcases[count++] = new TestCase ( SECTION, "RegExp.input = 'abcd12357efg'; (new RegExp('[h-z]+')).test(RegExp.input)",
+ false, (new RegExp('[h-z]+')).test(RegExp.input));
function test()
{
testcases[count++] = new TestCase ( SECTION, "RegExp['$_'] = 'abcd12357efg'; /\\d+/.exec('2345')",
String(["2345"]), String(/\d+/.exec('2345')));
- // RegExp['$_'] = "abcd12357efg"; /\d+/.exec()
+ // RegExp['$_'] = "abcd12357efg"; /\d+/.exec(RegExp.input)
RegExp['$_'] = "abcd12357efg";
- testcases[count++] = new TestCase ( SECTION, "RegExp['$_'] = 'abcd12357efg'; /\\d+/.exec()",
- String(["12357"]), String(/\d+/.exec()));
+ testcases[count++] = new TestCase ( SECTION, "RegExp['$_'] = 'abcd12357efg'; /\\d+/.exec(RegExp.input)",
+ String(["12357"]), String(/\d+/.exec(RegExp.input)));
- // RegExp['$_'] = "abcd12357efg"; /[h-z]+/.exec()
+ // RegExp['$_'] = "abcd12357efg"; /[h-z]+/.exec(RegExp.input)
RegExp['$_'] = "abcd12357efg";
- testcases[count++] = new TestCase ( SECTION, "RegExp['$_'] = 'abcd12357efg'; /[h-z]+/.exec()",
- null, /[h-z]+/.exec());
+ testcases[count++] = new TestCase ( SECTION, "RegExp['$_'] = 'abcd12357efg'; /[h-z]+/.exec(RegExp.input)",
+ null, /[h-z]+/.exec(RegExp.input));
// RegExp['$_'] = "abcd12357efg"; /\d+/.test('2345')
RegExp['$_'] = "abcd12357efg";
testcases[count++] = new TestCase ( SECTION, "RegExp['$_'] = 'abcd12357efg'; /\\d+/.test('2345')",
true, /\d+/.test('2345'));
- // RegExp['$_'] = "abcd12357efg"; /\d+/.test()
+ // RegExp['$_'] = "abcd12357efg"; /\d+/.test(RegExp.input)
RegExp['$_'] = "abcd12357efg";
- testcases[count++] = new TestCase ( SECTION, "RegExp['$_'] = 'abcd12357efg'; /\\d+/.test()",
- true, /\d+/.test());
+ testcases[count++] = new TestCase ( SECTION, "RegExp['$_'] = 'abcd12357efg'; /\\d+/.test(RegExp.input)",
+ true, /\d+/.test(RegExp.input));
- // RegExp['$_'] = "abcd12357efg"; /[h-z]+/.test()
+ // RegExp['$_'] = "abcd12357efg"; /[h-z]+/.test(RegExp.input)
RegExp['$_'] = "abcd12357efg";
- testcases[count++] = new TestCase ( SECTION, "RegExp['$_'] = 'abcd12357efg'; /[h-z]+/.test()",
- false, /[h-z]+/.test());
+ testcases[count++] = new TestCase ( SECTION, "RegExp['$_'] = 'abcd12357efg'; /[h-z]+/.test(RegExp.input)",
+ false, /[h-z]+/.test(RegExp.input));
- // RegExp['$_'] = "abcd12357efg"; (new RegExp('\d+')).test()
+ // RegExp['$_'] = "abcd12357efg"; (new RegExp('\d+')).test(RegExp.input)
RegExp['$_'] = "abcd12357efg";
- testcases[count++] = new TestCase ( SECTION, "RegExp['$_'] = 'abcd12357efg'; (new RegExp('\d+')).test()",
- true, (new RegExp('\d+')).test());
+ testcases[count++] = new TestCase ( SECTION, "RegExp['$_'] = 'abcd12357efg'; (new RegExp('\d+')).test(RegExp.input)",
+ true, (new RegExp('\d+')).test(RegExp.input));
- // RegExp['$_'] = "abcd12357efg"; (new RegExp('[h-z]+')).test()
+ // RegExp['$_'] = "abcd12357efg"; (new RegExp('[h-z]+')).test(RegExp.input)
RegExp['$_'] = "abcd12357efg";
- testcases[count++] = new TestCase ( SECTION, "RegExp['$_'] = 'abcd12357efg'; (new RegExp('[h-z]+')).test()",
- false, (new RegExp('[h-z]+')).test());
+ testcases[count++] = new TestCase ( SECTION, "RegExp['$_'] = 'abcd12357efg'; (new RegExp('[h-z]+')).test(RegExp.input)",
+ false, (new RegExp('[h-z]+')).test(RegExp.input));
function test()
{
from settings import *
-jscore_excludes = ['jsc.cpp', 'ucptable.cpp']
-jscore_excludes.extend(get_excludes(jscore_dir, ['*Brew.cpp', '*CF.cpp', '*Symbian.cpp']))
-
-sources = []
+def build(bld):
-jscore_excludes.extend(get_excludes(jscore_dir, ['*None.cpp']))
+ import Options
-if building_on_win32:
- jscore_excludes += ['ExecutableAllocatorPosix.cpp', 'MarkStackPosix.cpp', 'ThreadingPthreads.cpp']
- sources += ['jit/ExecutableAllocatorWin.cpp', 'runtime/MarkStackWin.cpp']
-else:
- jscore_excludes.append('JSStringRefBSTR.cpp')
- jscore_excludes.extend(get_excludes(jscore_dir, ['*Win.cpp']))
+ jscore_excludes = ['jsc.cpp', 'ProfilerServer.mm', 'ExecutableAllocatorPosix.cpp']
+ jscore_excludes.extend(get_excludes(jscore_dir, ['*Brew.cpp', '*CF.cpp', '*Symbian.cpp']))
-def generate_jscore_derived_sources():
- # build the derived sources
- js_dir = jscore_dir
- if building_on_win32:
- js_dir = get_output('cygpath --unix "%s"' % js_dir)
- derived_sources_dir = os.path.join(jscore_dir, 'DerivedSources')
- if not os.path.exists(derived_sources_dir):
- os.mkdir(derived_sources_dir)
+ jscore_excludes.extend(get_excludes(jscore_dir, ['*None.cpp']))
- olddir = os.getcwd()
- os.chdir(derived_sources_dir)
+ sources = []
- command = 'make -f %s/DerivedSources.make JavaScriptCore=%s BUILT_PRODUCTS_DIR=%s all FEATURE_DEFINES="%s"' % (js_dir, js_dir, js_dir, ' '.join(feature_defines))
- os.system(command)
- os.chdir(olddir)
+ if Options.options.port == "wx":
+ if building_on_win32:
+ jscore_excludes += ['MarkStackPosix.cpp', 'OSAllocatorPosix.cpp', 'ThreadingPthreads.cpp']
+ sources += ['heap/MarkStackWin.cpp']
+ else:
+ jscore_excludes.append('JSStringRefBSTR.cpp')
+ jscore_excludes.extend(get_excludes(jscore_dir, ['*Win.cpp']))
-def set_options(opt):
- common_set_options(opt)
-
-def configure(conf):
- common_configure(conf)
- generate_jscore_derived_sources()
-
-def build(bld):
- import Options
-
- full_dirs = get_dirs_for_features(jscore_dir, features=[build_port], dirs=jscore_dirs)
+ full_dirs = get_dirs_for_features(jscore_dir, features=[Options.options.port.lower()], dirs=jscore_dirs)
includes = common_includes + full_dirs
if sys.platform.startswith('darwin'):
uselib_local = '',
install_path = output_dir)
- jscore.find_sources_in_dirs(full_dirs, excludes = jscore_excludes)
-
+ jscore.find_sources_in_dirs(full_dirs, excludes = jscore_excludes)
+
obj = bld.new_task_gen(
features = 'cxx cprogram',
includes = '. .. assembler DerivedSources ForwardingHeaders ' + ' '.join(includes),
install_path = output_dir,
)
- # we'll get an error if exceptions are on because of an unwind error when using __try
if building_on_win32:
- flags = obj.env.CXXFLAGS
- flags.remove('/EHsc')
- obj.env.CXXFLAGS = flags
+ myenv = obj.env.copy()
+ myenv.CXXFLAGS = myenv.CXXFLAGS[:]
+ myenv.CXXFLAGS.remove('/EHsc')
+ obj.env = myenv
bld.install_files(os.path.join(output_dir, 'JavaScriptCore'), 'API/*.h')
inline bool isASCII(wchar_t c) { return !(c & ~0x7F); }
#endif
inline bool isASCII(int c) { return !(c & ~0x7F); }
+ inline bool isASCII(unsigned c) { return !(c & ~0x7F); }
inline bool isASCIIAlpha(char c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; }
inline bool isASCIIAlpha(unsigned short c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; }
inline bool isASCIIAlpha(wchar_t c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; }
#endif
inline bool isASCIIAlpha(int c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; }
+ inline bool isASCIIAlpha(unsigned c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; }
inline bool isASCIIAlphanumeric(char c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); }
inline bool isASCIIAlphanumeric(unsigned short c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); }
inline bool isASCIIAlphanumeric(wchar_t c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); }
#endif
inline bool isASCIIAlphanumeric(int c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); }
+ inline bool isASCIIAlphanumeric(unsigned c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); }
inline bool isASCIIDigit(char c) { return (c >= '0') & (c <= '9'); }
inline bool isASCIIDigit(unsigned short c) { return (c >= '0') & (c <= '9'); }
inline bool isASCIIDigit(wchar_t c) { return (c >= '0') & (c <= '9'); }
#endif
inline bool isASCIIDigit(int c) { return (c >= '0') & (c <= '9'); }
+ inline bool isASCIIDigit(unsigned c) { return (c >= '0') & (c <= '9'); }
inline bool isASCIIHexDigit(char c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); }
inline bool isASCIIHexDigit(unsigned short c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); }
inline bool isASCIIHexDigit(wchar_t c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); }
#endif
inline bool isASCIIHexDigit(int c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); }
+ inline bool isASCIIHexDigit(unsigned c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); }
inline bool isASCIIOctalDigit(char c) { return (c >= '0') & (c <= '7'); }
inline bool isASCIIOctalDigit(unsigned short c) { return (c >= '0') & (c <= '7'); }
inline bool isASCIIOctalDigit(wchar_t c) { return (c >= '0') & (c <= '7'); }
#endif
inline bool isASCIIOctalDigit(int c) { return (c >= '0') & (c <= '7'); }
+ inline bool isASCIIOctalDigit(unsigned c) { return (c >= '0') & (c <= '7'); }
inline bool isASCIILower(char c) { return c >= 'a' && c <= 'z'; }
inline bool isASCIILower(unsigned short c) { return c >= 'a' && c <= 'z'; }
inline bool isASCIILower(wchar_t c) { return c >= 'a' && c <= 'z'; }
#endif
inline bool isASCIILower(int c) { return c >= 'a' && c <= 'z'; }
+ inline bool isASCIILower(unsigned c) { return c >= 'a' && c <= 'z'; }
inline bool isASCIIUpper(char c) { return c >= 'A' && c <= 'Z'; }
inline bool isASCIIUpper(unsigned short c) { return c >= 'A' && c <= 'Z'; }
inline bool isASCIIUpper(wchar_t c) { return c >= 'A' && c <= 'Z'; }
#endif
inline bool isASCIIUpper(int c) { return c >= 'A' && c <= 'Z'; }
+ inline bool isASCIIUpper(unsigned c) { return c >= 'A' && c <= 'Z'; }
/*
Statistics from a run of Apple's page load test for callers of isASCIISpace:
inline bool isASCIISpace(wchar_t c) { return c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9)); }
#endif
inline bool isASCIISpace(int c) { return c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9)); }
+ inline bool isASCIISpace(unsigned c) { return c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9)); }
inline char toASCIILower(char c) { return c | ((c >= 'A' && c <= 'Z') << 5); }
inline unsigned short toASCIILower(unsigned short c) { return c | ((c >= 'A' && c <= 'Z') << 5); }
inline wchar_t toASCIILower(wchar_t c) { return c | ((c >= 'A' && c <= 'Z') << 5); }
#endif
inline int toASCIILower(int c) { return c | ((c >= 'A' && c <= 'Z') << 5); }
+ inline unsigned toASCIILower(unsigned c) { return c | ((c >= 'A' && c <= 'Z') << 5); }
+ // FIXME: Why do these need static_cast?
inline char toASCIIUpper(char c) { return static_cast<char>(c & ~((c >= 'a' && c <= 'z') << 5)); }
inline unsigned short toASCIIUpper(unsigned short c) { return static_cast<unsigned short>(c & ~((c >= 'a' && c <= 'z') << 5)); }
#if !COMPILER(MSVC) || defined(_NATIVE_WCHAR_T_DEFINED)
inline wchar_t toASCIIUpper(wchar_t c) { return static_cast<wchar_t>(c & ~((c >= 'a' && c <= 'z') << 5)); }
#endif
inline int toASCIIUpper(int c) { return static_cast<int>(c & ~((c >= 'a' && c <= 'z') << 5)); }
+ inline unsigned toASCIIUpper(unsigned c) { return static_cast<unsigned>(c & ~((c >= 'a' && c <= 'z') << 5)); }
inline int toASCIIHexValue(char c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; }
+ inline int toASCIIHexValue(char upperValue, char lowerValue) { ASSERT(isASCIIHexDigit(upperValue) && isASCIIHexDigit(lowerValue)); return ((toASCIIHexValue(upperValue) << 4) & 0xF0) | toASCIIHexValue(lowerValue); }
inline int toASCIIHexValue(unsigned short c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; }
#if !COMPILER(MSVC) || defined(_NATIVE_WCHAR_T_DEFINED)
inline int toASCIIHexValue(wchar_t c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; }
#endif
inline int toASCIIHexValue(int c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; }
+ inline int toASCIIHexValue(unsigned c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; }
+
+ inline char lowerNibbleToASCIIHexDigit(char c) { char nibble = c & 0xF; return nibble < 10 ? '0' + nibble : 'A' + nibble - 10; }
+ inline char upperNibbleToASCIIHexDigit(char c) { char nibble = (c >> 4) & 0xF; return nibble < 10 ? '0' + nibble : 'A' + nibble - 10; }
inline bool isASCIIPrintable(char c) { return c >= ' ' && c <= '~'; }
inline bool isASCIIPrintable(unsigned short c) { return c >= ' ' && c <= '~'; }
inline bool isASCIIPrintable(wchar_t c) { return c >= ' ' && c <= '~'; }
#endif
inline bool isASCIIPrintable(int c) { return c >= ' ' && c <= '~'; }
+ inline bool isASCIIPrintable(unsigned c) { return c >= ' ' && c <= '~'; }
}
using WTF::isASCII;
using WTF::toASCIIHexValue;
using WTF::toASCIILower;
using WTF::toASCIIUpper;
+using WTF::lowerNibbleToASCIIHexDigit;
+using WTF::upperNibbleToASCIIHexDigit;
#endif
#define AVL_TREE_H_
#include "Assertions.h"
+#include <wtf/FixedArray.h>
namespace WTF {
void reset() { for (unsigned i = 0; i < maxDepth; ++i) m_data[i] = false; }
private:
- bool m_data[maxDepth];
+ FixedArray<bool, maxDepth> m_data;
};
// How to determine maxDepth:
--- /dev/null
+/*
+ * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+#ifndef WTF_Alignment_h
+#define WTF_Alignment_h
+
+#include <wtf/Platform.h>
+
+#if COMPILER(GCC) || COMPILER(MINGW) || COMPILER(RVCT) || COMPILER(WINSCW) || COMPILER(GCCE)
+ #define WTF_ALIGN_OF(type) __alignof__(type)
+ #define WTF_ALIGNED(variable_type, variable, n) variable_type variable __attribute__((__aligned__(n)))
+#elif COMPILER(MSVC)
+ #define WTF_ALIGN_OF(type) __alignof(type)
+ #define WTF_ALIGNED(variable_type, variable, n) __declspec(align(n)) variable_type variable
+#else
+ #error WTF_ALIGN macros need alignment control.
+#endif
+
+#endif // WTF_Alignment_h
#endif
#ifndef UNLIKELY
-#if COMPILER(GCC)
+#if COMPILER(GCC) || (RVCT_VERSION_AT_LEAST(3, 0, 0, 0) && defined(__GNUC__))
#define UNLIKELY(x) __builtin_expect((x), 0)
#else
#define UNLIKELY(x) (x)
#endif
#ifndef LIKELY
-#if COMPILER(GCC)
+#if COMPILER(GCC) || (RVCT_VERSION_AT_LEAST(3, 0, 0, 0) && defined(__GNUC__))
#define LIKELY(x) __builtin_expect((x), 1)
#else
#define LIKELY(x) (x)
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+// The vprintf_stderr_common function triggers this error in the Mac build.
+// Feel free to remove this pragma if this file builds on Mac.
+// According to http://gcc.gnu.org/onlinedocs/gcc-4.2.1/gcc/Diagnostic-Pragmas.html#Diagnostic-Pragmas
+// we need to place this directive before any data or functions are defined.
+#pragma GCC diagnostic ignored "-Wmissing-format-attribute"
+
#include "config.h"
#include "Assertions.h"
#include <CoreFoundation/CFString.h>
-#if COMPILER(MSVC) && !OS(WINCE)
+#if COMPILER(MSVC) && !OS(WINCE) && !PLATFORM(BREWMP)
#ifndef WINVER
#define WINVER 0x0500
#endif
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0500
#endif
-#include <windows.h>
#include <crtdbg.h>
#endif
-#if OS(WINCE)
-#include <winbase.h>
+#if OS(WINDOWS)
+#include <windows.h>
+#endif
+
+#if PLATFORM(BREWMP)
+#include <AEEdbg.h>
+#include <wtf/Vector.h>
+#endif
+
+#if PLATFORM(MAC)
+#include <cxxabi.h>
+#include <dlfcn.h>
+#include <execinfo.h>
#endif
extern "C" {
+#if PLATFORM(BREWMP)
+
+static void printLog(const Vector<char>& buffer)
+{
+ // Each call to DBGPRINTF generates at most 128 bytes of output on the Windows SDK.
+ // On Qualcomm chipset targets, DBGPRINTF() comes out the diag port (though this may change).
+ // The length of each output string is constrained even more than on the Windows SDK.
+#if COMPILER(MSVC)
+ const int printBufferSize = 128;
+#else
+ const int printBufferSize = 32;
+#endif
+
+ char printBuffer[printBufferSize + 1];
+ printBuffer[printBufferSize] = 0; // to guarantee null termination
+
+ const char* p = buffer.data();
+ const char* end = buffer.data() + buffer.size();
+ while (p < end) {
+ strncpy(printBuffer, p, printBufferSize);
+ dbg_Message(printBuffer, DBG_MSG_LEVEL_HIGH, __FILE__, __LINE__);
+ p += printBufferSize;
+ }
+}
+
+#endif
+
WTF_ATTRIBUTE_PRINTF(1, 0)
static void vprintf_stderr_common(const char* format, va_list args)
{
free(buffer);
CFRelease(str);
CFRelease(cfFormat);
- } else
+ return;
+ }
#if OS(SYMBIAN)
vfprintf(stdout, format, args);
#else
static void printCallSite(const char* file, int line, const char* function)
{
-#if OS(WIN) && !OS(WINCE) && defined _DEBUG
+#if OS(WINDOWS) && !OS(WINCE) && defined(_DEBUG)
_CrtDbgReport(_CRT_WARN, file, line, NULL, "%s\n", function);
#else
- printf_stderr_common("(%s:%d %s)\n", file, line, function);
+ // By using this format, which matches the format used by MSVC for compiler errors, developers
+ // using Visual Studio can double-click the file/line number in the Output Window to have the
+ // editor navigate to that line of code. It seems fine for other developers, too.
+ printf_stderr_common("%s(%d) : %s\n", file, line, function);
#endif
}
printCallSite(file, line, function);
}
+void WTFReportBacktrace()
+{
+#if PLATFORM(MAC)
+ static const int maxFrames = 32;
+ void* samples[maxFrames];
+ int frames = backtrace(samples, maxFrames);
+
+ for (int i = 1; i < frames; ++i) {
+ void* pointer = samples[i];
+
+ // Try to get a symbol name from the dynamic linker.
+ Dl_info info;
+ if (dladdr(pointer, &info) && info.dli_sname) {
+ const char* mangledName = info.dli_sname;
+
+ // Assume c++ & try to demangle the name.
+ char* demangledName = abi::__cxa_demangle(mangledName, 0, 0, 0);
+ if (demangledName) {
+ fprintf(stderr, "%-3d %s\n", i, demangledName);
+ free(demangledName);
+ } else
+ fprintf(stderr, "%-3d %s\n", i, mangledName);
+ } else
+ fprintf(stderr, "%-3d %p\n", i, pointer);
+ }
+#endif
+}
+
void WTFReportFatalError(const char* file, int line, const char* function, const char* format, ...)
{
printf_stderr_common("FATAL ERROR: ");
va_start(args, format);
vprintf_stderr_common(format, args);
va_end(args);
- if (format[strlen(format) - 1] != '\n')
+
+ size_t formatLength = strlen(format);
+ if (formatLength && format[formatLength - 1] != '\n')
printf_stderr_common("\n");
}
va_start(args, format);
vprintf_stderr_common(format, args);
va_end(args);
- if (format[strlen(format) - 1] != '\n')
+
+ size_t formatLength = strlen(format);
+ if (formatLength && format[formatLength - 1] != '\n')
printf_stderr_common("\n");
+
printCallSite(file, line, function);
}
#include <stdbool.h>
-#if COMPILER(MSVC)
#include <stddef.h>
-#else
+
+#if !COMPILER(MSVC)
#include <inttypes.h>
#endif
#include <e32debug.h>
#endif
+#if PLATFORM(BREWMP)
+#include <AEEError.h>
+#include <AEEdbg.h>
+#endif
+
#ifdef NDEBUG
/* Disable ASSERT* macros in release mode. */
#define ASSERTIONS_DISABLED_DEFAULT 1
#define HAVE_VARIADIC_MACRO 1
#endif
+#ifndef BACKTRACE_DISABLED
+#define BACKTRACE_DISABLED ASSERTIONS_DISABLED_DEFAULT
+#endif
+
#ifndef ASSERT_DISABLED
#define ASSERT_DISABLED ASSERTIONS_DISABLED_DEFAULT
#endif
#else
#define CLANG_ANALYZER_NORETURN
#endif
+/* For project uses WTF but has no config.h, we need to explicitly set the export defines here. */
+#ifndef WTF_EXPORT_PRIVATE
+#define WTF_EXPORT_PRIVATE
+#endif
/* These helper functions are always declared, but not necessarily always defined if the corresponding function is disabled. */
WTFLogChannelState state;
} WTFLogChannel;
-void WTFReportAssertionFailure(const char* file, int line, const char* function, const char* assertion) CLANG_ANALYZER_NORETURN;
-void WTFReportAssertionFailureWithMessage(const char* file, int line, const char* function, const char* assertion, const char* format, ...) CLANG_ANALYZER_NORETURN WTF_ATTRIBUTE_PRINTF(5, 6);
-void WTFReportArgumentAssertionFailure(const char* file, int line, const char* function, const char* argName, const char* assertion) CLANG_ANALYZER_NORETURN;
-void WTFReportFatalError(const char* file, int line, const char* function, const char* format, ...) CLANG_ANALYZER_NORETURN WTF_ATTRIBUTE_PRINTF(4, 5);
-void WTFReportError(const char* file, int line, const char* function, const char* format, ...) WTF_ATTRIBUTE_PRINTF(4, 5);
-void WTFLog(WTFLogChannel* channel, const char* format, ...) WTF_ATTRIBUTE_PRINTF(2, 3);
-void WTFLogVerbose(const char* file, int line, const char* function, WTFLogChannel* channel, const char* format, ...) WTF_ATTRIBUTE_PRINTF(5, 6);
+WTF_EXPORT_PRIVATE void WTFReportAssertionFailure(const char* file, int line, const char* function, const char* assertion) CLANG_ANALYZER_NORETURN;
+WTF_EXPORT_PRIVATE void WTFReportAssertionFailureWithMessage(const char* file, int line, const char* function, const char* assertion, const char* format, ...) CLANG_ANALYZER_NORETURN WTF_ATTRIBUTE_PRINTF(5, 6);
+WTF_EXPORT_PRIVATE void WTFReportArgumentAssertionFailure(const char* file, int line, const char* function, const char* argName, const char* assertion) CLANG_ANALYZER_NORETURN;
+WTF_EXPORT_PRIVATE void WTFReportBacktrace();
+WTF_EXPORT_PRIVATE void WTFReportFatalError(const char* file, int line, const char* function, const char* format, ...) CLANG_ANALYZER_NORETURN WTF_ATTRIBUTE_PRINTF(4, 5);
+WTF_EXPORT_PRIVATE void WTFReportError(const char* file, int line, const char* function, const char* format, ...) WTF_ATTRIBUTE_PRINTF(4, 5);
+WTF_EXPORT_PRIVATE void WTFLog(WTFLogChannel* channel, const char* format, ...) WTF_ATTRIBUTE_PRINTF(2, 3);
+WTF_EXPORT_PRIVATE void WTFLogVerbose(const char* file, int line, const char* function, WTFLogChannel* channel, const char* format, ...) WTF_ATTRIBUTE_PRINTF(5, 6);
#ifdef __cplusplus
}
__DEBUGGER(); \
User::Panic(_L("Webkit CRASH"),0); \
} while(false)
+#elif PLATFORM(BREWMP)
+#define CRASH() do { \
+ dbg_Message("WebKit CRASH", DBG_MSG_LEVEL_FATAL, __FILE__, __LINE__); \
+ *(int *)(uintptr_t)0xbbadbeef = 0; \
+ ((void(*)())0)(); /* More reliable, but doesn't say BBADBEEF */ \
+} while(false)
#else
#define CRASH() do { \
+ WTFReportBacktrace(); \
*(int *)(uintptr_t)0xbbadbeef = 0; \
((void(*)())0)(); /* More reliable, but doesn't say BBADBEEF */ \
} while(false)
#endif
#endif
+/* BACKTRACE
+
+ Print a backtrace to the same location as ASSERT messages.
+*/
+
+#if BACKTRACE_DISABLED
+
+#define BACKTRACE() ((void)0)
+
+#else
+
+#define BACKTRACE() do { \
+ WTFReportBacktrace(); \
+} while(false)
+
+#endif
+
/* ASSERT, ASSERT_NOT_REACHED, ASSERT_UNUSED
These macros are compiled out of release builds.
#define ASSERT(assertion) ((void)0)
#define ASSERT_NOT_REACHED() ((void)0)
+
+#if COMPILER(INTEL) && !OS(WINDOWS) || COMPILER(RVCT)
+template<typename T>
+inline void assertUnused(T& x) { (void)x; }
+#define ASSERT_UNUSED(variable, assertion) (assertUnused(variable))
+#else
#define ASSERT_UNUSED(variable, assertion) ((void)variable)
+#endif
#else
} \
while (0)
#endif
+
+/* ASSERT_WITH_MESSAGE_UNUSED */
+
+#if COMPILER(MSVC7_OR_LOWER)
+#define ASSERT_WITH_MESSAGE_UNUSED(variable, assertion) ((void)0)
+#elif COMPILER(WINSCW)
+#define ASSERT_WITH_MESSAGE_UNUSED(variable, assertion, arg...) ((void)0)
+#elif ASSERT_MSG_DISABLED
+#if COMPILER(INTEL) && !OS(WINDOWS) || COMPILER(RVCT)
+template<typename T>
+inline void assertWithMessageUnused(T& x) { (void)x; }
+#define ASSERT_WITH_MESSAGE_UNUSED(variable, assertion, ...) (assertWithMessageUnused(variable))
+#else
+#define ASSERT_WITH_MESSAGE_UNUSED(variable, assertion, ...) ((void)variable)
+#endif
+#else
+#define ASSERT_WITH_MESSAGE_UNUSED(variable, assertion, ...) do \
+ if (!(assertion)) { \
+ WTFReportAssertionFailureWithMessage(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #assertion, __VA_ARGS__); \
+ CRASH(); \
+ } \
+while (0)
+#endif
/* ASSERT_ARG */
#define LOG_VERBOSE(channel, ...) WTFLogVerbose(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, &JOIN_LOG_CHANNEL_WITH_PREFIX(LOG_CHANNEL_PREFIX, channel), __VA_ARGS__)
#endif
+#if ENABLE(GC_VALIDATION)
+#define ASSERT_GC_OBJECT_LOOKS_VALID(cell) do { \
+ if (!(cell))\
+ CRASH();\
+ if (cell->unvalidatedStructure()->unvalidatedStructure() != cell->unvalidatedStructure()->unvalidatedStructure()->unvalidatedStructure())\
+ CRASH();\
+} while (0)
+
+#define ASSERT_GC_OBJECT_INHERITS(object, classInfo) do {\
+ ASSERT_GC_OBJECT_LOOKS_VALID(object); \
+ if (!object->inherits(classInfo)) \
+ CRASH();\
+} while (0)
+
+#else
+#define ASSERT_GC_OBJECT_LOOKS_VALID(cell) do { (void)cell; } while (0)
+#define ASSERT_GC_OBJECT_INHERITS(object, classInfo) do { (void)object; (void)classInfo; } while (0)
+#endif
+
#endif /* WTF_Assertions_h */
namespace WTF {
#if OS(WINDOWS)
-#define WTF_USE_LOCKFREE_THREADSAFESHARED 1
+#define WTF_USE_LOCKFREE_THREADSAFEREFCOUNTED 1
#if COMPILER(MINGW) || COMPILER(MSVC7_OR_LOWER) || OS(WINCE)
inline int atomicIncrement(int* addend) { return InterlockedIncrement(reinterpret_cast<long*>(addend)); }
#endif
#elif OS(DARWIN)
-#define WTF_USE_LOCKFREE_THREADSAFESHARED 1
+#define WTF_USE_LOCKFREE_THREADSAFEREFCOUNTED 1
inline int atomicIncrement(int volatile* addend) { return OSAtomicIncrement32Barrier(const_cast<int*>(addend)); }
inline int atomicDecrement(int volatile* addend) { return OSAtomicDecrement32Barrier(const_cast<int*>(addend)); }
inline int atomicDecrement(int volatile* addend) { return android_atomic_dec(addend); }
#elif COMPILER(GCC) && !CPU(SPARC64) && !OS(SYMBIAN) // sizeof(_Atomic_word) != sizeof(int) on sparc64 gcc
-#define WTF_USE_LOCKFREE_THREADSAFESHARED 1
+#define WTF_USE_LOCKFREE_THREADSAFEREFCOUNTED 1
inline int atomicIncrement(int volatile* addend) { return __gnu_cxx::__exchange_and_add(addend, 1) + 1; }
inline int atomicDecrement(int volatile* addend) { return __gnu_cxx::__exchange_and_add(addend, -1) - 1; }
} // namespace WTF
-#if USE(LOCKFREE_THREADSAFESHARED)
+#if USE(LOCKFREE_THREADSAFEREFCOUNTED)
using WTF::atomicDecrement;
using WTF::atomicIncrement;
#endif
--- /dev/null
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+#ifndef Bitmap_h
+#define Bitmap_h
+
+#include "FixedArray.h"
+#include "StdLibExtras.h"
+#include <stdint.h>
+#include <string.h>
+
+namespace WTF {
+
+template<size_t size>
+class Bitmap {
+private:
+ typedef uint32_t WordType;
+
+public:
+ Bitmap();
+
+ bool get(size_t) const;
+ void set(size_t);
+ bool testAndSet(size_t);
+ size_t nextPossiblyUnset(size_t) const;
+ void clear(size_t);
+ void clearAll();
+ int64_t findRunOfZeros(size_t) const;
+ size_t count(size_t = 0) const;
+ size_t isEmpty() const;
+ size_t isFull() const;
+
+private:
+ static const WordType wordSize = sizeof(WordType) * 8;
+ static const WordType words = (size + wordSize - 1) / wordSize;
+
+ // the literal '1' is of type signed int. We want to use an unsigned
+ // version of the correct size when doing the calculations because if
+ // WordType is larger than int, '1 << 31' will first be sign extended
+ // and then casted to unsigned, meaning that set(31) when WordType is
+ // a 64 bit unsigned int would give 0xffff8000
+ static const WordType one = 1;
+
+ FixedArray<WordType, words> bits;
+};
+
+template<size_t size>
+inline Bitmap<size>::Bitmap()
+{
+ clearAll();
+}
+
+template<size_t size>
+inline bool Bitmap<size>::get(size_t n) const
+{
+ return !!(bits[n / wordSize] & (one << (n % wordSize)));
+}
+
+template<size_t size>
+inline void Bitmap<size>::set(size_t n)
+{
+ bits[n / wordSize] |= (one << (n % wordSize));
+}
+
+template<size_t size>
+inline bool Bitmap<size>::testAndSet(size_t n)
+{
+ WordType mask = one << (n % wordSize);
+ size_t index = n / wordSize;
+ bool result = bits[index] & mask;
+ bits[index] |= mask;
+ return result;
+}
+
+template<size_t size>
+inline void Bitmap<size>::clear(size_t n)
+{
+ bits[n / wordSize] &= ~(one << (n % wordSize));
+}
+
+template<size_t size>
+inline void Bitmap<size>::clearAll()
+{
+ memset(bits.data(), 0, sizeof(bits));
+}
+
+template<size_t size>
+inline size_t Bitmap<size>::nextPossiblyUnset(size_t start) const
+{
+ if (!~bits[start / wordSize])
+ return ((start / wordSize) + 1) * wordSize;
+ return start + 1;
+}
+
+template<size_t size>
+inline int64_t Bitmap<size>::findRunOfZeros(size_t runLength) const
+{
+ if (!runLength)
+ runLength = 1;
+
+ for (size_t i = 0; i <= (size - runLength) ; i++) {
+ bool found = true;
+ for (size_t j = i; j <= (i + runLength - 1) ; j++) {
+ if (get(j)) {
+ found = false;
+ break;
+ }
+ }
+ if (found)
+ return i;
+ }
+ return -1;
+}
+
+template<size_t size>
+inline size_t Bitmap<size>::count(size_t start) const
+{
+ size_t result = 0;
+ for ( ; (start % wordSize); ++start) {
+ if (get(start))
+ ++result;
+ }
+ for (size_t i = start / wordSize; i < words; ++i)
+ result += WTF::bitCount(bits[i]);
+ return result;
+}
+
+template<size_t size>
+inline size_t Bitmap<size>::isEmpty() const
+{
+ for (size_t i = 0; i < words; ++i)
+ if (bits[i])
+ return false;
+ return true;
+}
+
+template<size_t size>
+inline size_t Bitmap<size>::isFull() const
+{
+ for (size_t i = 0; i < words; ++i)
+ if (~bits[i])
+ return false;
+ return true;
+}
+
+}
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef BlockStack_h
+#define BlockStack_h
+
+#include <wtf/Assertions.h>
+#include <wtf/Vector.h>
+
+namespace WTF {
+
+template <typename T> class BlockStack {
+public:
+ static const size_t blockSize = 4096;
+ static const size_t blockLength = blockSize / sizeof(T);
+
+ BlockStack();
+ ~BlockStack();
+
+ T* grow();
+ void shrink(T*);
+
+ const Vector<T*>& blocks();
+
+private:
+ Vector<T*> m_blocks;
+ T* m_spareBlock; // Used to avoid thrash at block boundaries.
+};
+
+template <typename T> BlockStack<T>::BlockStack()
+ : m_spareBlock(0)
+{
+}
+
+template <typename T> BlockStack<T>::~BlockStack()
+{
+ if (m_spareBlock)
+ free(m_spareBlock);
+ for (size_t i = 0; i < m_blocks.size(); ++i)
+ free(m_blocks[i]);
+}
+
+template <typename T> inline const Vector<T*>& BlockStack<T>::blocks()
+{
+ return m_blocks;
+}
+
+template <typename T> T* BlockStack<T>::grow()
+{
+ T* block = m_spareBlock ? m_spareBlock : static_cast<T*>(malloc(blockSize));
+ m_spareBlock = 0;
+
+ m_blocks.append(block);
+ return block;
+}
+
+template <typename T> void BlockStack<T>::shrink(T* newEnd)
+{
+ ASSERT(newEnd != m_blocks.last() + blockLength);
+ m_spareBlock = m_blocks.last();
+ m_blocks.removeLast();
+
+ while (m_blocks.last() + blockLength != newEnd) {
+ free(m_blocks.last());
+ m_blocks.removeLast();
+ }
+}
+
+}
+
+using WTF::BlockStack;
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef BloomFilter_h
+#define BloomFilter_h
+
+#include <wtf/AlwaysInline.h>
+#include <wtf/text/AtomicString.h>
+
+namespace WTF {
+
+// Counting bloom filter with k=2 and 8 bit counters. Uses 2^keyBits bytes of memory.
+// False positive rate is approximately (1-e^(-2n/m))^2, where n is the number of unique
+// keys and m is the table size (==2^keyBits).
+template <unsigned keyBits>
+class BloomFilter {
+public:
+ COMPILE_ASSERT(keyBits <= 16, bloom_filter_key_size);
+
+ static const size_t tableSize = 1 << keyBits;
+ static const unsigned keyMask = (1 << keyBits) - 1;
+ static uint8_t maximumCount() { return std::numeric_limits<uint8_t>::max(); }
+
+ BloomFilter() { clear(); }
+
+ void add(unsigned hash);
+ void remove(unsigned hash);
+
+ // The filter may give false positives (claim it may contain a key it doesn't)
+ // but never false negatives (claim it doesn't contain a key it does).
+ bool mayContain(unsigned hash) const { return firstSlot(hash) && secondSlot(hash); }
+
+ // The filter must be cleared before reuse even if all keys are removed.
+ // Otherwise overflowed keys will stick around.
+ void clear();
+
+ void add(const AtomicString& string) { add(string.impl()->existingHash()); }
+ void add(const String& string) { add(string.impl()->hash()); }
+ void remove(const AtomicString& string) { remove(string.impl()->existingHash()); }
+ void remove(const String& string) { remove(string.impl()->hash()); }
+
+ bool mayContain(const AtomicString& string) const { return mayContain(string.impl()->existingHash()); }
+ bool mayContain(const String& string) const { return mayContain(string.impl()->hash()); }
+
+#if !ASSERT_DISABLED
+ // Slow.
+ bool likelyEmpty() const;
+ bool isClear() const;
+#endif
+
+private:
+ uint8_t& firstSlot(unsigned hash) { return m_table[hash & keyMask]; }
+ uint8_t& secondSlot(unsigned hash) { return m_table[(hash >> 16) & keyMask]; }
+ const uint8_t& firstSlot(unsigned hash) const { return m_table[hash & keyMask]; }
+ const uint8_t& secondSlot(unsigned hash) const { return m_table[(hash >> 16) & keyMask]; }
+
+ uint8_t m_table[tableSize];
+};
+
+template <unsigned keyBits>
+inline void BloomFilter<keyBits>::add(unsigned hash)
+{
+ uint8_t& first = firstSlot(hash);
+ uint8_t& second = secondSlot(hash);
+ if (LIKELY(first < maximumCount()))
+ ++first;
+ if (LIKELY(second < maximumCount()))
+ ++second;
+}
+
+template <unsigned keyBits>
+inline void BloomFilter<keyBits>::remove(unsigned hash)
+{
+ uint8_t& first = firstSlot(hash);
+ uint8_t& second = secondSlot(hash);
+ ASSERT(first);
+ ASSERT(second);
+ // In case of an overflow, the slot sticks in the table until clear().
+ if (LIKELY(first < maximumCount()))
+ --first;
+ if (LIKELY(second < maximumCount()))
+ --second;
+}
+
+template <unsigned keyBits>
+inline void BloomFilter<keyBits>::clear()
+{
+ memset(m_table, 0, tableSize);
+}
+
+#if !ASSERT_DISABLED
+template <unsigned keyBits>
+bool BloomFilter<keyBits>::likelyEmpty() const
+{
+ for (size_t n = 0; n < tableSize; ++n) {
+ if (m_table[n] && m_table[n] != maximumCount())
+ return false;
+ }
+ return true;
+}
+
+template <unsigned keyBits>
+bool BloomFilter<keyBits>::isClear() const
+{
+ for (size_t n = 0; n < tableSize; ++n) {
+ if (m_table[n])
+ return false;
+ }
+ return true;
+}
+#endif
+
+}
+
+using WTF::BloomFilter;
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef BumpPointerAllocator_h
+#define BumpPointerAllocator_h
+
+#include <wtf/PageAllocation.h>
+
+namespace WTF {
+
+#define MINIMUM_BUMP_POOL_SIZE 0x1000
+
+class BumpPointerPool {
+public:
+ // ensureCapacity will check whether the current pool has capacity to
+ // allocate 'size' bytes of memory If it does not, it will attempt to
+ // allocate a new pool (which will be added to this one in a chain).
+ //
+ // If allocation fails (out of memory) this method will return null.
+ // If the return value is non-null, then callers should update any
+ // references they have to this current (possibly full) BumpPointerPool
+ // to instead point to the newly returned BumpPointerPool.
+ BumpPointerPool* ensureCapacity(size_t size)
+ {
+ void* allocationEnd = static_cast<char*>(m_current) + size;
+ ASSERT(allocationEnd > m_current); // check for overflow
+ if (allocationEnd <= static_cast<void*>(this))
+ return this;
+ return ensureCapacityCrossPool(this, size);
+ }
+
+ // alloc should only be called after calling ensureCapacity; as such
+ // alloc will never fail.
+ void* alloc(size_t size)
+ {
+ void* current = m_current;
+ void* allocationEnd = static_cast<char*>(current) + size;
+ ASSERT(allocationEnd > current); // check for overflow
+ ASSERT(allocationEnd <= static_cast<void*>(this));
+ m_current = allocationEnd;
+ return current;
+ }
+
+ // The dealloc method releases memory allocated using alloc. Memory
+ // must be released in a LIFO fashion, e.g. if the client calls alloc
+ // four times, returning pointer A, B, C, D, then the only valid order
+ // in which these may be deallocaed is D, C, B, A.
+ //
+ // The client may optionally skip some deallocations. In the example
+ // above, it would be valid to only explicitly dealloc C, A (D being
+ // dealloced along with C, B along with A).
+ //
+ // If pointer was not allocated from this pool (or pools) then dealloc
+ // will CRASH(). Callers should update any references they have to
+ // this current BumpPointerPool to instead point to the returned
+ // BumpPointerPool.
+ BumpPointerPool* dealloc(void* position)
+ {
+ if ((position >= m_start) && (position <= static_cast<void*>(this))) {
+ ASSERT(position <= m_current);
+ m_current = position;
+ return this;
+ }
+ return deallocCrossPool(this, position);
+ }
+
+private:
+ // Placement operator new, returns the last 'size' bytes of allocation for use as this.
+ void* operator new(size_t size, const PageAllocation& allocation)
+ {
+ ASSERT(size < allocation.size());
+ return reinterpret_cast<char*>(reinterpret_cast<intptr_t>(allocation.base()) + allocation.size()) - size;
+ }
+
+ BumpPointerPool(const PageAllocation& allocation)
+ : m_current(allocation.base())
+ , m_start(allocation.base())
+ , m_next(0)
+ , m_previous(0)
+ , m_allocation(allocation)
+ {
+ }
+
+ static BumpPointerPool* create(size_t minimumCapacity = 0)
+ {
+ // Add size of BumpPointerPool object, check for overflow.
+ minimumCapacity += sizeof(BumpPointerPool);
+ if (minimumCapacity < sizeof(BumpPointerPool))
+ return 0;
+
+ size_t poolSize = MINIMUM_BUMP_POOL_SIZE;
+ while (poolSize < minimumCapacity) {
+ poolSize <<= 1;
+ // The following if check relies on MINIMUM_BUMP_POOL_SIZE being a power of 2!
+ ASSERT(!(MINIMUM_BUMP_POOL_SIZE & (MINIMUM_BUMP_POOL_SIZE - 1)));
+ if (!poolSize)
+ return 0;
+ }
+
+ PageAllocation allocation = PageAllocation::allocate(poolSize);
+ if (!!allocation)
+ return new(allocation) BumpPointerPool(allocation);
+ return 0;
+ }
+
+ void shrink()
+ {
+ ASSERT(!m_previous);
+ m_current = m_start;
+ while (m_next) {
+ BumpPointerPool* nextNext = m_next->m_next;
+ m_next->destroy();
+ m_next = nextNext;
+ }
+ }
+
+ void destroy()
+ {
+ m_allocation.deallocate();
+ }
+
+ static BumpPointerPool* ensureCapacityCrossPool(BumpPointerPool* previousPool, size_t size)
+ {
+ // The pool passed should not have capacity, so we'll start with the next one.
+ ASSERT(previousPool);
+ ASSERT((static_cast<char*>(previousPool->m_current) + size) > previousPool->m_current); // check for overflow
+ ASSERT((static_cast<char*>(previousPool->m_current) + size) > static_cast<void*>(previousPool));
+ BumpPointerPool* pool = previousPool->m_next;
+
+ while (true) {
+ if (!pool) {
+ // We've run to the end; allocate a new pool.
+ pool = BumpPointerPool::create(size);
+ previousPool->m_next = pool;
+ pool->m_previous = previousPool;
+ return pool;
+ }
+
+ //
+ void* current = pool->m_current;
+ void* allocationEnd = static_cast<char*>(current) + size;
+ ASSERT(allocationEnd > current); // check for overflow
+ if (allocationEnd <= static_cast<void*>(pool))
+ return pool;
+ }
+ }
+
+ static BumpPointerPool* deallocCrossPool(BumpPointerPool* pool, void* position)
+ {
+ // Should only be called if position is not in the current pool.
+ ASSERT((position < pool->m_start) || (position > static_cast<void*>(pool)));
+
+ while (true) {
+ // Unwind the current pool to the start, move back in the chain to the previous pool.
+ pool->m_current = pool->m_start;
+ pool = pool->m_previous;
+
+ // position was nowhere in the chain!
+ if (!pool)
+ CRASH();
+
+ if ((position >= pool->m_start) && (position <= static_cast<void*>(pool))) {
+ ASSERT(position <= pool->m_current);
+ pool->m_current = position;
+ return pool;
+ }
+ }
+ }
+
+ void* m_current;
+ void* m_start;
+ BumpPointerPool* m_next;
+ BumpPointerPool* m_previous;
+ PageAllocation m_allocation;
+
+ friend class BumpPointerAllocator;
+};
+
+// A BumpPointerAllocator manages a set of BumpPointerPool objects, which
+// can be used for LIFO (stack like) allocation.
+//
+// To begin allocating using this class call startAllocator(). The result
+// of this method will be null if the initial pool allocation fails, or a
+// pointer to a BumpPointerPool object that can be used to perform
+// allocations. Whilst running no memory will be released until
+// stopAllocator() is called. At this point all allocations made through
+// this allocator will be reaped, and underlying memory may be freed.
+//
+// (In practice we will still hold on to the initial pool to allow allocation
+// to be quickly restared, but aditional pools will be freed).
+//
+// This allocator is non-renetrant, it is encumbant on the clients to ensure
+// startAllocator() is not called again until stopAllocator() has been called.
+class BumpPointerAllocator {
+public:
+ BumpPointerAllocator()
+ : m_head(0)
+ {
+ }
+
+ ~BumpPointerAllocator()
+ {
+ if (m_head)
+ m_head->destroy();
+ }
+
+ BumpPointerPool* startAllocator()
+ {
+ if (!m_head)
+ m_head = BumpPointerPool::create();
+ return m_head;
+ }
+
+ void stopAllocator()
+ {
+ if (m_head)
+ m_head->shrink();
+ }
+
+private:
+ BumpPointerPool* m_head;
+};
+
+}
+
+using WTF::BumpPointerAllocator;
+
+#endif // BumpPointerAllocator_h
#include "config.h"
#include "ByteArray.h"
+#include "StdLibExtras.h"
namespace WTF {
PassRefPtr<ByteArray> ByteArray::create(size_t size)
{
- unsigned char* buffer = new unsigned char[size + sizeof(ByteArray) - sizeof(size_t)];
+ unsigned char* buffer = new unsigned char[size + OBJECT_OFFSETOF(ByteArray, m_data)];
ASSERT((reinterpret_cast<size_t>(buffer) & 3) == 0);
return adoptRef(new (buffer) ByteArray(size));
}
#ifndef ByteArray_h
#define ByteArray_h
+#include <limits.h>
#include <wtf/PassRefPtr.h>
+#include <wtf/Platform.h>
#include <wtf/RefCounted.h>
namespace WTF {
{
}
size_t m_size;
- unsigned char m_data[sizeof(size_t)];
+// MSVC can't handle correctly unsized array.
+// warning C4200: nonstandard extension used : zero-sized array in struct/union
+// Cannot generate copy-ctor or copy-assignment operator when UDT contains a zero-sized array
+#if COMPILER(MSVC)
+ unsigned char m_data[INT_MAX];
+#else
+ unsigned char m_data[];
+#endif
};
-}
+} // namespace WTF
+
+using WTF::ByteArray;
#endif
--- /dev/null
+SET(WTF_HEADERS
+ ASCIICType.h
+ AVLTree.h
+ Alignment.h
+ AlwaysInline.h
+ Assertions.h
+ Atomics.h
+ Bitmap.h
+ BumpPointerAllocator.h
+ ByteArray.h
+ Complex.h
+ CrossThreadRefCounted.h
+ CryptographicallyRandomNumber.h
+ CurrentTime.h
+ DateMath.h
+ DecimalNumber.h
+ Decoder.h
+ Deque.h
+ DisallowCType.h
+ DoublyLinkedList.h
+ DynamicAnnotations.h
+ Encoder.h
+ FastAllocBase.h
+ FastMalloc.h
+ FixedArray.h
+ Forward.h
+ GetPtr.h
+ HashCountedSet.h
+ HashFunctions.h
+ HashIterators.h
+ HashMap.h
+ HashSet.h
+ HashTable.h
+ HashTraits.h
+ HexNumber.h
+ ListHashSet.h
+ ListRefPtr.h
+ Locker.h
+ MD5.h
+ MainThread.h
+ MallocZoneSupport.h
+ MathExtras.h
+ MessageQueue.h
+ NonCopyingSort.h
+ Noncopyable.h
+ NotFound.h
+ NullPtr.h
+ OSAllocator.h
+ OSRandomSource.h
+ OwnArrayPtr.h
+ OwnFastMallocPtr.h
+ OwnPtr.h
+ OwnPtrCommon.h
+ PageAllocation.h
+ PageAllocationAligned.h
+ PageBlock.h
+ PageReservation.h
+ PassOwnArrayPtr.h
+ PassOwnPtr.h
+ PassRefPtr.h
+ PassTraits.h
+ ParallelJobs.h
+ ParallelJobsGeneric.h
+ ParallelJobsLibdispatch.h
+ ParallelJobsOpenMP.h
+ Platform.h
+ PossiblyNull.h
+ RandomNumber.h
+ RandomNumberSeed.h
+ RefCounted.h
+ RefCountedLeakCounter.h
+ RefPtr.h
+ RefPtrHashMap.h
+ RetainPtr.h
+ SegmentedVector.h
+ SHA1.h
+ StackBounds.h
+ StaticConstructors.h
+ StdLibExtras.h
+ StringExtras.h
+ StringHasher.h
+ TCPackedCache.h
+ TCPageMap.h
+ TCSpinLock.h
+ TCSystemAlloc.h
+ ThreadIdentifierDataPthreads.h
+ ThreadSafeRefCounted.h
+ ThreadSpecific.h
+ Threading.h
+ ThreadingPrimitives.h
+ TypeTraits.h
+ UnusedParam.h
+ VMTags.h
+ ValueCheck.h
+ Vector.h
+ VectorTraits.h
+ WTFThreadData.h
+ dtoa.h
+
+ text/AtomicString.h
+ text/AtomicStringImpl.h
+ text/CString.h
+ text/StringBuffer.h
+ text/StringHash.h
+ text/StringImpl.h
+ text/StringImplBase.h
+ text/WTFString.h
+
+ unicode/CharacterNames.h
+ unicode/Collator.h
+ unicode/UTF8.h
+ unicode/Unicode.h
+)
+
+SET(WTF_SOURCES
+ Assertions.cpp
+ ByteArray.cpp
+ CryptographicallyRandomNumber.cpp
+ CurrentTime.cpp
+ DecimalNumber.cpp
+ DynamicAnnotations.cpp
+ FastMalloc.cpp
+ HashTable.cpp
+ MainThread.cpp
+ MD5.cpp
+ OSRandomSource.cpp
+ ParallelJobsGeneric.cpp
+ RandomNumber.cpp
+ RefCountedLeakCounter.cpp
+ SHA1.cpp
+ StackBounds.cpp
+ StringExtras.cpp
+ Threading.cpp
+ TypeTraits.cpp
+ WTFThreadData.cpp
+ dtoa.cpp
+
+ text/AtomicString.cpp
+ text/CString.cpp
+ text/StringBuilder.cpp
+ text/StringImpl.cpp
+ text/StringStatics.cpp
+ text/WTFString.cpp
+
+ unicode/UTF8.cpp
+)
+
+SET(WTF_LIBRARIES
+)
+
+SET(WTF_PORT_FLAGS )
+INCLUDE_IF_EXISTS(${JAVASCRIPTCORE_DIR}/wtf/CMakeLists${PORT}.txt)
+
+LIST(APPEND WTF_INCLUDE_DIRECTORIES
+ "${CMAKE_BINARY_DIR}"
+ "${CMAKE_SOURCE_DIR}/ThirdParty"
+)
+
+WEBKIT_WRAP_SOURCELIST(${WTF_SOURCES})
+INCLUDE_DIRECTORIES(${WTF_INCLUDE_DIRECTORIES})
+ADD_DEFINITIONS(-DBUILDING_WTF)
+ADD_LIBRARY(${WTF_LIBRARY_NAME} ${WTF_LIBRARY_TYPE} ${WTF_HEADERS} ${WTF_SOURCES})
+TARGET_LINK_LIBRARIES(${WTF_LIBRARY_NAME} ${WTF_LIBRARIES})
+
+IF (WTF_LINK_FLAGS)
+ ADD_TARGET_PROPERTIES(${WTF_LIBRARY_NAME} LINK_FLAGS "${WTF_LINK_FLAGS}")
+ENDIF ()
+
+IF (SHARED_CORE)
+ SET_TARGET_PROPERTIES(${WTF_LIBRARY_NAME} PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION_MAJOR})
+ INSTALL(TARGETS ${WTF_LIBRARY_NAME} DESTINATION lib)
+ENDIF ()
--- /dev/null
+IF (ENABLE_FAST_MALLOC)
+ LIST(APPEND WTF_SOURCES
+ TCSystemAlloc.cpp
+ )
+ELSE ()
+ ADD_DEFINITIONS(-DUSE_SYSTEM_MALLOC=1)
+ENDIF()
+
+LIST(APPEND WTF_SOURCES
+ efl/MainThreadEfl.cpp
+
+ ThreadIdentifierDataPthreads.cpp
+ ThreadingPthreads.cpp
+
+ unicode/icu/CollatorICU.cpp
+)
+
+IF (ENABLE_GLIB_SUPPORT)
+ LIST(APPEND WTF_SOURCES
+ gobject/GOwnPtr.cpp
+ gobject/GRefPtr.cpp
+ )
+
+ LIST(APPEND WTF_INCLUDE_DIRECTORIES
+ ${Glib_INCLUDE_DIRS}
+ ${JAVASCRIPTCORE_DIR}/wtf/gobject
+ )
+
+ LIST(APPEND WTF_LIBRARIES
+ ${Glib_LIBRARIES}
+ )
+ENDIF ()
+
+LIST(APPEND WTF_LIBRARIES
+ pthread
+ ${ICU_LIBRARIES}
+)
+
+LIST(APPEND WTF_LINK_FLAGS
+ ${ECORE_LDFLAGS}
+)
+
+LIST(APPEND WTF_INCLUDE_DIRECTORIES
+ ${ECORE_INCLUDE_DIRS}
+ ${JAVASCRIPTCORE_DIR}/wtf/unicode/
+)
--- /dev/null
+LIST(APPEND WTF_HEADERS
+ unicode/wince/UnicodeWinCE.h
+
+ ${3RDPARTY_DIR}/ce-compat/ce_time.h
+ ${3RDPARTY_DIR}/ce-compat/ce_unicode.h
+)
+
+LIST(APPEND WTF_SOURCES
+ NullPtr.cpp
+ OSAllocatorWin.cpp
+ TCSystemAlloc.cpp
+ ThreadingWin.cpp
+ ThreadSpecificWin.cpp
+
+ unicode/CollatorDefault.cpp
+ unicode/wince/UnicodeWinCE.cpp
+
+ win/MainThreadWin.cpp
+ win/OwnPtrWin.cpp
+
+ ${3RDPARTY_DIR}/ce-compat/ce_time.c
+ ${3RDPARTY_DIR}/ce-compat/ce_unicode.cpp
+)
+
+LIST(APPEND WTF_LIBRARIES
+ mmtimer
+)
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef Complex_h
-#define Complex_h
+#ifndef WTF_Complex_h
+#define WTF_Complex_h
#include <complex>
#include <wtf/MathExtras.h>
-namespace WebCore {
+namespace WTF {
typedef std::complex<double> Complex;
return Complex(magnitude * cos(phase), magnitude * sin(phase));
}
-} // namespace WebCore
+} // namespace WTF
-#endif // Complex_h
+using WTF::Complex;
+using WTF::complexFromMagnitudePhase;
+
+#endif // WTF_Complex_h
/*
* Copyright (C) 2009 Google Inc. All rights reserved.
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
#ifndef CrossThreadRefCounted_h
#define CrossThreadRefCounted_h
-#include <wtf/Noncopyable.h>
-#include <wtf/PassRefPtr.h>
-#include <wtf/RefCounted.h>
-#include <wtf/Threading.h>
+#include "PassRefPtr.h"
+#include "RefCounted.h"
+#include "Threading.h"
#include <wtf/iphone/WebCoreThread.h>
namespace WTF {
- // Used to allowing sharing data across classes and threads (like ThreadedSafeShared).
+ // Used to allowing sharing data across classes and threads (like ThreadSafeRefCounted).
//
- // Why not just use ThreadSafeShared?
- // ThreadSafeShared can have a significant perf impact when used in low level classes
+ // Why not just use ThreadSafeRefCounted?
+ // ThreadSafeRefCounted can have a significant perf impact when used in low level classes
// (like UString) that get ref/deref'ed a lot. This class has the benefit of doing fast ref
// counts like RefPtr whenever possible, but it has the downside that you need to copy it
// to use it on another thread.
// with respect to the original and any other copies. The underlying m_data is jointly
// owned by the original instance and all copies.
template<class T>
- class CrossThreadRefCounted : public Noncopyable {
+ class CrossThreadRefCounted {
+ WTF_MAKE_NONCOPYABLE(CrossThreadRefCounted);
public:
static PassRefPtr<CrossThreadRefCounted<T> > create(T* data)
{
}
private:
- CrossThreadRefCounted(T* data, ThreadSafeSharedBase* threadedCounter)
+ CrossThreadRefCounted(T* data, ThreadSafeRefCountedBase* threadedCounter)
: m_threadSafeRefCounter(threadedCounter)
, m_data(data)
#ifndef NDEBUG
, m_threadId(0)
#endif
{
+ // We use RefCountedBase in an unusual way here, so get rid of the requirement
+ // that adoptRef be called on it.
+ m_refCounter.relaxAdoptionRequirement();
}
~CrossThreadRefCounted()
#endif
RefCountedBase m_refCounter;
- ThreadSafeSharedBase* m_threadSafeRefCounter;
+ ThreadSafeRefCountedBase* m_threadSafeRefCounter;
T* m_data;
#ifndef NDEBUG
ThreadIdentifier m_threadId;
if (m_threadSafeRefCounter)
m_threadSafeRefCounter->ref();
else
- m_threadSafeRefCounter = new ThreadSafeSharedBase(2);
+ m_threadSafeRefCounter = new ThreadSafeRefCountedBase(2);
return adoptRef(new CrossThreadRefCounted<T>(m_data, m_threadSafeRefCounter));
}
--- /dev/null
+/*
+ * Copyright (c) 1996, David Mazieres <dm@uun.org>
+ * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Arc4 random number generator for OpenBSD.
+ *
+ * This code is derived from section 17.1 of Applied Cryptography,
+ * second edition, which describes a stream cipher allegedly
+ * compatible with RSA Labs "RC4" cipher (the actual description of
+ * which is a trade secret). The same algorithm is used as a stream
+ * cipher called "arcfour" in Tatu Ylonen's ssh package.
+ *
+ * RC4 is a registered trademark of RSA Laboratories.
+ */
+
+#include "config.h"
+#include "CryptographicallyRandomNumber.h"
+
+#include "MainThread.h"
+#include "OSRandomSource.h"
+#include "StdLibExtras.h"
+#include "ThreadingPrimitives.h"
+
+namespace WTF {
+
+#if USE(OS_RANDOMNESS)
+
+namespace {
+
+class ARC4Stream {
+public:
+ ARC4Stream();
+
+ uint8_t i;
+ uint8_t j;
+ uint8_t s[256];
+};
+
+class ARC4RandomNumberGenerator {
+public:
+ ARC4RandomNumberGenerator();
+
+ uint32_t randomNumber();
+ void randomValues(void* buffer, size_t length);
+
+private:
+ inline void addRandomData(unsigned char *data, int length);
+ void stir();
+ void stirIfNeeded();
+ inline uint8_t getByte();
+ inline uint32_t getWord();
+
+ ARC4Stream m_stream;
+ int m_count;
+#if ENABLE(WTF_MULTIPLE_THREADS)
+ Mutex m_mutex;
+#endif
+};
+
+ARC4Stream::ARC4Stream()
+{
+ for (int n = 0; n < 256; n++)
+ s[n] = n;
+ i = 0;
+ j = 0;
+}
+
+ARC4RandomNumberGenerator::ARC4RandomNumberGenerator()
+ : m_count(0)
+{
+}
+
+void ARC4RandomNumberGenerator::addRandomData(unsigned char* data, int length)
+{
+ m_stream.i--;
+ for (int n = 0; n < 256; n++) {
+ m_stream.i++;
+ uint8_t si = m_stream.s[m_stream.i];
+ m_stream.j += si + data[n % length];
+ m_stream.s[m_stream.i] = m_stream.s[m_stream.j];
+ m_stream.s[m_stream.j] = si;
+ }
+ m_stream.j = m_stream.i;
+}
+
+void ARC4RandomNumberGenerator::stir()
+{
+ unsigned char randomness[128];
+ size_t length = sizeof(randomness);
+ cryptographicallyRandomValuesFromOS(randomness, length);
+ addRandomData(randomness, length);
+
+ // Discard early keystream, as per recommendations in:
+ // http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps
+ for (int i = 0; i < 256; i++)
+ getByte();
+ m_count = 1600000;
+}
+
+void ARC4RandomNumberGenerator::stirIfNeeded()
+{
+ if (m_count <= 0)
+ stir();
+}
+
+uint8_t ARC4RandomNumberGenerator::getByte()
+{
+ m_stream.i++;
+ uint8_t si = m_stream.s[m_stream.i];
+ m_stream.j += si;
+ uint8_t sj = m_stream.s[m_stream.j];
+ m_stream.s[m_stream.i] = sj;
+ m_stream.s[m_stream.j] = si;
+ return (m_stream.s[(si + sj) & 0xff]);
+}
+
+uint32_t ARC4RandomNumberGenerator::getWord()
+{
+ uint32_t val;
+ val = getByte() << 24;
+ val |= getByte() << 16;
+ val |= getByte() << 8;
+ val |= getByte();
+ return val;
+}
+
+uint32_t ARC4RandomNumberGenerator::randomNumber()
+{
+#if ENABLE(WTF_MULTIPLE_THREADS)
+ MutexLocker locker(m_mutex);
+#else
+ ASSERT(isMainThread());
+#endif
+
+ m_count -= 4;
+ stirIfNeeded();
+ return getWord();
+}
+
+void ARC4RandomNumberGenerator::randomValues(void* buffer, size_t length)
+{
+#if ENABLE(WTF_MULTIPLE_THREADS)
+ MutexLocker locker(m_mutex);
+#else
+ ASSERT(isMainThread());
+#endif
+
+ unsigned char* result = reinterpret_cast<unsigned char*>(buffer);
+ stirIfNeeded();
+ while (length--) {
+ m_count--;
+ stirIfNeeded();
+ result[length] = getByte();
+ }
+}
+
+ARC4RandomNumberGenerator& sharedRandomNumberGenerator()
+{
+ DEFINE_STATIC_LOCAL(ARC4RandomNumberGenerator, randomNumberGenerator, ());
+ return randomNumberGenerator;
+}
+
+}
+
+uint32_t cryptographicallyRandomNumber()
+{
+ return sharedRandomNumberGenerator().randomNumber();
+}
+
+void cryptographicallyRandomValues(void* buffer, size_t length)
+{
+ sharedRandomNumberGenerator().randomValues(buffer, length);
+}
+
+#endif
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WTF_CryptographicallyRandomNumber_h
+#define WTF_CryptographicallyRandomNumber_h
+
+#include <stdint.h>
+
+namespace WTF {
+
+#if USE(OS_RANDOMNESS)
+uint32_t cryptographicallyRandomNumber();
+void cryptographicallyRandomValues(void* buffer, size_t length);
+#endif
+
+}
+
+#if USE(OS_RANDOMNESS)
+using WTF::cryptographicallyRandomNumber;
+using WTF::cryptographicallyRandomValues;
+#endif
+
+#endif
#if OS(WINDOWS)
-// Windows is first since we want to use hires timers, despite PLATFORM(CF)
+// Windows is first since we want to use hires timers, despite USE(CF)
// being defined.
// If defined, WIN32_LEAN_AND_MEAN disables timeBeginPeriod/timeEndPeriod.
#undef WIN32_LEAN_AND_MEAN
// QueryPerformanceCounter has high resolution, but is only usable to measure time intervals.
// To combine them, we call ftime and QueryPerformanceCounter initially. Later calls will use QueryPerformanceCounter
// by itself, adding the delta to the saved ftime. We periodically re-sync to correct for drift.
- static bool started;
static double syncLowResUTCTime;
static double syncHighResUpTime;
static double lastUTCTime;
namespace WTF {
- // Returns the current UTC time in seconds, counted from January 1, 1970.
- // Precision varies depending on platform but is usually as good or better
- // than a millisecond.
- double currentTime();
+// Returns the current UTC time in seconds, counted from January 1, 1970.
+// Precision varies depending on platform but is usually as good or better
+// than a millisecond.
+double currentTime();
- // Same thing, in milliseconds.
- inline double currentTimeMS()
- {
- return currentTime() * 1000.0;
- }
+// Same thing, in milliseconds.
+inline double currentTimeMS()
+{
+ return currentTime() * 1000.0;
+}
- inline void getLocalTime(const time_t* localTime, struct tm* localTM)
- {
- #if COMPILER(MSVC7_OR_LOWER) || COMPILER(MINGW) || OS(WINCE)
- *localTM = *localtime(localTime);
- #elif COMPILER(MSVC)
- localtime_s(localTM, localTime);
- #else
- localtime_r(localTime, localTM);
- #endif
- }
+inline void getLocalTime(const time_t* localTime, struct tm* localTM)
+{
+#if COMPILER(MSVC7_OR_LOWER) || COMPILER(MINGW) || OS(WINCE)
+ *localTM = *localtime(localTime);
+#elif COMPILER(MSVC)
+ localtime_s(localTM, localTime);
+#else
+ localtime_r(localTime, localTM);
+#endif
+}
} // namespace WTF
using WTF::currentTime;
+using WTF::currentTimeMS;
using WTF::getLocalTime;
#endif // CurrentTime_h
* Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
* Copyright (C) 2009 Google Inc. All rights reserved.
* Copyright (C) 2007-2009 Torch Mobile, Inc.
+ * Copyright (C) 2010 &yet, LLC. (nate@andyet.net)
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
#include "Assertions.h"
#include "ASCIICType.h"
#include "CurrentTime.h"
+#if USE(JSC)
+#include "JSObject.h"
+#endif
#include "MathExtras.h"
+#if USE(JSC)
+#include "ScopeChain.h"
+#endif
+#include "StdLibExtras.h"
#include "StringExtras.h"
#include <algorithm>
return year;
}
-static int32_t calculateUTCOffset()
+int32_t calculateUTCOffset()
{
#if PLATFORM(BREWMP)
time_t localTime = static_cast<time_t>(currentTime());
}
// Get the DST offset, given a time in UTC
-static double calculateDSTOffset(double ms, double utcOffset)
+double calculateDSTOffset(double ms, double utcOffset)
{
// On Mac OS X, the call to localtime (see calculateDSTOffsetSimple) will return historically accurate
// DST information (e.g. New Zealand did not have DST from 1946 to 1974) however the JavaScript
equivalentYearForDST(2000); // Need to call once to initialize a static used in this function.
}
-static inline double ymdhmsToSeconds(long year, int mon, int day, int hour, int minute, int second)
+static inline double ymdhmsToSeconds(long year, int mon, int day, int hour, int minute, double second)
{
double days = (day - 32075)
+ floor(1461 * (year + 4800.0 + (mon - 14) / 12) / 4)
return true;
}
+double parseES5DateFromNullTerminatedCharacters(const char* dateString)
+{
+ // This parses a date of the form defined in ECMA-262-5, section 15.9.1.15
+ // (similar to RFC 3339 / ISO 8601: YYYY-MM-DDTHH:mm:ss[.sss]Z).
+ // In most cases it is intentionally strict (e.g. correct field widths, no stray whitespace).
+
+ static const long daysPerMonth[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+ const char* currentPosition = dateString;
+ char* postParsePosition;
+
+ // This is a bit more lenient on the year string than ES5 specifies:
+ // instead of restricting to 4 digits (or 6 digits with mandatory +/-),
+ // it accepts any integer value. Consider this an implementation fallback.
+ long year;
+ if (!parseLong(currentPosition, &postParsePosition, 10, &year))
+ return NaN;
+ if (*postParsePosition != '-')
+ return NaN;
+ currentPosition = postParsePosition + 1;
+
+ long month;
+ if (!isASCIIDigit(*currentPosition))
+ return NaN;
+ if (!parseLong(currentPosition, &postParsePosition, 10, &month))
+ return NaN;
+ if (*postParsePosition != '-' || (postParsePosition - currentPosition) != 2)
+ return NaN;
+ currentPosition = postParsePosition + 1;
+
+ long day;
+ if (!isASCIIDigit(*currentPosition))
+ return NaN;
+ if (!parseLong(currentPosition, &postParsePosition, 10, &day))
+ return NaN;
+ if (*postParsePosition != 'T' || (postParsePosition - currentPosition) != 2)
+ return NaN;
+ currentPosition = postParsePosition + 1;
+
+ long hours;
+ if (!isASCIIDigit(*currentPosition))
+ return NaN;
+ if (!parseLong(currentPosition, &postParsePosition, 10, &hours))
+ return NaN;
+ if (*postParsePosition != ':' || (postParsePosition - currentPosition) != 2)
+ return NaN;
+ currentPosition = postParsePosition + 1;
+
+ long minutes;
+ if (!isASCIIDigit(*currentPosition))
+ return NaN;
+ if (!parseLong(currentPosition, &postParsePosition, 10, &minutes))
+ return NaN;
+ if (*postParsePosition != ':' || (postParsePosition - currentPosition) != 2)
+ return NaN;
+ currentPosition = postParsePosition + 1;
+
+ long intSeconds;
+ if (!isASCIIDigit(*currentPosition))
+ return NaN;
+ if (!parseLong(currentPosition, &postParsePosition, 10, &intSeconds))
+ return NaN;
+ if ((postParsePosition - currentPosition) != 2)
+ return NaN;
+
+ double seconds = intSeconds;
+ if (*postParsePosition == '.') {
+ currentPosition = postParsePosition + 1;
+
+ // In ECMA-262-5 it's a bit unclear if '.' can be present without milliseconds, but
+ // a reasonable interpretation guided by the given examples and RFC 3339 says "no".
+ // We check the next character to avoid reading +/- timezone hours after an invalid decimal.
+ if (!isASCIIDigit(*currentPosition))
+ return NaN;
+
+ // We are more lenient than ES5 by accepting more or less than 3 fraction digits.
+ long fracSeconds;
+ if (!parseLong(currentPosition, &postParsePosition, 10, &fracSeconds))
+ return NaN;
+
+ long numFracDigits = postParsePosition - currentPosition;
+ seconds += fracSeconds * pow(10.0, static_cast<double>(-numFracDigits));
+ }
+ currentPosition = postParsePosition;
+
+ // A few of these checks could be done inline above, but since many of them are interrelated
+ // we would be sacrificing readability to "optimize" the (presumably less common) failure path.
+ if (month < 1 || month > 12)
+ return NaN;
+ if (day < 1 || day > daysPerMonth[month - 1])
+ return NaN;
+ if (month == 2 && day > 28 && !isLeapYear(year))
+ return NaN;
+ if (hours < 0 || hours > 24)
+ return NaN;
+ if (hours == 24 && (minutes || seconds))
+ return NaN;
+ if (minutes < 0 || minutes > 59)
+ return NaN;
+ if (seconds < 0 || seconds >= 61)
+ return NaN;
+ if (seconds > 60) {
+ // Discard leap seconds by clamping to the end of a minute.
+ seconds = 60;
+ }
+
+ long timeZoneSeconds = 0;
+ if (*currentPosition != 'Z') {
+ bool tzNegative;
+ if (*currentPosition == '-')
+ tzNegative = true;
+ else if (*currentPosition == '+')
+ tzNegative = false;
+ else
+ return NaN;
+ currentPosition += 1;
+
+ long tzHours;
+ long tzHoursAbs;
+ long tzMinutes;
+
+ if (!isASCIIDigit(*currentPosition))
+ return NaN;
+ if (!parseLong(currentPosition, &postParsePosition, 10, &tzHours))
+ return NaN;
+ if (*postParsePosition != ':' || (postParsePosition - currentPosition) != 2)
+ return NaN;
+ tzHoursAbs = abs(tzHours);
+ currentPosition = postParsePosition + 1;
+
+ if (!isASCIIDigit(*currentPosition))
+ return NaN;
+ if (!parseLong(currentPosition, &postParsePosition, 10, &tzMinutes))
+ return NaN;
+ if ((postParsePosition - currentPosition) != 2)
+ return NaN;
+ currentPosition = postParsePosition;
+
+ if (tzHoursAbs > 24)
+ return NaN;
+ if (tzMinutes < 0 || tzMinutes > 59)
+ return NaN;
+
+ timeZoneSeconds = 60 * (tzMinutes + (60 * tzHoursAbs));
+ if (tzNegative)
+ timeZoneSeconds = -timeZoneSeconds;
+ } else {
+ currentPosition += 1;
+ }
+ if (*currentPosition)
+ return NaN;
+
+ double dateSeconds = ymdhmsToSeconds(year, month, day, hours, minutes, seconds) - timeZoneSeconds;
+ return dateSeconds * msPerSecond;
+}
+
// Odd case where 'exec' is allowed to be 0, to accomodate a caller in WebCore.
static double parseDateFromNullTerminatedCharacters(const char* dateString, bool& haveTZ, int& offset)
{
}
}
}
+
+ // The year may be after the time but before the time zone, but don't
+ // confuse a time zone specificed as an offset from UTC (e.g. +0100) with a
+ // four-digit year.
+ if (year <= 0 && *dateString != '+' && *dateString != '-') {
+ if (!parseLong(dateString, &newPosStr, 10, &year))
+ year = 0;
+ dateString = newPosStr;
+ skipSpacesAndComments(dateString);
+ }
// Don't fail if the time zone is missing.
// Some websites omit the time zone (4275206).
}
haveTZ = true;
} else {
- for (int i = 0; i < int(sizeof(known_zones) / sizeof(KnownZone)); i++) {
+ for (size_t i = 0; i < WTF_ARRAY_LENGTH(known_zones); ++i) {
if (0 == strncasecmp(dateString, known_zones[i].tzName, strlen(known_zones[i].tzName))) {
offset = known_zones[i].tzOffset;
dateString += strlen(known_zones[i].tzName);
tm.year = year - 1900;
tm.isDST = dstOff != 0.0;
tm.utcOffset = static_cast<long>((dstOff + utcOff) / WTF::msPerSecond);
- tm.timeZone = NULL;
+ tm.timeZone = nullptr;
}
double parseDateFromNullTerminatedCharacters(ExecState* exec, const char* dateString)
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
* Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
* Copyright (C) 2009 Google Inc. All rights reserved.
+ * Copyright (C) 2010 Research In Motion Limited. All rights reserved.
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
#define DateMath_h
#include <math.h>
+#include <stdint.h>
#include <string.h>
#include <time.h>
#include <wtf/CurrentTime.h>
#include <wtf/Noncopyable.h>
+#include <wtf/OwnArrayPtr.h>
+#include <wtf/PassOwnArrayPtr.h>
#include <wtf/UnusedParam.h>
namespace WTF {
void initializeDates();
int equivalentYearForDST(int year);
-// Not really math related, but this is currently the only shared place to put these.
+// Not really math related, but this is currently the only shared place to put these.
+double parseES5DateFromNullTerminatedCharacters(const char* dateString);
double parseDateFromNullTerminatedCharacters(const char* dateString);
double timeClip(double);
int monthFromDayInYear(int dayInYear, bool leapYear);
int dayInMonthFromDayInYear(int dayInYear, bool leapYear);
+// Returns offset milliseconds for UTC and DST.
+int32_t calculateUTCOffset();
+double calculateDSTOffset(double ms, double utcOffset);
+
} // namespace WTF
+using WTF::adoptArrayPtr;
using WTF::dateToDaysFrom1970;
using WTF::dayInMonthFromDayInYear;
using WTF::dayInYear;
using WTF::minutesPerHour;
using WTF::monthFromDayInYear;
using WTF::msPerDay;
+using WTF::msPerMinute;
using WTF::msPerSecond;
using WTF::msToYear;
using WTF::secondsPerMinute;
+using WTF::parseDateFromNullTerminatedCharacters;
+using WTF::calculateUTCOffset;
+using WTF::calculateDSTOffset;
#if USE(JSC)
namespace JSC {
// Intentionally overridding the default tm of the system.
// The members of tm differ on various operating systems.
-struct GregorianDateTime : Noncopyable {
+struct GregorianDateTime {
+ WTF_MAKE_NONCOPYABLE(GregorianDateTime);
+public:
GregorianDateTime()
: second(0)
, minute(0)
, year(0)
, isDST(0)
, utcOffset(0)
- , timeZone(0)
- {
- }
-
- ~GregorianDateTime()
{
- delete [] timeZone;
}
GregorianDateTime(ExecState* exec, const tm& inTm)
#if HAVE(TM_ZONE)
int inZoneSize = strlen(inTm.tm_zone) + 1;
- timeZone = new char[inZoneSize];
- strncpy(timeZone, inTm.tm_zone, inZoneSize);
+ timeZone = adoptArrayPtr(new char[inZoneSize]);
+ strncpy(timeZone.get(), inTm.tm_zone, inZoneSize);
#else
- timeZone = 0;
+ timeZone = nullptr;
#endif
}
ret.tm_gmtoff = static_cast<long>(utcOffset);
#endif
#if HAVE(TM_ZONE)
- ret.tm_zone = timeZone;
+ ret.tm_zone = timeZone.get();
#endif
return ret;
isDST = rhs.isDST;
utcOffset = rhs.utcOffset;
if (rhs.timeZone) {
- int inZoneSize = strlen(rhs.timeZone) + 1;
- timeZone = new char[inZoneSize];
- strncpy(timeZone, rhs.timeZone, inZoneSize);
+ int inZoneSize = strlen(rhs.timeZone.get()) + 1;
+ timeZone = adoptArrayPtr(new char[inZoneSize]);
+ strncpy(timeZone.get(), rhs.timeZone.get(), inZoneSize);
} else
- timeZone = 0;
+ timeZone = nullptr;
}
int second;
int year;
int isDST;
int utcOffset;
- char* timeZone;
+ OwnArrayPtr<char> timeZone;
};
static inline int gmtoffset(const GregorianDateTime& t)
--- /dev/null
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DecimalNumber.h"
+#include <math.h>
+#include <wtf/MathExtras.h>
+#include <wtf/text/WTFString.h>
+
+namespace WTF {
+
+unsigned DecimalNumber::bufferLengthForStringDecimal() const
+{
+ unsigned length = 0;
+ // if the exponent is negative the number decimal representation is of the form:
+ // [<sign>]0.[<zeros>]<significand>
+ if (m_exponent < 0) {
+ if (m_sign)
+ ++length;
+ length += 2; // for "0."
+ length += -m_exponent - 1;
+ length += m_precision;
+ return length;
+ }
+
+ unsigned digitsBeforeDecimalPoint = m_exponent + 1;
+
+ // If the precision is <= than the number of digits to get up to the decimal
+ // point, then there is no fractional part, number is of the form:
+ // [<sign>]<significand>[<zeros>]
+ if (m_precision <= digitsBeforeDecimalPoint) {
+ if (m_sign)
+ ++length;
+ length += m_precision;
+ length += digitsBeforeDecimalPoint - m_precision;
+ return length;
+ }
+
+ // If we get here, number starts before the decimal point, and ends after it,
+ // as such is of the form:
+ // [<sign>]<significand-begin>.<significand-end>
+ if (m_sign)
+ ++length;
+ length += digitsBeforeDecimalPoint;
+ ++length; // for decimal point
+ length += m_precision - digitsBeforeDecimalPoint;
+
+ return length;
+}
+
+unsigned DecimalNumber::bufferLengthForStringExponential() const
+{
+ unsigned length = 0;
+ if (m_sign)
+ ++length;
+
+ // Add the significand
+ ++length;
+
+ if (m_precision > 1) {
+ ++length; // for decimal point
+ length += m_precision - 1;
+ }
+
+ // Add "e+" or "e-"
+ length += 2;
+
+ int exponent = (m_exponent >= 0) ? m_exponent : -m_exponent;
+
+ // Add the exponent
+ if (exponent >= 100)
+ ++length;
+ if (exponent >= 10)
+ ++length;
+ ++length;
+
+ return length;
+}
+
+unsigned DecimalNumber::toStringDecimal(UChar* buffer, unsigned bufferLength) const
+{
+ ASSERT_UNUSED(bufferLength, bufferLength >= bufferLengthForStringDecimal());
+
+ // Should always be at least one digit to add to the string!
+ ASSERT(m_precision);
+ UChar* next = buffer;
+
+ // if the exponent is negative the number decimal representation is of the form:
+ // [<sign>]0.[<zeros>]<significand>
+ if (m_exponent < 0) {
+ unsigned zeros = -m_exponent - 1;
+
+ if (m_sign)
+ *next++ = '-';
+ *next++ = '0';
+ *next++ = '.';
+ for (unsigned i = 0; i < zeros; ++i)
+ *next++ = '0';
+ for (unsigned i = 0; i < m_precision; ++i)
+ *next++ = m_significand[i];
+
+ return next - buffer;
+ }
+
+ unsigned digitsBeforeDecimalPoint = m_exponent + 1;
+
+ // If the precision is <= than the number of digits to get up to the decimal
+ // point, then there is no fractional part, number is of the form:
+ // [<sign>]<significand>[<zeros>]
+ if (m_precision <= digitsBeforeDecimalPoint) {
+ if (m_sign)
+ *next++ = '-';
+ for (unsigned i = 0; i < m_precision; ++i)
+ *next++ = m_significand[i];
+ for (unsigned i = 0; i < (digitsBeforeDecimalPoint - m_precision); ++i)
+ *next++ = '0';
+
+ return next - buffer;
+ }
+
+ // If we get here, number starts before the decimal point, and ends after it,
+ // as such is of the form:
+ // [<sign>]<significand-begin>.<significand-end>
+
+ if (m_sign)
+ *next++ = '-';
+ for (unsigned i = 0; i < digitsBeforeDecimalPoint; ++i)
+ *next++ = m_significand[i];
+ *next++ = '.';
+ for (unsigned i = digitsBeforeDecimalPoint; i < m_precision; ++i)
+ *next++ = m_significand[i];
+
+ return next - buffer;
+}
+
+unsigned DecimalNumber::toStringExponential(UChar* buffer, unsigned bufferLength) const
+{
+ ASSERT_UNUSED(bufferLength, bufferLength >= bufferLengthForStringExponential());
+
+ // Should always be at least one digit to add to the string!
+ ASSERT(m_precision);
+ UChar* next = buffer;
+
+ // Add the sign
+ if (m_sign)
+ *next++ = '-';
+
+ // Add the significand
+ *next++ = m_significand[0];
+ if (m_precision > 1) {
+ *next++ = '.';
+ for (unsigned i = 1; i < m_precision; ++i)
+ *next++ = m_significand[i];
+ }
+
+ // Add "e+" or "e-"
+ *next++ = 'e';
+ int exponent;
+ if (m_exponent >= 0) {
+ *next++ = '+';
+ exponent = m_exponent;
+ } else {
+ *next++ = '-';
+ exponent = -m_exponent;
+ }
+
+ // Add the exponent
+ if (exponent >= 100)
+ *next++ = '0' + exponent / 100;
+ if (exponent >= 10)
+ *next++ = '0' + (exponent % 100) / 10;
+ *next++ = '0' + exponent % 10;
+
+ return next - buffer;
+}
+
+} // namespace WTF
--- /dev/null
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DecimalNumber_h
+#define DecimalNumber_h
+
+#include <math.h>
+#include <wtf/dtoa.h>
+#include <wtf/MathExtras.h>
+#include <wtf/text/WTFString.h>
+
+namespace WTF {
+
+enum RoundingSignificantFiguresType { RoundingSignificantFigures };
+enum RoundingDecimalPlacesType { RoundingDecimalPlaces };
+
+class DecimalNumber {
+public:
+ DecimalNumber(double d)
+ {
+ ASSERT(!isnan(d) && !isinf(d));
+ dtoa(m_significand, d, m_sign, m_exponent, m_precision);
+
+ ASSERT(m_precision);
+ // Zero should always have exponent 0.
+ ASSERT(m_significand[0] != '0' || !m_exponent);
+ // No values other than zero should have a leading zero.
+ ASSERT(m_significand[0] != '0' || m_precision == 1);
+ // No values other than zero should have trailing zeros.
+ ASSERT(m_significand[0] == '0' || m_significand[m_precision - 1] != '0');
+ }
+
+ DecimalNumber(double d, RoundingSignificantFiguresType, unsigned significantFigures)
+ {
+ ASSERT(!isnan(d) && !isinf(d));
+ dtoaRoundSF(m_significand, d, significantFigures, m_sign, m_exponent, m_precision);
+
+ ASSERT(significantFigures && significantFigures <= sizeof(DtoaBuffer));
+ while (m_precision < significantFigures)
+ m_significand[m_precision++] = '0';
+
+ ASSERT(m_precision);
+ // Zero should always have exponent 0.
+ ASSERT(m_significand[0] != '0' || !m_exponent);
+ }
+
+ DecimalNumber(double d, RoundingDecimalPlacesType, unsigned decimalPlaces)
+ {
+ ASSERT(!isnan(d) && !isinf(d));
+ dtoaRoundDP(m_significand, d, decimalPlaces, m_sign, m_exponent, m_precision);
+
+ unsigned significantFigures = 1 + m_exponent + decimalPlaces;
+ ASSERT(significantFigures && significantFigures <= sizeof(DtoaBuffer));
+ while (m_precision < significantFigures)
+ m_significand[m_precision++] = '0';
+
+ ASSERT(m_precision);
+ // Zero should always have exponent 0.
+ ASSERT(m_significand[0] != '0' || !m_exponent);
+ }
+
+ unsigned bufferLengthForStringDecimal() const;
+ unsigned bufferLengthForStringExponential() const;
+
+ unsigned toStringDecimal(UChar* buffer, unsigned bufferLength) const;
+ unsigned toStringExponential(UChar* buffer, unsigned bufferLength) const;
+
+ bool sign() const { return m_sign; }
+ int exponent() const { return m_exponent; }
+ const char* significand() const { return m_significand; } // significand contains precision characters, is not null-terminated.
+ unsigned precision() const { return m_precision; }
+
+private:
+ bool m_sign;
+ int m_exponent;
+ DtoaBuffer m_significand;
+ unsigned m_precision;
+};
+
+} // namespace WTF
+
+using WTF::DecimalNumber;
+using WTF::RoundingSignificantFigures;
+using WTF::RoundingDecimalPlaces;
+
+#endif // DecimalNumber_h
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef Decoder_h
+#define Decoder_h
+
+#include <wtf/Vector.h>
+
+namespace WTF {
+
+class String;
+
+class Decoder {
+protected:
+ Decoder() { }
+ virtual ~Decoder() { }
+
+public:
+ virtual bool decodeBytes(Vector<uint8_t>&) = 0;
+
+ virtual bool decodeBool(bool&) = 0;
+ virtual bool decodeUInt32(uint32_t&) = 0;
+ virtual bool decodeUInt64(uint64_t&) = 0;
+ virtual bool decodeInt32(int32_t&) = 0;
+ virtual bool decodeInt64(int64_t&) = 0;
+ virtual bool decodeFloat(float&) = 0;
+ virtual bool decodeDouble(double&) = 0;
+ virtual bool decodeString(String&) = 0;
+};
+
+} // namespace WTF
+
+using WTF::Decoder;
+
+#endif // Decoder_h
// FIXME: Could move what Vector and Deque share into a separate file.
// Deque doesn't actually use Vector.
+#include "PassTraits.h"
#include "Vector.h"
namespace WTF {
- template<typename T> class DequeIteratorBase;
- template<typename T> class DequeIterator;
- template<typename T> class DequeConstIterator;
- template<typename T> class DequeReverseIterator;
- template<typename T> class DequeConstReverseIterator;
+ template<typename T, size_t inlineCapacity> class DequeIteratorBase;
+ template<typename T, size_t inlineCapacity> class DequeIterator;
+ template<typename T, size_t inlineCapacity> class DequeConstIterator;
+ template<typename T, size_t inlineCapacity> class DequeReverseIterator;
+ template<typename T, size_t inlineCapacity> class DequeConstReverseIterator;
- template<typename T>
- class Deque : public FastAllocBase {
+ template<typename T, size_t inlineCapacity = 0>
+ class Deque {
+ WTF_MAKE_FAST_ALLOCATED;
public:
- typedef DequeIterator<T> iterator;
- typedef DequeConstIterator<T> const_iterator;
- typedef DequeReverseIterator<T> reverse_iterator;
- typedef DequeConstReverseIterator<T> const_reverse_iterator;
+ typedef DequeIterator<T, inlineCapacity> iterator;
+ typedef DequeConstIterator<T, inlineCapacity> const_iterator;
+ typedef DequeReverseIterator<T, inlineCapacity> reverse_iterator;
+ typedef DequeConstReverseIterator<T, inlineCapacity> const_reverse_iterator;
+ typedef PassTraits<T> Pass;
+ typedef typename PassTraits<T>::PassType PassType;
Deque();
- Deque(const Deque<T>&);
- Deque& operator=(const Deque<T>&);
+ Deque(const Deque<T, inlineCapacity>&);
+ Deque& operator=(const Deque<T, inlineCapacity>&);
~Deque();
- void swap(Deque<T>&);
+ void swap(Deque<T, inlineCapacity>&);
size_t size() const { return m_start <= m_end ? m_end - m_start : m_end + m_buffer.capacity() - m_start; }
bool isEmpty() const { return m_start == m_end; }
T& first() { ASSERT(m_start != m_end); return m_buffer.buffer()[m_start]; }
const T& first() const { ASSERT(m_start != m_end); return m_buffer.buffer()[m_start]; }
+ PassType takeFirst();
template<typename U> void append(const U&);
template<typename U> void prepend(const U&);
iterator findIf(Predicate&);
private:
- friend class DequeIteratorBase<T>;
+ friend class DequeIteratorBase<T, inlineCapacity>;
- typedef VectorBuffer<T, 0> Buffer;
+ typedef VectorBuffer<T, inlineCapacity> Buffer;
typedef VectorTypeOperations<T> TypeOperations;
- typedef DequeIteratorBase<T> IteratorBase;
+ typedef DequeIteratorBase<T, inlineCapacity> IteratorBase;
void remove(size_t position);
void invalidateIterators();
#endif
};
- template<typename T>
+ template<typename T, size_t inlineCapacity = 0>
class DequeIteratorBase {
private:
- typedef DequeIteratorBase<T> Base;
+ typedef DequeIteratorBase<T, inlineCapacity> Base;
protected:
DequeIteratorBase();
- DequeIteratorBase(const Deque<T>*, size_t);
+ DequeIteratorBase(const Deque<T, inlineCapacity>*, size_t);
DequeIteratorBase(const Base&);
Base& operator=(const Base&);
~DequeIteratorBase();
void checkValidity() const;
void checkValidity(const Base&) const;
- Deque<T>* m_deque;
+ Deque<T, inlineCapacity>* m_deque;
size_t m_index;
- friend class Deque<T>;
+ friend class Deque<T, inlineCapacity>;
#ifndef NDEBUG
mutable DequeIteratorBase* m_next;
#endif
};
- template<typename T>
- class DequeIterator : public DequeIteratorBase<T> {
+ template<typename T, size_t inlineCapacity = 0>
+ class DequeIterator : public DequeIteratorBase<T, inlineCapacity> {
private:
- typedef DequeIteratorBase<T> Base;
- typedef DequeIterator<T> Iterator;
+ typedef DequeIteratorBase<T, inlineCapacity> Base;
+ typedef DequeIterator<T, inlineCapacity> Iterator;
public:
- DequeIterator(Deque<T>* deque, size_t index) : Base(deque, index) { }
+ DequeIterator(Deque<T, inlineCapacity>* deque, size_t index) : Base(deque, index) { }
DequeIterator(const Iterator& other) : Base(other) { }
DequeIterator& operator=(const Iterator& other) { Base::assign(other); return *this; }
// postfix -- intentionally omitted
};
- template<typename T>
- class DequeConstIterator : public DequeIteratorBase<T> {
+ template<typename T, size_t inlineCapacity = 0>
+ class DequeConstIterator : public DequeIteratorBase<T, inlineCapacity> {
private:
- typedef DequeIteratorBase<T> Base;
- typedef DequeConstIterator<T> Iterator;
- typedef DequeIterator<T> NonConstIterator;
+ typedef DequeIteratorBase<T, inlineCapacity> Base;
+ typedef DequeConstIterator<T, inlineCapacity> Iterator;
+ typedef DequeIterator<T, inlineCapacity> NonConstIterator;
public:
- DequeConstIterator(const Deque<T>* deque, size_t index) : Base(deque, index) { }
+ DequeConstIterator(const Deque<T, inlineCapacity>* deque, size_t index) : Base(deque, index) { }
DequeConstIterator(const Iterator& other) : Base(other) { }
DequeConstIterator(const NonConstIterator& other) : Base(other) { }
// postfix -- intentionally omitted
};
- template<typename T>
- class DequeReverseIterator : public DequeIteratorBase<T> {
+ template<typename T, size_t inlineCapacity = 0>
+ class DequeReverseIterator : public DequeIteratorBase<T, inlineCapacity> {
private:
- typedef DequeIteratorBase<T> Base;
- typedef DequeReverseIterator<T> Iterator;
+ typedef DequeIteratorBase<T, inlineCapacity> Base;
+ typedef DequeReverseIterator<T, inlineCapacity> Iterator;
public:
- DequeReverseIterator(const Deque<T>* deque, size_t index) : Base(deque, index) { }
+ DequeReverseIterator(const Deque<T, inlineCapacity>* deque, size_t index) : Base(deque, index) { }
DequeReverseIterator(const Iterator& other) : Base(other) { }
DequeReverseIterator& operator=(const Iterator& other) { Base::assign(other); return *this; }
// postfix -- intentionally omitted
};
- template<typename T>
- class DequeConstReverseIterator : public DequeIteratorBase<T> {
+ template<typename T, size_t inlineCapacity = 0>
+ class DequeConstReverseIterator : public DequeIteratorBase<T, inlineCapacity> {
private:
- typedef DequeIteratorBase<T> Base;
- typedef DequeConstReverseIterator<T> Iterator;
- typedef DequeReverseIterator<T> NonConstIterator;
+ typedef DequeIteratorBase<T, inlineCapacity> Base;
+ typedef DequeConstReverseIterator<T, inlineCapacity> Iterator;
+ typedef DequeReverseIterator<T, inlineCapacity> NonConstIterator;
public:
- DequeConstReverseIterator(const Deque<T>* deque, size_t index) : Base(deque, index) { }
+ DequeConstReverseIterator(const Deque<T, inlineCapacity>* deque, size_t index) : Base(deque, index) { }
DequeConstReverseIterator(const Iterator& other) : Base(other) { }
DequeConstReverseIterator(const NonConstIterator& other) : Base(other) { }
};
#ifdef NDEBUG
- template<typename T> inline void Deque<T>::checkValidity() const { }
- template<typename T> inline void Deque<T>::checkIndexValidity(size_t) const { }
- template<typename T> inline void Deque<T>::invalidateIterators() { }
+ template<typename T, size_t inlineCapacity> inline void Deque<T, inlineCapacity>::checkValidity() const { }
+ template<typename T, size_t inlineCapacity> inline void Deque<T, inlineCapacity>::checkIndexValidity(size_t) const { }
+ template<typename T, size_t inlineCapacity> inline void Deque<T, inlineCapacity>::invalidateIterators() { }
#else
- template<typename T>
- void Deque<T>::checkValidity() const
+ template<typename T, size_t inlineCapacity>
+ void Deque<T, inlineCapacity>::checkValidity() const
{
+ // In this implementation a capacity of 1 would confuse append() and
+ // other places that assume the index after capacity - 1 is 0.
+ ASSERT(m_buffer.capacity() != 1);
+
if (!m_buffer.capacity()) {
ASSERT(!m_start);
ASSERT(!m_end);
}
}
- template<typename T>
- void Deque<T>::checkIndexValidity(size_t index) const
+ template<typename T, size_t inlineCapacity>
+ void Deque<T, inlineCapacity>::checkIndexValidity(size_t index) const
{
ASSERT(index <= m_buffer.capacity());
if (m_start <= m_end) {
}
}
- template<typename T>
- void Deque<T>::invalidateIterators()
+ template<typename T, size_t inlineCapacity>
+ void Deque<T, inlineCapacity>::invalidateIterators()
{
IteratorBase* next;
for (IteratorBase* p = m_iterators; p; p = next) {
}
#endif
- template<typename T>
- inline Deque<T>::Deque()
+ template<typename T, size_t inlineCapacity>
+ inline Deque<T, inlineCapacity>::Deque()
: m_start(0)
, m_end(0)
#ifndef NDEBUG
checkValidity();
}
- template<typename T>
- inline Deque<T>::Deque(const Deque<T>& other)
+ template<typename T, size_t inlineCapacity>
+ inline Deque<T, inlineCapacity>::Deque(const Deque<T, inlineCapacity>& other)
: m_start(other.m_start)
, m_end(other.m_end)
, m_buffer(other.m_buffer.capacity())
}
}
- template<typename T>
- void deleteAllValues(const Deque<T>& collection)
+ template<typename T, size_t inlineCapacity>
+ void deleteAllValues(const Deque<T, inlineCapacity>& collection)
{
- typedef typename Deque<T>::const_iterator iterator;
+ typedef typename Deque<T, inlineCapacity>::const_iterator iterator;
iterator end = collection.end();
for (iterator it = collection.begin(); it != end; ++it)
delete *it;
}
- template<typename T>
- inline Deque<T>& Deque<T>::operator=(const Deque<T>& other)
+ template<typename T, size_t inlineCapacity>
+ inline Deque<T, inlineCapacity>& Deque<T, inlineCapacity>::operator=(const Deque<T, inlineCapacity>& other)
{
+ // FIXME: This is inefficient if we're using an inline buffer and T is
+ // expensive to copy since it will copy the buffer twice instead of once.
Deque<T> copy(other);
swap(copy);
return *this;
}
- template<typename T>
- inline void Deque<T>::destroyAll()
+ template<typename T, size_t inlineCapacity>
+ inline void Deque<T, inlineCapacity>::destroyAll()
{
if (m_start <= m_end)
TypeOperations::destruct(m_buffer.buffer() + m_start, m_buffer.buffer() + m_end);
}
}
- template<typename T>
- inline Deque<T>::~Deque()
+ template<typename T, size_t inlineCapacity>
+ inline Deque<T, inlineCapacity>::~Deque()
{
checkValidity();
invalidateIterators();
destroyAll();
}
- template<typename T>
- inline void Deque<T>::swap(Deque<T>& other)
+ template<typename T, size_t inlineCapacity>
+ inline void Deque<T, inlineCapacity>::swap(Deque<T, inlineCapacity>& other)
{
checkValidity();
other.checkValidity();
other.checkValidity();
}
- template<typename T>
- inline void Deque<T>::clear()
+ template<typename T, size_t inlineCapacity>
+ inline void Deque<T, inlineCapacity>::clear()
{
checkValidity();
invalidateIterators();
checkValidity();
}
- template<typename T>
+ template<typename T, size_t inlineCapacity>
template<typename Predicate>
- inline DequeIterator<T> Deque<T>::findIf(Predicate& predicate)
+ inline DequeIterator<T, inlineCapacity> Deque<T, inlineCapacity>::findIf(Predicate& predicate)
{
iterator end_iterator = end();
for (iterator it = begin(); it != end_iterator; ++it) {
return end_iterator;
}
- template<typename T>
- inline void Deque<T>::expandCapacityIfNeeded()
+ template<typename T, size_t inlineCapacity>
+ inline void Deque<T, inlineCapacity>::expandCapacityIfNeeded()
{
if (m_start) {
if (m_end + 1 != m_start)
expandCapacity();
}
- template<typename T>
- void Deque<T>::expandCapacity()
+ template<typename T, size_t inlineCapacity>
+ void Deque<T, inlineCapacity>::expandCapacity()
{
checkValidity();
size_t oldCapacity = m_buffer.capacity();
checkValidity();
}
- template<typename T> template<typename U>
- inline void Deque<T>::append(const U& value)
+ template<typename T, size_t inlineCapacity>
+ inline typename Deque<T, inlineCapacity>::PassType Deque<T, inlineCapacity>::takeFirst()
+ {
+ T oldFirst = Pass::transfer(first());
+ removeFirst();
+ return Pass::transfer(oldFirst);
+ }
+
+ template<typename T, size_t inlineCapacity> template<typename U>
+ inline void Deque<T, inlineCapacity>::append(const U& value)
{
checkValidity();
expandCapacityIfNeeded();
checkValidity();
}
- template<typename T> template<typename U>
- inline void Deque<T>::prepend(const U& value)
+ template<typename T, size_t inlineCapacity> template<typename U>
+ inline void Deque<T, inlineCapacity>::prepend(const U& value)
{
checkValidity();
expandCapacityIfNeeded();
checkValidity();
}
- template<typename T>
- inline void Deque<T>::removeFirst()
+ template<typename T, size_t inlineCapacity>
+ inline void Deque<T, inlineCapacity>::removeFirst()
{
checkValidity();
invalidateIterators();
checkValidity();
}
- template<typename T>
- inline void Deque<T>::remove(iterator& it)
+ template<typename T, size_t inlineCapacity>
+ inline void Deque<T, inlineCapacity>::remove(iterator& it)
{
it.checkValidity();
remove(it.m_index);
}
- template<typename T>
- inline void Deque<T>::remove(const_iterator& it)
+ template<typename T, size_t inlineCapacity>
+ inline void Deque<T, inlineCapacity>::remove(const_iterator& it)
{
it.checkValidity();
remove(it.m_index);
}
- template<typename T>
- inline void Deque<T>::remove(size_t position)
+ template<typename T, size_t inlineCapacity>
+ inline void Deque<T, inlineCapacity>::remove(size_t position)
{
if (position == m_end)
return;
}
#ifdef NDEBUG
- template<typename T> inline void DequeIteratorBase<T>::checkValidity() const { }
- template<typename T> inline void DequeIteratorBase<T>::checkValidity(const DequeIteratorBase<T>&) const { }
- template<typename T> inline void DequeIteratorBase<T>::addToIteratorsList() { }
- template<typename T> inline void DequeIteratorBase<T>::removeFromIteratorsList() { }
+ template<typename T, size_t inlineCapacity> inline void DequeIteratorBase<T, inlineCapacity>::checkValidity() const { }
+ template<typename T, size_t inlineCapacity> inline void DequeIteratorBase<T, inlineCapacity>::checkValidity(const DequeIteratorBase<T, inlineCapacity>&) const { }
+ template<typename T, size_t inlineCapacity> inline void DequeIteratorBase<T, inlineCapacity>::addToIteratorsList() { }
+ template<typename T, size_t inlineCapacity> inline void DequeIteratorBase<T, inlineCapacity>::removeFromIteratorsList() { }
#else
- template<typename T>
- void DequeIteratorBase<T>::checkValidity() const
+ template<typename T, size_t inlineCapacity>
+ void DequeIteratorBase<T, inlineCapacity>::checkValidity() const
{
ASSERT(m_deque);
m_deque->checkIndexValidity(m_index);
}
- template<typename T>
- void DequeIteratorBase<T>::checkValidity(const Base& other) const
+ template<typename T, size_t inlineCapacity>
+ void DequeIteratorBase<T, inlineCapacity>::checkValidity(const Base& other) const
{
checkValidity();
other.checkValidity();
ASSERT(m_deque == other.m_deque);
}
- template<typename T>
- void DequeIteratorBase<T>::addToIteratorsList()
+ template<typename T, size_t inlineCapacity>
+ void DequeIteratorBase<T, inlineCapacity>::addToIteratorsList()
{
if (!m_deque)
m_next = 0;
m_previous = 0;
}
- template<typename T>
- void DequeIteratorBase<T>::removeFromIteratorsList()
+ template<typename T, size_t inlineCapacity>
+ void DequeIteratorBase<T, inlineCapacity>::removeFromIteratorsList()
{
if (!m_deque) {
ASSERT(!m_next);
}
#endif
- template<typename T>
- inline DequeIteratorBase<T>::DequeIteratorBase()
+ template<typename T, size_t inlineCapacity>
+ inline DequeIteratorBase<T, inlineCapacity>::DequeIteratorBase()
: m_deque(0)
{
}
- template<typename T>
- inline DequeIteratorBase<T>::DequeIteratorBase(const Deque<T>* deque, size_t index)
- : m_deque(const_cast<Deque<T>*>(deque))
+ template<typename T, size_t inlineCapacity>
+ inline DequeIteratorBase<T, inlineCapacity>::DequeIteratorBase(const Deque<T, inlineCapacity>* deque, size_t index)
+ : m_deque(const_cast<Deque<T, inlineCapacity>*>(deque))
, m_index(index)
{
addToIteratorsList();
checkValidity();
}
- template<typename T>
- inline DequeIteratorBase<T>::DequeIteratorBase(const Base& other)
+ template<typename T, size_t inlineCapacity>
+ inline DequeIteratorBase<T, inlineCapacity>::DequeIteratorBase(const Base& other)
: m_deque(other.m_deque)
, m_index(other.m_index)
{
checkValidity();
}
- template<typename T>
- inline DequeIteratorBase<T>& DequeIteratorBase<T>::operator=(const Base& other)
+ template<typename T, size_t inlineCapacity>
+ inline DequeIteratorBase<T, inlineCapacity>& DequeIteratorBase<T, inlineCapacity>::operator=(const Base& other)
{
checkValidity();
other.checkValidity();
return *this;
}
- template<typename T>
- inline DequeIteratorBase<T>::~DequeIteratorBase()
+ template<typename T, size_t inlineCapacity>
+ inline DequeIteratorBase<T, inlineCapacity>::~DequeIteratorBase()
{
#ifndef NDEBUG
removeFromIteratorsList();
#endif
}
- template<typename T>
- inline bool DequeIteratorBase<T>::isEqual(const Base& other) const
+ template<typename T, size_t inlineCapacity>
+ inline bool DequeIteratorBase<T, inlineCapacity>::isEqual(const Base& other) const
{
checkValidity(other);
return m_index == other.m_index;
}
- template<typename T>
- inline void DequeIteratorBase<T>::increment()
+ template<typename T, size_t inlineCapacity>
+ inline void DequeIteratorBase<T, inlineCapacity>::increment()
{
checkValidity();
ASSERT(m_index != m_deque->m_end);
checkValidity();
}
- template<typename T>
- inline void DequeIteratorBase<T>::decrement()
+ template<typename T, size_t inlineCapacity>
+ inline void DequeIteratorBase<T, inlineCapacity>::decrement()
{
checkValidity();
ASSERT(m_index != m_deque->m_start);
checkValidity();
}
- template<typename T>
- inline T* DequeIteratorBase<T>::after() const
+ template<typename T, size_t inlineCapacity>
+ inline T* DequeIteratorBase<T, inlineCapacity>::after() const
{
checkValidity();
ASSERT(m_index != m_deque->m_end);
return &m_deque->m_buffer.buffer()[m_index];
}
- template<typename T>
- inline T* DequeIteratorBase<T>::before() const
+ template<typename T, size_t inlineCapacity>
+ inline T* DequeIteratorBase<T, inlineCapacity>::before() const
{
checkValidity();
ASSERT(m_index != m_deque->m_start);
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DoublyLinkedList_h
+#define DoublyLinkedList_h
+
+namespace WTF {
+
+template <typename Node> class DoublyLinkedList {
+public:
+ DoublyLinkedList();
+
+ bool isEmpty();
+
+ Node* head();
+
+ void append(Node*);
+ void remove(Node*);
+
+private:
+ Node* m_head;
+ Node* m_tail;
+};
+
+template <typename Node> inline DoublyLinkedList<Node>::DoublyLinkedList()
+ : m_head(0)
+ , m_tail(0)
+{
+}
+
+template <typename Node> inline bool DoublyLinkedList<Node>::isEmpty()
+{
+ return !m_head;
+}
+
+template <typename Node> inline Node* DoublyLinkedList<Node>::head()
+{
+ return m_head;
+}
+
+template <typename Node> inline void DoublyLinkedList<Node>::append(Node* node)
+{
+ if (!m_tail) {
+ ASSERT(!m_head);
+ m_head = node;
+ m_tail = node;
+ node->setPrev(0);
+ node->setNext(0);
+ return;
+ }
+
+ ASSERT(m_head);
+ m_tail->setNext(node);
+ node->setPrev(m_tail);
+ node->setNext(0);
+ m_tail = node;
+}
+
+template <typename Node> inline void DoublyLinkedList<Node>::remove(Node* node)
+{
+ if (node->prev()) {
+ ASSERT(node != m_head);
+ node->prev()->setNext(node->next());
+ } else {
+ ASSERT(node == m_head);
+ m_head = node->next();
+ }
+
+ if (node->next()) {
+ ASSERT(node != m_tail);
+ node->next()->setPrev(node->prev());
+ } else {
+ ASSERT(node == m_tail);
+ m_tail = node->prev();
+ }
+}
+
+} // namespace WTF
+
+using WTF::DoublyLinkedList;
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "DynamicAnnotations.h"
+
+#if USE(DYNAMIC_ANNOTATIONS)
+void WTFAnnotateBenignRaceSized(const char*, int, const volatile void*, long, const char*) { }
+void WTFAnnotateHappensBefore(const char*, int, const volatile void*) { }
+void WTFAnnotateHappensAfter(const char*, int, const volatile void*) { }
+#endif // USE(DYNAMIC_ANNOTATIONS)
--- /dev/null
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WTF_DynamicAnnotations_h
+#define WTF_DynamicAnnotations_h
+
+/* This file defines dynamic annotations for use with dynamic analysis
+ * tool such as ThreadSanitizer, Valgrind, etc.
+ *
+ * Dynamic annotation is a source code annotation that affects
+ * the generated code (that is, the annotation is not a comment).
+ * Each such annotation is attached to a particular
+ * instruction and/or to a particular object (address) in the program.
+ *
+ * By using dynamic annotations a developer can give more details to the dynamic
+ * analysis tool to improve its precision.
+ *
+ * In C/C++ program the annotations are represented as C macros.
+ * With the default build flags, these macros are empty, hence don't affect
+ * performance of a compiled binary.
+ * If dynamic annotations are enabled, they just call no-op functions.
+ * The dynamic analysis tools can intercept these functions and replace them
+ * with their own implementations.
+ *
+ * See http://code.google.com/p/data-race-test/wiki/DynamicAnnotations for more information.
+ */
+
+#if USE(DYNAMIC_ANNOTATIONS)
+/* Tell data race detector that we're not interested in reports on the given address range. */
+#define WTF_ANNOTATE_BENIGN_RACE_SIZED(address, size, description) WTFAnnotateBenignRaceSized(__FILE__, __LINE__, address, size, description)
+#define WTF_ANNOTATE_BENIGN_RACE(pointer, description) WTFAnnotateBenignRaceSized(__FILE__, __LINE__, pointer, sizeof(*(pointer)), description)
+
+/* Annotations for user-defined synchronization mechanisms.
+ * These annotations can be used to define happens-before arcs in user-defined
+ * synchronization mechanisms: the race detector will infer an arc from
+ * the former to the latter when they share the same argument pointer.
+ *
+ * The most common case requiring annotations is atomic reference counting:
+ * bool deref() {
+ * ANNOTATE_HAPPENS_BEFORE(&m_refCount);
+ * if (!atomicDecrement(&m_refCount)) {
+ * // m_refCount is now 0
+ * ANNOTATE_HAPPENS_AFTER(&m_refCount);
+ * // "return true; happens-after each atomicDecrement of m_refCount"
+ * return true;
+ * }
+ * return false;
+ * }
+ */
+#define WTF_ANNOTATE_HAPPENS_BEFORE(address) WTFAnnotateHappensBefore(__FILE__, __LINE__, address)
+#define WTF_ANNOTATE_HAPPENS_AFTER(address) WTFAnnotateHappensAfter(__FILE__, __LINE__, address)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/* Don't use these directly, use the above macros instead. */
+void WTFAnnotateBenignRaceSized(const char* file, int line, const volatile void* memory, long size, const char* description);
+void WTFAnnotateHappensBefore(const char* file, int line, const volatile void* address);
+void WTFAnnotateHappensAfter(const char* file, int line, const volatile void* address);
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#else // USE(DYNAMIC_ANNOTATIONS)
+/* These macros are empty when dynamic annotations are not enabled so you can
+ * use them without affecting the performance of release binaries. */
+#define WTF_ANNOTATE_BENIGN_RACE_SIZED(address, size, description)
+#define WTF_ANNOTATE_BENIGN_RACE(pointer, description)
+#define WTF_ANNOTATE_HAPPENS_BEFORE(address)
+#define WTF_ANNOTATE_HAPPENS_AFTER(address)
+#endif // USE(DYNAMIC_ANNOTATIONS)
+
+#endif // WTF_DynamicAnnotations_h
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef Encoder_h
+#define Encoder_h
+
+#include <stdint.h>
+
+namespace WTF {
+
+class String;
+
+class Encoder {
+protected:
+ Encoder() { }
+ virtual ~Encoder() { }
+
+public:
+ virtual void encodeBytes(const uint8_t*, size_t) = 0;
+
+ virtual void encodeBool(bool) = 0;
+ virtual void encodeUInt32(uint32_t) = 0;
+ virtual void encodeUInt64(uint64_t) = 0;
+ virtual void encodeInt32(int32_t) = 0;
+ virtual void encodeInt64(int64_t) = 0;
+ virtual void encodeFloat(float) = 0;
+ virtual void encodeDouble(double) = 0;
+ virtual void encodeString(const String&) = 0;
+};
+
+} // namespace WTF
+
+using WTF::Encoder;
+
+#endif // Encoder_h
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file handles shared library symbol export decorations. It is recommended
+ * that all WebKit projects use these definitions so that symbol exports work
+ * properly on all platforms and compilers that WebKit builds under.
+ */
+
+#ifndef ExportMacros_h
+#define ExportMacros_h
+
+#include "Platform.h"
+
+#if !PLATFORM(CHROMIUM) && OS(WINDOWS) && !COMPILER(GCC)
+#define WTF_EXPORT __declspec(dllexport)
+#define WTF_IMPORT __declspec(dllimport)
+#elif defined(__GNUC__) && !defined(__CC_ARM) && !defined(__ARMCC__)
+#define WTF_EXPORT __attribute__((visibility("default")))
+#define WTF_IMPORT WTF_EXPORT
+#else
+#define WTF_EXPORT
+#define WTF_IMPORT
+#endif
+
+#endif /* ExportMacros_h */
// Provides customizable overrides of fastMalloc/fastFree and operator new/delete
//
// Provided functionality:
+// Macro: WTF_MAKE_FAST_ALLOCATED
// namespace WTF {
-// class FastAllocBase;
//
// T* fastNew<T>();
// T* fastNew<T>(arg);
// FastDelete assumes that the underlying
//
// Example usage:
-// class Widget : public FastAllocBase { ... };
+// class Widget {
+// WTF_MAKE_FAST_ALLOCATED
+// ...
+// };
+//
+// struct Data {
+// WTF_MAKE_FAST_ALLOCATED
+// public:
+// ...
+// };
//
// char* charPtr = fastNew<char>();
// fastDelete(charPtr);
#include "FastMalloc.h"
#include "TypeTraits.h"
-namespace WTF {
+#define WTF_MAKE_FAST_ALLOCATED \
+public: \
+ void* operator new(size_t, void* p) { return p; } \
+ void* operator new[](size_t, void* p) { return p; } \
+ \
+ void* operator new(size_t size) \
+ { \
+ void* p = ::WTF::fastMalloc(size); \
+ ::WTF::fastMallocMatchValidateMalloc(p, ::WTF::Internal::AllocTypeClassNew); \
+ return p; \
+ } \
+ \
+ void operator delete(void* p) \
+ { \
+ ::WTF::fastMallocMatchValidateFree(p, ::WTF::Internal::AllocTypeClassNew); \
+ ::WTF::fastFree(p); \
+ } \
+ \
+ void* operator new[](size_t size) \
+ { \
+ void* p = ::WTF::fastMalloc(size); \
+ ::WTF::fastMallocMatchValidateMalloc(p, ::WTF::Internal::AllocTypeClassNewArray); \
+ return p; \
+ } \
+ \
+ void operator delete[](void* p) \
+ { \
+ ::WTF::fastMallocMatchValidateFree(p, ::WTF::Internal::AllocTypeClassNewArray); \
+ ::WTF::fastFree(p); \
+ } \
+private: \
+typedef int ThisIsHereToForceASemicolonAfterThisMacro
- class FastAllocBase {
- public:
- // Placement operator new.
- void* operator new(size_t, void* p) { return p; }
- void* operator new[](size_t, void* p) { return p; }
-
- void* operator new(size_t size)
- {
- void* p = fastMalloc(size);
- fastMallocMatchValidateMalloc(p, Internal::AllocTypeClassNew);
- return p;
- }
-
- void operator delete(void* p)
- {
- fastMallocMatchValidateFree(p, Internal::AllocTypeClassNew);
- fastFree(p);
- }
-
- void* operator new[](size_t size)
- {
- void* p = fastMalloc(size);
- fastMallocMatchValidateMalloc(p, Internal::AllocTypeClassNewArray);
- return p;
- }
-
- void operator delete[](void* p)
- {
- fastMallocMatchValidateFree(p, Internal::AllocTypeClassNewArray);
- fastFree(p);
- }
- };
+namespace WTF {
// fastNew / fastDelete
} // namespace WTF
-using WTF::FastAllocBase;
using WTF::fastDeleteSkippingDestructor;
#endif // FastAllocBase_h
// Copyright (c) 2005, 2007, Google Inc.
// All rights reserved.
-// Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+// Copyright (C) 2005, 2006, 2007, 2008, 2009, 2011 Apple Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
#include "Assertions.h"
#include <limits>
-#if ENABLE(JSC_MULTIPLE_THREADS)
+#if ENABLE(WTF_MULTIPLE_THREADS)
#include <pthread.h>
#endif
-#if USE(PTHREAD_GETSPECIFIC_DIRECT)
-#include <System/pthread_machdep.h>
-#endif
+#include <wtf/StdLibExtras.h>
#ifndef NO_TCMALLOC_SAMPLES
#ifdef WTF_CHANGES
#endif
// Use a background thread to periodically scavenge memory to release back to the system
-// https://bugs.webkit.org/show_bug.cgi?id=27900: don't turn this on for Tiger until we have figured out why it caused a crash.
#define USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY 0
#ifndef NDEBUG
namespace WTF {
-#if ENABLE(JSC_MULTIPLE_THREADS)
+#if ENABLE(WTF_MULTIPLE_THREADS)
static pthread_key_t isForbiddenKey;
static pthread_once_t isForbiddenKeyOnce = PTHREAD_ONCE_INIT;
static void initializeIsForbiddenKey()
{
staticIsForbidden = false;
}
-#endif // ENABLE(JSC_MULTIPLE_THREADS)
+#endif // ENABLE(WTF_MULTIPLE_THREADS)
} // namespace WTF
#endif // NDEBUG
namespace WTF {
-#if ENABLE(FAST_MALLOC_MATCH_VALIDATION)
namespace Internal {
-
+#if !ENABLE(WTF_MALLOC_VALIDATION)
+void fastMallocMatchFailed(void*);
+#else
+COMPILE_ASSERT(((sizeof(ValidationHeader) % sizeof(AllocAlignmentInteger)) == 0), ValidationHeader_must_produce_correct_alignment);
+#endif
void fastMallocMatchFailed(void*)
{
CRASH();
} // namespace Internal
-#endif
void* fastZeroedMalloc(size_t n)
{
char* fastStrDup(const char* src)
{
- int len = strlen(src) + 1;
+ size_t len = strlen(src) + 1;
char* dup = static_cast<char*>(fastMalloc(len));
-
- if (dup)
- memcpy(dup, src, len);
-
+ memcpy(dup, src, len);
return dup;
}
-
+
TryMallocReturnValue tryFastZeroedMalloc(size_t n)
{
void* result;
#if OS(DARWIN)
#include <malloc/malloc.h>
-#elif COMPILER(MSVC)
+#elif OS(WINDOWS)
#include <malloc.h>
#endif
{
ASSERT(!isForbidden());
-#if ENABLE(FAST_MALLOC_MATCH_VALIDATION)
- if (std::numeric_limits<size_t>::max() - sizeof(AllocAlignmentInteger) <= n) // If overflow would occur...
+#if ENABLE(WTF_MALLOC_VALIDATION)
+ if (std::numeric_limits<size_t>::max() - Internal::ValidationBufferSize <= n) // If overflow would occur...
return 0;
- void* result = malloc(n + sizeof(AllocAlignmentInteger));
+ void* result = malloc(n + Internal::ValidationBufferSize);
if (!result)
return 0;
-
- *static_cast<AllocAlignmentInteger*>(result) = Internal::AllocTypeMalloc;
- result = static_cast<AllocAlignmentInteger*>(result) + 1;
-
+ Internal::ValidationHeader* header = static_cast<Internal::ValidationHeader*>(result);
+ header->m_size = n;
+ header->m_type = Internal::AllocTypeMalloc;
+ header->m_prefix = static_cast<unsigned>(Internal::ValidationPrefix);
+ result = header + 1;
+ *Internal::fastMallocValidationSuffix(result) = Internal::ValidationSuffix;
+ fastMallocValidate(result);
return result;
#else
return malloc(n);
{
ASSERT(!isForbidden());
-#if ENABLE(FAST_MALLOC_MATCH_VALIDATION)
+#if ENABLE(WTF_MALLOC_VALIDATION)
TryMallocReturnValue returnValue = tryFastMalloc(n);
void* result;
- returnValue.getValue(result);
+ if (!returnValue.getValue(result))
+ CRASH();
#else
void* result = malloc(n);
#endif
{
ASSERT(!isForbidden());
-#if ENABLE(FAST_MALLOC_MATCH_VALIDATION)
+#if ENABLE(WTF_MALLOC_VALIDATION)
size_t totalBytes = n_elements * element_size;
- if (n_elements > 1 && element_size && (totalBytes / element_size) != n_elements || (std::numeric_limits<size_t>::max() - sizeof(AllocAlignmentInteger) <= totalBytes))
+ if (n_elements > 1 && element_size && (totalBytes / element_size) != n_elements)
return 0;
- totalBytes += sizeof(AllocAlignmentInteger);
- void* result = malloc(totalBytes);
- if (!result)
+ TryMallocReturnValue returnValue = tryFastMalloc(totalBytes);
+ void* result;
+ if (!returnValue.getValue(result))
return 0;
-
memset(result, 0, totalBytes);
- *static_cast<AllocAlignmentInteger*>(result) = Internal::AllocTypeMalloc;
- result = static_cast<AllocAlignmentInteger*>(result) + 1;
+ fastMallocValidate(result);
return result;
#else
return calloc(n_elements, element_size);
{
ASSERT(!isForbidden());
-#if ENABLE(FAST_MALLOC_MATCH_VALIDATION)
+#if ENABLE(WTF_MALLOC_VALIDATION)
TryMallocReturnValue returnValue = tryFastCalloc(n_elements, element_size);
void* result;
- returnValue.getValue(result);
+ if (!returnValue.getValue(result))
+ CRASH();
#else
void* result = calloc(n_elements, element_size);
#endif
{
ASSERT(!isForbidden());
-#if ENABLE(FAST_MALLOC_MATCH_VALIDATION)
+#if ENABLE(WTF_MALLOC_VALIDATION)
if (!p)
return;
-
- AllocAlignmentInteger* header = Internal::fastMallocMatchValidationValue(p);
- if (*header != Internal::AllocTypeMalloc)
- Internal::fastMallocMatchFailed(p);
+
+ fastMallocMatchValidateFree(p, Internal::AllocTypeMalloc);
+ Internal::ValidationHeader* header = Internal::fastMallocValidationHeader(p);
+ memset(p, 0xCC, header->m_size);
free(header);
#else
free(p);
{
ASSERT(!isForbidden());
-#if ENABLE(FAST_MALLOC_MATCH_VALIDATION)
+#if ENABLE(WTF_MALLOC_VALIDATION)
if (p) {
- if (std::numeric_limits<size_t>::max() - sizeof(AllocAlignmentInteger) <= n) // If overflow would occur...
+ if (std::numeric_limits<size_t>::max() - Internal::ValidationBufferSize <= n) // If overflow would occur...
return 0;
- AllocAlignmentInteger* header = Internal::fastMallocMatchValidationValue(p);
- if (*header != Internal::AllocTypeMalloc)
- Internal::fastMallocMatchFailed(p);
- void* result = realloc(header, n + sizeof(AllocAlignmentInteger));
+ fastMallocValidate(p);
+ Internal::ValidationHeader* result = static_cast<Internal::ValidationHeader*>(realloc(Internal::fastMallocValidationHeader(p), n + Internal::ValidationBufferSize));
if (!result)
return 0;
-
- // This should not be needed because the value is already there:
- // *static_cast<AllocAlignmentInteger*>(result) = Internal::AllocTypeMalloc;
- result = static_cast<AllocAlignmentInteger*>(result) + 1;
+ result->m_size = n;
+ result = result + 1;
+ *fastMallocValidationSuffix(result) = Internal::ValidationSuffix;
+ fastMallocValidate(result);
return result;
} else {
return fastMalloc(n);
{
ASSERT(!isForbidden());
-#if ENABLE(FAST_MALLOC_MATCH_VALIDATION)
+#if ENABLE(WTF_MALLOC_VALIDATION)
TryMallocReturnValue returnValue = tryFastRealloc(p, n);
void* result;
- returnValue.getValue(result);
+ if (!returnValue.getValue(result))
+ CRASH();
#else
void* result = realloc(p, n);
#endif
size_t fastMallocSize(const void* p)
{
-#if OS(DARWIN)
+#if ENABLE(WTF_MALLOC_VALIDATION)
+ return Internal::fastMallocValidationHeader(const_cast<void*>(p))->m_size;
+#elif OS(DARWIN)
return malloc_size(p);
-#elif COMPILER(MSVC)
+#elif OS(WINDOWS) && !PLATFORM(BREWMP)
+ // Brew MP uses its own memory allocator, so _msize does not work on the Brew MP simulator.
return _msize(const_cast<void*>(p));
#else
return 1;
#include "TCSpinLock.h"
#include "TCSystemAlloc.h"
#include <algorithm>
-#include <errno.h>
#include <limits>
#include <pthread.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
+#if HAVE(ERRNO_H)
+#include <errno.h>
+#endif
#if OS(UNIX)
#include <unistd.h>
#endif
-#if COMPILER(MSVC)
+#if OS(WINDOWS)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <wtf/HashSet.h>
#include <wtf/Vector.h>
#endif
+
+#if HAVE(HEADER_DETECTION_H)
+#include "HeaderDetection.h"
+#endif
+
#if HAVE(DISPATCH_H)
#include <dispatch/dispatch.h>
#endif
+#if HAVE(PTHREAD_MACHDEP_H)
+#include <System/pthread_machdep.h>
+
+#if defined(__PTK_FRAMEWORK_JAVASCRIPTCORE_KEY0)
+#define WTF_USE_PTHREAD_GETSPECIFIC_DIRECT 1
+#endif
+#endif
#ifndef PRIuS
#define PRIuS "zu"
// call to the function on Mac OS X, and it's used in performance-critical code. So we
// use a function pointer. But that's not necessarily faster on other platforms, and we had
// problems with this technique on Windows, so we'll do this only on Mac OS X.
-#if USE(PTHREAD_GETSPECIFIC_DIRECT)
-#define pthread_getspecific(key) _pthread_getspecific_direct(key)
-#define pthread_setspecific(key, val) _pthread_setspecific_direct(key, (val))
-#else
#if OS(DARWIN)
+#if !USE(PTHREAD_GETSPECIFIC_DIRECT)
static void* (*pthread_getspecific_function_pointer)(pthread_key_t) = pthread_getspecific;
#define pthread_getspecific(key) pthread_getspecific_function_pointer(key)
+#else
+#define pthread_getspecific(key) _pthread_getspecific_direct(key)
+#define pthread_setspecific(key, val) _pthread_setspecific_direct(key, (val))
#endif
#endif
if (!new_allocation)
CRASH();
- *(void**)new_allocation = allocated_regions_;
+ *reinterpret_cast_ptr<void**>(new_allocation) = allocated_regions_;
allocated_regions_ = new_allocation;
free_area_ = new_allocation + kAlignedSize;
free_avail_ = kAllocIncrement - kAlignedSize;
template <class Recorder>
void recordAdministrativeRegions(Recorder& recorder, const RemoteMemoryReader& reader)
{
- vm_address_t adminAllocation = reinterpret_cast<vm_address_t>(allocated_regions_);
- while (adminAllocation) {
- recorder.recordRegion(adminAllocation, kAllocIncrement);
- adminAllocation = *reader(reinterpret_cast<vm_address_t*>(adminAllocation));
- }
+ for (void* adminAllocation = allocated_regions_; adminAllocation; adminAllocation = reader.nextEntryInLinkedList(reinterpret_cast<void**>(adminAllocation)))
+ recorder.recordRegion(reinterpret_cast<vm_address_t>(adminAllocation), kAllocIncrement);
}
#endif
};
#endif
+static SpinLock pageheap_lock = SPINLOCK_INITIALIZER;
+
class TCMalloc_PageHeap {
public:
void init();
}
bool Check();
- bool CheckList(Span* list, Length min_pages, Length max_pages);
+ bool CheckList(Span* list, Length min_pages, Length max_pages, bool decommitted);
// Release all pages on the free list for reuse by the OS:
void ReleaseFreePages();
void scavenge();
ALWAYS_INLINE bool shouldScavenge() const;
-#if !HAVE(DISPATCH_H)
+#if HAVE(DISPATCH_H) || OS(WINDOWS)
+ void periodicScavenge();
+ ALWAYS_INLINE bool isScavengerSuspended();
+ ALWAYS_INLINE void scheduleScavenger();
+ ALWAYS_INLINE void rescheduleScavenger();
+ ALWAYS_INLINE void suspendScavenger();
+#endif
+
+#if HAVE(DISPATCH_H)
+ dispatch_queue_t m_scavengeQueue;
+ dispatch_source_t m_scavengeTimer;
+ bool m_scavengingSuspended;
+#elif OS(WINDOWS)
+ static void CALLBACK scavengerTimerFired(void*, BOOLEAN);
+ HANDLE m_scavengeQueueTimer;
+#else
static NO_RETURN_WITH_VALUE void* runScavengerThread(void*);
NO_RETURN void scavengerThread();
pthread_mutex_t m_scavengeMutex;
pthread_cond_t m_scavengeCondition;
-#else // !HAVE(DISPATCH_H)
- void periodicScavenge();
-
- dispatch_queue_t m_scavengeQueue;
- dispatch_source_t m_scavengeTimer;
- bool m_scavengingScheduled;
#endif
#endif // USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY
#if USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY
-#if !HAVE(DISPATCH_H)
+#if HAVE(DISPATCH_H)
void TCMalloc_PageHeap::initializeScavenger()
{
- pthread_mutex_init(&m_scavengeMutex, 0);
- pthread_cond_init(&m_scavengeCondition, 0);
- m_scavengeThreadActive = true;
- pthread_t thread;
- pthread_create(&thread, 0, runScavengerThread, this);
+ m_scavengeQueue = dispatch_queue_create("com.apple.JavaScriptCore.FastMallocSavenger", NULL);
+ m_scavengeTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, m_scavengeQueue);
+ dispatch_time_t startTime = dispatch_time(DISPATCH_TIME_NOW, kScavengeDelayInSeconds * NSEC_PER_SEC);
+ dispatch_source_set_timer(m_scavengeTimer, startTime, kScavengeDelayInSeconds * NSEC_PER_SEC, 1000 * NSEC_PER_USEC);
+ dispatch_source_set_event_handler(m_scavengeTimer, ^{ periodicScavenge(); });
+ m_scavengingSuspended = true;
}
-void* TCMalloc_PageHeap::runScavengerThread(void* context)
+ALWAYS_INLINE bool TCMalloc_PageHeap::isScavengerSuspended()
{
- static_cast<TCMalloc_PageHeap*>(context)->scavengerThread();
-#if COMPILER(MSVC)
- // Without this, Visual Studio will complain that this method does not return a value.
- return 0;
-#endif
+ ASSERT(pageheap_lock.IsHeld());
+ return m_scavengingSuspended;
}
-ALWAYS_INLINE void TCMalloc_PageHeap::signalScavenger()
+ALWAYS_INLINE void TCMalloc_PageHeap::scheduleScavenger()
+{
+ ASSERT(pageheap_lock.IsHeld());
+ m_scavengingSuspended = false;
+ dispatch_resume(m_scavengeTimer);
+}
+
+ALWAYS_INLINE void TCMalloc_PageHeap::rescheduleScavenger()
+{
+ // Nothing to do here for libdispatch.
+}
+
+ALWAYS_INLINE void TCMalloc_PageHeap::suspendScavenger()
+{
+ ASSERT(pageheap_lock.IsHeld());
+ m_scavengingSuspended = true;
+ dispatch_suspend(m_scavengeTimer);
+}
+
+#elif OS(WINDOWS)
+
+void TCMalloc_PageHeap::scavengerTimerFired(void* context, BOOLEAN)
+{
+ static_cast<TCMalloc_PageHeap*>(context)->periodicScavenge();
+}
+
+void TCMalloc_PageHeap::initializeScavenger()
+{
+ m_scavengeQueueTimer = 0;
+}
+
+ALWAYS_INLINE bool TCMalloc_PageHeap::isScavengerSuspended()
+{
+ ASSERT(IsHeld(pageheap_lock));
+ return !m_scavengeQueueTimer;
+}
+
+ALWAYS_INLINE void TCMalloc_PageHeap::scheduleScavenger()
+{
+ // We need to use WT_EXECUTEONLYONCE here and reschedule the timer, because
+ // Windows will fire the timer event even when the function is already running.
+ ASSERT(IsHeld(pageheap_lock));
+ CreateTimerQueueTimer(&m_scavengeQueueTimer, 0, scavengerTimerFired, this, kScavengeDelayInSeconds * 1000, 0, WT_EXECUTEONLYONCE);
+}
+
+ALWAYS_INLINE void TCMalloc_PageHeap::rescheduleScavenger()
+{
+ // We must delete the timer and create it again, because it is not possible to retrigger a timer on Windows.
+ suspendScavenger();
+ scheduleScavenger();
+}
+
+ALWAYS_INLINE void TCMalloc_PageHeap::suspendScavenger()
{
- if (!m_scavengeThreadActive && shouldScavenge())
- pthread_cond_signal(&m_scavengeCondition);
+ ASSERT(IsHeld(pageheap_lock));
+ HANDLE scavengeQueueTimer = m_scavengeQueueTimer;
+ m_scavengeQueueTimer = 0;
+ DeleteTimerQueueTimer(0, scavengeQueueTimer, 0);
}
-#else // !HAVE(DISPATCH_H)
+#else
void TCMalloc_PageHeap::initializeScavenger()
{
- m_scavengeQueue = dispatch_queue_create("com.apple.JavaScriptCore.FastMallocSavenger", NULL);
- m_scavengeTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, m_scavengeQueue);
- dispatch_time_t startTime = dispatch_time(DISPATCH_TIME_NOW, kScavengeDelayInSeconds * NSEC_PER_SEC);
- dispatch_source_set_timer(m_scavengeTimer, startTime, kScavengeDelayInSeconds * NSEC_PER_SEC, 1000 * NSEC_PER_USEC);
- dispatch_source_set_event_handler(m_scavengeTimer, ^{ periodicScavenge(); });
- m_scavengingScheduled = false;
+ // Create a non-recursive mutex.
+#if !defined(PTHREAD_MUTEX_NORMAL) || PTHREAD_MUTEX_NORMAL == PTHREAD_MUTEX_DEFAULT
+ pthread_mutex_init(&m_scavengeMutex, 0);
+#else
+ pthread_mutexattr_t attr;
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
+
+ pthread_mutex_init(&m_scavengeMutex, &attr);
+
+ pthread_mutexattr_destroy(&attr);
+#endif
+
+ pthread_cond_init(&m_scavengeCondition, 0);
+ m_scavengeThreadActive = true;
+ pthread_t thread;
+ pthread_create(&thread, 0, runScavengerThread, this);
+}
+
+void* TCMalloc_PageHeap::runScavengerThread(void* context)
+{
+ static_cast<TCMalloc_PageHeap*>(context)->scavengerThread();
+#if (COMPILER(MSVC) || COMPILER(SUNCC))
+ // Without this, Visual Studio and Sun Studio will complain that this method does not return a value.
+ return 0;
+#endif
}
ALWAYS_INLINE void TCMalloc_PageHeap::signalScavenger()
{
- if (!m_scavengingScheduled && shouldScavenge()) {
- m_scavengingScheduled = true;
- dispatch_resume(m_scavengeTimer);
- }
+ // m_scavengeMutex should be held before accessing m_scavengeThreadActive.
+ ASSERT(pthread_mutex_trylock(m_scavengeMutex));
+ if (!m_scavengeThreadActive && shouldScavenge())
+ pthread_cond_signal(&m_scavengeCondition);
}
#endif
size_t pagesToRelease = min_free_committed_pages_since_last_scavenge_ * kScavengePercentage;
size_t targetPageCount = std::max<size_t>(kMinimumFreeCommittedPageCount, free_committed_pages_ - pagesToRelease);
+ Length lastFreeCommittedPages = free_committed_pages_;
while (free_committed_pages_ > targetPageCount) {
+ ASSERT(Check());
for (int i = kMaxPages; i > 0 && free_committed_pages_ >= targetPageCount; i--) {
SpanList* slist = (static_cast<size_t>(i) == kMaxPages) ? &large_ : &free_[i];
// If the span size is bigger than kMinSpanListsWithSpans pages return all the spans in the list, else return all but 1 span.
// Return only 50% of a spanlist at a time so spans of size 1 are not the only ones left.
- size_t numSpansToReturn = (i > kMinSpanListsWithSpans) ? DLL_Length(&slist->normal) : static_cast<size_t>(.5 * DLL_Length(&slist->normal));
+ size_t length = DLL_Length(&slist->normal);
+ size_t numSpansToReturn = (i > kMinSpanListsWithSpans) ? length : length / 2;
for (int j = 0; static_cast<size_t>(j) < numSpansToReturn && !DLL_IsEmpty(&slist->normal) && free_committed_pages_ > targetPageCount; j++) {
Span* s = slist->normal.prev;
DLL_Remove(s);
DLL_Prepend(&slist->returned, s);
}
}
+
+ if (lastFreeCommittedPages == free_committed_pages_)
+ break;
+ lastFreeCommittedPages = free_committed_pages_;
}
min_free_committed_pages_since_last_scavenge_ = free_committed_pages_;
bool TCMalloc_PageHeap::Check() {
ASSERT(free_[0].normal.next == &free_[0].normal);
ASSERT(free_[0].returned.next == &free_[0].returned);
- CheckList(&large_.normal, kMaxPages, 1000000000);
- CheckList(&large_.returned, kMaxPages, 1000000000);
+ CheckList(&large_.normal, kMaxPages, 1000000000, false);
+ CheckList(&large_.returned, kMaxPages, 1000000000, true);
for (Length s = 1; s < kMaxPages; s++) {
- CheckList(&free_[s].normal, s, s);
- CheckList(&free_[s].returned, s, s);
+ CheckList(&free_[s].normal, s, s, false);
+ CheckList(&free_[s].returned, s, s, true);
}
return true;
}
#if ASSERT_DISABLED
-bool TCMalloc_PageHeap::CheckList(Span*, Length, Length) {
+bool TCMalloc_PageHeap::CheckList(Span*, Length, Length, bool) {
return true;
}
#else
-bool TCMalloc_PageHeap::CheckList(Span* list, Length min_pages, Length max_pages) {
+bool TCMalloc_PageHeap::CheckList(Span* list, Length min_pages, Length max_pages, bool decommitted) {
for (Span* s = list->next; s != list; s = s->next) {
CHECK_CONDITION(s->free);
CHECK_CONDITION(s->length >= min_pages);
CHECK_CONDITION(s->length <= max_pages);
CHECK_CONDITION(GetDescriptor(s->start) == s);
CHECK_CONDITION(GetDescriptor(s->start+s->length-1) == s);
+ CHECK_CONDITION(s->decommitted == decommitted);
}
return true;
}
while (!DLL_IsEmpty(list)) {
Span* s = list->prev;
DLL_Remove(s);
+ s->decommitted = true;
DLL_Prepend(returned, s);
TCMalloc_SystemRelease(reinterpret_cast<void*>(s->start << kPageShift),
static_cast<size_t>(s->length << kPageShift));
template <class Finder, class Reader>
void enumerateFreeObjects(Finder& finder, const Reader& reader)
{
- for (void* nextObject = list_; nextObject; nextObject = *reader(reinterpret_cast<void**>(nextObject)))
+ for (void* nextObject = list_; nextObject; nextObject = reader.nextEntryInLinkedList(reinterpret_cast<void**>(nextObject)))
finder.visit(nextObject);
}
#endif
class TCMalloc_ThreadCache {
private:
typedef TCMalloc_ThreadCache_FreeList FreeList;
-#if COMPILER(MSVC)
+#if OS(WINDOWS)
typedef DWORD ThreadIdentifier;
#else
typedef pthread_t ThreadIdentifier;
Span* remoteSpan = nonempty_.next;
for (Span* span = reader(remoteSpan); span && remoteSpan != remoteNonempty; remoteSpan = span->next, span = (span->next ? reader(span->next) : 0)) {
- for (void* nextObject = span->objects; nextObject; nextObject = *reader(reinterpret_cast<void**>(nextObject)))
+ for (void* nextObject = span->objects; nextObject; nextObject = reader.nextEntryInLinkedList(reinterpret_cast<void**>(nextObject)))
finder.visit(nextObject);
}
}
static TCMalloc_Central_FreeListPadded central_cache[kNumClasses];
// Page-level allocator
-static SpinLock pageheap_lock = SPINLOCK_INITIALIZER;
-
-#if PLATFORM(ARM)
-static void* pageheap_memory[(sizeof(TCMalloc_PageHeap) + sizeof(void*) - 1) / sizeof(void*)] __attribute__((aligned));
-#else
static AllocAlignmentInteger pageheap_memory[(sizeof(TCMalloc_PageHeap) + sizeof(AllocAlignmentInteger) - 1) / sizeof(AllocAlignmentInteger)];
-#endif
static bool phinited = false;
// Avoid extra level of indirection by making "pageheap" be just an alias
#if USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY
-#if !HAVE(DISPATCH_H)
-#if OS(WINDOWS)
-static void sleep(unsigned seconds)
+#if HAVE(DISPATCH_H) || OS(WINDOWS)
+
+void TCMalloc_PageHeap::periodicScavenge()
{
- ::Sleep(seconds * 1000);
+ SpinLockHolder h(&pageheap_lock);
+ pageheap->scavenge();
+
+ if (shouldScavenge()) {
+ rescheduleScavenger();
+ return;
+ }
+
+ suspendScavenger();
}
-#endif
+
+ALWAYS_INLINE void TCMalloc_PageHeap::signalScavenger()
+{
+ ASSERT(pageheap_lock.IsHeld());
+ if (isScavengerSuspended() && shouldScavenge())
+ scheduleScavenger();
+}
+
+#else
void TCMalloc_PageHeap::scavengerThread()
{
}
}
-#else
-
-void TCMalloc_PageHeap::periodicScavenge()
-{
- {
- SpinLockHolder h(&pageheap_lock);
- pageheap->scavenge();
- }
-
- if (!shouldScavenge()) {
- m_scavengingScheduled = false;
- dispatch_suspend(m_scavengeTimer);
- }
-}
-#endif // HAVE(DISPATCH_H)
+#endif
#endif
// Until then, we use a slow path to get the heap object.
static bool tsd_inited = false;
#if USE(PTHREAD_GETSPECIFIC_DIRECT)
-static pthread_key_t heap_key = __PTK_FRAMEWORK_JAVASCRIPTCORE_KEY0;
+static const pthread_key_t heap_key = __PTK_FRAMEWORK_JAVASCRIPTCORE_KEY0;
#else
static pthread_key_t heap_key;
#endif
-#if COMPILER(MSVC)
+#if OS(WINDOWS)
DWORD tlsIndex = TLS_OUT_OF_INDEXES;
#endif
static ALWAYS_INLINE void setThreadHeap(TCMalloc_ThreadCache* heap)
{
- // still do pthread_setspecific when using MSVC fast TLS to
- // benefit from the delete callback.
+#if USE(PTHREAD_GETSPECIFIC_DIRECT)
+ // Can't have two libraries both doing this in the same process,
+ // so check and make this crash right away.
+ if (pthread_getspecific(heap_key))
+ CRASH();
+#endif
+
+ // Still do pthread_setspecific even if there's an alternate form
+ // of thread-local storage in use, to benefit from the delete callback.
pthread_setspecific(heap_key, heap);
-#if COMPILER(MSVC)
+
+#if OS(WINDOWS)
TlsSetValue(tlsIndex, heap);
#endif
}
if (span) pageheap->RegisterSizeClass(span, size_class_);
}
if (span == NULL) {
+#if HAVE(ERRNO_H)
MESSAGE("allocation failed: %d\n", errno);
+#elif OS(WINDOWS)
+ MESSAGE("allocation failed: %d\n", ::GetLastError());
+#else
+ MESSAGE("allocation failed\n");
+#endif
lock_.Lock();
return;
}
char* nptr;
while ((nptr = ptr + size) <= limit) {
*tail = ptr;
- tail = reinterpret_cast<void**>(ptr);
+ tail = reinterpret_cast_ptr<void**>(ptr);
ptr = nptr;
num++;
}
// __thread is faster, but only when the kernel supports it
if (KernelSupportsTLS())
return threadlocal_heap;
-#elif COMPILER(MSVC)
+#elif OS(WINDOWS)
return static_cast<TCMalloc_ThreadCache*>(TlsGetValue(tlsIndex));
#else
return static_cast<TCMalloc_ThreadCache*>(pthread_getspecific(heap_key));
#else
pthread_key_create(&heap_key, DestroyThreadCache);
#endif
-#if COMPILER(MSVC)
+#if OS(WINDOWS)
tlsIndex = TlsAlloc();
#endif
tsd_inited = true;
-#if !COMPILER(MSVC)
+#if !OS(WINDOWS)
// We may have used a fake pthread_t for the main thread. Fix it.
pthread_t zero;
memset(&zero, 0, sizeof(zero));
ASSERT(pageheap_lock.IsHeld());
#endif
for (TCMalloc_ThreadCache* h = thread_heaps; h != NULL; h = h->next_) {
-#if COMPILER(MSVC)
+#if OS(WINDOWS)
if (h->tid_ == 0) {
h->tid_ = GetCurrentThreadId();
}
{
SpinLockHolder h(&pageheap_lock);
-#if COMPILER(MSVC)
+#if OS(WINDOWS)
DWORD me;
if (!tsd_inited) {
me = 0;
// In that case, the heap for this thread has already been created
// and added to the linked list. So we search for that first.
for (TCMalloc_ThreadCache* h = thread_heaps; h != NULL; h = h->next_) {
-#if COMPILER(MSVC)
+#if OS(WINDOWS)
if (h->tid_ == me) {
#else
if (pthread_equal(h->tid_, me)) {
if (heap->in_setspecific_) return; // Do not disturb the active caller
heap->in_setspecific_ = true;
- pthread_setspecific(heap_key, NULL);
+ setThreadHeap(NULL);
#ifdef HAVE_TLS
// Also update the copy in __thread
threadlocal_heap = NULL;
ALWAYS_INLINE
#endif
void* malloc(size_t size) {
-#if ENABLE(FAST_MALLOC_MATCH_VALIDATION)
- if (std::numeric_limits<size_t>::max() - sizeof(AllocAlignmentInteger) <= size) // If overflow would occur...
+#if ENABLE(WTF_MALLOC_VALIDATION)
+ if (std::numeric_limits<size_t>::max() - Internal::ValidationBufferSize <= size) // If overflow would occur...
return 0;
- size += sizeof(AllocAlignmentInteger);
- void* result = do_malloc(size);
+ void* result = do_malloc(size + Internal::ValidationBufferSize);
if (!result)
return 0;
- *static_cast<AllocAlignmentInteger*>(result) = Internal::AllocTypeMalloc;
- result = static_cast<AllocAlignmentInteger*>(result) + 1;
+ Internal::ValidationHeader* header = static_cast<Internal::ValidationHeader*>(result);
+ header->m_size = size;
+ header->m_type = Internal::AllocTypeMalloc;
+ header->m_prefix = static_cast<unsigned>(Internal::ValidationPrefix);
+ result = header + 1;
+ *Internal::fastMallocValidationSuffix(result) = Internal::ValidationSuffix;
+ fastMallocValidate(result);
#else
void* result = do_malloc(size);
#endif
MallocHook::InvokeDeleteHook(ptr);
#endif
-#if ENABLE(FAST_MALLOC_MATCH_VALIDATION)
+#if ENABLE(WTF_MALLOC_VALIDATION)
if (!ptr)
return;
- AllocAlignmentInteger* header = Internal::fastMallocMatchValidationValue(ptr);
- if (*header != Internal::AllocTypeMalloc)
- Internal::fastMallocMatchFailed(ptr);
+ fastMallocValidate(ptr);
+ Internal::ValidationHeader* header = Internal::fastMallocValidationHeader(ptr);
+ memset(ptr, 0xCC, header->m_size);
do_free(header);
#else
do_free(ptr);
void* fastCalloc(size_t n, size_t elem_size)
{
- return calloc<true>(n, elem_size);
+ void* result = calloc<true>(n, elem_size);
+#if ENABLE(WTF_MALLOC_VALIDATION)
+ fastMallocValidate(result);
+#endif
+ return result;
}
TryMallocReturnValue tryFastCalloc(size_t n, size_t elem_size)
{
- return calloc<false>(n, elem_size);
+ void* result = calloc<false>(n, elem_size);
+#if ENABLE(WTF_MALLOC_VALIDATION)
+ fastMallocValidate(result);
+#endif
+ return result;
}
template <bool crashOnFailure>
if (n > 1 && elem_size && (totalBytes / elem_size) != n)
return 0;
-#if ENABLE(FAST_MALLOC_MATCH_VALIDATION)
- if (std::numeric_limits<size_t>::max() - sizeof(AllocAlignmentInteger) <= totalBytes) // If overflow would occur...
- return 0;
-
- totalBytes += sizeof(AllocAlignmentInteger);
- void* result = do_malloc(totalBytes);
+#if ENABLE(WTF_MALLOC_VALIDATION)
+ void* result = malloc<crashOnFailure>(totalBytes);
if (!result)
return 0;
memset(result, 0, totalBytes);
- *static_cast<AllocAlignmentInteger*>(result) = Internal::AllocTypeMalloc;
- result = static_cast<AllocAlignmentInteger*>(result) + 1;
+ fastMallocValidate(result);
#else
void* result = do_malloc(totalBytes);
if (result != NULL) {
void* fastRealloc(void* old_ptr, size_t new_size)
{
- return realloc<true>(old_ptr, new_size);
+#if ENABLE(WTF_MALLOC_VALIDATION)
+ fastMallocValidate(old_ptr);
+#endif
+ void* result = realloc<true>(old_ptr, new_size);
+#if ENABLE(WTF_MALLOC_VALIDATION)
+ fastMallocValidate(result);
+#endif
+ return result;
}
TryMallocReturnValue tryFastRealloc(void* old_ptr, size_t new_size)
{
- return realloc<false>(old_ptr, new_size);
+#if ENABLE(WTF_MALLOC_VALIDATION)
+ fastMallocValidate(old_ptr);
+#endif
+ void* result = realloc<false>(old_ptr, new_size);
+#if ENABLE(WTF_MALLOC_VALIDATION)
+ fastMallocValidate(result);
+#endif
+ return result;
}
template <bool crashOnFailure>
#endif
void* realloc(void* old_ptr, size_t new_size) {
if (old_ptr == NULL) {
-#if ENABLE(FAST_MALLOC_MATCH_VALIDATION)
- void* result = malloc(new_size);
+#if ENABLE(WTF_MALLOC_VALIDATION)
+ void* result = malloc<crashOnFailure>(new_size);
#else
void* result = do_malloc(new_size);
#ifndef WTF_CHANGES
return NULL;
}
-#if ENABLE(FAST_MALLOC_MATCH_VALIDATION)
- if (std::numeric_limits<size_t>::max() - sizeof(AllocAlignmentInteger) <= new_size) // If overflow would occur...
+#if ENABLE(WTF_MALLOC_VALIDATION)
+ if (std::numeric_limits<size_t>::max() - Internal::ValidationBufferSize <= new_size) // If overflow would occur...
return 0;
- new_size += sizeof(AllocAlignmentInteger);
- AllocAlignmentInteger* header = Internal::fastMallocMatchValidationValue(old_ptr);
- if (*header != Internal::AllocTypeMalloc)
- Internal::fastMallocMatchFailed(old_ptr);
+ Internal::ValidationHeader* header = Internal::fastMallocValidationHeader(old_ptr);
+ fastMallocValidate(old_ptr);
old_ptr = header;
+ header->m_size = new_size;
+ new_size += Internal::ValidationBufferSize;
#endif
// Get the size of the old entry
// that we already know the sizeclass of old_ptr. The benefit
// would be small, so don't bother.
do_free(old_ptr);
-#if ENABLE(FAST_MALLOC_MATCH_VALIDATION)
- new_ptr = static_cast<AllocAlignmentInteger*>(new_ptr) + 1;
+#if ENABLE(WTF_MALLOC_VALIDATION)
+ new_ptr = static_cast<Internal::ValidationHeader*>(new_ptr) + 1;
+ *Internal::fastMallocValidationSuffix(new_ptr) = Internal::ValidationSuffix;
#endif
return new_ptr;
} else {
-#if ENABLE(FAST_MALLOC_MATCH_VALIDATION)
- old_ptr = static_cast<AllocAlignmentInteger*>(old_ptr) + 1; // Set old_ptr back to the user pointer.
+#if ENABLE(WTF_MALLOC_VALIDATION)
+ old_ptr = static_cast<Internal::ValidationHeader*>(old_ptr) + 1; // Set old_ptr back to the user pointer.
+ *Internal::fastMallocValidationSuffix(old_ptr) = Internal::ValidationSuffix;
#endif
return old_ptr;
}
size_t fastMallocSize(const void* ptr)
{
+#if ENABLE(WTF_MALLOC_VALIDATION)
+ return Internal::fastMallocValidationHeader(const_cast<void*>(ptr))->m_size;
+#else
const PageID p = reinterpret_cast<uintptr_t>(ptr) >> kPageShift;
Span* span = pageheap->GetDescriptorEnsureSafe(p);
return ByteSizeForClass(cl);
return span->length << kPageShift;
+#endif
}
#if OS(DARWIN)
return 1;
Span* span = m_reader(reinterpret_cast<Span*>(ptr));
+ if (!span)
+ return 1;
+
if (span->free) {
void* ptr = reinterpret_cast<void*>(span->start << kPageShift);
m_freeObjectFinder.visit(ptr);
} else if (span->sizeclass) {
// Walk the free list of the small-object span, keeping track of each object seen
- for (void* nextObject = span->objects; nextObject; nextObject = *m_reader(reinterpret_cast<void**>(nextObject)))
+ for (void* nextObject = span->objects; nextObject; nextObject = m_reader.nextEntryInLinkedList(reinterpret_cast<void**>(nextObject)))
m_freeObjectFinder.visit(nextObject);
}
return span->length;
return 1;
Span* span = m_reader(reinterpret_cast<Span*>(ptr));
- if (!span->start)
+ if (!span || !span->start)
return 1;
if (m_seenPointers.contains(ptr))
extern "C" {
malloc_introspection_t jscore_fastmalloc_introspection = { &FastMallocZone::enumerate, &FastMallocZone::goodSize, &FastMallocZone::check, &FastMallocZone::print,
&FastMallocZone::log, &FastMallocZone::forceLock, &FastMallocZone::forceUnlock, &FastMallocZone::statistics
+
, 0 // zone_locked will not be called on the zone unless it advertises itself as version five or higher.
, 0, 0, 0, 0 // These members will not be used unless the zone advertises itself as version seven or higher.
+
};
}
AllocTypeNew, // Encompasses global operator new.
AllocTypeNewArray // Encompasses global operator new[].
};
+
+ enum {
+ ValidationPrefix = 0xf00df00d,
+ ValidationSuffix = 0x0badf00d
+ };
+
+ typedef unsigned ValidationTag;
+
+ struct ValidationHeader {
+ AllocType m_type;
+ unsigned m_size;
+ ValidationTag m_prefix;
+ unsigned m_alignment;
+ };
+
+ static const int ValidationBufferSize = sizeof(ValidationHeader) + sizeof(ValidationTag);
}
-#if ENABLE(FAST_MALLOC_MATCH_VALIDATION)
+#if ENABLE(WTF_MALLOC_VALIDATION)
// Malloc validation is a scheme whereby a tag is attached to an
// allocation which identifies how it was originally allocated.
// is implemented.
namespace Internal {
+
+ // Handle a detected alloc/free mismatch. By default this calls CRASH().
+ void fastMallocMatchFailed(void* p);
- // Return the AllocType tag associated with the allocated block p.
- inline AllocType fastMallocMatchValidationType(const void* p)
+ inline ValidationHeader* fastMallocValidationHeader(void* p)
{
- const AllocAlignmentInteger* type = static_cast<const AllocAlignmentInteger*>(p) - 1;
- return static_cast<AllocType>(*type);
+ return reinterpret_cast<ValidationHeader*>(static_cast<char*>(p) - sizeof(ValidationHeader));
}
- // Return the address of the AllocType tag associated with the allocated block p.
- inline AllocAlignmentInteger* fastMallocMatchValidationValue(void* p)
+ inline ValidationTag* fastMallocValidationSuffix(void* p)
+ {
+ ValidationHeader* header = fastMallocValidationHeader(p);
+ if (header->m_prefix != static_cast<unsigned>(ValidationPrefix))
+ fastMallocMatchFailed(p);
+
+ return reinterpret_cast<ValidationTag*>(static_cast<char*>(p) + header->m_size);
+ }
+
+ // Return the AllocType tag associated with the allocated block p.
+ inline AllocType fastMallocMatchValidationType(void* p)
{
- return reinterpret_cast<AllocAlignmentInteger*>(static_cast<char*>(p) - sizeof(AllocAlignmentInteger));
+ return fastMallocValidationHeader(p)->m_type;
}
// Set the AllocType tag to be associaged with the allocated block p.
inline void setFastMallocMatchValidationType(void* p, AllocType allocType)
{
- AllocAlignmentInteger* type = static_cast<AllocAlignmentInteger*>(p) - 1;
- *type = static_cast<AllocAlignmentInteger>(allocType);
+ fastMallocValidationHeader(p)->m_type = allocType;
}
- // Handle a detected alloc/free mismatch. By default this calls CRASH().
- void fastMallocMatchFailed(void* p);
-
} // namespace Internal
// This is a higher level function which is used by FastMalloc-using code.
}
// This is a higher level function which is used by FastMalloc-using code.
- inline void fastMallocMatchValidateFree(void* p, Internal::AllocType allocType)
+ inline void fastMallocMatchValidateFree(void* p, Internal::AllocType)
{
if (!p)
return;
+
+ Internal::ValidationHeader* header = Internal::fastMallocValidationHeader(p);
+ if (header->m_prefix != static_cast<unsigned>(Internal::ValidationPrefix))
+ Internal::fastMallocMatchFailed(p);
- if (Internal::fastMallocMatchValidationType(p) != allocType)
+ if (*Internal::fastMallocValidationSuffix(p) != Internal::ValidationSuffix)
Internal::fastMallocMatchFailed(p);
+
Internal::setFastMallocMatchValidationType(p, Internal::AllocTypeMalloc); // Set it to this so that fastFree thinks it's OK.
}
+ inline void fastMallocValidate(void* p)
+ {
+ if (!p)
+ return;
+
+ Internal::ValidationHeader* header = Internal::fastMallocValidationHeader(p);
+ if (header->m_prefix != static_cast<unsigned>(Internal::ValidationPrefix))
+ Internal::fastMallocMatchFailed(p);
+
+ if (*Internal::fastMallocValidationSuffix(p) != Internal::ValidationSuffix)
+ Internal::fastMallocMatchFailed(p);
+ }
+
#else
inline void fastMallocMatchValidateMalloc(void*, Internal::AllocType)
#define WTF_PRIVATE_INLINE inline
#endif
-#if !defined(_CRTDBG_MAP_ALLOC) && !(defined(USE_SYSTEM_MALLOC) && USE_SYSTEM_MALLOC)
+#if !defined(_CRTDBG_MAP_ALLOC) && !(defined(USE_SYSTEM_MALLOC) && USE_SYSTEM_MALLOC && !PLATFORM(BREWMP))
// The nothrow functions here are actually not all that helpful, because fastMalloc will
// call CRASH() rather than returning 0, and returning 0 is what nothrow is all about.
--- /dev/null
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FixedArray_h
+#define FixedArray_h
+
+#include <wtf/Assertions.h>
+
+namespace WTF {
+
+template <typename T, size_t Size> class FixedArray {
+public:
+ T& operator[](size_t i)
+ {
+ ASSERT(i < Size);
+ return m_data[i];
+ }
+
+ const T& operator[](size_t i) const
+ {
+ ASSERT(i < Size);
+ return m_data[i];
+ }
+
+ T* data() { return m_data; }
+ size_t size() const { return Size; }
+
+private:
+ T m_data[Size];
+};
+
+} // namespace WTF
+
+using WTF::FixedArray;
+
+#endif // FixedArray_h
/*
- * Copyright (C) 2006, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2009, 2011 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
template<typename T> class ListRefPtr;
template<typename T> class OwnArrayPtr;
template<typename T> class OwnPtr;
+ template<typename T> class PassOwnArrayPtr;
template<typename T> class PassOwnPtr;
template<typename T> class PassRefPtr;
template<typename T> class RefPtr;
template<typename T, size_t inlineCapacity> class Vector;
+
+ class AtomicString;
+ class AtomicStringImpl;
+ class CString;
+ class Decoder;
+ class Encoder;
+ class String;
+ class StringBuffer;
+ class StringImpl;
}
using WTF::ListRefPtr;
using WTF::OwnArrayPtr;
using WTF::OwnPtr;
+using WTF::PassOwnArrayPtr;
using WTF::PassOwnPtr;
using WTF::PassRefPtr;
using WTF::RefPtr;
using WTF::Vector;
+using WTF::AtomicString;
+using WTF::AtomicStringImpl;
+using WTF::CString;
+using WTF::Encoder;
+using WTF::Decoder;
+using WTF::String;
+using WTF::StringBuffer;
+using WTF::StringImpl;
+
#endif // WTF_Forward_h
#define WTF_HashCountedSet_h
#include "Assertions.h"
-#include "FastAllocBase.h"
#include "HashMap.h"
#include "Vector.h"
namespace WTF {
template<typename Value, typename HashFunctions = typename DefaultHash<Value>::Hash,
- typename Traits = HashTraits<Value> > class HashCountedSet : public FastAllocBase {
+ typename Traits = HashTraits<Value> > class HashCountedSet {
+ WTF_MAKE_FAST_ALLOCATED;
private:
typedef HashMap<Value, unsigned, HashFunctions, Traits> ImplType;
public:
typedef HashTableConstKeysIterator<HashTableType, KeyType, MappedType> Keys;
typedef HashTableConstValuesIterator<HashTableType, KeyType, MappedType> Values;
+ HashTableConstIteratorAdapter() {}
HashTableConstIteratorAdapter(const typename HashTableType::const_iterator& impl) : m_impl(impl) {}
const ValueType* get() const { return (const ValueType*)m_impl.get(); }
typedef HashTableKeysIterator<HashTableType, KeyType, MappedType> Keys;
typedef HashTableValuesIterator<HashTableType, KeyType, MappedType> Values;
+ HashTableIteratorAdapter() {}
HashTableIteratorAdapter(const typename HashTableType::iterator& impl) : m_impl(impl) {}
ValueType* get() const { return (ValueType*)m_impl.get(); }
template<typename KeyArg, typename MappedArg, typename HashArg = typename DefaultHash<KeyArg>::Hash,
typename KeyTraitsArg = HashTraits<KeyArg>, typename MappedTraitsArg = HashTraits<MappedArg> >
- class HashMap : public FastAllocBase {
+ class HashMap {
+ WTF_MAKE_FAST_ALLOCATED;
private:
typedef KeyTraitsArg KeyTraits;
typedef MappedTraitsArg MappedTraits;
template<typename T> struct IdentityExtractor;
template<typename ValueArg, typename HashArg = typename DefaultHash<ValueArg>::Hash,
- typename TraitsArg = HashTraits<ValueArg> > class HashSet : public FastAllocBase {
+ typename TraitsArg = HashTraits<ValueArg> > class HashSet {
+ WTF_MAKE_FAST_ALLOCATED;
private:
typedef HashArg HashFunctions;
typedef TraitsArg ValueTraits;
HashFunctions, ValueTraits, ValueTraits> HashTableType;
public:
- typedef HashTableIteratorAdapter<HashTableType, ValueType> iterator;
+ typedef HashTableConstIteratorAdapter<HashTableType, ValueType> iterator;
typedef HashTableConstIteratorAdapter<HashTableType, ValueType> const_iterator;
void swap(HashSet&);
int capacity() const;
bool isEmpty() const;
- iterator begin();
- iterator end();
- const_iterator begin() const;
- const_iterator end() const;
+ iterator begin() const;
+ iterator end() const;
- iterator find(const ValueType&);
- const_iterator find(const ValueType&) const;
+ iterator find(const ValueType&) const;
bool contains(const ValueType&) const;
// An alternate version of find() that finds the object by hashing and comparing
// must have the following function members:
// static unsigned hash(const T&);
// static bool equal(const ValueType&, const T&);
- template<typename T, typename HashTranslator> iterator find(const T&);
- template<typename T, typename HashTranslator> const_iterator find(const T&) const;
+ template<typename T, typename HashTranslator> iterator find(const T&) const;
template<typename T, typename HashTranslator> bool contains(const T&) const;
// The return value is a pair of an interator to the new value's location,
}
template<typename T, typename U, typename V>
- inline typename HashSet<T, U, V>::iterator HashSet<T, U, V>::begin()
+ inline typename HashSet<T, U, V>::iterator HashSet<T, U, V>::begin() const
{
return m_impl.begin();
}
template<typename T, typename U, typename V>
- inline typename HashSet<T, U, V>::iterator HashSet<T, U, V>::end()
+ inline typename HashSet<T, U, V>::iterator HashSet<T, U, V>::end() const
{
return m_impl.end();
}
template<typename T, typename U, typename V>
- inline typename HashSet<T, U, V>::const_iterator HashSet<T, U, V>::begin() const
- {
- return m_impl.begin();
- }
-
- template<typename T, typename U, typename V>
- inline typename HashSet<T, U, V>::const_iterator HashSet<T, U, V>::end() const
- {
- return m_impl.end();
- }
-
- template<typename T, typename U, typename V>
- inline typename HashSet<T, U, V>::iterator HashSet<T, U, V>::find(const ValueType& value)
- {
- return m_impl.find(value);
- }
-
- template<typename T, typename U, typename V>
- inline typename HashSet<T, U, V>::const_iterator HashSet<T, U, V>::find(const ValueType& value) const
+ inline typename HashSet<T, U, V>::iterator HashSet<T, U, V>::find(const ValueType& value) const
{
return m_impl.find(value);
}
template<typename Value, typename HashFunctions, typename Traits>
template<typename T, typename HashTranslator>
typename HashSet<Value, HashFunctions, Traits>::iterator
- inline HashSet<Value, HashFunctions, Traits>::find(const T& value)
- {
- typedef HashSetTranslatorAdapter<ValueType, ValueTraits, T, HashTranslator> Adapter;
- return m_impl.template find<T, Adapter>(value);
- }
-
- template<typename Value, typename HashFunctions, typename Traits>
- template<typename T, typename HashTranslator>
- typename HashSet<Value, HashFunctions, Traits>::const_iterator
inline HashSet<Value, HashFunctions, Traits>::find(const T& value) const
{
typedef HashSetTranslatorAdapter<ValueType, ValueTraits, T, HashTranslator> Adapter;
}
template<typename T, typename U, typename V>
- pair<typename HashSet<T, U, V>::iterator, bool> HashSet<T, U, V>::add(const ValueType& value)
+ inline pair<typename HashSet<T, U, V>::iterator, bool> HashSet<T, U, V>::add(const ValueType& value)
{
return m_impl.add(value);
}
template<typename Value, typename HashFunctions, typename Traits>
template<typename T, typename HashTranslator>
- pair<typename HashSet<Value, HashFunctions, Traits>::iterator, bool>
+ inline pair<typename HashSet<Value, HashFunctions, Traits>::iterator, bool>
HashSet<Value, HashFunctions, Traits>::add(const T& value)
{
typedef HashSetTranslatorAdapter<ValueType, ValueTraits, T, HashTranslator> Adapter;
public:
HashTableConstIterator()
{
- addIterator(0, this);
+ addIterator(static_cast<const HashTableType*>(0), this);
}
// default copy, assignment and destructor are OK if CHECK_HASHTABLE_ITERATORS is 0
using std::swap;
-#if !COMPILER(MSVC)
- // Visual C++ has a swap for pairs defined.
+ // Work around MSVC's standard library, whose swap for pairs does not swap by component.
+ template<typename T> inline void hashTableSwap(T& a, T& b)
+ {
+ swap(a, b);
+ }
- // swap pairs by component, in case of pair members that specialize swap
- template<typename T, typename U> inline void swap(pair<T, U>& a, pair<T, U>& b)
+ // Swap pairs by component, in case of pair members that specialize swap.
+ template<typename T, typename U> inline void hashTableSwap(pair<T, U>& a, pair<T, U>& b)
{
swap(a.first, b.first);
swap(a.second, b.second);
}
-#endif
template<typename T, bool useSwap> struct Mover;
- template<typename T> struct Mover<T, true> { static void move(T& from, T& to) { swap(from, to); } };
+ template<typename T> struct Mover<T, true> { static void move(T& from, T& to) { hashTableSwap(from, to); } };
template<typename T> struct Mover<T, false> { static void move(T& from, T& to) { to = from; } };
template<typename Key, typename Value, typename HashFunctions> class IdentityHashTranslator {
void remove(const KeyType&);
void remove(iterator);
void removeWithoutEntryConsistencyCheck(iterator);
+ void removeWithoutEntryConsistencyCheck(const_iterator);
void clear();
static bool isEmptyBucket(const ValueType& value) { return Extractor::extract(value) == KeyTraits::emptyValue(); }
removeAndInvalidateWithoutEntryConsistencyCheck(const_cast<ValueType*>(it.m_iterator.m_position));
}
+ template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
+ inline void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::removeWithoutEntryConsistencyCheck(const_iterator it)
+ {
+ if (it == end())
+ return;
+
+ removeAndInvalidateWithoutEntryConsistencyCheck(const_cast<ValueType*>(it.m_position));
+ }
+
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
inline void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::remove(const KeyType& key)
{
// iterator adapters
template<typename HashTableType, typename ValueType> struct HashTableConstIteratorAdapter {
+ HashTableConstIteratorAdapter() {}
HashTableConstIteratorAdapter(const typename HashTableType::const_iterator& impl) : m_impl(impl) {}
const ValueType* get() const { return (const ValueType*)m_impl.get(); }
};
template<typename HashTableType, typename ValueType> struct HashTableIteratorAdapter {
+ HashTableIteratorAdapter() {}
HashTableIteratorAdapter(const typename HashTableType::iterator& impl) : m_impl(impl) {}
ValueType* get() const { return (ValueType*)m_impl.get(); }
static bool isDeletedValue(P* value) { return value == reinterpret_cast<P*>(-1); }
};
- template<typename P> struct HashTraits<RefPtr<P> > : GenericHashTraits<RefPtr<P> > {
+ template<typename T> struct SimpleClassHashTraits : GenericHashTraits<T> {
static const bool emptyValueIsZero = true;
- static void constructDeletedValue(RefPtr<P>& slot) { new (&slot) RefPtr<P>(HashTableDeletedValue); }
- static bool isDeletedValue(const RefPtr<P>& value) { return value.isHashTableDeletedValue(); }
+ static void constructDeletedValue(T& slot) { new (&slot) T(HashTableDeletedValue); }
+ static bool isDeletedValue(const T& value) { return value.isHashTableDeletedValue(); }
};
+ template<typename P> struct HashTraits<RefPtr<P> > : SimpleClassHashTraits<RefPtr<P> > { };
+
// special traits for pairs, helpful for their use in HashMap implementation
template<typename FirstTraitsArg, typename SecondTraitsArg>
--- /dev/null
+/*
+ * Copyright (C) 2011 Research In Motion Limited. All rights reserved.
+ *
+ * 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.
+ */
+
+#ifndef HexNumber_h
+#define HexNumber_h
+
+#include <wtf/text/StringConcatenate.h>
+
+namespace WTF {
+
+enum HexConversionMode {
+ Lowercase,
+ Uppercase
+};
+
+namespace Internal {
+
+static const char* hexDigitsForMode(HexConversionMode mode)
+{
+ static const char lowerHexDigits[17] = "0123456789abcdef";
+ static const char upperHexDigits[17] = "0123456789ABCDEF";
+ return mode == Lowercase ? lowerHexDigits : upperHexDigits;
+}
+
+}; // namespace Internal
+
+template<typename T>
+inline void appendByteAsHex(unsigned char byte, T& destination, HexConversionMode mode = Uppercase)
+{
+ const char* hexDigits = Internal::hexDigitsForMode(mode);
+ destination.append(hexDigits[byte >> 4]);
+ destination.append(hexDigits[byte & 0xF]);
+}
+
+template<typename T>
+inline void placeByteAsHexCompressIfPossible(unsigned char byte, T& destination, unsigned& index, HexConversionMode mode = Uppercase)
+{
+ const char* hexDigits = Internal::hexDigitsForMode(mode);
+ if (byte >= 0x10)
+ destination[index++] = hexDigits[byte >> 4];
+ destination[index++] = hexDigits[byte & 0xF];
+}
+
+template<typename T>
+inline void placeByteAsHex(unsigned char byte, T& destination, HexConversionMode mode = Uppercase)
+{
+ const char* hexDigits = Internal::hexDigitsForMode(mode);
+ *destination++ = hexDigits[byte >> 4];
+ *destination++ = hexDigits[byte & 0xF];
+}
+
+template<typename T>
+inline void appendUnsignedAsHex(unsigned number, T& destination, HexConversionMode mode = Uppercase)
+{
+ const char* hexDigits = Internal::hexDigitsForMode(mode);
+ Vector<UChar, 8> result;
+ do {
+ result.prepend(hexDigits[number % 16]);
+ number >>= 4;
+ } while (number > 0);
+
+ destination.append(result.data(), result.size());
+}
+
+// Same as appendUnsignedAsHex, but using exactly 'desiredDigits' for the conversion.
+template<typename T>
+inline void appendUnsignedAsHexFixedSize(unsigned number, T& destination, unsigned desiredDigits, HexConversionMode mode = Uppercase)
+{
+ ASSERT(desiredDigits);
+
+ const char* hexDigits = Internal::hexDigitsForMode(mode);
+ Vector<UChar, 8> result;
+ do {
+ result.prepend(hexDigits[number % 16]);
+ number >>= 4;
+ } while (result.size() < desiredDigits);
+
+ ASSERT(result.size() == desiredDigits);
+ destination.append(result.data(), result.size());
+}
+
+} // namespace WTF
+
+using WTF::appendByteAsHex;
+using WTF::appendUnsignedAsHex;
+using WTF::appendUnsignedAsHexFixedSize;
+using WTF::placeByteAsHex;
+using WTF::placeByteAsHexCompressIfPossible;
+using WTF::Lowercase;
+
+#endif // HexNumber_h
/*
* Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, Benjamin Poulain <ikipou@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
#include "Assertions.h"
#include "HashSet.h"
#include "OwnPtr.h"
+#include "PassOwnPtr.h"
+#include "StdLibExtras.h"
namespace WTF {
template<typename ValueArg, size_t inlineCapacity> struct ListHashSetNodeAllocator;
template<typename ValueArg, size_t inlineCapacity, typename HashArg> struct ListHashSetNodeHashFunctions;
- template<typename ValueArg, size_t inlineCapacity = 256, typename HashArg = typename DefaultHash<ValueArg>::Hash> class ListHashSet : public FastAllocBase {
+ template<typename ValueArg, size_t inlineCapacity = 256, typename HashArg = typename DefaultHash<ValueArg>::Hash> class ListHashSet {
+ WTF_MAKE_FAST_ALLOCATED;
private:
typedef ListHashSetNode<ValueArg, inlineCapacity> Node;
typedef ListHashSetNodeAllocator<ValueArg, inlineCapacity> NodeAllocator;
const_iterator begin() const;
const_iterator end() const;
+ ValueType& first();
+ const ValueType& first() const;
+
+ ValueType& last();
+ const ValueType& last() const;
+ void removeLast();
+
iterator find(const ValueType&);
const_iterator find(const ValueType&) const;
bool contains(const ValueType&) const;
+ // An alternate version of find() that finds the object by hashing and comparing
+ // with some other type, to avoid the cost of type conversion.
+ // The HashTranslator interface is defined in HashSet.
+ template<typename T, typename HashTranslator> iterator find(const T&);
+ template<typename T, typename HashTranslator> const_iterator find(const T&) const;
+ template<typename T, typename HashTranslator> bool contains(const T&) const;
+
// the return value is a pair of an iterator to the new value's location,
// and a bool that is true if an new entry was added
pair<iterator, bool> add(const ValueType&);
}
private:
- Node* pool() { return reinterpret_cast<Node*>(m_pool.pool); }
+ Node* pool() { return reinterpret_cast_ptr<Node*>(m_pool.pool); }
Node* pastPool() { return pool() + m_poolSize; }
bool inPool(Node* node)
inline ListHashSet<T, inlineCapacity, U>::ListHashSet()
: m_head(0)
, m_tail(0)
- , m_allocator(new NodeAllocator)
+ , m_allocator(adoptPtr(new NodeAllocator))
{
}
inline ListHashSet<T, inlineCapacity, U>::ListHashSet(const ListHashSet& other)
: m_head(0)
, m_tail(0)
- , m_allocator(new NodeAllocator)
+ , m_allocator(adoptPtr(new NodeAllocator))
{
const_iterator end = other.end();
for (const_iterator it = other.begin(); it != end; ++it)
return makeConstIterator(0);
}
+ template<typename T, size_t inlineCapacity, typename U>
+ inline T& ListHashSet<T, inlineCapacity, U>::first()
+ {
+ ASSERT(!isEmpty());
+ return m_head->m_value;
+ }
+
+ template<typename T, size_t inlineCapacity, typename U>
+ inline const T& ListHashSet<T, inlineCapacity, U>::first() const
+ {
+ ASSERT(!isEmpty());
+ return m_head->m_value;
+ }
+
+ template<typename T, size_t inlineCapacity, typename U>
+ inline T& ListHashSet<T, inlineCapacity, U>::last()
+ {
+ ASSERT(!isEmpty());
+ return m_tail->m_value;
+ }
+
+ template<typename T, size_t inlineCapacity, typename U>
+ inline const T& ListHashSet<T, inlineCapacity, U>::last() const
+ {
+ ASSERT(!isEmpty());
+ return m_tail->m_value;
+ }
+
+ template<typename T, size_t inlineCapacity, typename U>
+ inline void ListHashSet<T, inlineCapacity, U>::removeLast()
+ {
+ ASSERT(!isEmpty());
+ m_impl.remove(m_tail);
+ unlinkAndDelete(m_tail);
+ }
+
template<typename T, size_t inlineCapacity, typename U>
inline typename ListHashSet<T, inlineCapacity, U>::iterator ListHashSet<T, inlineCapacity, U>::find(const ValueType& value)
{
return makeConstIterator(*it);
}
+ template<typename ValueType, size_t inlineCapacity, typename T, typename Translator>
+ struct ListHashSetTranslatorAdapter {
+ private:
+ typedef ListHashSetNode<ValueType, inlineCapacity> Node;
+ public:
+ static unsigned hash(const T& key) { return Translator::hash(key); }
+ static bool equal(Node* const& a, const T& b) { return Translator::equal(a->m_value, b); }
+ };
+
+ template<typename ValueType, size_t inlineCapacity, typename U>
+ template<typename T, typename HashTranslator>
+ inline typename ListHashSet<ValueType, inlineCapacity, U>::iterator ListHashSet<ValueType, inlineCapacity, U>::find(const T& value)
+ {
+ typedef ListHashSetTranslatorAdapter<ValueType, inlineCapacity, T, HashTranslator> Adapter;
+ ImplTypeConstIterator it = m_impl.template find<T, Adapter>(value);
+ if (it == m_impl.end())
+ return end();
+ return makeIterator(*it);
+ }
+
+ template<typename ValueType, size_t inlineCapacity, typename U>
+ template<typename T, typename HashTranslator>
+ inline typename ListHashSet<ValueType, inlineCapacity, U>::const_iterator ListHashSet<ValueType, inlineCapacity, U>::find(const T& value) const
+ {
+ typedef ListHashSetTranslatorAdapter<ValueType, inlineCapacity, T, HashTranslator> Adapter;
+ ImplTypeConstIterator it = m_impl.template find<T, Adapter>(value);
+ if (it == m_impl.end())
+ return end();
+ return makeConstIterator(*it);
+ }
+
+ template<typename ValueType, size_t inlineCapacity, typename U>
+ template<typename T, typename HashTranslator>
+ inline bool ListHashSet<ValueType, inlineCapacity, U>::contains(const T& value) const
+ {
+ typedef ListHashSetTranslatorAdapter<ValueType, inlineCapacity, T, HashTranslator> Adapter;
+ return m_impl.template contains<T, Adapter>(value);
+ }
+
template<typename T, size_t inlineCapacity, typename U>
inline bool ListHashSet<T, inlineCapacity, U>::contains(const ValueType& value) const
{
namespace WTF {
-template <typename T> class Locker : public Noncopyable {
+template <typename T> class Locker {
+ WTF_MAKE_NONCOPYABLE(Locker);
public:
Locker(T& lockable) : m_lockable(lockable) { m_lockable.lock(); }
~Locker() { m_lockable.unlock(); }
#include "StringExtras.h"
#include "text/CString.h"
#endif
+#include <wtf/StdLibExtras.h>
namespace WTF {
{
MD5 md5;
md5.addBytes(reinterpret_cast<const uint8_t*>(input.data()), input.length());
- Vector<uint8_t, 16> digest = md5.checksum();
+ Vector<uint8_t, 16> digest;
+ md5.checksum(digest);
char* buf = 0;
CString actual = CString::newUninitialized(32, buf);
for (size_t i = 0; i < 16; i++) {
snprintf(buf, 3, "%02x", digest.at(i));
buf += 2;
}
- ASSERT_WITH_MESSAGE(actual == expected, "input:%s[%d] actual:%s expected:%s", input.data(), input.length(), actual.data(), expected.data());
+ ASSERT_WITH_MESSAGE(actual == expected, "input:%s[%lu] actual:%s expected:%s", input.data(), static_cast<unsigned long>(input.length()), actual.data(), expected.data());
}
static void testMD5()
do {
uint32_t t = static_cast<uint32_t>(buf[3] << 8 | buf[2]) << 16 | buf[1] << 8 | buf[0];
ASSERT_WITH_MESSAGE(!(reinterpret_cast<uintptr_t>(buf) % sizeof(t)), "alignment error of buf");
- *reinterpret_cast<uint32_t *>(buf) = t;
+ *reinterpret_cast_ptr<uint32_t *>(buf) = t;
buf += 4;
} while (--longs);
}
MD5::MD5()
{
+ // FIXME: Move unit tests somewhere outside the constructor. See bug 55853.
testMD5();
m_buf[0] = 0x67452301;
m_buf[1] = 0xefcdab89;
}
memcpy(p, buf, t);
reverseBytes(m_in, 16);
- MD5Transform(m_buf, reinterpret_cast<uint32_t*>(m_in)); // m_in is 4-byte aligned.
+ MD5Transform(m_buf, reinterpret_cast_ptr<uint32_t*>(m_in)); // m_in is 4-byte aligned.
buf += t;
length -= t;
}
while (length >= 64) {
memcpy(m_in, buf, 64);
reverseBytes(m_in, 16);
- MD5Transform(m_buf, reinterpret_cast<uint32_t*>(m_in)); // m_in is 4-byte aligned.
+ MD5Transform(m_buf, reinterpret_cast_ptr<uint32_t*>(m_in)); // m_in is 4-byte aligned.
buf += 64;
length -= 64;
}
memcpy(m_in, buf, length);
}
-Vector<uint8_t, 16> MD5::checksum()
+void MD5::checksum(Vector<uint8_t, 16>& digest)
{
// Compute number of bytes mod 64
unsigned count = (m_bits[0] >> 3) & 0x3F;
// Two lots of padding: Pad the first block to 64 bytes
memset(p, 0, count);
reverseBytes(m_in, 16);
- MD5Transform(m_buf, reinterpret_cast<uint32_t *>(m_in)); // m_in is 4-byte aligned.
+ MD5Transform(m_buf, reinterpret_cast_ptr<uint32_t *>(m_in)); // m_in is 4-byte aligned.
// Now fill the next block with 56 bytes
memset(m_in, 0, 56);
// Append length in bits and transform
// m_in is 4-byte aligned.
- (reinterpret_cast<uint32_t*>(m_in))[14] = m_bits[0];
- (reinterpret_cast<uint32_t*>(m_in))[15] = m_bits[1];
+ (reinterpret_cast_ptr<uint32_t*>(m_in))[14] = m_bits[0];
+ (reinterpret_cast_ptr<uint32_t*>(m_in))[15] = m_bits[1];
- MD5Transform(m_buf, reinterpret_cast<uint32_t*>(m_in));
+ MD5Transform(m_buf, reinterpret_cast_ptr<uint32_t*>(m_in));
reverseBytes(reinterpret_cast<uint8_t*>(m_buf), 4);
- Vector<uint8_t, 16> digest;
+
+ // Now, m_buf contains checksum result.
+ if (!digest.isEmpty())
+ digest.clear();
digest.append(reinterpret_cast<uint8_t*>(m_buf), 16);
// In case it's sensitive
memset(m_buf, 0, sizeof(m_buf));
memset(m_bits, 0, sizeof(m_bits));
memset(m_in, 0, sizeof(m_in));
- return digest;
}
} // namespace WTF
void addBytes(const uint8_t* input, size_t length);
// checksum has a side effect of resetting the state of the object.
- Vector<uint8_t, 16> checksum();
+ void checksum(Vector<uint8_t, 16>&);
private:
uint32_t m_buf[4];
#include "StdLibExtras.h"
#include "Threading.h"
+#include <wtf/iphone/WebCoreThread.h>
+
#if PLATFORM(CHROMIUM)
#error Chromium uses a different main thread implementation
#endif
MutexLocker locker(mainThreadFunctionQueueMutex());
if (!functionQueue().size())
break;
- invocation = functionQueue().first();
- functionQueue().removeFirst();
+ invocation = functionQueue().takeFirst();
}
invocation.function(invocation.context);
- if (invocation.syncFlag)
+ if (invocation.syncFlag) {
+ MutexLocker locker(mainThreadFunctionQueueMutex());
invocation.syncFlag->signal();
+ }
// If we are running accumulated functions for too long so UI may become unresponsive, we need to
// yield so the user input can be processed. Otherwise user may not be able to even close the window.
void setMainThreadCallbacksPaused(bool paused)
{
- ASSERT(isMainThread());
+ ASSERT((isMainThread() || pthread_main_np()) && WebCoreWebThreadIsLockedOrDisabled());
if (callbacksPaused == paused)
return;
scheduleDispatchFunctionsOnMainThread();
}
-#if !PLATFORM(MAC) && !PLATFORM(QT)
+#if !PLATFORM(MAC) && !PLATFORM(QT) && !PLATFORM(BREWMP)
bool isMainThread()
{
return currentThread() == mainThreadIdentifier;
{
void* output;
kern_return_t err = (*m_reader)(m_task, address, size, static_cast<void**>(&output));
- ASSERT(!err);
if (err)
output = 0;
return output;
{
return static_cast<T*>((*this)(reinterpret_cast<vm_address_t>(address), size));
}
+
+ template <typename T>
+ T* nextEntryInLinkedList(T** address) const
+ {
+ T** output = (*this)(address);
+ if (!output)
+ return 0;
+ return *output;
+ }
};
} // namespace WTF
#ifndef WTF_MathExtras_h
#define WTF_MathExtras_h
+#include <algorithm>
#include <cmath>
#include <float.h>
+#include <limits>
#include <stdlib.h>
#if OS(SOLARIS)
const float piFloat = static_cast<float>(M_PI);
#endif
+#ifndef M_PI_2
+const double piOverTwoDouble = 1.57079632679489661923;
+const float piOverTwoFloat = 1.57079632679489661923f;
+#else
+const double piOverTwoDouble = M_PI_2;
+const float piOverTwoFloat = static_cast<float>(M_PI_2);
+#endif
+
#ifndef M_PI_4
const double piOverFourDouble = 0.785398163397448309616;
const float piOverFourFloat = 0.785398163397448309616f;
inline bool isinf(double x) { return !finite(x) && !isnand(x); }
#endif
#ifndef signbit
-inline bool signbit(double x) { return x < 0.0; } // FIXME: Wrong for negative 0.
+inline bool signbit(double x) { return copysign(1.0, x) < 0; }
#endif
#endif
#endif
-#if COMPILER(MSVC) || COMPILER(RVCT)
+#if COMPILER(MSVC) || (COMPILER(RVCT) && !(RVCT_VERSION_AT_LEAST(3, 0, 0, 0)))
// We must not do 'num + 0.5' or 'num - 0.5' because they can cause precision loss.
static double round(double num)
inline double copysign(double x, double y) { return _copysign(x, y); }
inline int isfinite(double x) { return _finite(x); }
+// MSVC's math.h does not currently supply log2.
+inline double log2(double num)
+{
+ // This constant is roughly M_LN2, which is not provided by default on Windows.
+ return log(num) / 0.693147180559945309417232121458176568;
+}
+
// Work around a bug in Win, where atan2(+-infinity, +-infinity) yields NaN instead of specific values.
inline double wtf_atan2(double x, double y)
{
inline float rad2grad(float r) { return r * 200.0f / piFloat; }
inline float grad2rad(float g) { return g * piFloat / 200.0f; }
-#if !COMPILER(MSVC) && !COMPILER(WINSCW) && !(COMPILER(RVCT) && OS(SYMBIAN))
+inline int clampToInteger(double x)
+{
+ const double intMax = static_cast<double>(std::numeric_limits<int>::max());
+ const double intMin = static_cast<double>(std::numeric_limits<int>::min());
+
+ if (x >= intMax)
+ return std::numeric_limits<int>::max();
+ if (x <= intMin)
+ return std::numeric_limits<int>::min();
+ return static_cast<int>(x);
+}
+
+inline float clampToFloat(double x)
+{
+ const double floatMax = static_cast<double>(std::numeric_limits<float>::max());
+ const double floatMin = -static_cast<double>(std::numeric_limits<float>::max());
+
+ if (x >= floatMax)
+ return std::numeric_limits<float>::max();
+ if (x <= floatMin)
+ return -std::numeric_limits<float>::max();
+ return static_cast<float>(x);
+}
+
+inline int clampToPositiveInteger(double x)
+{
+ const double intMax = static_cast<double>(std::numeric_limits<int>::max());
+
+ if (x >= intMax)
+ return std::numeric_limits<int>::max();
+ if (x <= 0)
+ return 0;
+ return static_cast<int>(x);
+}
+
+inline int clampToInteger(float x)
+{
+ const float intMax = static_cast<float>(std::numeric_limits<int>::max());
+ const float intMin = static_cast<float>(std::numeric_limits<int>::min());
+
+ if (x >= intMax)
+ return std::numeric_limits<int>::max();
+ if (x <= intMin)
+ return std::numeric_limits<int>::min();
+ return static_cast<int>(x);
+}
+
+inline int clampToPositiveInteger(float x)
+{
+ const float intMax = static_cast<float>(std::numeric_limits<int>::max());
+
+ if (x >= intMax)
+ return std::numeric_limits<int>::max();
+ if (x <= 0)
+ return 0;
+ return static_cast<int>(x);
+}
+
+inline int clampToInteger(unsigned x)
+{
+ const unsigned intMax = static_cast<unsigned>(std::numeric_limits<int>::max());
+
+ if (x >= intMax)
+ return std::numeric_limits<int>::max();
+ return static_cast<int>(x);
+}
+
+#if !COMPILER(MSVC) && !(COMPILER(RVCT) && PLATFORM(BREWMP)) && !OS(SOLARIS) && !OS(SYMBIAN)
using std::isfinite;
using std::isinf;
using std::isnan;
enum MessageQueueWaitResult {
MessageQueueTerminated, // Queue was destroyed while waiting for message.
MessageQueueTimeout, // Timeout was specified and it expired.
- MessageQueueMessageReceived, // A message was successfully received and returned.
+ MessageQueueMessageReceived // A message was successfully received and returned.
};
// The queue takes ownership of messages and transfer it to the new owner
// when messages are fetched from the queue.
// Essentially, MessageQueue acts as a queue of OwnPtr<DataType>.
template<typename DataType>
- class MessageQueue : public Noncopyable {
+ class MessageQueue {
+ WTF_MAKE_NONCOPYABLE(MessageQueue);
public:
MessageQueue() : m_killed(false) { }
~MessageQueue();
inline void MessageQueue<DataType>::append(PassOwnPtr<DataType> message)
{
MutexLocker lock(m_mutex);
- m_queue.append(message.release());
+ m_queue.append(message.leakPtr());
m_condition.signal();
}
{
MutexLocker lock(m_mutex);
bool wasEmpty = m_queue.isEmpty();
- m_queue.append(message.release());
+ m_queue.append(message.leakPtr());
m_condition.signal();
return wasEmpty;
}
inline void MessageQueue<DataType>::prepend(PassOwnPtr<DataType> message)
{
MutexLocker lock(m_mutex);
- m_queue.prepend(message.release());
+ m_queue.prepend(message.leakPtr());
m_condition.signal();
}
inline PassOwnPtr<DataType> MessageQueue<DataType>::waitForMessage()
{
MessageQueueWaitResult exitReason;
- PassOwnPtr<DataType> result = waitForMessageFilteredWithTimeout(exitReason, MessageQueue<DataType>::alwaysTruePredicate, infiniteTime());
+ OwnPtr<DataType> result = waitForMessageFilteredWithTimeout(exitReason, MessageQueue<DataType>::alwaysTruePredicate, infiniteTime());
ASSERT(exitReason == MessageQueueTerminated || exitReason == MessageQueueMessageReceived);
- return result;
+ return result.release();
}
template<typename DataType>
if (m_killed) {
result = MessageQueueTerminated;
- return 0;
+ return nullptr;
}
if (timedOut) {
result = MessageQueueTimeout;
- return 0;
+ return nullptr;
}
ASSERT(found != m_queue.end());
- DataType* message = *found;
+ OwnPtr<DataType> message = adoptPtr(*found);
m_queue.remove(found);
result = MessageQueueMessageReceived;
- return message;
+ return message.release();
}
template<typename DataType>
{
MutexLocker lock(m_mutex);
if (m_killed)
- return 0;
+ return nullptr;
if (m_queue.isEmpty())
- return 0;
+ return nullptr;
- DataType* message = m_queue.first();
- m_queue.removeFirst();
- return message;
+ return adoptPtr(m_queue.takeFirst());
}
template<typename DataType>
--- /dev/null
+/*
+ * Copyright (C) 2010 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef WTF_NonCopyingSort_h
+#define WTF_NonCopyingSort_h
+
+namespace WTF {
+
+using std::swap;
+
+template<typename RandomAccessIterator, typename Predicate>
+inline void siftDown(RandomAccessIterator array, ptrdiff_t start, ptrdiff_t end, Predicate compareLess)
+{
+ ptrdiff_t root = start;
+
+ while (root * 2 + 1 <= end) {
+ ptrdiff_t child = root * 2 + 1;
+ if (child < end && compareLess(array[child], array[child + 1]))
+ child++;
+
+ if (compareLess(array[root], array[child])) {
+ swap(array[root], array[child]);
+ root = child;
+ } else
+ return;
+ }
+}
+
+template<typename RandomAccessIterator, typename Predicate>
+inline void heapify(RandomAccessIterator array, ptrdiff_t count, Predicate compareLess)
+{
+ ptrdiff_t start = (count - 2) / 2;
+
+ while (start >= 0) {
+ siftDown(array, start, count - 1, compareLess);
+ start--;
+ }
+}
+
+template<typename RandomAccessIterator, typename Predicate>
+void heapSort(RandomAccessIterator start, RandomAccessIterator end, Predicate compareLess)
+{
+ ptrdiff_t count = end - start;
+ heapify(start, count, compareLess);
+
+ ptrdiff_t endIndex = count - 1;
+ while (endIndex > 0) {
+ swap(start[endIndex], start[0]);
+ siftDown(start, 0, endIndex - 1, compareLess);
+ endIndex--;
+ }
+}
+
+template<typename RandomAccessIterator, typename Predicate>
+inline void nonCopyingSort(RandomAccessIterator start, RandomAccessIterator end, Predicate compareLess)
+{
+ // heapsort happens to use only swaps, not copies, but the essential thing about
+ // this function is the fact that it does not copy, not the specific algorithm
+ heapSort(start, end, compareLess);
+}
+
+} // namespace WTF
+
+using WTF::nonCopyingSort;
+
+#endif // WTF_NonCopyingSort_h
/*
- * Copyright (C) 2006 Apple Computer, Inc.
+ * Copyright (C) 2006, 2010 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
#ifndef WTF_Noncopyable_h
#define WTF_Noncopyable_h
-// We don't want argument-dependent lookup to pull in everything from the WTF
-// namespace when you use Noncopyable, so put it in its own namespace.
-
-#include "FastAllocBase.h"
-
-namespace WTFNoncopyable {
-
- class Noncopyable : public FastAllocBase {
- Noncopyable(const Noncopyable&);
- Noncopyable& operator=(const Noncopyable&);
- protected:
- Noncopyable() { }
- ~Noncopyable() { }
- };
-
- class NoncopyableCustomAllocated {
- NoncopyableCustomAllocated(const NoncopyableCustomAllocated&);
- NoncopyableCustomAllocated& operator=(const NoncopyableCustomAllocated&);
- protected:
- NoncopyableCustomAllocated() { }
- ~NoncopyableCustomAllocated() { }
- };
-
-} // namespace WTFNoncopyable
-
-using WTFNoncopyable::Noncopyable;
-using WTFNoncopyable::NoncopyableCustomAllocated;
+#ifndef __has_feature
+ #define __has_feature(x) 0
+#endif
+
+#if __has_feature(cxx_deleted_functions)
+ #define WTF_MAKE_NONCOPYABLE(ClassName) \
+ _Pragma("clang diagnostic push") \
+ _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") \
+ _Pragma("clang diagnostic ignored \"-Wc++0x-extensions\"") \
+ private: \
+ ClassName(const ClassName&) = delete; \
+ ClassName& operator=(const ClassName&) = delete; \
+ _Pragma("clang diagnostic pop")
+#else
+ #define WTF_MAKE_NONCOPYABLE(ClassName) \
+ private: \
+ ClassName(const ClassName&); \
+ ClassName& operator=(const ClassName&)
+#endif
#endif // WTF_Noncopyable_h
--- /dev/null
+/*
+
+Copyright (C) 2010 Apple Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "config.h"
+#include "NullPtr.h"
+
+#if !HAVE(NULLPTR)
+
+std::nullptr_t nullptr;
+
+#endif
--- /dev/null
+/*
+
+Copyright (C) 2010 Apple Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef NullPtr_h
+#define NullPtr_h
+
+// For compilers and standard libraries that do not yet include it, this adds the
+// nullptr_t type and nullptr object. They are defined in the same namespaces they
+// would be in compiler and library that had the support.
+
+#ifndef __has_feature
+ #define __has_feature(feature) 0
+#endif
+
+#if __has_feature(cxx_nullptr) || (GCC_VERSION_AT_LEAST(4, 6, 0) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || (defined(_MSC_VER) && _MSC_VER >= 1600)
+
+#define HAVE_NULLPTR 1
+
+#else
+
+namespace std {
+ class nullptr_t { };
+}
+
+extern std::nullptr_t nullptr;
+
+#endif
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef OSAllocator_h
+#define OSAllocator_h
+
+#include <wtf/UnusedParam.h>
+#include <wtf/VMTags.h>
+#include <wtf/VMTags.h>
+
+namespace WTF {
+
+class OSAllocator {
+public:
+ enum Usage {
+ UnknownUsage = -1,
+ FastMallocPages = VM_TAG_FOR_TCMALLOC_MEMORY,
+ JSGCHeapPages = VM_TAG_FOR_COLLECTOR_MEMORY,
+ JSVMStackPages = VM_TAG_FOR_REGISTERFILE_MEMORY,
+ JSJITCodePages = VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY,
+ };
+
+ // These methods are symmetric; reserveUncommitted allocates VM in an uncommitted state,
+ // releaseDecommitted should be called on a region of VM allocated by a single reservation,
+ // the memory must all currently be in a decommitted state.
+ static void* reserveUncommitted(size_t, Usage = UnknownUsage, bool writable = true, bool executable = false, bool includesGuardPages = false);
+ static void releaseDecommitted(void*, size_t);
+
+ // These methods are symmetric; they commit or decommit a region of VM (uncommitted VM should
+ // never be accessed, since the OS may not have attached physical memory for these regions).
+ // Clients should only call commit on uncommitted regions and decommit on committed regions.
+ static void commit(void*, size_t, bool writable, bool executable);
+ static void decommit(void*, size_t);
+
+ // These methods are symmetric; reserveAndCommit allocates VM in an committed state,
+ // decommitAndRelease should be called on a region of VM allocated by a single reservation,
+ // the memory must all currently be in a committed state.
+ static void* reserveAndCommit(size_t, Usage = UnknownUsage, bool writable = true, bool executable = false, bool includesGuardPages = false);
+ static void decommitAndRelease(void* base, size_t size);
+
+ // These methods are akin to reserveAndCommit/decommitAndRelease, above - however rather than
+ // committing/decommitting the entire region additional parameters allow a subregion to be
+ // specified.
+ static void* reserveAndCommit(size_t reserveSize, size_t commitSize, Usage = UnknownUsage, bool writable = true, bool executable = false);
+ static void decommitAndRelease(void* releaseBase, size_t releaseSize, void* decommitBase, size_t decommitSize);
+};
+
+inline void* OSAllocator::reserveAndCommit(size_t reserveSize, size_t commitSize, Usage usage, bool writable, bool executable)
+{
+ void* base = reserveUncommitted(reserveSize, usage, writable, executable);
+ commit(base, commitSize, writable, executable);
+ return base;
+}
+
+inline void OSAllocator::decommitAndRelease(void* releaseBase, size_t releaseSize, void* decommitBase, size_t decommitSize)
+{
+ ASSERT(decommitBase >= releaseBase && (static_cast<char*>(decommitBase) + decommitSize) <= (static_cast<char*>(releaseBase) + releaseSize));
+#if OS(WINCE) || OS(SYMBIAN)
+ // On most platforms we can actually skip this final decommit; releasing the VM will
+ // implicitly decommit any physical memory in the region. This is not true on WINCE.
+ // On Symbian, this makes implementation simpler and better aligned with the RChunk API
+ decommit(decommitBase, decommitSize);
+#else
+ UNUSED_PARAM(decommitBase);
+ UNUSED_PARAM(decommitSize);
+#endif
+ releaseDecommitted(releaseBase, releaseSize);
+}
+
+inline void OSAllocator::decommitAndRelease(void* base, size_t size)
+{
+ decommitAndRelease(base, size, base, size);
+}
+
+} // namespace WTF
+
+using WTF::OSAllocator;
+
+#endif // OSAllocator_h
--- /dev/null
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "OSAllocator.h"
+
+#include "PageAllocation.h"
+#include <errno.h>
+#include <sys/mman.h>
+#include <wtf/Assertions.h>
+#include <wtf/UnusedParam.h>
+
+namespace WTF {
+
+void* OSAllocator::reserveUncommitted(size_t bytes, Usage usage, bool writable, bool executable, bool includesGuardPages)
+{
+ void* result = reserveAndCommit(bytes, usage, writable, executable, includesGuardPages);
+#if HAVE(MADV_FREE_REUSE)
+ // To support the "reserve then commit" model, we have to initially decommit.
+ while (madvise(result, bytes, MADV_FREE_REUSABLE) == -1 && errno == EAGAIN) { }
+#endif
+ return result;
+}
+
+void* OSAllocator::reserveAndCommit(size_t bytes, Usage usage, bool writable, bool executable, bool includesGuardPages)
+{
+ // All POSIX reservations start out logically committed.
+ int protection = PROT_READ;
+ if (writable)
+ protection |= PROT_WRITE;
+ if (executable)
+ protection |= PROT_EXEC;
+
+ int flags = MAP_PRIVATE | MAP_ANON;
+#if defined MAP_JIT
+ if (executable)
+ flags |= MAP_JIT;
+#endif
+
+#if OS(DARWIN)
+ int fd = usage;
+#else
+ int fd = -1;
+#endif
+
+ void* result = 0;
+#if (OS(DARWIN) && CPU(X86_64))
+ if (executable) {
+ ASSERT(includesGuardPages);
+ // Cook up an address to allocate at, using the following recipe:
+ // 17 bits of zero, stay in userspace kids.
+ // 26 bits of randomness for ASLR.
+ // 21 bits of zero, at least stay aligned within one level of the pagetables.
+ //
+ // But! - as a temporary workaround for some plugin problems (rdar://problem/6812854),
+ // for now instead of 2^26 bits of ASLR lets stick with 25 bits of randomization plus
+ // 2^24, which should put up somewhere in the middle of userspace (in the address range
+ // 0x200000000000 .. 0x5fffffffffff).
+ intptr_t randomLocation = 0;
+ randomLocation = arc4random() & ((1 << 25) - 1);
+ randomLocation += (1 << 24);
+ randomLocation <<= 21;
+ result = reinterpret_cast<void*>(randomLocation);
+ }
+#endif
+
+ result = mmap(result, bytes, protection, flags, fd, 0);
+ if (result == MAP_FAILED) {
+ #if ENABLE(INTERPRETER)
+ if (executable)
+ result = 0;
+ else
+ #endif
+ CRASH();
+ }
+ if (result && includesGuardPages) {
+ // We use mmap to remap the guardpages rather than using mprotect as
+ // mprotect results in multiple references to the code region. This
+ // breaks the madvise based mechanism we use to return physical memory
+ // to the OS.
+ mmap(result, pageSize(), PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANON, fd, 0);
+ mmap(static_cast<char*>(result) + bytes - pageSize(), pageSize(), PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANON, fd, 0);
+ }
+
+ return result;
+}
+
+void OSAllocator::commit(void* address, size_t bytes, bool, bool)
+{
+#if HAVE(MADV_FREE_REUSE)
+ while (madvise(address, bytes, MADV_FREE_REUSE) == -1 && errno == EAGAIN) { }
+#else
+ // Non-MADV_FREE_REUSE reservations automatically commit on demand.
+ UNUSED_PARAM(address);
+ UNUSED_PARAM(bytes);
+#endif
+}
+
+void OSAllocator::decommit(void* address, size_t bytes)
+{
+#if HAVE(MADV_FREE_REUSE)
+ while (madvise(address, bytes, MADV_FREE_REUSABLE) == -1 && errno == EAGAIN) { }
+#elif HAVE(MADV_FREE)
+ while (madvise(address, bytes, MADV_FREE) == -1 && errno == EAGAIN) { }
+#elif HAVE(MADV_DONTNEED)
+ while (madvise(address, bytes, MADV_DONTNEED) == -1 && errno == EAGAIN) { }
+#else
+ UNUSED_PARAM(address);
+ UNUSED_PARAM(bytes);
+#endif
+}
+
+void OSAllocator::releaseDecommitted(void* address, size_t bytes)
+{
+ int result = munmap(address, bytes);
+ if (result == -1)
+ CRASH();
+}
+
+} // namespace WTF
--- /dev/null
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "OSAllocator.h"
+
+#include "PageAllocatorSymbian.h"
+
+namespace WTF {
+
+// Array to store code chunks used by JIT engine(s)
+static RPointerArray<SymbianChunk> codeChunksContainer;
+
+// The singleton data allocator (non code)
+static PageAllocatorSymbian dataAllocator;
+
+_LIT(KErrorStringInternalConsistency, "OSAllocator:ConsistencyError");
+_LIT(KErrorStringChunkCreation, "OSAllocator:ChunkInitError");
+_LIT(KErrorStringPageSize, "OSAllocator:WrongPageSize");
+
+// Makes a new code chunk for a JIT engine with everything in committed state
+static void* allocateCodeChunk(size_t bytes)
+{
+ RChunk c;
+ TInt error = c.CreateLocalCode(bytes, bytes);
+ __ASSERT_ALWAYS(error == KErrNone, User::Panic(KErrorStringChunkCreation, error));
+
+ codeChunksContainer.Append(new SymbianChunk(c.Handle()));
+ return static_cast<void*>(c.Base());
+}
+
+// Frees the _entire_ code chunk in which this address resides.
+static bool deallocateCodeChunk(void* address)
+{
+ bool found = false;
+ for (int i = 0; i < codeChunksContainer.Count(); i++) {
+ SymbianChunk* p = codeChunksContainer[i];
+ if (p && p->contains(address)) {
+ codeChunksContainer.Remove(i);
+ delete p;
+ found = true;
+ }
+ }
+ return found;
+}
+
+// Return the (singleton) object that manages all non-code VM operations
+static PageAllocatorSymbian* dataAllocatorInstance()
+{
+ return &dataAllocator;
+}
+
+// Reserve memory and return the base address of the region
+void* OSAllocator::reserveUncommitted(size_t reservationSize, Usage usage, bool , bool executable, bool)
+{
+ void* base = 0;
+ if (executable)
+ base = allocateCodeChunk(reservationSize);
+ else
+ base = dataAllocatorInstance()->reserve(reservationSize);
+ return base;
+}
+
+// Inverse operation of reserveUncommitted()
+void OSAllocator::releaseDecommitted(void* parkedBase, size_t bytes)
+{
+ if (dataAllocatorInstance()->contains(parkedBase))
+ dataAllocatorInstance()->release(parkedBase, bytes);
+
+ // NOOP for code chunks (JIT) because we released them in decommit()
+}
+
+// Commit what was previously reserved via reserveUncommitted()
+void OSAllocator::commit(void* address, size_t bytes, bool, bool executable)
+{
+ // For code chunks, we commit (early) in reserveUncommitted(), so NOOP
+ // For data regions, do real work
+ if (!executable)
+ dataAllocatorInstance()->commit(address, bytes);
+}
+
+void OSAllocator::decommit(void* address, size_t bytes)
+{
+ if (dataAllocatorInstance()->contains(address))
+ dataAllocatorInstance()->decommit(address, bytes);
+ else
+ deallocateCodeChunk(address); // for code chunk, decommit AND release
+}
+
+void* OSAllocator::reserveAndCommit(size_t bytes, Usage usage, bool writable, bool executable, bool)
+{
+ void* base = reserveUncommitted(bytes, usage, writable, executable);
+ commit(base, bytes, writable, executable);
+ return base;
+}
+
+
+// The PageAllocatorSymbian class helps map OSAllocator calls for reserve/commit/decommit
+// to a single large Symbian chunk. Only works with multiples of page size, and as a corollary
+// all addresses accepted or returned by it are also page-sized aligned.
+// Design notes:
+// - We initialize a chunk up-front with a large reservation size
+// - The entire reservation reserve is logically divided into pageSized blocks (4K on Symbian)
+// - The map maintains 1 bit for each of the 4K-sized region in our address space
+// - OSAllocator::reserveUncommitted() requests lead to 1 or more bits being set in map
+// to indicate internally reserved state. The VM address corresponding to the first bit is returned.
+// - OSAllocator::commit() actually calls RChunk.commit() and commits *all or part* of the region
+// reserved via reserveUncommitted() previously.
+// - OSAllocator::decommit() calls RChunk.decommit()
+// - OSAllocator::releaseDecommitted() unparks all the bits in the map, but trusts that a previously
+// call to decommit() would have returned the memory to the OS
+PageAllocatorSymbian::PageAllocatorSymbian()
+{
+ __ASSERT_ALWAYS(m_pageSize == WTF::pageSize(), User::Panic(KErrorStringPageSize, m_pageSize));
+
+ RChunk chunk;
+ TInt error = chunk.CreateDisconnectedLocal(0, 0, TInt(largeReservationSize));
+ __ASSERT_ALWAYS(error == KErrNone, User::Panic(KErrorStringChunkCreation, error));
+
+ m_chunk = new SymbianChunk(chunk.Handle()); // takes ownership of chunk
+}
+
+PageAllocatorSymbian::~PageAllocatorSymbian()
+{
+ delete m_chunk;
+}
+
+// Reserves a region internally in the bitmap
+void* PageAllocatorSymbian::reserve(size_t bytes)
+{
+ // Find first available region
+ const size_t nPages = bytes / m_pageSize;
+ const int64_t startIdx = m_map.findRunOfZeros(nPages);
+
+ // Pseudo OOM
+ if (startIdx < 0)
+ return 0;
+
+ for (size_t i = startIdx; i < startIdx + nPages ; i++)
+ m_map.set(i);
+
+ return static_cast<void*>( m_chunk->m_base + (TUint)(m_pageSize * startIdx) );
+}
+
+// Reverses the effects of a reserve() call
+void PageAllocatorSymbian::release(void* address, size_t bytes)
+{
+ const size_t startIdx = (static_cast<char*>(address) - m_chunk->m_base) / m_pageSize;
+ const size_t nPages = bytes / m_pageSize;
+ for (size_t i = startIdx; i < startIdx + nPages ; i++)
+ m_map.clear(i);
+}
+
+// Actually commit memory from the OS, after a previous call to reserve()
+bool PageAllocatorSymbian::commit(void* address, size_t bytes)
+{
+ // sanity check that bits were previously set
+ const size_t idx = (static_cast<char*>(address) - m_chunk->m_base) / m_pageSize;
+ const size_t nPages = bytes / m_pageSize;
+ __ASSERT_ALWAYS(m_map.get(idx), User::Panic(KErrorStringInternalConsistency, idx));
+ __ASSERT_ALWAYS(m_map.get(idx+nPages-1), User::Panic(KErrorStringInternalConsistency, idx+nPages-1));
+
+ TInt error = m_chunk->Commit(static_cast<char*>(address) - m_chunk->m_base, bytes);
+ return (error == KErrNone);
+}
+
+// Inverse operation of commit(), a release() should follow later
+bool PageAllocatorSymbian::decommit(void* address, size_t bytes)
+{
+ TInt error = m_chunk->Decommit(static_cast<char*>(address) - m_chunk->m_base, bytes);
+ return (error == KErrNone);
+}
+
+bool PageAllocatorSymbian::contains(const void* address) const
+{
+ return m_chunk->contains(address);
+}
+
+} // namespace WTF
--- /dev/null
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "OSAllocator.h"
+
+#include "windows.h"
+#include <wtf/Assertions.h>
+
+namespace WTF {
+
+static inline DWORD protection(bool writable, bool executable)
+{
+ return executable ?
+ (writable ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ) :
+ (writable ? PAGE_READWRITE : PAGE_READONLY);
+}
+
+void* OSAllocator::reserveUncommitted(size_t bytes, Usage, bool writable, bool executable)
+{
+ void* result = VirtualAlloc(0, bytes, MEM_RESERVE, protection(writable, executable));
+ if (!result)
+ CRASH();
+ return result;
+}
+
+void* OSAllocator::reserveAndCommit(size_t bytes, Usage, bool writable, bool executable)
+{
+ void* result = VirtualAlloc(0, bytes, MEM_RESERVE | MEM_COMMIT, protection(writable, executable));
+ if (!result)
+ CRASH();
+ return result;
+}
+
+void OSAllocator::commit(void* address, size_t bytes, bool writable, bool executable)
+{
+ void* result = VirtualAlloc(address, bytes, MEM_COMMIT, protection(writable, executable));
+ if (!result)
+ CRASH();
+}
+
+void OSAllocator::decommit(void* address, size_t bytes)
+{
+ bool result = VirtualFree(address, bytes, MEM_DECOMMIT);
+ if (!result)
+ CRASH();
+}
+
+void OSAllocator::releaseDecommitted(void* address, size_t bytes)
+{
+ // According to http://msdn.microsoft.com/en-us/library/aa366892(VS.85).aspx,
+ // dwSize must be 0 if dwFreeType is MEM_RELEASE.
+ bool result = VirtualFree(address, 0, MEM_RELEASE);
+ if (!result)
+ CRASH();
+}
+
+} // namespace WTF
--- /dev/null
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GOOGLE, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "OSRandomSource.h"
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#if OS(SYMBIAN)
+#include <e32math.h>
+#endif
+
+#if OS(UNIX)
+#include <fcntl.h>
+#include <unistd.h>
+#endif
+
+#if OS(WINDOWS)
+#include <windows.h>
+#include <wincrypt.h> // windows.h must be included before wincrypt.h.
+#endif
+
+namespace WTF {
+
+#if USE(OS_RANDOMNESS)
+void cryptographicallyRandomValuesFromOS(unsigned char* buffer, size_t length)
+{
+#if OS(SYMBIAN)
+ TInt random;
+ while (length > sizeof(random)) {
+ random = Math::Random();
+ memcpy(buffer, &random, sizeof(random));
+ length -= sizeof(random);
+ buffer += sizeof(random);
+ }
+ if (length > 0) {
+ random = Math::Random();
+ memcpy(buffer, &random, length);
+ }
+#elif OS(UNIX)
+ int fd = open("/dev/urandom", O_RDONLY, 0);
+ if (fd < 0)
+ CRASH(); // We need /dev/urandom for this API to work...
+
+ if (read(fd, buffer, length) != static_cast<ssize_t>(length))
+ CRASH();
+
+ close(fd);
+#elif OS(WINDOWS)
+ HCRYPTPROV hCryptProv = 0;
+ if (!CryptAcquireContext(&hCryptProv, 0, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
+ CRASH();
+ if (!CryptGenRandom(hCryptProv, length, buffer))
+ CRASH();
+ CryptReleaseContext(hCryptProv, 0);
+#else
+ #error "This configuration doesn't have a strong source of randomness."
+ // WARNING: When adding new sources of OS randomness, the randomness must
+ // be of cryptographic quality!
+#endif
+}
+#endif
+
+}
--- /dev/null
+/*
+ * Copyright (C) Google, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GOOGLE, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WTF_OSRandomSource_h
+#define WTF_OSRandomSource_h
+
+namespace WTF {
+
+#if USE(OS_RANDOMNESS)
+// This function attempts to fill buffer with randomness from the operating
+// system. If insufficient randomness is available, the buffer will be
+// partially filled. Rather than calling this function directly, consider
+// calling cryptographicallyRandomNumber or cryptographicallyRandomValues.
+void cryptographicallyRandomValuesFromOS(unsigned char* buffer, size_t length);
+#endif
+
+}
+
+#endif
/*
- * Copyright (C) 2006 Apple Computer, Inc.
+ * Copyright (C) 2006, 2010 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
#ifndef WTF_OwnArrayPtr_h
#define WTF_OwnArrayPtr_h
+#include "Assertions.h"
+#include "Noncopyable.h"
+#include "NullPtr.h"
+#include "PassOwnArrayPtr.h"
#include <algorithm>
-#include <wtf/Assertions.h>
-#include <wtf/Noncopyable.h>
namespace WTF {
- template <typename T> class OwnArrayPtr : public Noncopyable {
- public:
- explicit OwnArrayPtr(T* ptr = 0) : m_ptr(ptr) { }
- ~OwnArrayPtr() { safeDelete(); }
+template<typename T> class PassOwnArrayPtr;
+template<typename T> PassOwnArrayPtr<T> adoptArrayPtr(T*);
- T* get() const { return m_ptr; }
- T* release() { T* ptr = m_ptr; m_ptr = 0; return ptr; }
+template <typename T> class OwnArrayPtr {
+public:
+ typedef T* PtrType;
- void set(T* ptr) { ASSERT(m_ptr != ptr); safeDelete(); m_ptr = ptr; }
- void clear() { safeDelete(); m_ptr = 0; }
+ OwnArrayPtr() : m_ptr(0) { }
- T& operator*() const { ASSERT(m_ptr); return *m_ptr; }
- T* operator->() const { ASSERT(m_ptr); return m_ptr; }
+ // See comment in PassOwnArrayPtr.h for why this takes a const reference.
+ template<typename U> OwnArrayPtr(const PassOwnArrayPtr<U>& o);
- T& operator[](std::ptrdiff_t i) const { ASSERT(m_ptr); ASSERT(i >= 0); return m_ptr[i]; }
+ // This copy constructor is used implicitly by gcc when it generates
+ // transients for assigning a PassOwnArrayPtr<T> object to a stack-allocated
+ // OwnArrayPtr<T> object. It should never be called explicitly and gcc
+ // should optimize away the constructor when generating code.
+ OwnArrayPtr(const OwnArrayPtr<T>&);
- bool operator!() const { return !m_ptr; }
+ ~OwnArrayPtr() { deleteOwnedArrayPtr(m_ptr); }
- // This conversion operator allows implicit conversion to bool but not to other integer types.
+ PtrType get() const { return m_ptr; }
+
+ void clear();
+ PassOwnArrayPtr<T> release();
+ PtrType leakPtr() WARN_UNUSED_RETURN;
+
+ T& operator*() const { ASSERT(m_ptr); return *m_ptr; }
+ PtrType operator->() const { ASSERT(m_ptr); return m_ptr; }
+
+ T& operator[](std::ptrdiff_t i) const { ASSERT(m_ptr); ASSERT(i >= 0); return m_ptr[i]; }
+
+ bool operator!() const { return !m_ptr; }
+
+ // This conversion operator allows implicit conversion to bool but not to other integer types.
#if COMPILER(WINSCW)
- operator bool() const { return m_ptr; }
+ operator bool() const { return m_ptr; }
#else
- typedef T* OwnArrayPtr::*UnspecifiedBoolType;
- operator UnspecifiedBoolType() const { return m_ptr ? &OwnArrayPtr::m_ptr : 0; }
+ typedef T* OwnArrayPtr::*UnspecifiedBoolType;
+ operator UnspecifiedBoolType() const { return m_ptr ? &OwnArrayPtr::m_ptr : 0; }
#endif
- void swap(OwnArrayPtr& o) { std::swap(m_ptr, o.m_ptr); }
+ OwnArrayPtr& operator=(const PassOwnArrayPtr<T>&);
+ OwnArrayPtr& operator=(std::nullptr_t) { clear(); return *this; }
+ template<typename U> OwnArrayPtr& operator=(const PassOwnArrayPtr<U>&);
+
+ void swap(OwnArrayPtr& o) { std::swap(m_ptr, o.m_ptr); }
- private:
- void safeDelete() { typedef char known[sizeof(T) ? 1 : -1]; if (sizeof(known)) delete [] m_ptr; }
+#ifdef LOOSE_OWN_ARRAY_PTR
+ explicit OwnArrayPtr(PtrType ptr) : m_ptr(ptr) { }
+ void set(PtrType);
+#endif
- T* m_ptr;
- };
-
- template <typename T> inline void swap(OwnArrayPtr<T>& a, OwnArrayPtr<T>& b) { a.swap(b); }
+private:
+ PtrType m_ptr;
+};
+
+template<typename T> template<typename U> inline OwnArrayPtr<T>::OwnArrayPtr(const PassOwnArrayPtr<U>& o)
+ : m_ptr(o.leakPtr())
+{
+}
+
+template<typename T> inline void OwnArrayPtr<T>::clear()
+{
+ PtrType ptr = m_ptr;
+ m_ptr = 0;
+ deleteOwnedArrayPtr(ptr);
+}
+
+template<typename T> inline PassOwnArrayPtr<T> OwnArrayPtr<T>::release()
+{
+ PtrType ptr = m_ptr;
+ m_ptr = 0;
+ return adoptArrayPtr(ptr);
+}
+
+template<typename T> inline typename OwnArrayPtr<T>::PtrType OwnArrayPtr<T>::leakPtr()
+{
+ PtrType ptr = m_ptr;
+ m_ptr = 0;
+ return ptr;
+}
+
+#ifdef LOOSE_OWN_ARRAY_PTR
+template<typename T> inline void OwnArrayPtr<T>::set(PtrType ptr)
+{
+ ASSERT(!ptr || m_ptr != ptr);
+ PtrType oldPtr = m_ptr;
+ m_ptr = ptr;
+ deleteOwnedArrayPtr(oldPtr);
+}
+#endif
- template <typename T> inline T* getPtr(const OwnArrayPtr<T>& p)
- {
- return p.get();
- }
+template<typename T> inline OwnArrayPtr<T>& OwnArrayPtr<T>::operator=(const PassOwnArrayPtr<T>& o)
+{
+ PtrType ptr = m_ptr;
+ m_ptr = o.leakPtr();
+ ASSERT(!ptr || m_ptr != ptr);
+ deleteOwnedArrayPtr(ptr);
+ return *this;
+}
+
+template<typename T> template<typename U> inline OwnArrayPtr<T>& OwnArrayPtr<T>::operator=(const PassOwnArrayPtr<U>& o)
+{
+ PtrType ptr = m_ptr;
+ m_ptr = o.leakPtr();
+ ASSERT(!ptr || m_ptr != ptr);
+ deleteOwnedArrayPtr(ptr);
+ return *this;
+}
+
+template <typename T> inline void swap(OwnArrayPtr<T>& a, OwnArrayPtr<T>& b)
+{
+ a.swap(b);
+}
+
+template<typename T, typename U> inline bool operator==(const OwnArrayPtr<T>& a, U* b)
+{
+ return a.get() == b;
+}
+
+template<typename T, typename U> inline bool operator==(T* a, const OwnArrayPtr<U>& b)
+{
+ return a == b.get();
+}
+
+template<typename T, typename U> inline bool operator!=(const OwnArrayPtr<T>& a, U* b)
+{
+ return a.get() != b;
+}
+
+template<typename T, typename U> inline bool operator!=(T* a, const OwnArrayPtr<U>& b)
+{
+ return a != b.get();
+}
+
+template <typename T> inline T* getPtr(const OwnArrayPtr<T>& p)
+{
+ return p.get();
+}
} // namespace WTF
#define OwnFastMallocPtr_h
#include "FastMalloc.h"
-#include "Noncopyable.h"
namespace WTF {
- template<class T> class OwnFastMallocPtr : public Noncopyable {
+ template<class T> class OwnFastMallocPtr {
+ WTF_MAKE_NONCOPYABLE(OwnFastMallocPtr);
public:
explicit OwnFastMallocPtr(T* ptr) : m_ptr(ptr)
{
/*
- * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
#define WTF_OwnPtr_h
#include "Assertions.h"
-#include "Noncopyable.h"
+#include "NullPtr.h"
#include "OwnPtrCommon.h"
#include "TypeTraits.h"
#include <algorithm>
// Unlike most of our smart pointers, OwnPtr can take either the pointer type or the pointed-to type.
- template <typename T> class PassOwnPtr;
+ template<typename T> class PassOwnPtr;
+ template<typename T> PassOwnPtr<T> adoptPtr(T*);
- template <typename T> class OwnPtr : public Noncopyable {
+ template<typename T> class OwnPtr {
public:
typedef typename RemovePointer<T>::Type ValueType;
typedef ValueType* PtrType;
- explicit OwnPtr(PtrType ptr = 0) : m_ptr(ptr) { }
+ OwnPtr() : m_ptr(0) { }
+
// See comment in PassOwnPtr.h for why this takes a const reference.
- template <typename U> OwnPtr(const PassOwnPtr<U>& o);
+ template<typename U> OwnPtr(const PassOwnPtr<U>& o);
// This copy constructor is used implicitly by gcc when it generates
// transients for assigning a PassOwnPtr<T> object to a stack-allocated
- // OwnPtr<T> object. It should never be called explicitly and gcc
+ // OwnPtr<T> object. It should never be called explicitly and gcc
// should optimize away the constructor when generating code.
- OwnPtr(const OwnPtr<ValueType>& o);
+ OwnPtr(const OwnPtr<ValueType>&);
~OwnPtr() { deleteOwnedPtr(m_ptr); }
PtrType get() const { return m_ptr; }
- PtrType release() { PtrType ptr = m_ptr; m_ptr = 0; return ptr; }
-
- // FIXME: This should be renamed to adopt.
- void set(PtrType ptr) { ASSERT(!ptr || m_ptr != ptr); deleteOwnedPtr(m_ptr); m_ptr = ptr; }
- void clear() { deleteOwnedPtr(m_ptr); m_ptr = 0; }
+ void clear();
+ PassOwnPtr<T> release();
+ PtrType leakPtr() WARN_UNUSED_RETURN;
ValueType& operator*() const { ASSERT(m_ptr); return *m_ptr; }
PtrType operator->() const { ASSERT(m_ptr); return m_ptr; }
operator UnspecifiedBoolType() const { return m_ptr ? &OwnPtr::m_ptr : 0; }
OwnPtr& operator=(const PassOwnPtr<T>&);
- template <typename U> OwnPtr& operator=(const PassOwnPtr<U>&);
+ OwnPtr& operator=(std::nullptr_t) { clear(); return *this; }
+ template<typename U> OwnPtr& operator=(const PassOwnPtr<U>&);
void swap(OwnPtr& o) { std::swap(m_ptr, o.m_ptr); }
+#ifdef LOOSE_OWN_PTR
+ explicit OwnPtr(PtrType ptr) : m_ptr(ptr) { }
+ void set(PtrType);
+#endif
+
private:
+ OwnPtr& operator=(const OwnPtr<T>&);
+
+ // We should never have two OwnPtrs for the same underlying object (otherwise we'll get
+ // double-destruction), so these equality operators should never be needed.
+ template<typename U> bool operator==(const OwnPtr<U>&) { COMPILE_ASSERT(!sizeof(U*), OwnPtrs_should_never_be_equal); return false; }
+ template<typename U> bool operator!=(const OwnPtr<U>&) { COMPILE_ASSERT(!sizeof(U*), OwnPtrs_should_never_be_equal); return false; }
+ template<typename U> bool operator==(const PassOwnPtr<U>&) { COMPILE_ASSERT(!sizeof(U*), OwnPtrs_should_never_be_equal); return false; }
+ template<typename U> bool operator!=(const PassOwnPtr<U>&) { COMPILE_ASSERT(!sizeof(U*), OwnPtrs_should_never_be_equal); return false; }
+
PtrType m_ptr;
};
- template <typename T> template <typename U> inline OwnPtr<T>::OwnPtr(const PassOwnPtr<U>& o)
- : m_ptr(o.release())
+ template<typename T> template<typename U> inline OwnPtr<T>::OwnPtr(const PassOwnPtr<U>& o)
+ : m_ptr(o.leakPtr())
+ {
+ }
+
+ template<typename T> inline void OwnPtr<T>::clear()
+ {
+ PtrType ptr = m_ptr;
+ m_ptr = 0;
+ deleteOwnedPtr(ptr);
+ }
+
+ template<typename T> inline PassOwnPtr<T> OwnPtr<T>::release()
+ {
+ PtrType ptr = m_ptr;
+ m_ptr = 0;
+ return adoptPtr(ptr);
+ }
+
+ template<typename T> inline typename OwnPtr<T>::PtrType OwnPtr<T>::leakPtr()
{
+ PtrType ptr = m_ptr;
+ m_ptr = 0;
+ return ptr;
+ }
+
+#ifdef LOOSE_OWN_PTR
+ template<typename T> inline void OwnPtr<T>::set(PtrType ptr)
+ {
+ ASSERT(!ptr || m_ptr != ptr);
+ PtrType oldPtr = m_ptr;
+ m_ptr = ptr;
+ deleteOwnedPtr(oldPtr);
}
+#endif
- template <typename T> inline OwnPtr<T>& OwnPtr<T>::operator=(const PassOwnPtr<T>& o)
+ template<typename T> inline OwnPtr<T>& OwnPtr<T>::operator=(const PassOwnPtr<T>& o)
{
- T* ptr = m_ptr;
- m_ptr = o.release();
+ PtrType ptr = m_ptr;
+ m_ptr = o.leakPtr();
ASSERT(!ptr || m_ptr != ptr);
- if (ptr)
- deleteOwnedPtr(ptr);
+ deleteOwnedPtr(ptr);
return *this;
}
- template <typename T> template <typename U> inline OwnPtr<T>& OwnPtr<T>::operator=(const PassOwnPtr<U>& o)
+ template<typename T> template<typename U> inline OwnPtr<T>& OwnPtr<T>::operator=(const PassOwnPtr<U>& o)
{
- T* ptr = m_ptr;
- m_ptr = o.release();
+ PtrType ptr = m_ptr;
+ m_ptr = o.leakPtr();
ASSERT(!ptr || m_ptr != ptr);
- if (ptr)
- deleteOwnedPtr(ptr);
+ deleteOwnedPtr(ptr);
return *this;
}
- template <typename T> inline void swap(OwnPtr<T>& a, OwnPtr<T>& b)
+ template<typename T> inline void swap(OwnPtr<T>& a, OwnPtr<T>& b)
{
a.swap(b);
}
- template <typename T, typename U> inline bool operator==(const OwnPtr<T>& a, U* b)
+ template<typename T, typename U> inline bool operator==(const OwnPtr<T>& a, U* b)
{
return a.get() == b;
}
- template <typename T, typename U> inline bool operator==(T* a, const OwnPtr<U>& b)
+ template<typename T, typename U> inline bool operator==(T* a, const OwnPtr<U>& b)
{
return a == b.get();
}
- template <typename T, typename U> inline bool operator!=(const OwnPtr<T>& a, U* b)
+ template<typename T, typename U> inline bool operator!=(const OwnPtr<T>& a, U* b)
{
return a.get() != b;
}
- template <typename T, typename U> inline bool operator!=(T* a, const OwnPtr<U>& b)
+ template<typename T, typename U> inline bool operator!=(T* a, const OwnPtr<U>& b)
{
return a != b.get();
}
- template <typename T> inline typename OwnPtr<T>::PtrType getPtr(const OwnPtr<T>& p)
+ template<typename T> inline typename OwnPtr<T>::PtrType getPtr(const OwnPtr<T>& p)
{
return p.get();
}
#if PLATFORM(BREWMP)
// Forward delcarations at this point avoid the need to include BREW includes
// in WTF headers.
+typedef struct _ISocket ISocket;
typedef struct _IFileMgr IFileMgr;
typedef struct _IFile IFile;
typedef struct IBitmap IBitmap;
+typedef struct ISSL ISSL;
+typedef struct IMemGroup IMemGroup;
+typedef struct IMemSpace IMemSpace;
#endif
namespace WTF {
void deleteOwnedPtr(IFileMgr*);
void deleteOwnedPtr(IFile*);
void deleteOwnedPtr(IBitmap*);
+ void deleteOwnedPtr(ISSL*);
+ void deleteOwnedPtr(ISocket*);
+ void deleteOwnedPtr(IMemGroup*);
+ void deleteOwnedPtr(IMemSpace*);
#endif
} // namespace WTF
--- /dev/null
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PageAllocation_h
+#define PageAllocation_h
+
+#include <wtf/Assertions.h>
+#include <wtf/OSAllocator.h>
+#include <wtf/PageBlock.h>
+#include <wtf/UnusedParam.h>
+#include <wtf/VMTags.h>
+#include <algorithm>
+
+#if OS(DARWIN)
+#include <mach/mach_init.h>
+#include <mach/vm_map.h>
+#endif
+
+#if OS(HAIKU)
+#include <OS.h>
+#endif
+
+#if OS(WINDOWS)
+#include <malloc.h>
+#include <windows.h>
+#endif
+
+#if OS(SYMBIAN)
+#include <e32hal.h>
+#include <e32std.h>
+#endif
+
+#if HAVE(ERRNO_H)
+#include <errno.h>
+#endif
+
+#if HAVE(MMAP)
+#include <sys/mman.h>
+#include <unistd.h>
+#endif
+
+namespace WTF {
+
+/*
+ PageAllocation
+
+ The PageAllocation class provides a cross-platform memory allocation interface
+ with similar capabilities to posix mmap/munmap. Memory is allocated by calling
+ PageAllocation::allocate, and deallocated by calling deallocate on the
+ PageAllocation object. The PageAllocation holds the allocation's base pointer
+ and size.
+
+ The allocate method is passed the size required (which must be a multiple of
+ the system page size, which can be accessed using PageAllocation::pageSize).
+ Callers may also optinally provide a flag indicating the usage (for use by
+ system memory usage tracking tools, where implemented), and boolean values
+ specifying the required protection (defaulting to writable, non-executable).
+*/
+
+class PageAllocation : private PageBlock {
+public:
+ PageAllocation()
+ {
+ }
+
+ using PageBlock::size;
+ using PageBlock::base;
+
+#ifndef __clang__
+ using PageBlock::operator bool;
+#else
+ // FIXME: This is a workaround for <rdar://problem/8876150>, wherein Clang incorrectly emits an access
+ // control warning when a client tries to use operator bool exposed above via "using PageBlock::operator bool".
+ operator bool() const { return PageBlock::operator bool(); }
+#endif
+
+ static PageAllocation allocate(size_t size, OSAllocator::Usage usage = OSAllocator::UnknownUsage, bool writable = true, bool executable = false)
+ {
+ ASSERT(isPageAligned(size));
+ return PageAllocation(OSAllocator::reserveAndCommit(size, usage, writable, executable), size);
+ }
+
+ void deallocate()
+ {
+ // Clear base & size before calling release; if this is *inside* allocation
+ // then we won't be able to clear then after deallocating the memory.
+ PageAllocation tmp;
+ std::swap(tmp, *this);
+
+ ASSERT(tmp);
+ ASSERT(!*this);
+
+ OSAllocator::decommitAndRelease(tmp.base(), tmp.size());
+ }
+
+private:
+ PageAllocation(void* base, size_t size)
+ : PageBlock(base, size, false)
+ {
+ }
+};
+
+} // namespace WTF
+
+using WTF::PageAllocation;
+
+#endif // PageAllocation_h
--- /dev/null
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "PageAllocationAligned.h"
+
+namespace WTF {
+
+PageAllocationAligned PageAllocationAligned::allocate(size_t size, size_t alignment, OSAllocator::Usage usage, bool writable, bool executable)
+{
+ ASSERT(isPageAligned(size));
+ ASSERT(isPageAligned(alignment));
+ ASSERT(isPowerOfTwo(alignment));
+ ASSERT(size >= alignment);
+ size_t alignmentMask = alignment - 1;
+
+#if OS(DARWIN)
+ int flags = VM_FLAGS_ANYWHERE;
+ if (usage != OSAllocator::UnknownUsage)
+ flags |= usage;
+ int protection = PROT_READ;
+ if (writable)
+ protection |= PROT_WRITE;
+ if (executable)
+ protection |= PROT_EXEC;
+
+ vm_address_t address = 0;
+ vm_map(current_task(), &address, size, alignmentMask, flags, MEMORY_OBJECT_NULL, 0, FALSE, protection, PROT_READ | PROT_WRITE | PROT_EXEC, VM_INHERIT_DEFAULT);
+ return PageAllocationAligned(reinterpret_cast<void*>(address), size);
+#else
+ size_t alignmentDelta = alignment - pageSize();
+
+ // Resererve with suffcient additional VM to correctly align.
+ size_t reservationSize = size + alignmentDelta;
+ void* reservationBase = OSAllocator::reserveUncommitted(reservationSize, usage, writable, executable);
+
+ // Select an aligned region within the reservation and commit.
+ void* alignedBase = reinterpret_cast<uintptr_t>(reservationBase) & alignmentMask
+ ? reinterpret_cast<void*>((reinterpret_cast<uintptr_t>(reservationBase) & ~alignmentMask) + alignment)
+ : reservationBase;
+ OSAllocator::commit(alignedBase, size, writable, executable);
+
+ return PageAllocationAligned(alignedBase, size, reservationBase, reservationSize);
+#endif
+}
+
+void PageAllocationAligned::deallocate()
+{
+ // Clear base & size before calling release; if this is *inside* allocation
+ // then we won't be able to clear then after deallocating the memory.
+ PageAllocationAligned tmp;
+ std::swap(tmp, *this);
+
+ ASSERT(tmp);
+ ASSERT(!*this);
+
+#if OS(DARWIN)
+ vm_deallocate(current_task(), reinterpret_cast<vm_address_t>(tmp.base()), tmp.size());
+#else
+ ASSERT(tmp.m_reservation.contains(tmp.base(), tmp.size()));
+ OSAllocator::decommitAndRelease(tmp.m_reservation.base(), tmp.m_reservation.size(), tmp.base(), tmp.size());
+#endif
+}
+
+} // namespace WTF
--- /dev/null
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PageAllocationAligned_h
+#define PageAllocationAligned_h
+
+#include <wtf/OSAllocator.h>
+#include <wtf/PageReservation.h>
+
+namespace WTF {
+
+class PageAllocationAligned : private PageBlock {
+public:
+ PageAllocationAligned()
+ {
+ }
+
+ using PageBlock::operator bool;
+ using PageBlock::size;
+ using PageBlock::base;
+
+ static PageAllocationAligned allocate(size_t size, size_t alignment, OSAllocator::Usage usage = OSAllocator::UnknownUsage, bool writable = true, bool executable = false);
+
+ void deallocate();
+
+private:
+#if OS(DARWIN)
+ PageAllocationAligned(void* base, size_t size)
+ : PageBlock(base, size, false)
+ {
+ }
+#else
+ PageAllocationAligned(void* base, size_t size, void* reservationBase, size_t reservationSize)
+ : PageBlock(base, size, false)
+ , m_reservation(reservationBase, reservationSize, false)
+ {
+ }
+
+ PageBlock m_reservation;
+#endif
+};
+
+
+} // namespace WTF
+
+using WTF::PageAllocationAligned;
+
+#endif // PageAllocationAligned_h
--- /dev/null
+/*
+ * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PageAllocatorSymbian_h
+#define PageAllocatorSymbian_h
+
+#include <e32std.h>
+#include <wtf/Bitmap.h>
+
+namespace WTF {
+
+size_t pageSize();
+
+// Convenience wrapper around an RChunk
+class SymbianChunk : public RChunk {
+
+public:
+ SymbianChunk(TInt handle)
+ {
+ SetHandle(handle);
+ // prevent kernel calls by caching these
+ m_base = reinterpret_cast<char*>(Base());
+ m_maxSize = MaxSize();
+ }
+
+ ~SymbianChunk()
+ {
+ Decommit(0, m_maxSize);
+ Close();
+ }
+
+ // checks if address is in chunk's virtual address space
+ bool contains(const void* address) const
+ {
+ return (static_cast<const char*>(address) >= m_base && static_cast<const char*>(address) < (m_base + m_maxSize));
+ }
+
+ char* m_base;
+ size_t m_maxSize;
+
+};
+
+// Size of the large up-front reservation
+#if defined(__WINS__)
+// Emulator has limited virtual address space
+const size_t largeReservationSize = 96*1024*1024;
+#else
+// HW has plenty of virtual addresses
+const size_t largeReservationSize = 256*1024*1024;
+#endif
+
+class PageAllocatorSymbian {
+
+public:
+ PageAllocatorSymbian();
+ ~PageAllocatorSymbian();
+
+ void* reserve(size_t);
+ void release(void*, size_t);
+ bool commit(void*, size_t);
+ bool decommit(void*, size_t);
+
+ bool contains(const void*) const;
+
+private:
+ static const size_t m_pageSize = 4096;
+ SymbianChunk* m_chunk;
+ Bitmap<largeReservationSize / m_pageSize> m_map;
+
+};
+
+} // namespace WTF
+
+#endif // PageAllocatorSymbian_h
+
--- /dev/null
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "PageBlock.h"
+
+#if OS(UNIX) && !OS(SYMBIAN)
+#include <unistd.h>
+#endif
+
+#if OS(WINDOWS)
+#include <malloc.h>
+#include <windows.h>
+#endif
+
+#if OS(SYMBIAN)
+#include <e32hal.h>
+#include <e32std.h>
+#endif
+
+namespace WTF {
+
+static size_t s_pageSize;
+
+#if OS(UNIX) && !OS(SYMBIAN)
+
+inline size_t systemPageSize()
+{
+ return getpagesize();
+}
+
+#elif OS(WINDOWS)
+
+inline size_t systemPageSize()
+{
+ static size_t size = 0;
+ SYSTEM_INFO system_info;
+ GetSystemInfo(&system_info);
+ size = system_info.dwPageSize;
+ return size;
+}
+
+#elif OS(SYMBIAN)
+
+inline size_t systemPageSize()
+{
+ static TInt page_size = 0;
+ UserHal::PageSizeInBytes(page_size);
+ return page_size;
+}
+
+#endif
+
+size_t pageSize()
+{
+ if (!s_pageSize)
+ s_pageSize = systemPageSize();
+ ASSERT(isPowerOfTwo(s_pageSize));
+ return s_pageSize;
+}
+
+} // namespace WTF
--- /dev/null
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PageBlock_h
+#define PageBlock_h
+
+namespace WTF {
+
+size_t pageSize();
+inline bool isPageAligned(void* address) { return !(reinterpret_cast<intptr_t>(address) & (pageSize() - 1)); }
+inline bool isPageAligned(size_t size) { return !(size & (pageSize() - 1)); }
+inline bool isPowerOfTwo(size_t size) { return !(size & (size - 1)); }
+
+class PageBlock {
+public:
+ PageBlock();
+ PageBlock(const PageBlock&);
+ PageBlock(void*, size_t, bool hasGuardPages);
+
+ void* base() const { return m_base; }
+ size_t size() const { return m_size; }
+
+ operator bool() const { return !!m_realBase; }
+
+ bool contains(void* containedBase, size_t containedSize)
+ {
+ return containedBase >= m_base
+ && (static_cast<char*>(containedBase) + containedSize) <= (static_cast<char*>(m_base) + m_size);
+ }
+
+private:
+ void* m_realBase;
+ void* m_base;
+ size_t m_size;
+};
+
+inline PageBlock::PageBlock()
+ : m_realBase(0)
+ , m_base(0)
+ , m_size(0)
+{
+}
+
+inline PageBlock::PageBlock(const PageBlock& other)
+ : m_realBase(other.m_realBase)
+ , m_base(other.m_base)
+ , m_size(other.m_size)
+{
+}
+
+inline PageBlock::PageBlock(void* base, size_t size, bool hasGuardPages)
+ : m_realBase(base)
+ , m_base(static_cast<char*>(base) + ((base && hasGuardPages) ? pageSize() : 0))
+ , m_size(size)
+{
+}
+
+} // namespace WTF
+
+using WTF::pageSize;
+using WTF::isPageAligned;
+using WTF::isPageAligned;
+using WTF::isPowerOfTwo;
+
+#endif // PageBlock_h
--- /dev/null
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PageReservation_h
+#define PageReservation_h
+
+#include <wtf/PageAllocation.h>
+
+namespace WTF {
+
+/*
+ PageReservation
+
+ Like PageAllocation, the PageReservation class provides a cross-platform memory
+ allocation interface, but with a set of capabilities more similar to that of
+ VirtualAlloc than posix mmap. PageReservation can be used to allocate virtual
+ memory without committing physical memory pages using PageReservation::reserve.
+ Following a call to reserve all memory in the region is in a decommited state,
+ in which the memory should not be used (accessing the memory may cause a fault).
+
+ Before using memory it must be committed by calling commit, which is passed start
+ and size values (both of which require system page size granularity). One the
+ committed memory is no longer needed 'decommit' may be called to return the
+ memory to its devommitted state. Commit should only be called on memory that is
+ currently decommitted, and decommit should only be called on memory regions that
+ are currently committed. All memory should be decommited before the reservation
+ is deallocated. Values in memory may not be retained accross a pair of calls if
+ the region of memory is decommitted and then committed again.
+
+ Memory protection should not be changed on decommitted memory, and if protection
+ is changed on memory while it is committed it should be returned to the orignal
+ protection before decommit is called.
+*/
+
+class PageReservation : private PageBlock {
+public:
+ PageReservation()
+ : m_committed(0)
+ , m_writable(false)
+ , m_executable(false)
+ {
+ }
+
+ using PageBlock::base;
+ using PageBlock::size;
+
+#ifndef __clang__
+ using PageBlock::operator bool;
+#else
+ // FIXME: This is a workaround for <rdar://problem/8876150>, wherein Clang incorrectly emits an access
+ // control warning when a client tries to use operator bool exposed above via "using PageBlock::operator bool".
+ operator bool() const { return PageBlock::operator bool(); }
+#endif
+
+ void commit(void* start, size_t size)
+ {
+ ASSERT(*this);
+ ASSERT(isPageAligned(start));
+ ASSERT(isPageAligned(size));
+ ASSERT(contains(start, size));
+
+ m_committed += size;
+ OSAllocator::commit(start, size, m_writable, m_executable);
+ }
+
+ void decommit(void* start, size_t size)
+ {
+ ASSERT(*this);
+ ASSERT(isPageAligned(start));
+ ASSERT(isPageAligned(size));
+ ASSERT(contains(start, size));
+
+ m_committed -= size;
+ OSAllocator::decommit(start, size);
+ }
+
+ size_t committed()
+ {
+ return m_committed;
+ }
+
+ static PageReservation reserve(size_t size, OSAllocator::Usage usage = OSAllocator::UnknownUsage, bool writable = true, bool executable = false)
+ {
+ ASSERT(isPageAligned(size));
+ return PageReservation(OSAllocator::reserveUncommitted(size, usage, writable, executable), size, writable, executable, false);
+ }
+
+ static PageReservation reserveWithGuardPages(size_t size, OSAllocator::Usage usage = OSAllocator::UnknownUsage, bool writable = true, bool executable = false)
+ {
+ ASSERT(isPageAligned(size));
+ return PageReservation(OSAllocator::reserveUncommitted(size + pageSize() * 2, usage, writable, executable, true), size, writable, executable, true);
+ }
+
+ void deallocate()
+ {
+ ASSERT(!m_committed);
+
+ // Clear base & size before calling release; if this is *inside* allocation
+ // then we won't be able to clear then after deallocating the memory.
+ PageReservation tmp;
+ std::swap(tmp, *this);
+
+ ASSERT(tmp);
+ ASSERT(!*this);
+
+ OSAllocator::releaseDecommitted(tmp.base(), tmp.size());
+ }
+
+private:
+ PageReservation(void* base, size_t size, bool writable, bool executable, bool hasGuardPages)
+ : PageBlock(base, size, hasGuardPages)
+ , m_committed(0)
+ , m_writable(writable)
+ , m_executable(executable)
+ {
+ }
+
+ size_t m_committed;
+ bool m_writable;
+ bool m_executable;
+};
+
+}
+
+using WTF::PageReservation;
+
+#endif // PageReservation_h
--- /dev/null
+/*
+ * Copyright (C) 2011 University of Szeged
+ * Copyright (C) 2011 Gabor Loki <loki@webkit.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ParallelJobs_h
+#define ParallelJobs_h
+
+#include "Assertions.h"
+#include "Noncopyable.h"
+#include "RefPtr.h"
+#include <wtf/Vector.h>
+
+#if ENABLE(PARALLEL_JOBS)
+
+// Usage:
+//
+// #if ENABLE(PARALLEL_JOBS)
+//
+// // Initialize parallel jobs
+// ParallelJobs<TypeOfParameter> parallelJobs(&worker [, requestedNumberOfJobs]);
+//
+// // Fill the parameter array
+// for(i = 0; i < parallelJobs.numberOfJobs(); ++i) {
+// TypeOfParameter& params = parallelJobs.parameter(i);
+// params.attr1 = localVars ...
+// ...
+// }
+//
+// // Execute parallel jobs
+// parallelJobs.execute();
+//
+// #else
+//
+// inlineFunction(args...);
+//
+// #endif // ENABLE(PARALLEL_JOBS)
+
+#if ENABLE(THREADING_GENERIC)
+#include "ParallelJobsGeneric.h"
+
+#elif ENABLE(THREADING_OPENMP)
+#include "ParallelJobsOpenMP.h"
+
+#elif ENABLE(THREADING_LIBDISPATCH)
+#include "ParallelJobsLibdispatch.h"
+
+#else
+#error "No parallel processing API for ParallelJobs"
+
+#endif
+
+namespace WTF {
+
+template<typename Type>
+class ParallelJobs {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ typedef void (*WorkerFunction)(Type*);
+
+ ParallelJobs(WorkerFunction func, int requestedJobNumber = 0) :
+ m_parallelEnvironment(reinterpret_cast<ParallelEnvironment::ThreadFunction>(func), sizeof(Type), requestedJobNumber)
+ {
+ m_parameters.grow(m_parallelEnvironment.numberOfJobs());
+ ASSERT(numberOfJobs() == m_parameters.size());
+ }
+
+ size_t numberOfJobs()
+ {
+ return m_parameters.size();
+ }
+
+ Type& parameter(size_t i)
+ {
+ return m_parameters[i];
+ }
+
+ void execute()
+ {
+ m_parallelEnvironment.execute(reinterpret_cast<unsigned char*>(m_parameters.data()));
+ }
+
+private:
+ ParallelEnvironment m_parallelEnvironment;
+ Vector<Type> m_parameters;
+};
+
+} // namespace WTF
+
+using WTF::ParallelJobs;
+
+#endif // ENABLE(PARALLEL_JOBS)
+
+#endif // ParallelJobs_h
--- /dev/null
+/*
+ * Copyright (C) 2011 University of Szeged
+ * Copyright (C) 2011 Gabor Loki <loki@webkit.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(PARALLEL_JOBS) && ENABLE(THREADING_GENERIC)
+
+#include "ParallelJobs.h"
+
+namespace WTF {
+
+Vector< RefPtr<ParallelEnvironment::ThreadPrivate> >* ParallelEnvironment::s_threadPool = 0;
+
+bool ParallelEnvironment::ThreadPrivate::tryLockFor(ParallelEnvironment* parent)
+{
+ bool locked = m_mutex.tryLock();
+
+ if (!locked)
+ return false;
+
+ if (m_parent) {
+ m_mutex.unlock();
+ return false;
+ }
+
+ if (!m_threadID)
+ m_threadID = createThread(&ParallelEnvironment::ThreadPrivate::workerThread, this, "Parallel worker");
+
+ if (m_threadID)
+ m_parent = parent;
+
+ m_mutex.unlock();
+ return m_threadID;
+}
+
+void ParallelEnvironment::ThreadPrivate::execute(ThreadFunction threadFunction, void* parameters)
+{
+ MutexLocker lock(m_mutex);
+
+ m_threadFunction = threadFunction;
+ m_parameters = parameters;
+ m_running = true;
+ m_threadCondition.signal();
+}
+
+void ParallelEnvironment::ThreadPrivate::waitForFinish()
+{
+ MutexLocker lock(m_mutex);
+
+ while (m_running)
+ m_threadCondition.wait(m_mutex);
+}
+
+void* ParallelEnvironment::ThreadPrivate::workerThread(void* threadData)
+{
+ ThreadPrivate* sharedThread = reinterpret_cast<ThreadPrivate*>(threadData);
+ MutexLocker lock(sharedThread->m_mutex);
+
+ while (sharedThread->m_threadID) {
+ if (sharedThread->m_running) {
+ (*sharedThread->m_threadFunction)(sharedThread->m_parameters);
+ sharedThread->m_running = false;
+ sharedThread->m_parent = 0;
+ sharedThread->m_threadCondition.signal();
+ }
+
+ sharedThread->m_threadCondition.wait(sharedThread->m_mutex);
+ }
+ return 0;
+}
+
+} // namespace WTF
+
+#endif // ENABLE(PARALLEL_JOBS) && ENABLE(THREADING_GENERIC)
--- /dev/null
+/*
+ * Copyright (C) 2011 University of Szeged
+ * Copyright (C) 2011 Gabor Loki <loki@webkit.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ParallelJobsGeneric_h
+#define ParallelJobsGeneric_h
+
+#if ENABLE(THREADING_GENERIC)
+
+#include <wtf/RefCounted.h>
+#include <wtf/Threading.h>
+
+namespace WTF {
+
+static const unsigned int maxParallelThreads = 2;
+
+class ParallelEnvironment {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ typedef void (*ThreadFunction)(void*);
+
+ ParallelEnvironment(ThreadFunction threadFunction, size_t sizeOfParameter, unsigned int requestedJobNumber) :
+ m_threadFunction(threadFunction),
+ m_sizeOfParameter(sizeOfParameter)
+ {
+ if (!requestedJobNumber || requestedJobNumber > maxParallelThreads)
+ requestedJobNumber = maxParallelThreads;
+
+ if (!s_threadPool)
+ s_threadPool = new Vector< RefPtr<ThreadPrivate> >();
+
+ // The main thread should be also a worker.
+ unsigned int maxNewThreads = requestedJobNumber - 1;
+
+ for (unsigned int i = 0; i < maxParallelThreads && m_threads.size() < maxNewThreads; ++i) {
+ if (s_threadPool->size() < i + 1)
+ s_threadPool->append(ThreadPrivate::create());
+
+ if ((*s_threadPool)[i]->tryLockFor(this))
+ m_threads.append((*s_threadPool)[i]);
+ }
+
+ m_numberOfJobs = m_threads.size() + 1;
+ }
+
+ int numberOfJobs()
+ {
+ return m_numberOfJobs;
+ }
+
+ void execute(unsigned char* parameters)
+ {
+ size_t i;
+ for (i = 0; i < m_threads.size(); ++i) {
+ m_threads[i]->execute(m_threadFunction, parameters);
+ parameters += m_sizeOfParameter;
+ }
+
+ // The work for the main thread
+ (*m_threadFunction)(parameters);
+
+ // Wait until all jobs are done.
+ for (i = 0; i < m_threads.size(); ++i)
+ m_threads[i]->waitForFinish();
+ }
+
+ class ThreadPrivate : public RefCounted<ThreadPrivate> {
+ public:
+ ThreadPrivate()
+ : m_threadID(0)
+ , m_running(false)
+ , m_parent(0)
+ {
+ }
+
+ bool tryLockFor(ParallelEnvironment*);
+
+ void execute(ThreadFunction, void*);
+
+ void waitForFinish();
+
+ static PassRefPtr<ThreadPrivate> create()
+ {
+ return adoptRef(new ThreadPrivate());
+ }
+
+ static void* workerThread(void*);
+
+ private:
+ ThreadIdentifier m_threadID;
+ bool m_running;
+ ParallelEnvironment* m_parent;
+
+ mutable Mutex m_mutex;
+ ThreadCondition m_threadCondition;
+
+ ThreadFunction m_threadFunction;
+ void* m_parameters;
+ };
+
+private:
+ ThreadFunction m_threadFunction;
+ size_t m_sizeOfParameter;
+ int m_numberOfJobs;
+
+ Vector< RefPtr<ThreadPrivate> > m_threads;
+ static Vector< RefPtr<ThreadPrivate> >* s_threadPool;
+};
+
+} // namespace WTF
+
+#endif // ENABLE(THREADING_GENERIC)
+
+
+#endif // ParallelJobsGeneric_h
--- /dev/null
+/*
+ * Copyright (C) 2011 University of Szeged
+ * Copyright (C) 2011 Gabor Loki <loki@webkit.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ParallelJobsLibdispatch_h
+#define ParallelJobsLibdispatch_h
+
+#if ENABLE(THREADING_LIBDISPATCH)
+
+#include <dispatch/dispatch.h>
+
+namespace WTF {
+
+static const int maxParallelThreads = 2;
+
+class ParallelEnvironment {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ typedef void (*ThreadFunction)(void*);
+
+ ParallelEnvironment(ThreadFunction threadFunction, size_t sizeOfParameter, int requestedJobNumber) :
+ m_threadFunction(threadFunction),
+ m_sizeOfParameter(sizeOfParameter)
+ {
+ if (!requestedJobNumber || requestedJobNumber > maxParallelThreads)
+ requestedJobNumber = maxParallelThreads;
+
+ ASSERT(requestedJobNumber > 0);
+
+ m_numberOfJobs = requestedJobNumber;
+ }
+
+ int numberOfJobs()
+ {
+ return m_numberOfJobs;
+ }
+
+ void execute(unsigned char* parameters)
+ {
+ // libdispatch is NOT supported inside a template
+ dispatch_queue_t parallelJobsQueue = dispatch_queue_create("ParallelJobs", 0);
+
+ for (int i = 0; i < m_numberOfJobs - 1; ++i) {
+ dispatch_async(parallelJobsQueue, ^{(*m_threadFunction)(parameters);});
+ parameters += m_sizeOfParameter;
+ }
+
+ // The work for the main thread. Wait until all jobs are done.
+ dispatch_sync(parallelJobsQueue, ^{(*m_threadFunction)(parameters);});
+ }
+
+private:
+ ThreadFunction m_threadFunction;
+ size_t m_sizeOfParameter;
+ int m_numberOfJobs;
+};
+
+} // namespace WTF
+
+#endif // ENABLE(THREADING_LIBDISPATCH)
+
+#endif // ParallelJobsLibdispatch_h
--- /dev/null
+/*
+ * Copyright (C) 2011 University of Szeged
+ * Copyright (C) 2011 Gabor Loki <loki@webkit.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ParallelJobsOpenMP_h
+#define ParallelJobsOpenMP_h
+
+#if ENABLE(THREADING_OPENMP)
+
+#include <omp.h>
+
+namespace WTF {
+
+class ParallelEnvironment {
+ WTF_MAKE_NONCOPYABLE(ParallelEnvironment);
+public:
+ typedef void (*ThreadFunction)(void*);
+
+ ParallelEnvironment(ThreadFunction threadFunction, size_t sizeOfParameter, int requestedJobNumber) :
+ m_threadFunction(threadFunction),
+ m_sizeOfParameter(sizeOfParameter)
+ {
+ int maxNumberOfThreads = omp_get_max_threads();
+
+ if (!requestedJobNumber || requestedJobNumber > maxNumberOfThreads)
+ requestedJobNumber = maxNumberOfThreads;
+
+ ASSERT(requestedJobNumber > 0);
+
+ m_numberOfJobs = requestedJobNumber;
+
+ }
+
+ int numberOfJobs()
+ {
+ return m_numberOfJobs;
+ }
+
+ void execute(unsigned char* parameters)
+ {
+ omp_set_num_threads(m_numberOfJobs);
+
+#pragma omp parallel for
+ for (int i = 0; i < m_numberOfJobs; ++i)
+ (*m_threadFunction)(parameters + i * m_sizeOfParameter);
+ }
+
+private:
+ ThreadFunction m_threadFunction;
+ size_t m_sizeOfParameter;
+ int m_numberOfJobs;
+};
+
+} // namespace WTF
+
+#endif // ENABLE(THREADING_OPENMP)
+
+#endif // ParallelJobsOpenMP_h
--- /dev/null
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WTF_PassOwnArrayPtr_h
+#define WTF_PassOwnArrayPtr_h
+
+#include "Assertions.h"
+#include "NullPtr.h"
+#include "TypeTraits.h"
+
+namespace WTF {
+
+template<typename T> class OwnArrayPtr;
+template<typename T> class PassOwnArrayPtr;
+template<typename T> PassOwnArrayPtr<T> adoptArrayPtr(T*);
+template<typename T> void deleteOwnedArrayPtr(T* ptr);
+
+template<typename T> class PassOwnArrayPtr {
+public:
+ typedef T* PtrType;
+
+ PassOwnArrayPtr() : m_ptr(0) { }
+
+#if !defined(LOOSE_PASS_OWN_PTR) || !HAVE(NULLPTR)
+ PassOwnArrayPtr(std::nullptr_t) : m_ptr(0) { }
+#endif
+
+ // It somewhat breaks the type system to allow transfer of ownership out of
+ // a const PassOwnArrayPtr. However, it makes it much easier to work with PassOwnArrayPtr
+ // temporaries, and we don't have a need to use real const PassOwnArrayPtrs anyway.
+ PassOwnArrayPtr(const PassOwnArrayPtr& o) : m_ptr(o.leakPtr()) { }
+ template<typename U> PassOwnArrayPtr(const PassOwnArrayPtr<U>& o) : m_ptr(o.leakPtr()) { }
+
+ ~PassOwnArrayPtr() { deleteOwnedArrayPtr(m_ptr); }
+
+ PtrType get() const { return m_ptr; }
+
+ void clear();
+ PtrType leakPtr() const WARN_UNUSED_RETURN;
+
+ T& operator*() const { ASSERT(m_ptr); return *m_ptr; }
+ PtrType operator->() const { ASSERT(m_ptr); return m_ptr; }
+
+ bool operator!() const { return !m_ptr; }
+
+ // This conversion operator allows implicit conversion to bool but not to other integer types.
+#if COMPILER(WINSCW)
+ operator bool() const { return m_ptr; }
+#else
+ typedef PtrType PassOwnArrayPtr::*UnspecifiedBoolType;
+ operator UnspecifiedBoolType() const { return m_ptr ? &PassOwnArrayPtr::m_ptr : 0; }
+#endif
+
+ PassOwnArrayPtr& operator=(const PassOwnArrayPtr<T>&);
+#if !defined(LOOSE_PASS_OWN_ARRAY_PTR) || !HAVE(NULLPTR)
+ PassOwnArrayPtr& operator=(std::nullptr_t) { clear(); return *this; }
+#endif
+ template<typename U> PassOwnArrayPtr& operator=(const PassOwnArrayPtr<U>&);
+
+ template<typename U> friend PassOwnArrayPtr<U> adoptArrayPtr(U*);
+
+#ifdef LOOSE_PASS_OWN_ARRAY_PTR
+ PassOwnArrayPtr(PtrType ptr) : m_ptr(ptr) { }
+ PassOwnArrayPtr& operator=(PtrType);
+#endif
+
+private:
+#ifndef LOOSE_PASS_OWN_ARRAY_PTR
+ explicit PassOwnArrayPtr(PtrType ptr) : m_ptr(ptr) { }
+#endif
+
+ mutable PtrType m_ptr;
+};
+
+template<typename T> inline void PassOwnArrayPtr<T>::clear()
+{
+ PtrType ptr = m_ptr;
+ m_ptr = 0;
+ deleteOwnedArrayPtr(ptr);
+}
+
+template<typename T> inline typename PassOwnArrayPtr<T>::PtrType PassOwnArrayPtr<T>::leakPtr() const
+{
+ PtrType ptr = m_ptr;
+ m_ptr = 0;
+ return ptr;
+}
+
+#ifdef LOOSE_PASS_OWN_ARRAY_PTR
+template<typename T> inline PassOwnArrayPtr<T>& PassOwnArrayPtr<T>::operator=(PtrType optr)
+{
+ PtrType ptr = m_ptr;
+ m_ptr = optr;
+ ASSERT(!ptr || m_ptr != ptr);
+ if (ptr)
+ deleteOwnedArrayPtr(ptr);
+ return *this;
+}
+#endif
+
+template<typename T> inline PassOwnArrayPtr<T>& PassOwnArrayPtr<T>::operator=(const PassOwnArrayPtr<T>& optr)
+{
+ PtrType ptr = m_ptr;
+ m_ptr = optr.leakPtr();
+ ASSERT(!ptr || m_ptr != ptr);
+ if (ptr)
+ deleteOwnedArrayPtr(ptr);
+ return *this;
+}
+
+template<typename T> template<typename U> inline PassOwnArrayPtr<T>& PassOwnArrayPtr<T>::operator=(const PassOwnArrayPtr<U>& optr)
+{
+ PtrType ptr = m_ptr;
+ m_ptr = optr.leakPtr();
+ ASSERT(!ptr || m_ptr != ptr);
+ if (ptr)
+ deleteOwnedArrayPtr(ptr);
+ return *this;
+}
+
+template<typename T, typename U> inline bool operator==(const PassOwnArrayPtr<T>& a, const PassOwnArrayPtr<U>& b)
+{
+ return a.get() == b.get();
+}
+
+template<typename T, typename U> inline bool operator==(const PassOwnArrayPtr<T>& a, const OwnArrayPtr<U>& b)
+{
+ return a.get() == b.get();
+}
+
+template<typename T, typename U> inline bool operator==(const OwnArrayPtr<T>& a, const PassOwnArrayPtr<U>& b)
+{
+ return a.get() == b.get();
+}
+
+template<typename T, typename U> inline bool operator==(const PassOwnArrayPtr<T>& a, U* b)
+{
+ return a.get() == b;
+}
+
+template<typename T, typename U> inline bool operator==(T* a, const PassOwnArrayPtr<U>& b)
+{
+ return a == b.get();
+}
+
+template<typename T, typename U> inline bool operator!=(const PassOwnArrayPtr<T>& a, const PassOwnArrayPtr<U>& b)
+{
+ return a.get() != b.get();
+}
+
+template<typename T, typename U> inline bool operator!=(const PassOwnArrayPtr<T>& a, const OwnArrayPtr<U>& b)
+{
+ return a.get() != b.get();
+}
+
+template<typename T, typename U> inline bool operator!=(const OwnArrayPtr<T>& a, const PassOwnArrayPtr<U>& b)
+{
+ return a.get() != b.get();
+}
+
+template<typename T, typename U> inline bool operator!=(const PassOwnArrayPtr<T>& a, U* b)
+{
+ return a.get() != b;
+}
+
+template<typename T, typename U> inline bool operator!=(T* a, const PassOwnArrayPtr<U>& b)
+{
+ return a != b.get();
+}
+
+template<typename T> inline PassOwnArrayPtr<T> adoptArrayPtr(T* ptr)
+{
+ return PassOwnArrayPtr<T>(ptr);
+}
+
+template<typename T> inline void deleteOwnedArrayPtr(T* ptr)
+{
+ typedef char known[sizeof(T) ? 1 : -1];
+ if (sizeof(known))
+ delete [] ptr;
+}
+
+template<typename T, typename U> inline PassOwnArrayPtr<T> static_pointer_cast(const PassOwnArrayPtr<U>& p)
+{
+ return adoptArrayPtr(static_cast<T*>(p.leakPtr()));
+}
+
+template<typename T, typename U> inline PassOwnArrayPtr<T> const_pointer_cast(const PassOwnArrayPtr<U>& p)
+{
+ return adoptArrayPtr(const_cast<T*>(p.leakPtr()));
+}
+
+template<typename T> inline T* getPtr(const PassOwnArrayPtr<T>& p)
+{
+ return p.get();
+}
+
+} // namespace WTF
+
+using WTF::PassOwnArrayPtr;
+using WTF::adoptArrayPtr;
+using WTF::const_pointer_cast;
+using WTF::static_pointer_cast;
+
+#endif // WTF_PassOwnArrayPtr_h
/*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2009, 2010 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
#define WTF_PassOwnPtr_h
#include "Assertions.h"
+#include "NullPtr.h"
#include "OwnPtrCommon.h"
#include "TypeTraits.h"
+#if !PLATFORM(CHROMIUM) && !PLATFORM(WIN) && !PLATFORM(MAC) && !PLATFORM(QT)
+// Remove this once we make all WebKit code compatible with stricter rules about PassOwnPtr.
+#define LOOSE_PASS_OWN_PTR
+#endif
+
namespace WTF {
// Unlike most of our smart pointers, PassOwnPtr can take either the pointer type or the pointed-to type.
- template <typename T> class OwnPtr;
+ template<typename T> class OwnPtr;
+ template<typename T> class PassOwnPtr;
+ template<typename T> PassOwnPtr<T> adoptPtr(T*);
- template <typename T> class PassOwnPtr {
+ template<typename T> class PassOwnPtr {
public:
typedef typename RemovePointer<T>::Type ValueType;
typedef ValueType* PtrType;
- PassOwnPtr(PtrType ptr = 0) : m_ptr(ptr) { }
+ PassOwnPtr() : m_ptr(0) { }
+ PassOwnPtr(std::nullptr_t) : m_ptr(0) { }
+
// It somewhat breaks the type system to allow transfer of ownership out of
// a const PassOwnPtr. However, it makes it much easier to work with PassOwnPtr
- // temporaries, and we don't really have a need to use real const PassOwnPtrs
- // anyway.
- PassOwnPtr(const PassOwnPtr& o) : m_ptr(o.release()) { }
- template <typename U> PassOwnPtr(const PassOwnPtr<U>& o) : m_ptr(o.release()) { }
+ // temporaries, and we don't have a need to use real const PassOwnPtrs anyway.
+ PassOwnPtr(const PassOwnPtr& o) : m_ptr(o.leakPtr()) { }
+ template<typename U> PassOwnPtr(const PassOwnPtr<U>& o) : m_ptr(o.leakPtr()) { }
~PassOwnPtr() { deleteOwnedPtr(m_ptr); }
PtrType get() const { return m_ptr; }
- void clear() { m_ptr = 0; }
- PtrType release() const { PtrType ptr = m_ptr; m_ptr = 0; return ptr; }
+ void clear();
+ PtrType leakPtr() const WARN_UNUSED_RETURN;
ValueType& operator*() const { ASSERT(m_ptr); return *m_ptr; }
PtrType operator->() const { ASSERT(m_ptr); return m_ptr; }
typedef PtrType PassOwnPtr::*UnspecifiedBoolType;
operator UnspecifiedBoolType() const { return m_ptr ? &PassOwnPtr::m_ptr : 0; }
- PassOwnPtr& operator=(T*);
PassOwnPtr& operator=(const PassOwnPtr<T>&);
- template <typename U> PassOwnPtr& operator=(const PassOwnPtr<U>&);
+#if !defined(LOOSE_PASS_OWN_PTR) || !HAVE(NULLPTR)
+ PassOwnPtr& operator=(std::nullptr_t) { clear(); return *this; }
+#endif
+ template<typename U> PassOwnPtr& operator=(const PassOwnPtr<U>&);
+
+ template<typename U> friend PassOwnPtr<U> adoptPtr(U*);
+
+#ifdef LOOSE_PASS_OWN_PTR
+ PassOwnPtr(PtrType ptr) : m_ptr(ptr) { }
+ PassOwnPtr& operator=(PtrType);
+#endif
private:
+#ifndef LOOSE_PASS_OWN_PTR
+ explicit PassOwnPtr(PtrType ptr) : m_ptr(ptr) { }
+#endif
+
+ // We should never have two OwnPtrs for the same underlying object (otherwise we'll get
+ // double-destruction), so these equality operators should never be needed.
+ template<typename U> bool operator==(const PassOwnPtr<U>&) { COMPILE_ASSERT(!sizeof(U*), OwnPtrs_should_never_be_equal); return false; }
+ template<typename U> bool operator!=(const PassOwnPtr<U>&) { COMPILE_ASSERT(!sizeof(U*), OwnPtrs_should_never_be_equal); return false; }
+ template<typename U> bool operator==(const OwnPtr<U>&) { COMPILE_ASSERT(!sizeof(U*), OwnPtrs_should_never_be_equal); return false; }
+ template<typename U> bool operator!=(const OwnPtr<U>&) { COMPILE_ASSERT(!sizeof(U*), OwnPtrs_should_never_be_equal); return false; }
+
mutable PtrType m_ptr;
};
- template <typename T> inline PassOwnPtr<T>& PassOwnPtr<T>::operator=(T* optr)
+ template<typename T> inline void PassOwnPtr<T>::clear()
{
- T* ptr = m_ptr;
+ PtrType ptr = m_ptr;
+ m_ptr = 0;
+ deleteOwnedPtr(ptr);
+ }
+
+ template<typename T> inline typename PassOwnPtr<T>::PtrType PassOwnPtr<T>::leakPtr() const
+ {
+ PtrType ptr = m_ptr;
+ m_ptr = 0;
+ return ptr;
+ }
+
+#ifdef LOOSE_PASS_OWN_PTR
+ template<typename T> inline PassOwnPtr<T>& PassOwnPtr<T>::operator=(PtrType optr)
+ {
+ PtrType ptr = m_ptr;
m_ptr = optr;
ASSERT(!ptr || m_ptr != ptr);
if (ptr)
deleteOwnedPtr(ptr);
return *this;
}
+#endif
- template <typename T> inline PassOwnPtr<T>& PassOwnPtr<T>::operator=(const PassOwnPtr<T>& optr)
+ template<typename T> inline PassOwnPtr<T>& PassOwnPtr<T>::operator=(const PassOwnPtr<T>& optr)
{
- T* ptr = m_ptr;
- m_ptr = optr.release();
+ PtrType ptr = m_ptr;
+ m_ptr = optr.leakPtr();
ASSERT(!ptr || m_ptr != ptr);
if (ptr)
deleteOwnedPtr(ptr);
return *this;
}
- template <typename T> template <typename U> inline PassOwnPtr<T>& PassOwnPtr<T>::operator=(const PassOwnPtr<U>& optr)
+ template<typename T> template<typename U> inline PassOwnPtr<T>& PassOwnPtr<T>::operator=(const PassOwnPtr<U>& optr)
{
- T* ptr = m_ptr;
- m_ptr = optr.release();
+ PtrType ptr = m_ptr;
+ m_ptr = optr.leakPtr();
ASSERT(!ptr || m_ptr != ptr);
if (ptr)
deleteOwnedPtr(ptr);
return *this;
}
- template <typename T, typename U> inline bool operator==(const PassOwnPtr<T>& a, const PassOwnPtr<U>& b)
+ template<typename T, typename U> inline bool operator==(const PassOwnPtr<T>& a, const PassOwnPtr<U>& b)
{
return a.get() == b.get();
}
- template <typename T, typename U> inline bool operator==(const PassOwnPtr<T>& a, const OwnPtr<U>& b)
+ template<typename T, typename U> inline bool operator==(const PassOwnPtr<T>& a, const OwnPtr<U>& b)
{
return a.get() == b.get();
}
- template <typename T, typename U> inline bool operator==(const OwnPtr<T>& a, const PassOwnPtr<U>& b)
+ template<typename T, typename U> inline bool operator==(const OwnPtr<T>& a, const PassOwnPtr<U>& b)
{
return a.get() == b.get();
}
- template <typename T, typename U> inline bool operator==(const PassOwnPtr<T>& a, U* b)
+ template<typename T, typename U> inline bool operator==(const PassOwnPtr<T>& a, U* b)
{
return a.get() == b;
}
- template <typename T, typename U> inline bool operator==(T* a, const PassOwnPtr<U>& b)
+ template<typename T, typename U> inline bool operator==(T* a, const PassOwnPtr<U>& b)
{
return a == b.get();
}
- template <typename T, typename U> inline bool operator!=(const PassOwnPtr<T>& a, const PassOwnPtr<U>& b)
+ template<typename T, typename U> inline bool operator!=(const PassOwnPtr<T>& a, const PassOwnPtr<U>& b)
{
return a.get() != b.get();
}
- template <typename T, typename U> inline bool operator!=(const PassOwnPtr<T>& a, const OwnPtr<U>& b)
+ template<typename T, typename U> inline bool operator!=(const PassOwnPtr<T>& a, const OwnPtr<U>& b)
{
return a.get() != b.get();
}
- template <typename T, typename U> inline bool operator!=(const OwnPtr<T>& a, const PassOwnPtr<U>& b)
+ template<typename T, typename U> inline bool operator!=(const OwnPtr<T>& a, const PassOwnPtr<U>& b)
{
return a.get() != b.get();
}
- template <typename T, typename U> inline bool operator!=(const PassOwnPtr<T>& a, U* b)
+ template<typename T, typename U> inline bool operator!=(const PassOwnPtr<T>& a, U* b)
{
return a.get() != b;
}
- template <typename T, typename U> inline bool operator!=(T* a, const PassOwnPtr<U>& b)
+ template<typename T, typename U> inline bool operator!=(T* a, const PassOwnPtr<U>& b)
{
return a != b.get();
}
- template <typename T, typename U> inline PassOwnPtr<T> static_pointer_cast(const PassOwnPtr<U>& p)
+ template<typename T> inline PassOwnPtr<T> adoptPtr(T* ptr)
+ {
+ return PassOwnPtr<T>(ptr);
+ }
+
+ template<typename T, typename U> inline PassOwnPtr<T> static_pointer_cast(const PassOwnPtr<U>& p)
{
- return PassOwnPtr<T>(static_cast<T*>(p.release()));
+ return adoptPtr(static_cast<T*>(p.leakPtr()));
}
- template <typename T, typename U> inline PassOwnPtr<T> const_pointer_cast(const PassOwnPtr<U>& p)
+ template<typename T, typename U> inline PassOwnPtr<T> const_pointer_cast(const PassOwnPtr<U>& p)
{
- return PassOwnPtr<T>(const_cast<T*>(p.release()));
+ return adoptPtr(const_cast<T*>(p.leakPtr()));
}
- template <typename T> inline T* getPtr(const PassOwnPtr<T>& p)
+ template<typename T> inline T* getPtr(const PassOwnPtr<T>& p)
{
return p.get();
}
} // namespace WTF
using WTF::PassOwnPtr;
+using WTF::adoptPtr;
using WTF::const_pointer_cast;
using WTF::static_pointer_cast;
/*
- * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
#define WTF_PassRefPtr_h
#include "AlwaysInline.h"
+#include "NullPtr.h"
namespace WTF {
template<typename T> class RefPtr;
template<typename T> class PassRefPtr;
- template <typename T> PassRefPtr<T> adoptRef(T*);
+ template<typename T> PassRefPtr<T> adoptRef(T*);
+ inline void adopted(const void*) { }
- // Remove inline for WINSCW compiler to prevent the compiler agressively resolving
- // T::ref() and T::deref(), which will fail compiling when PassRefPtr<T> is used as
- // a class member or function arguments before T is defined.
-
- // [Qt]r57240 broke Qt build (might be a gcc bug)
- // FIXME! See: https://bugs.webkit.org/show_bug.cgi?id=37253
- template<typename T>
#if !COMPILER(WINSCW)
#if !PLATFORM(QT)
- ALWAYS_INLINE
+ #define REF_DEREF_INLINE ALWAYS_INLINE
#else
- inline
+ // Using ALWAYS_INLINE broke the Qt build. This may be a GCC bug.
+ // See https://bugs.webkit.org/show_bug.cgi?id=37253 for details.
+ #define REF_DEREF_INLINE inline
#endif
+#else
+ // No inlining for WINSCW compiler to prevent the compiler agressively resolving
+ // T::ref() and T::deref(), which will fail compiling when PassRefPtr<T> is used as
+ // a class member or function arguments before T is defined.
+ #define REF_DEREF_INLINE
#endif
- void refIfNotNull(T* ptr)
+
+ template<typename T> REF_DEREF_INLINE void refIfNotNull(T* ptr)
{
if (LIKELY(ptr != 0))
ptr->ref();
}
- // [Qt]r57240 broke Qt build (might be a gcc bug)
- // FIXME! See: https://bugs.webkit.org/show_bug.cgi?id=37253
- template<typename T>
-#if !COMPILER(WINSCW)
-#if !PLATFORM(QT)
- ALWAYS_INLINE
-#else
- inline
-#endif
-#endif
- void derefIfNotNull(T* ptr)
+ template<typename T> REF_DEREF_INLINE void derefIfNotNull(T* ptr)
{
if (LIKELY(ptr != 0))
ptr->deref();
}
+ #undef REF_DEREF_INLINE
+
template<typename T> class PassRefPtr {
public:
- PassRefPtr() : m_ptr(0) {}
+ PassRefPtr() : m_ptr(0) { }
PassRefPtr(T* ptr) : m_ptr(ptr) { refIfNotNull(ptr); }
// It somewhat breaks the type system to allow transfer of ownership out of
// a const PassRefPtr. However, it makes it much easier to work with PassRefPtr
- // temporaries, and we don't really have a need to use real const PassRefPtrs
- // anyway.
- PassRefPtr(const PassRefPtr& o) : m_ptr(o.releaseRef()) {}
- template <typename U> PassRefPtr(const PassRefPtr<U>& o) : m_ptr(o.releaseRef()) { }
+ // temporaries, and we don't have a need to use real const PassRefPtrs anyway.
+ PassRefPtr(const PassRefPtr& o) : m_ptr(o.leakRef()) { }
+ template<typename U> PassRefPtr(const PassRefPtr<U>& o) : m_ptr(o.leakRef()) { }
ALWAYS_INLINE ~PassRefPtr() { derefIfNotNull(m_ptr); }
- template <class U>
- PassRefPtr(const RefPtr<U>& o) : m_ptr(o.get()) { T* ptr = m_ptr; refIfNotNull(ptr); }
+ template<typename U> PassRefPtr(const RefPtr<U>&);
T* get() const { return m_ptr; }
- void clear() { T* ptr = m_ptr; derefIfNotNull(ptr); m_ptr = 0; }
- T* releaseRef() const { T* tmp = m_ptr; m_ptr = 0; return tmp; }
+ void clear();
+ T* leakRef() const WARN_UNUSED_RETURN;
T& operator*() const { return *m_ptr; }
T* operator->() const { return m_ptr; }
-
+
bool operator!() const { return !m_ptr; }
// This conversion operator allows implicit conversion to bool but not to other integer types.
PassRefPtr& operator=(T*);
PassRefPtr& operator=(const PassRefPtr&);
- template <typename U> PassRefPtr& operator=(const PassRefPtr<U>&);
- template <typename U> PassRefPtr& operator=(const RefPtr<U>&);
+#if !HAVE(NULLPTR)
+ PassRefPtr& operator=(std::nullptr_t) { clear(); return *this; }
+#endif
+ template<typename U> PassRefPtr& operator=(const PassRefPtr<U>&);
+ template<typename U> PassRefPtr& operator=(const RefPtr<U>&);
friend PassRefPtr adoptRef<T>(T*);
+
+ // FIXME: Remove releaseRef once we change all callers to call leakRef instead.
+ T* releaseRef() const WARN_UNUSED_RETURN { return leakRef(); }
+
private:
// adopting constructor
- PassRefPtr(T* ptr, bool) : m_ptr(ptr) {}
+ PassRefPtr(T* ptr, bool) : m_ptr(ptr) { }
+
mutable T* m_ptr;
};
// NonNullPassRefPtr: Optimized for passing non-null pointers. A NonNullPassRefPtr
- // begins life non-null, and can only become null through a call to releaseRef()
+ // begins life non-null, and can only become null through a call to leakRef()
// or clear().
// FIXME: NonNullPassRefPtr could just inherit from PassRefPtr. However,
// if we use inheritance, GCC's optimizer fails to realize that destruction
// of a released NonNullPassRefPtr is a no-op. So, for now, just copy the
// most important code from PassRefPtr.
- template <typename T> class NonNullPassRefPtr {
+ template<typename T> class NonNullPassRefPtr {
public:
NonNullPassRefPtr(T* ptr)
: m_ptr(ptr)
m_ptr->ref();
}
- template <class U> NonNullPassRefPtr(const RefPtr<U>& o)
+ template<typename U> NonNullPassRefPtr(const RefPtr<U>& o)
: m_ptr(o.get())
{
ASSERT(m_ptr);
}
NonNullPassRefPtr(const NonNullPassRefPtr& o)
- : m_ptr(o.releaseRef())
+ : m_ptr(o.leakRef())
{
ASSERT(m_ptr);
}
- template <class U> NonNullPassRefPtr(const NonNullPassRefPtr<U>& o)
- : m_ptr(o.releaseRef())
+ template<typename U> NonNullPassRefPtr(const NonNullPassRefPtr<U>& o)
+ : m_ptr(o.leakRef())
{
ASSERT(m_ptr);
}
- template <class U> NonNullPassRefPtr(const PassRefPtr<U>& o)
- : m_ptr(o.releaseRef())
+ template<typename U> NonNullPassRefPtr(const PassRefPtr<U>& o)
+ : m_ptr(o.leakRef())
{
ASSERT(m_ptr);
}
T* get() const { return m_ptr; }
- void clear() { derefIfNotNull(m_ptr); m_ptr = 0; }
- T* releaseRef() const { T* tmp = m_ptr; m_ptr = 0; return tmp; }
+ void clear();
+ T* leakRef() const WARN_UNUSED_RETURN { T* tmp = m_ptr; m_ptr = 0; return tmp; }
T& operator*() const { return *m_ptr; }
T* operator->() const { return m_ptr; }
+ // FIXME: Remove releaseRef once we change all callers to call leakRef instead.
+ T* releaseRef() const WARN_UNUSED_RETURN { return leakRef(); }
+
private:
mutable T* m_ptr;
};
- template <typename T> template <typename U> inline PassRefPtr<T>& PassRefPtr<T>::operator=(const RefPtr<U>& o)
+ template<typename T> template<typename U> inline PassRefPtr<T>::PassRefPtr(const RefPtr<U>& o)
+ : m_ptr(o.get())
+ {
+ T* ptr = m_ptr;
+ refIfNotNull(ptr);
+ }
+
+ template<typename T> inline void PassRefPtr<T>::clear()
+ {
+ T* ptr = m_ptr;
+ m_ptr = 0;
+ derefIfNotNull(ptr);
+ }
+
+ template<typename T> inline T* PassRefPtr<T>::leakRef() const
+ {
+ T* ptr = m_ptr;
+ m_ptr = 0;
+ return ptr;
+ }
+
+ template<typename T> template<typename U> inline PassRefPtr<T>& PassRefPtr<T>::operator=(const RefPtr<U>& o)
{
T* optr = o.get();
refIfNotNull(optr);
return *this;
}
- template <typename T> inline PassRefPtr<T>& PassRefPtr<T>::operator=(T* optr)
+ template<typename T> inline PassRefPtr<T>& PassRefPtr<T>::operator=(T* optr)
{
refIfNotNull(optr);
T* ptr = m_ptr;
return *this;
}
- template <typename T> inline PassRefPtr<T>& PassRefPtr<T>::operator=(const PassRefPtr<T>& ref)
+ template<typename T> inline PassRefPtr<T>& PassRefPtr<T>::operator=(const PassRefPtr<T>& ref)
{
T* ptr = m_ptr;
- m_ptr = ref.releaseRef();
+ m_ptr = ref.leakRef();
derefIfNotNull(ptr);
return *this;
}
- template <typename T> template <typename U> inline PassRefPtr<T>& PassRefPtr<T>::operator=(const PassRefPtr<U>& ref)
+ template<typename T> template<typename U> inline PassRefPtr<T>& PassRefPtr<T>::operator=(const PassRefPtr<U>& ref)
{
T* ptr = m_ptr;
- m_ptr = ref.releaseRef();
+ m_ptr = ref.leakRef();
derefIfNotNull(ptr);
return *this;
}
- template <typename T, typename U> inline bool operator==(const PassRefPtr<T>& a, const PassRefPtr<U>& b)
+ template<typename T, typename U> inline bool operator==(const PassRefPtr<T>& a, const PassRefPtr<U>& b)
{
return a.get() == b.get();
}
- template <typename T, typename U> inline bool operator==(const PassRefPtr<T>& a, const RefPtr<U>& b)
+ template<typename T, typename U> inline bool operator==(const PassRefPtr<T>& a, const RefPtr<U>& b)
{
return a.get() == b.get();
}
- template <typename T, typename U> inline bool operator==(const RefPtr<T>& a, const PassRefPtr<U>& b)
+ template<typename T, typename U> inline bool operator==(const RefPtr<T>& a, const PassRefPtr<U>& b)
{
return a.get() == b.get();
}
- template <typename T, typename U> inline bool operator==(const PassRefPtr<T>& a, U* b)
+ template<typename T, typename U> inline bool operator==(const PassRefPtr<T>& a, U* b)
{
return a.get() == b;
}
- template <typename T, typename U> inline bool operator==(T* a, const PassRefPtr<U>& b)
+ template<typename T, typename U> inline bool operator==(T* a, const PassRefPtr<U>& b)
{
return a == b.get();
}
- template <typename T, typename U> inline bool operator!=(const PassRefPtr<T>& a, const PassRefPtr<U>& b)
+ template<typename T, typename U> inline bool operator!=(const PassRefPtr<T>& a, const PassRefPtr<U>& b)
{
return a.get() != b.get();
}
- template <typename T, typename U> inline bool operator!=(const PassRefPtr<T>& a, const RefPtr<U>& b)
+ template<typename T, typename U> inline bool operator!=(const PassRefPtr<T>& a, const RefPtr<U>& b)
{
return a.get() != b.get();
}
- template <typename T, typename U> inline bool operator!=(const RefPtr<T>& a, const PassRefPtr<U>& b)
+ template<typename T, typename U> inline bool operator!=(const RefPtr<T>& a, const PassRefPtr<U>& b)
{
return a.get() != b.get();
}
- template <typename T, typename U> inline bool operator!=(const PassRefPtr<T>& a, U* b)
+ template<typename T, typename U> inline bool operator!=(const PassRefPtr<T>& a, U* b)
{
return a.get() != b;
}
- template <typename T, typename U> inline bool operator!=(T* a, const PassRefPtr<U>& b)
+ template<typename T, typename U> inline bool operator!=(T* a, const PassRefPtr<U>& b)
{
return a != b.get();
}
- template <typename T> inline PassRefPtr<T> adoptRef(T* p)
+ template<typename T> inline PassRefPtr<T> adoptRef(T* p)
{
+ adopted(p);
return PassRefPtr<T>(p, true);
}
- template <typename T, typename U> inline PassRefPtr<T> static_pointer_cast(const PassRefPtr<U>& p)
+ template<typename T, typename U> inline PassRefPtr<T> static_pointer_cast(const PassRefPtr<U>& p)
{
- return adoptRef(static_cast<T*>(p.releaseRef()));
+ return adoptRef(static_cast<T*>(p.leakRef()));
}
- template <typename T, typename U> inline PassRefPtr<T> const_pointer_cast(const PassRefPtr<U>& p)
+ template<typename T, typename U> inline PassRefPtr<T> const_pointer_cast(const PassRefPtr<U>& p)
{
- return adoptRef(const_cast<T*>(p.releaseRef()));
+ return adoptRef(const_cast<T*>(p.leakRef()));
}
- template <typename T> inline T* getPtr(const PassRefPtr<T>& p)
+ template<typename T> inline T* getPtr(const PassRefPtr<T>& p)
{
return p.get();
}
+ template<typename T> inline void NonNullPassRefPtr<T>::clear()
+ {
+ T* ptr = m_ptr;
+ m_ptr = 0;
+ derefIfNotNull(ptr);
+ }
+
} // namespace WTF
using WTF::PassRefPtr;
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WTF_PassTraits_h
+#define WTF_PassTraits_h
+
+#include "OwnPtr.h"
+#include "RefPtr.h"
+
+// The PassTraits template exists to help optimize (or make possible) use
+// of WTF data structures with WTF smart pointers that have a Pass
+// variant for transfer of ownership
+
+namespace WTF {
+
+template<typename T> struct PassTraits {
+ typedef T Type;
+ typedef T PassType;
+ static PassType transfer(Type& value) { return value; }
+};
+
+template<typename T> struct PassTraits<OwnPtr<T> > {
+ typedef OwnPtr<T> Type;
+ typedef PassOwnPtr<T> PassType;
+ static PassType transfer(Type& value) { return value.release(); }
+};
+
+template<typename T> struct PassTraits<RefPtr<T> > {
+ typedef RefPtr<T> Type;
+ typedef PassRefPtr<T> PassType;
+ static PassType transfer(Type& value) { return value.release(); }
+};
+
+} // namespace WTF
+
+using WTF::PassTraits;
+
+#endif // WTF_PassTraits_h
/*
* Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
* Copyright (C) 2007-2009 Torch Mobile, Inc.
+ * Copyright (C) Research In Motion Limited 2010. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
#endif
/* COMPILER(RVCT) - ARM RealView Compilation Tools */
+/* COMPILER(RVCT4_OR_GREATER) - ARM RealView Compilation Tools 4.0 or greater */
#if defined(__CC_ARM) || defined(__ARMCC__)
#define WTF_COMPILER_RVCT 1
+#define RVCT_VERSION_AT_LEAST(major, minor, patch, build) (__ARMCC_VERSION >= (major * 100000 + minor * 10000 + patch * 1000 + build))
+#else
+/* Define this for !RVCT compilers, just so we can write things like RVCT_VERSION_AT_LEAST(3, 0, 0, 0). */
+#define RVCT_VERSION_AT_LEAST(major, minor, patch, build) 0
+#endif
+
+/* COMPILER(GCCE) - GNU Compiler Collection for Embedded */
+#if defined(__GCCE__)
+#define WTF_COMPILER_GCCE 1
+#define GCCE_VERSION (__GCCE__ * 10000 + __GCCE_MINOR__ * 100 + __GCCE_PATCHLEVEL__)
+#define GCCE_VERSION_AT_LEAST(major, minor, patch) (GCCE_VERSION >= (major * 10000 + minor * 100 + patch))
#endif
/* COMPILER(GCC) - GNU Compiler Collection */
#if defined(__GNUC__) && !COMPILER(RVCT)
#define WTF_COMPILER_GCC 1
#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
+#define GCC_VERSION_AT_LEAST(major, minor, patch) (GCC_VERSION >= (major * 10000 + minor * 100 + patch))
+#else
+/* Define this for !GCC compilers, just so we can write things like GCC_VERSION_AT_LEAST(4, 1, 0). */
+#define GCC_VERSION_AT_LEAST(major, minor, patch) 0
#endif
/* COMPILER(MINGW) - MinGW GCC */
#undef _WIN32
#endif
+/* COMPILER(INTEL) - Intel C++ Compiler */
+#if defined(__INTEL_COMPILER)
+#define WTF_COMPILER_INTEL 1
+#endif
+/* COMPILER(SUNCC) */
+#if defined(__SUNPRO_CC) || defined(__SUNPRO_C)
+#define WTF_COMPILER_SUNCC 1
+#endif
/* ==== CPU() - the target CPU architecture ==== */
/* CPU(MIPS) - MIPS 32-bit */
/* Note: Only O32 ABI is tested, so we enable it for O32 ABI for now. */
-#if (defined(mips) || defined(__mips__)) \
+#if (defined(mips) || defined(__mips__) || defined(MIPS) || defined(_MIPS_)) \
&& defined(_ABIO32)
#define WTF_CPU_MIPS 1
#if defined(__MIPSEB__)
#define WTF_MIPS_ARCH_REV __mips_isa_rev
#define WTF_MIPS_ISA_REV(v) (defined WTF_MIPS_ARCH_REV && WTF_MIPS_ARCH_REV == v)
#define WTF_MIPS_DOUBLE_FLOAT (defined __mips_hard_float && !defined __mips_single_float)
+#define WTF_MIPS_FP64 (defined __mips_fpr && __mips_fpr == 64)
+/* MIPS requires allocators to use aligned memory */
+#define WTF_USE_ARENA_ALLOC_ALIGNMENT_INTEGER 1
#endif /* MIPS */
/* CPU(PPC) - PowerPC 32-bit */
#define WTF_CPU_SPARC 1
#endif
+/* CPU(S390X) - S390 64-bit */
+#if defined(__s390x__)
+#define WTF_CPU_S390X 1
+#define WTF_CPU_BIG_ENDIAN 1
+#endif
+
+/* CPU(S390) - S390 32-bit */
+#if defined(__s390__)
+#define WTF_CPU_S390 1
+#define WTF_CPU_BIG_ENDIAN 1
+#endif
+
/* CPU(X86) - i386 / x86 32-bit */
#if defined(__i386__) \
|| defined(i386) \
|| defined(_ARM_)
#define WTF_CPU_ARM 1
-#if defined(__ARMEB__)
+#if defined(__ARMEB__) || (COMPILER(RVCT) && defined(__BIG_ENDIAN))
#define WTF_CPU_BIG_ENDIAN 1
#elif !defined(__ARM_EABI__) \
#elif defined(__ARM_ARCH_5__) \
|| defined(__ARM_ARCH_5T__) \
- || defined(__ARM_ARCH_5E__) \
- || defined(__ARM_ARCH_5TE__) \
- || defined(__ARM_ARCH_5TEJ__) \
|| defined(__MARM_ARMV5__)
#define WTF_ARM_ARCH_VERSION 5
+#elif defined(__ARM_ARCH_5E__) \
+ || defined(__ARM_ARCH_5TE__) \
+ || defined(__ARM_ARCH_5TEJ__)
+#define WTF_ARM_ARCH_VERSION 5
+/*ARMv5TE requires allocators to use aligned memory*/
+#define WTF_USE_ARENA_ALLOC_ALIGNMENT_INTEGER 1
+
#elif defined(__ARM_ARCH_6__) \
|| defined(__ARM_ARCH_6J__) \
|| defined(__ARM_ARCH_6K__) \
#define WTF_ARM_ARCH_VERSION 6
#elif defined(__ARM_ARCH_7A__) \
- || defined(__ARM_ARCH_7R__)
+ || defined(__ARM_ARCH_7F__) \
+ || defined(__ARM_ARCH_7R__) \
+ || defined(__ARM_ARCH_7S__)
#define WTF_ARM_ARCH_VERSION 7
/* RVCT sets _TARGET_ARCH_ARM */
#elif defined(__TARGET_ARCH_ARM)
#define WTF_ARM_ARCH_VERSION __TARGET_ARCH_ARM
+#if defined(__TARGET_ARCH_5E) \
+ || defined(__TARGET_ARCH_5TE) \
+ || defined(__TARGET_ARCH_5TEJ)
+/*ARMv5TE requires allocators to use aligned memory*/
+#define WTF_USE_ARENA_ALLOC_ALIGNMENT_INTEGER 1
+#endif
+
#else
#define WTF_ARM_ARCH_VERSION 0
#elif defined(__ARM_ARCH_6T2__) \
|| defined(__ARM_ARCH_7__) \
|| defined(__ARM_ARCH_7A__) \
+ || defined(__ARM_ARCH_7F__) \
|| defined(__ARM_ARCH_7R__) \
- || defined(__ARM_ARCH_7M__)
+ || defined(__ARM_ARCH_7M__) \
+ || defined(__ARM_ARCH_7S__)
#define WTF_THUMB_ARCH_VERSION 4
/* RVCT sets __TARGET_ARCH_THUMB */
# error "Cannot use both of WTF_CPU_ARM_TRADITIONAL and WTF_CPU_ARM_THUMB2 platforms"
#endif /* !defined(WTF_CPU_ARM_TRADITIONAL) && !defined(WTF_CPU_ARM_THUMB2) */
-#endif /* ARM */
+#if defined(__ARM_NEON__) && !defined(WTF_CPU_ARM_NEON)
+#define WTF_CPU_ARM_NEON 1
+#endif
+#endif /* ARM */
+#if CPU(ARM) || CPU(MIPS)
+#define WTF_CPU_NEEDS_ALIGNED_ACCESS 1
+#endif
/* ==== OS() - underlying operating system; only to be used for mandated low-level services like
virtual memory, not to choose a GUI toolkit ==== */
/* FIXME: BUILDING_ON_.., and TARGETING... macros should be folded into the OS() system */
#include <AvailabilityMacros.h>
-#if !defined(MAC_OS_X_VERSION_10_5) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5
-#define BUILDING_ON_TIGER 1
-#elif !defined(MAC_OS_X_VERSION_10_6) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
+#if !defined(MAC_OS_X_VERSION_10_6) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
#define BUILDING_ON_LEOPARD 1
#elif !defined(MAC_OS_X_VERSION_10_7) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
#define BUILDING_ON_SNOW_LEOPARD 1
#endif
-#if !defined(MAC_OS_X_VERSION_10_5) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
-#define TARGETING_TIGER 1
-#elif !defined(MAC_OS_X_VERSION_10_6) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6
+#if !defined(MAC_OS_X_VERSION_10_6) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6
#define TARGETING_LEOPARD 1
#elif !defined(MAC_OS_X_VERSION_10_7) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7
#define TARGETING_SNOW_LEOPARD 1
#endif
-/* OS(IPHONE_OS) - iPhone OS */
-/* OS(MAC_OS_X) - Mac OS X (not including iPhone OS) */
+/* OS(IOS) - iOS */
+/* OS(MAC_OS_X) - Mac OS X (not including iOS) */
#if OS(DARWIN) && ((defined(TARGET_OS_EMBEDDED) && TARGET_OS_EMBEDDED) \
|| (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) \
|| (defined(TARGET_IPHONE_SIMULATOR) && TARGET_IPHONE_SIMULATOR))
-#define WTF_OS_IPHONE_OS 1
+#define WTF_OS_IOS 1
#elif OS(DARWIN) && defined(TARGET_OS_MAC) && TARGET_OS_MAC
#define WTF_OS_MAC_OS_X 1
#endif
/* OS(FREEBSD) - FreeBSD */
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) || defined(__DragonFly__)
#define WTF_OS_FREEBSD 1
#endif
/* OS(NETBSD) - NetBSD */
#if defined(__NetBSD__)
-#define WTF_PLATFORM_NETBSD 1
+#define WTF_OS_NETBSD 1
#endif
/* OS(OPENBSD) - OpenBSD */
#define WTF_PLATFORM_WIN 1
#endif
-/* PLATFORM(IPHONE) */
+/* PLATFORM(IOS) */
/* FIXME: this is sometimes used as an OS switch and sometimes for higher-level things */
#if (defined(TARGET_OS_EMBEDDED) && TARGET_OS_EMBEDDED) || (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)
-#define WTF_PLATFORM_IPHONE 1
+#define WTF_PLATFORM_IOS 1
#endif
-/* PLATFORM(IPHONE_SIMULATOR) */
+/* PLATFORM(IOS_SIMULATOR) */
#if defined(TARGET_IPHONE_SIMULATOR) && TARGET_IPHONE_SIMULATOR
-#define WTF_PLATFORM_IPHONE 1
-#define WTF_PLATFORM_IPHONE_SIMULATOR 1
+#define WTF_PLATFORM_IOS 1
+#define WTF_PLATFORM_IOS_SIMULATOR 1
#else
-#define WTF_PLATFORM_IPHONE_SIMULATOR 0
+#define WTF_PLATFORM_IOS_SIMULATOR 0
#endif
-#if !defined(WTF_PLATFORM_IPHONE)
-#define WTF_PLATFORM_IPHONE 0
-#endif
-
-/* PLATFORM(ANDROID) */
-/* FIXME: this is sometimes used as an OS() switch, and other times to drive
- policy choices */
-#if defined(ANDROID)
-#define WTF_PLATFORM_ANDROID 1
+#if !defined(WTF_PLATFORM_IOS)
+#define WTF_PLATFORM_IOS 0
#endif
/* Graphics engines */
-/* PLATFORM(CG) and PLATFORM(CI) */
-#define WTF_PLATFORM_CG 1
+/* USE(CG) and PLATFORM(CI) */
+#define WTF_USE_CG 1
+#if PLATFORM(MAC) || PLATFORM(IOS) || (PLATFORM(WIN) && USE(CG))
+#define WTF_USE_CA 1
+#endif
-/* PLATFORM(SKIA) for Win/Linux, CG/CI for Mac */
+/* USE(SKIA) for Win/Linux, CG for Mac */
#if PLATFORM(CHROMIUM)
-#define ENABLE_HISTORY_ALWAYS_ASYNC 1
#if OS(DARWIN)
-#define WTF_PLATFORM_CG 1
-#define WTF_PLATFORM_CI 1
+#define WTF_USE_CG 1
#define WTF_USE_ATSUI 1
#define WTF_USE_CORE_TEXT 1
+#define WTF_USE_ICCJPEG 1
#else
-#define WTF_PLATFORM_SKIA 1
+#define WTF_USE_SKIA 1
+#define WTF_USE_CHROMIUM_NET 1
#endif
#endif
+#if PLATFORM(BREWMP)
+#define WTF_USE_SKIA 1
+#endif
+
#if PLATFORM(GTK)
-#define WTF_PLATFORM_CAIRO 1
+#define WTF_USE_CAIRO 1
#endif
-/* OS(WINCE) && PLATFORM(QT)
- We can not determine the endianess at compile time. For
- Qt for Windows CE the endianess is specified in the
- device specific makespec
-*/
-#if OS(WINCE) && PLATFORM(QT)
-# include <QtGlobal>
-# undef WTF_CPU_BIG_ENDIAN
-# undef WTF_CPU_MIDDLE_ENDIAN
-# if Q_BYTE_ORDER == Q_BIG_ENDIAN
-# define WTF_CPU_BIG_ENDIAN 1
-# endif
+#if OS(WINCE)
+#include <ce_time.h>
+#define WTF_USE_MERSENNE_TWISTER_19937 1
+#endif
-# include <ce_time.h>
+#if PLATFORM(QT) && OS(UNIX) && !OS(SYMBIAN) && !OS(DARWIN)
+#define WTF_USE_PTHREAD_BASED_QT 1
#endif
-#if (PLATFORM(IPHONE) || PLATFORM(MAC) || PLATFORM(WIN) || (PLATFORM(QT) && OS(DARWIN) && !ENABLE(SINGLE_THREADED))) && !defined(ENABLE_JSC_MULTIPLE_THREADS)
+#if (PLATFORM(GTK) || PLATFORM(IOS) || PLATFORM(MAC) || PLATFORM(WIN) || (PLATFORM(QT) && (OS(DARWIN) || USE(PTHREAD_BASED_QT)) && !ENABLE(SINGLE_THREADED))) && !defined(ENABLE_JSC_MULTIPLE_THREADS)
#define ENABLE_JSC_MULTIPLE_THREADS 1
#endif
+#if ENABLE(JSC_MULTIPLE_THREADS)
+#define ENABLE_WTF_MULTIPLE_THREADS 1
+#endif
+
/* On Windows, use QueryPerformanceCounter by default */
#if OS(WINDOWS)
#define WTF_USE_QUERY_PERFORMANCE_COUNTER 1
#endif
#if OS(WINCE) && !PLATFORM(QT)
-#undef ENABLE_JSC_MULTIPLE_THREADS
-#define ENABLE_JSC_MULTIPLE_THREADS 0
-#define USE_SYSTEM_MALLOC 0
-#define ENABLE_ICONDATABASE 0
-#define ENABLE_JAVASCRIPT_DEBUGGER 0
-#define ENABLE_FTPDIR 0
-#define ENABLE_PAN_SCROLLING 0
-#define ENABLE_WML 1
-#define HAVE_ACCESSIBILITY 0
-
#define NOMINMAX /* Windows min and max conflict with standard macros */
#define NOSHLWAPI /* shlwapi.h not available on WinCe */
#define _INC_ASSERT /* disable "assert.h" */
#define assert(x)
-/* _countof is only included in CE6; for CE5 we need to define it ourself */
-#ifndef _countof
-#define _countof(x) (sizeof(x) / sizeof((x)[0]))
-#endif
-
#endif /* OS(WINCE) && !PLATFORM(QT) */
#if PLATFORM(QT)
#define WTF_USE_QT4_UNICODE 1
-#if !defined(ENABLE_WIDGETS_10_SUPPORT)
-#define ENABLE_WIDGETS_10_SUPPORT 1
-#endif
#elif OS(WINCE)
#define WTF_USE_WINCE_UNICODE 1
+#elif PLATFORM(BREWMP)
+#define WTF_USE_BREWMP_UNICODE 1
#elif PLATFORM(GTK)
/* The GTK+ Unicode backend is configurable */
#else
#endif
-
#if PLATFORM(CHROMIUM) && OS(DARWIN)
-#define WTF_PLATFORM_CF 1
+#define WTF_USE_CF 1
#define WTF_USE_PTHREADS 1
#define HAVE_PTHREAD_RWLOCK 1
-#define WTF_USE_CARBON_SECURE_INPUT_MODE 1
#endif
#define DONT_FINALIZE_ON_MAIN_THREAD 1
+#if PLATFORM(BREWMP)
+#define ENABLE_SINGLE_THREADED 1
+#endif
+
#if PLATFORM(QT) && OS(DARWIN)
-#define WTF_PLATFORM_CF 1
+#define WTF_USE_CF 1
#endif
-#if OS(DARWIN) && !defined(BUILDING_ON_TIGER) && !PLATFORM(GTK) && !PLATFORM(QT)
+#if OS(DARWIN) && !PLATFORM(GTK) && !PLATFORM(QT)
#define ENABLE_PURGEABLE_MEMORY 1
#endif
#define ENABLE_CONTEXT_MENUS 0
#define ENABLE_DISK_IMAGE_CACHE 1
#define ENABLE_DRAG_SUPPORT 0
+#define ENABLE_DATA_TRANSFER_ITEMS 0
#define ENABLE_FTPDIR 1
#define ENABLE_GEOLOCATION 1
#define ENABLE_GEOLOCATION_PERMISSION_CACHE 1
#define ENABLE_JAVA_BRIDGE 0
#define ENABLE_NETSCAPE_PLUGIN_API 0
#define ENABLE_ORIENTATION_EVENTS 1
-#define ENABLE_RANGETYPE_AS_TEXT 1
#define ENABLE_REPAINT_THROTTLING 1
#define ENABLE_RESPECT_EXIF_ORIENTATION 1
+#define ENABLE_WEB_ARCHIVE 1
+#define HAVE_CFNETWORK_DATA_ARRAY_CALLBACK 1
#define HAVE_PTHREAD_RWLOCK 1
#define HAVE_READLINE 1
#define HAVE_RUNLOOP_TIMER 0
-#define WTF_PLATFORM_CF 1
+#define WTF_USE_CF 1
+#define WTF_USE_CFNETWORK 1
#define WTF_USE_PTHREADS 1
#define WTF_USE_WEB_THREAD 1
#define ENABLE_PURGEABLE_MEMORY 1
#endif
-#define WTF_USE_PTHREAD_GETSPECIFIC_DIRECT 1
-
#if defined(WTF_ARM_ARCH_VERSION) && WTF_ARM_ARCH_VERSION >= 7
// ARMv7;
#define WTF_USE_JSVALUE32_64 1
#endif
#endif
-#undef ENABLE_3D_CANVAS
+#undef ENABLE_WEBGL
#if defined(WTF_ARM_ARCH_VERSION) && WTF_ARM_ARCH_VERSION == 6
-#define ENABLE_3D_CANVAS 0
+#define ENABLE_WEBGL 0
#else
-#define ENABLE_3D_CANVAS 1
+#define ENABLE_WEBGL 1
#endif
#if PLATFORM(ANDROID)
#define WTF_USE_PTHREADS 1
-#define WTF_PLATFORM_SGL 1
#define USE_SYSTEM_MALLOC 1
#define ENABLE_JAVA_BRIDGE 1
#define LOG_DISABLED 1
This prevents unnecessary invals. */
#define ENABLE_TEXT_CARET 1
#define ENABLE_JAVASCRIPT_DEBUGGER 0
+#if !defined(ENABLE_JIT) && !ENABLE(ANDROID_JSC_JIT)
+#define ENABLE_JIT 0
+#endif
#endif
-#if PLATFORM(WIN)
-#define WTF_USE_WININET 1
+#if PLATFORM(WIN) && !OS(WINCE)
+#define WTF_USE_CF 1
+#define WTF_USE_PTHREADS 0
+#endif
+
+#if PLATFORM(WIN) && !OS(WINCE) && !PLATFORM(CHROMIUM) && !defined(WIN_CAIRO)
+#define WTF_USE_CFNETWORK 1
+#endif
+
+#define WTF_USE_CFURLCACHE 1
+#define WTF_USE_CFURLSTORAGESESSIONS 1
+
+#if PLATFORM(WIN) && !OS(WINCE) && !PLATFORM(CHROMIUM) && !PLATFORM(QT)
+#define ENABLE_WEB_ARCHIVE 1
+#endif
+
+#if PLATFORM(WIN) && !OS(WINCE) && !PLATFORM(CHROMIUM) && !defined(WIN_CAIRO) && !PLATFORM(QT)
+#define ENABLE_FULLSCREEN_API 1
#endif
#if PLATFORM(WX)
#define ENABLE_ASSEMBLER 1
#define ENABLE_GLOBAL_FASTMALLOC_NEW 0
#if OS(DARWIN)
-#define WTF_PLATFORM_CF 1
-#ifndef BUILDING_ON_TIGER
+#define WTF_USE_CF 1
#define WTF_USE_CORE_TEXT 1
-#else
-#define WTF_USE_ATSUI 1
-#endif
+#define ENABLE_WEB_ARCHIVE 1
#endif
#endif
#define USE_SYSTEM_MALLOC 1
#endif
+#if PLATFORM(BREWMP_SIMULATOR)
+#define ENABLE_JIT 0
+#endif
+
#if !defined(HAVE_ACCESSIBILITY)
#define HAVE_ACCESSIBILITY 1
#endif /* !defined(HAVE_ACCESSIBILITY) */
#define HAVE_SIGNAL_H 1
#endif
+#if !defined(HAVE_STRNSTR)
+#if OS(DARWIN) || OS(FREEBSD)
+#define HAVE_STRNSTR 1
+#endif
+#endif
+
#if !OS(WINDOWS) && !OS(SOLARIS) && !OS(QNX) \
&& !OS(SYMBIAN) && !OS(HAIKU) && !OS(RVCT) \
&& !OS(ANDROID) && !PLATFORM(BREWMP)
#define HAVE_SYS_PARAM_H 1
#define HAVE_SYS_TIME_H 1
#define HAVE_SYS_TIMEB_H 1
+#define WTF_USE_ACCELERATE 1
-#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+#ifndef TARGETING_LEOPARD
#define HAVE_DISPATCH_H 1
+#define HAVE_HOSTED_CORE_ANIMATION 1
#endif
#define HAVE_ERRNO_H 0
#else
#define HAVE_SYS_TIMEB_H 1
+#define HAVE_ALIGNED_MALLOC 1
+#define HAVE_ISDEBUGGERPRESENT 1
#endif
#define HAVE_VIRTUALALLOC 1
/* ENABLE macro defaults */
#if PLATFORM(QT)
-// We musn't customize the global operator new and delete for the Qt port.
+/* We must not customize the global operator new and delete for the Qt port. */
#define ENABLE_GLOBAL_FASTMALLOC_NEW 0
+#if !OS(UNIX) || OS(SYMBIAN)
+#define USE_SYSTEM_MALLOC 1
+#endif
#endif
/* fastMalloc match validation allows for runtime verification that
#define ENABLE_DRAG_SUPPORT 1
#endif
-#if !defined(ENABLE_DASHBOARD_SUPPORT)
-#define ENABLE_DASHBOARD_SUPPORT 0
+#if !defined(ENABLE_DATA_TRANSFER_ITEMS)
+#define ENABLE_DATA_TRANSFER_ITEMS 0
#endif
-#if !defined(ENABLE_WIDGETS_10_SUPPORT)
-#define ENABLE_WIDGETS_10_SUPPORT 0
+#if !defined(ENABLE_DASHBOARD_SUPPORT)
+#define ENABLE_DASHBOARD_SUPPORT 0
#endif
#if !defined(ENABLE_GEOLOCATION_PERMISSION_CACHE)
#define ENABLE_NETSCAPE_PLUGIN_API 1
#endif
+#if !defined(ENABLE_NETSCAPE_PLUGIN_METADATA_CACHE)
+#define ENABLE_NETSCAPE_PLUGIN_METADATA_CACHE 0
+#endif
+
#if !defined(ENABLE_PURGEABLE_MEMORY)
#define ENABLE_PURGEABLE_MEMORY 0
#endif
#define ENABLE_RESPECT_EXIF_ORIENTATION 0
#endif
-#if !defined(WTF_USE_PTHREAD_GETSPECIFIC_DIRECT)
-#define WTF_USE_PTHREAD_GETSPECIFIC_DIRECT 0
-#endif
-
#if !defined(ENABLE_OPCODE_STATS)
#define ENABLE_OPCODE_STATS 0
#endif
#define ENABLE_GEOLOCATION 0
#endif
+#if !defined(ENABLE_GESTURE_RECOGNIZER)
+#define ENABLE_GESTURE_RECOGNIZER 0
+#endif
+
#if !defined(ENABLE_NOTIFICATIONS)
#define ENABLE_NOTIFICATIONS 0
#endif
#define ENABLE_ON_FIRST_TEXTAREA_FOCUS_SELECT_ALL 0
#endif
-#if !defined(ENABLE_CONTENTEDITABLE)
-#define ENABLE_CONTENTEDITABLE 0
+#if !defined(ENABLE_FULLSCREEN_API)
+#define ENABLE_FULLSCREEN_API 0
#endif
-#if !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32) && !defined(WTF_USE_JSVALUE32_64)
+#if !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32_64)
#if (CPU(X86_64) && (OS(UNIX) || OS(WINDOWS))) \
|| (CPU(IA64) && !CPU(IA64_32)) \
|| CPU(ALPHA) \
- || CPU(SPARC64)
+ || CPU(SPARC64) \
+ || CPU(S390X) \
+ || CPU(PPC64)
#define WTF_USE_JSVALUE64 1
-#elif CPU(ARM_TRADITIONAL) && !PLATFORM(IPHONE) || CPU(PPC64) || CPU(MIPS) || (PLATFORM(IPHONE) && defined(WTF_ARM_ARCH_VERSION) && WTF_ARM_ARCH_VERSION == 6 && !defined(__llvm__))
-/* FIXME: <rdar://problem/7478149> gcc-4.2 compiler bug with USE(JSVALUE32_64) and armv6 target */
-#define WTF_USE_JSVALUE32 1
-#elif OS(WINDOWS) && COMPILER(MINGW)
-/* Using JSVALUE32_64 causes padding/alignement issues for JITStubArg
-on MinGW. See https://bugs.webkit.org/show_bug.cgi?id=29268 */
-#define WTF_USE_JSVALUE32 1
#else
#define WTF_USE_JSVALUE32_64 1
#endif
-#endif /* !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32) && !defined(WTF_USE_JSVALUE32_64) */
+#endif /* !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32_64) */
#if !defined(ENABLE_REPAINT_THROTTLING)
#define ENABLE_REPAINT_THROTTLING 0
#endif
-#if !defined(ENABLE_JIT)
+/* Disable the JIT on versions of GCC prior to 4.1 */
+#if !defined(ENABLE_JIT) && COMPILER(GCC) && !GCC_VERSION_AT_LEAST(4, 1, 0)
+#define ENABLE_JIT 0
+#endif
-/* The JIT is tested & working on x86_64 Mac */
-#if CPU(X86_64) && PLATFORM(MAC)
- #define ENABLE_JIT 1
-/* The JIT is tested & working on x86 Mac */
-#elif CPU(X86) && PLATFORM(MAC)
- #define ENABLE_JIT 1
- #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1
-#elif CPU(ARM_THUMB2) && PLATFORM(IPHONE)
- #define ENABLE_JIT 1
-/* The JIT is tested & working on Android */
-#elif CPU(ARM_THUMB2) && PLATFORM(ANDROID) && ENABLE(ANDROID_JSC_JIT)
- #define ENABLE_JIT 1
-/* The JIT is tested & working on x86 Windows */
-#elif CPU(X86) && PLATFORM(WIN)
- #define ENABLE_JIT 1
+/* JIT is not implemented for 64 bit on MSVC */
+#if !defined(ENABLE_JIT) && COMPILER(MSVC) && CPU(X86_64)
+#define ENABLE_JIT 0
#endif
-#if PLATFORM(QT) || PLATFORM(WX)
-#if CPU(X86_64) && OS(DARWIN)
- #define ENABLE_JIT 1
-#elif CPU(X86) && OS(DARWIN)
- #define ENABLE_JIT 1
- #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1
-#elif CPU(X86) && OS(WINDOWS) && COMPILER(MINGW) && GCC_VERSION >= 40100
- #define ENABLE_JIT 1
- #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1
-#elif CPU(X86_64) && OS(WINDOWS) && COMPILER(MINGW64) && GCC_VERSION >= 40100
- #define ENABLE_JIT 1
-#elif CPU(X86) && OS(WINDOWS) && COMPILER(MSVC)
- #define ENABLE_JIT 1
- #define WTF_USE_JIT_STUB_ARGUMENT_REGISTER 1
-#elif CPU(X86) && OS(LINUX) && GCC_VERSION >= 40100
- #define ENABLE_JIT 1
- #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1
-#elif CPU(X86_64) && OS(LINUX) && GCC_VERSION >= 40100
- #define ENABLE_JIT 1
-#elif CPU(ARM_TRADITIONAL) && OS(LINUX)
- #define ENABLE_JIT 1
-#elif CPU(ARM_TRADITIONAL) && OS(SYMBIAN) && COMPILER(RVCT)
- #define ENABLE_JIT 1
-#elif CPU(MIPS) && OS(LINUX)
- #define ENABLE_JIT 1
- #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 0
+/* The JIT is enabled by default on all x86, x64-64, ARM & MIPS platforms. */
+#if !defined(ENABLE_JIT) \
+ && (CPU(X86) || CPU(X86_64) || CPU(ARM) || CPU(MIPS)) \
+ && (OS(DARWIN) || !COMPILER(GCC) || GCC_VERSION_AT_LEAST(4, 1, 0)) \
+ && !OS(WINCE)
+#define ENABLE_JIT 1
#endif
-#endif /* PLATFORM(QT) */
-#endif /* !defined(ENABLE_JIT) */
+/* Currently only implemented for JSVALUE64, only tested on PLATFORM(MAC) */
+#if ENABLE(JIT) && USE(JSVALUE64) && PLATFORM(MAC)
+#define ENABLE_DFG_JIT 0
+/* Enabled with restrictions to circumvent known performance regressions. */
+#define ENABLE_DFG_JIT_RESTRICTIONS 0
+#endif
-#if 1 || !ENABLE(JIT)
+/* Ensure that either the JIT or the interpreter has been enabled. */
+#if !defined(ENABLE_INTERPRETER) && !ENABLE(JIT)
#define ENABLE_INTERPRETER 1
#endif
-
#if !(ENABLE(JIT) || ENABLE(INTERPRETER))
#error You have to have at least one execution model enabled to build JSC
#endif
-/* CPU architecture specific optimizations */
-#if CPU(ARM_TRADITIONAL)
-#if ENABLE(JIT) && !defined(ENABLE_JIT_OPTIMIZE_MOD) && WTF_ARM_ARCH_AT_LEAST(5)
-#define ENABLE_JIT_OPTIMIZE_MOD 1
-#endif
+#if CPU(SH4) && PLATFORM(QT)
+#define ENABLE_JIT 1
+#define ENABLE_YARR 1
+#define ENABLE_YARR_JIT 1
+#define WTF_USE_JIT_STUB_ARGUMENT_REGISTER 1
+#define ENABLE_ASSEMBLER 1
#endif
+/* Configure the JIT */
#if ENABLE(JIT)
-#ifndef ENABLE_JIT_OPTIMIZE_CALL
-#define ENABLE_JIT_OPTIMIZE_CALL 1
-#endif
-#ifndef ENABLE_JIT_OPTIMIZE_NATIVE_CALL
-#define ENABLE_JIT_OPTIMIZE_NATIVE_CALL 0
-#endif
-#ifndef ENABLE_JIT_OPTIMIZE_PROPERTY_ACCESS
-#define ENABLE_JIT_OPTIMIZE_PROPERTY_ACCESS 1
-#endif
-#ifndef ENABLE_JIT_OPTIMIZE_METHOD_CALLS
-#define ENABLE_JIT_OPTIMIZE_METHOD_CALLS 1
-#endif
-#ifndef ENABLE_JIT_OPTIMIZE_MOD
-#define ENABLE_JIT_OPTIMIZE_MOD 0
-#endif
+ #if CPU(ARM)
+ #if !defined(ENABLE_JIT_USE_SOFT_MODULO) && WTF_ARM_ARCH_AT_LEAST(5)
+ #define ENABLE_JIT_USE_SOFT_MODULO 1
+ #endif
+ #endif
+
+ #ifndef ENABLE_JIT_OPTIMIZE_CALL
+ #define ENABLE_JIT_OPTIMIZE_CALL 1
+ #endif
+ #ifndef ENABLE_JIT_OPTIMIZE_NATIVE_CALL
+ #define ENABLE_JIT_OPTIMIZE_NATIVE_CALL 1
+ #endif
+ #ifndef ENABLE_JIT_OPTIMIZE_PROPERTY_ACCESS
+ #define ENABLE_JIT_OPTIMIZE_PROPERTY_ACCESS 1
+ #endif
+ #ifndef ENABLE_JIT_OPTIMIZE_METHOD_CALLS
+ #define ENABLE_JIT_OPTIMIZE_METHOD_CALLS 1
+ #endif
#endif
#if CPU(X86) && COMPILER(MSVC)
#define JSC_HOST_CALL
#endif
-#if COMPILER(GCC)
+/* Configure the interpreter */
+#if COMPILER(GCC) || (RVCT_VERSION_AT_LEAST(4, 0, 0, 0) && defined(__GNUC__))
#define HAVE_COMPUTED_GOTO 1
#endif
-
#if HAVE(COMPUTED_GOTO) && ENABLE(INTERPRETER)
#define ENABLE_COMPUTED_GOTO_INTERPRETER 1
#endif
-/* Yet Another Regex Runtime. */
-#if !defined(ENABLE_YARR_JIT)
+/* Regular Expression Tracing - Set to 1 to trace RegExp's in jsc. Results dumped at exit */
+#define ENABLE_REGEXP_TRACING 0
-/* YARR supports x86 & x86-64, and has been tested on Mac and Windows. */
-#if (CPU(X86) && PLATFORM(MAC)) \
- || (CPU(X86_64) && PLATFORM(MAC)) \
- || (CPU(ARM_THUMB2) && PLATFORM(IPHONE)) \
- || (CPU(ARM_THUMB2) && PLATFORM(ANDROID) && ENABLE(ANDROID_JSC_JIT)) \
- || (CPU(X86) && PLATFORM(WIN)) \
- || (CPU(X86) && PLATFORM(WX))
-#define ENABLE_YARR 1
-#define ENABLE_YARR_JIT 1
-#endif
+/* Yet Another Regex Runtime - turned on by default for JIT enabled ports. */
+#if PLATFORM(CHROMIUM)
+#define ENABLE_YARR_JIT 0
-#if PLATFORM(QT)
-#if (CPU(X86) && OS(WINDOWS) && COMPILER(MINGW) && GCC_VERSION >= 40100) \
- || (CPU(X86_64) && OS(WINDOWS) && COMPILER(MINGW64) && GCC_VERSION >= 40100) \
- || (CPU(X86) && OS(WINDOWS) && COMPILER(MSVC)) \
- || (CPU(X86) && OS(LINUX) && GCC_VERSION >= 40100) \
- || (CPU(X86_64) && OS(LINUX) && GCC_VERSION >= 40100) \
- || (CPU(ARM_TRADITIONAL) && OS(LINUX)) \
- || (CPU(ARM_TRADITIONAL) && OS(SYMBIAN) && COMPILER(RVCT)) \
- || (CPU(MIPS) && OS(LINUX))
-#define ENABLE_YARR 1
+#elif ENABLE(JIT) && !defined(ENABLE_YARR_JIT)
#define ENABLE_YARR_JIT 1
-#endif
-#endif
-#endif /* !defined(ENABLE_YARR_JIT) */
-
-/* Sanity Check */
-#if ENABLE(YARR_JIT) && !ENABLE(YARR)
-#error "YARR_JIT requires YARR"
+/* Setting this flag compares JIT results with interpreter results. */
+#define ENABLE_YARR_JIT_DEBUG 0
#endif
#if ENABLE(JIT) || ENABLE(YARR_JIT)
#define ENABLE_PAN_SCROLLING 1
#endif
-/* Use the QXmlStreamReader implementation for XMLTokenizer */
+#if !defined(ENABLE_SMOOTH_SCROLLING)
+#define ENABLE_SMOOTH_SCROLLING 0
+#endif
+
+#if !defined(ENABLE_WEB_ARCHIVE)
+#define ENABLE_WEB_ARCHIVE 0
+#endif
+
+/* Use the QXmlStreamReader implementation for XMLDocumentParser */
/* Use the QXmlQuery implementation for XSLTProcessor */
#if PLATFORM(QT)
#define WTF_USE_QXMLSTREAM 1
#define WTF_USE_QXMLQUERY 1
#endif
-#if !PLATFORM(QT)
-#define WTF_USE_FONT_FAST_PATH 1
-#endif
-
#if PLATFORM(MAC)
/* Complex text framework */
-#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+#ifndef BUILDING_ON_LEOPARD
#define WTF_USE_ATSUI 0
#define WTF_USE_CORE_TEXT 1
#else
#define WTF_USE_ATSUI 1
#define WTF_USE_CORE_TEXT 0
#endif
-
-/* Accelerated compositing */
-#if !defined(BUILDING_ON_TIGER)
-#define WTF_USE_ACCELERATED_COMPOSITING 1
-#endif
#endif
+/* Accelerated compositing */
+#if PLATFORM(MAC) || PLATFORM(IOS) || PLATFORM(QT) || (PLATFORM(WIN) && !OS(WINCE) &&!defined(WIN_CAIRO))
#define WTF_USE_ACCELERATED_COMPOSITING 1
-
-/* FIXME: Defining ENABLE_3D_RENDERING here isn't really right, but it's always used with
- with WTF_USE_ACCELERATED_COMPOSITING, and it allows the feature to be turned on and
- off in one place. */
-#if PLATFORM(WIN)
-#include "QuartzCorePresent.h"
-#if QUARTZCORE_PRESENT
-#define WTF_USE_ACCELERATED_COMPOSITING 1
-#define ENABLE_3D_RENDERING 1
-#endif
#endif
-#if (PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)) || PLATFORM(IPHONE)
+#if (PLATFORM(MAC) && !defined(BUILDING_ON_LEOPARD)) || PLATFORM(IOS)
#define WTF_USE_PROTECTION_SPACE_AUTH_CALLBACK 1
#endif
+
#if COMPILER(GCC)
#define WARN_UNUSED_RETURN __attribute__ ((warn_unused_result))
#else
#define ENABLE_JSC_ZOMBIES 0
+/* FIXME: Eventually we should enable this for all platforms and get rid of the define. */
+#define WTF_USE_PLATFORM_STRATEGIES 1
+
+#if PLATFORM(WIN)
+#define WTF_USE_CROSS_PLATFORM_CONTEXT_MENUS 1
+#endif
+
+/* Geolocation request policy. pre-emptive policy is to acquire user permission before acquiring location.
+ Client based implementations will have option to choose between pre-emptive and nonpre-emptive permission policy.
+ pre-emptive permission policy is enabled by default for all client-based implementations. */
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+#define WTF_USE_PREEMPT_GEOLOCATION_PERMISSION 1
+#endif
+
#if CPU(ARM_THUMB2)
#define ENABLE_BRANCH_COMPACTION 1
#endif
+#if !defined(ENABLE_THREADING_OPENMP) && defined(_OPENMP)
+#define ENABLE_THREADING_OPENMP 1
+#endif
+
+#if !defined(ENABLE_PARALLEL_JOBS) && !ENABLE(SINGLE_THREADED) && (ENABLE(THREADING_GENERIC) || ENABLE(THREADING_LIBDISPATCH) || ENABLE(THREADING_OPENMP))
+#define ENABLE_PARALLEL_JOBS 1
+#endif
+
+#if ENABLE(GLIB_SUPPORT)
+#include "GTypedefs.h"
+#endif
+
+/* FIXME: This define won't be needed once #27551 is fully landed. However,
+ since most ports try to support sub-project independence, adding new headers
+ to WTF causes many ports to break, and so this way we can address the build
+ breakages one port at a time. */
+#define WTF_USE_EXPORT_MACROS 0
+
+#if (PLATFORM(QT) && !OS(SYMBIAN)) || PLATFORM(GTK)
+#define WTF_USE_UNIX_DOMAIN_SOCKETS 1
+#endif
+
+#ifndef NDEBUG
+#ifndef ENABLE_GC_VALIDATION
+#define ENABLE_GC_VALIDATION 1
+#endif
+#endif
+
#endif /* WTF_Platform_h */
#include "config.h"
#include "RandomNumber.h"
+#include "CryptographicallyRandomNumber.h"
#include "RandomNumberSeed.h"
#include <limits>
#include <stdint.h>
#include <stdlib.h>
-#if OS(WINCE)
+#if USE(MERSENNE_TWISTER_19937)
extern "C" {
-#include "wince/mt19937ar.c"
+#include "mt19937ar.c"
}
#endif
#include <AEEAppGen.h>
#include <AEESource.h>
#include <AEEStdLib.h>
+#include <wtf/brew/RefPtrBrew.h>
+#include <wtf/brew/ShellBrew.h>
#endif
namespace WTF {
-double weakRandomNumber()
+double randomNumber()
{
-#if COMPILER(MSVC) && defined(_CRT_RAND_S)
- // rand_s is incredibly slow on windows so we fall back on rand for Math.random
- return (rand() + (rand() / (RAND_MAX + 1.0))) / (RAND_MAX + 1.0);
-#elif PLATFORM(BREWMP)
- uint32_t bits;
- GETRAND(reinterpret_cast<byte*>(&bits), sizeof(uint32_t));
+#if USE(OS_RANDOMNESS)
+ uint32_t bits = cryptographicallyRandomNumber();
return static_cast<double>(bits) / (static_cast<double>(std::numeric_limits<uint32_t>::max()) + 1.0);
#else
- return randomNumber();
-#endif
-}
+ // Without OS_RANDOMNESS, we fall back to other random number generators
+ // that might not be cryptographically secure. Ideally, most ports would
+ // define USE(OS_RANDOMNESS).
-double randomNumber()
-{
-#if !ENABLE(JSC_MULTIPLE_THREADS)
+#if !ENABLE(WTF_MULTIPLE_THREADS)
static bool s_initialized = false;
if (!s_initialized) {
initializeRandomNumberGenerator();
s_initialized = true;
}
#endif
-
-#if COMPILER(MSVC) && defined(_CRT_RAND_S)
- uint32_t bits;
- rand_s(&bits);
- return static_cast<double>(bits) / (static_cast<double>(std::numeric_limits<uint32_t>::max()) + 1.0);
-#elif OS(DARWIN)
- uint32_t bits = arc4random();
- return static_cast<double>(bits) / (static_cast<double>(std::numeric_limits<uint32_t>::max()) + 1.0);
-#elif OS(UNIX)
- uint32_t part1 = random() & (RAND_MAX - 1);
- uint32_t part2 = random() & (RAND_MAX - 1);
- // random only provides 31 bits
- uint64_t fullRandom = part1;
- fullRandom <<= 31;
- fullRandom |= part2;
- // Mask off the low 53bits
- fullRandom &= (1LL << 53) - 1;
- return static_cast<double>(fullRandom)/static_cast<double>(1LL << 53);
-#elif OS(WINCE)
+#if USE(MERSENNE_TWISTER_19937)
return genrand_res53();
-#elif OS(WINDOWS)
- uint32_t part1 = rand() & (RAND_MAX - 1);
- uint32_t part2 = rand() & (RAND_MAX - 1);
- uint32_t part3 = rand() & (RAND_MAX - 1);
- uint32_t part4 = rand() & (RAND_MAX - 1);
- // rand only provides 15 bits on Win32
- uint64_t fullRandom = part1;
- fullRandom <<= 15;
- fullRandom |= part2;
- fullRandom <<= 15;
- fullRandom |= part3;
- fullRandom <<= 15;
- fullRandom |= part4;
-
- // Mask off the low 53bits
- fullRandom &= (1LL << 53) - 1;
- return static_cast<double>(fullRandom)/static_cast<double>(1LL << 53);
#elif PLATFORM(BREWMP)
uint32_t bits;
- ISource* randomSource;
-
- IShell* shell = reinterpret_cast<AEEApplet*>(GETAPPINSTANCE())->m_pIShell;
- ISHELL_CreateInstance(shell, AEECLSID_RANDOM, reinterpret_cast<void**>(&randomSource));
- ISOURCE_Read(randomSource, reinterpret_cast<char*>(&bits), 4);
- ISOURCE_Release(randomSource);
+ // Is this a cryptographically strong source of random numbers? If so, we
+ // should move this into OSRandomSource.
+ // http://csrc.nist.gov/groups/STM/cmvp/documents/140-1/140sp/140sp851.pdf
+ // is slightly unclear on this point, although it seems to imply that it is
+ // secure.
+ RefPtr<ISource> randomSource = createRefPtrInstance<ISource>(AEECLSID_RANDOM);
+ ISOURCE_Read(randomSource.get(), reinterpret_cast<char*>(&bits), 4);
return static_cast<double>(bits) / (static_cast<double>(std::numeric_limits<uint32_t>::max()) + 1.0);
#else
fullRandom &= (1LL << 53) - 1;
return static_cast<double>(fullRandom)/static_cast<double>(1LL << 53);
#endif
+#endif
}
}
// cryptographically secure if possible on the target platform
double randomNumber();
- // Returns a pseudo-random number in the range [0, 1), attempts to
- // produce a reasonable "random" number fast.
- // We only need this because rand_s is so slow on windows.
- double weakRandomNumber();
-
}
using WTF::randomNumber;
#include <unistd.h>
#endif
-#if OS(WINCE)
+#if USE(MERSENNE_TWISTER_19937)
extern "C" {
void init_by_array(unsigned long init_key[],int key_length);
}
// On Darwin we use arc4random which initialises itself.
#elif OS(WINCE)
// initialize rand()
- srand(static_cast<unsigned>(time(0)));
-
- // use rand() to initialize the real RNG
- unsigned long initializationBuffer[4];
- initializationBuffer[0] = (rand() << 16) | rand();
- initializationBuffer[1] = (rand() << 16) | rand();
- initializationBuffer[2] = (rand() << 16) | rand();
- initializationBuffer[3] = (rand() << 16) | rand();
- init_by_array(initializationBuffer, 4);
+ srand(GetTickCount());
#elif COMPILER(MSVC) && defined(_CRT_RAND_S)
// On Windows we use rand_s which initialises itself
+#elif PLATFORM(BREWMP)
+ // On Brew MP we use AEECLSID_RANDOM which initialises itself
#elif OS(UNIX)
// srandomdev is not guaranteed to exist on linux so we use this poor seed, this should be improved
timeval time;
#else
srand(static_cast<unsigned>(time(0)));
#endif
-}
-inline void initializeWeakRandomNumberGenerator()
-{
-#if COMPILER(MSVC) && defined(_CRT_RAND_S)
- // We need to initialise windows rand() explicitly for Math.random
- unsigned seed = 0;
- rand_s(&seed);
- srand(seed);
+#if USE(MERSENNE_TWISTER_19937)
+ // use rand() to initialize the Mersenne Twister random number generator.
+ unsigned long initializationBuffer[4];
+ initializationBuffer[0] = (rand() << 16) | rand();
+ initializationBuffer[1] = (rand() << 16) | rand();
+ initializationBuffer[2] = (rand() << 16) | rand();
+ initializationBuffer[3] = (rand() << 16) | rand();
+ init_by_array(initializationBuffer, 4);
#endif
}
+
}
#endif
/*
- * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
#ifndef RefCounted_h
#define RefCounted_h
-#include <wtf/Assertions.h>
-#include <wtf/Noncopyable.h>
+#include "Assertions.h"
+#include "FastAllocBase.h"
+#include "Noncopyable.h"
namespace WTF {
void ref()
{
ASSERT(!m_deletionHasBegun);
+ ASSERT(!m_adoptionIsRequired);
++m_refCount;
}
return m_refCount;
}
+ void relaxAdoptionRequirement()
+ {
+#ifndef NDEBUG
+ ASSERT(!m_deletionHasBegun);
+ ASSERT(m_adoptionIsRequired);
+ m_adoptionIsRequired = false;
+#endif
+ }
+
+ // Helper for generating JIT code. Please do not use for non-JIT purposes.
+ const int* addressOfCount() const
+ {
+ return &m_refCount;
+ }
+
protected:
RefCountedBase()
: m_refCount(1)
#ifndef NDEBUG
, m_deletionHasBegun(false)
+ , m_adoptionIsRequired(true)
#endif
{
}
~RefCountedBase()
{
+ ASSERT(m_deletionHasBegun);
+ ASSERT(!m_adoptionIsRequired);
}
// Returns whether the pointer should be freed or not.
bool derefBase()
{
ASSERT(!m_deletionHasBegun);
+ ASSERT(!m_adoptionIsRequired);
+
ASSERT(m_refCount > 0);
if (m_refCount == 1) {
#ifndef NDEBUG
return false;
}
- // Helper for generating JIT code. Please do not use for non-JIT purposes.
- int* addressOfCount()
- {
- return &m_refCount;
- }
-
#ifndef NDEBUG
bool deletionHasBegun() const
{
#endif
private:
- template<class T>
- friend class CrossThreadRefCounted;
+ template<typename T> friend class CrossThreadRefCounted;
+
+#ifndef NDEBUG
+ friend void adopted(RefCountedBase*);
+#endif
int m_refCount;
#ifndef NDEBUG
bool m_deletionHasBegun;
+ bool m_adoptionIsRequired;
#endif
};
+#ifndef NDEBUG
+
+inline void adopted(RefCountedBase* object)
+{
+ if (!object)
+ return;
+ ASSERT(!object->m_deletionHasBegun);
+ object->m_adoptionIsRequired = false;
+}
-template<class T> class RefCounted : public RefCountedBase, public Noncopyable {
+#endif
+
+template<typename T> class RefCounted : public RefCountedBase {
+ WTF_MAKE_NONCOPYABLE(RefCounted); WTF_MAKE_FAST_ALLOCATED;
public:
void deref()
{
}
protected:
+ RefCounted() { }
~RefCounted()
{
}
};
-template<class T> class RefCountedCustomAllocated : public RefCountedBase, public NoncopyableCustomAllocated {
+template<typename T> class RefCountedCustomAllocated : public RefCountedBase {
+ WTF_MAKE_NONCOPYABLE(RefCountedCustomAllocated);
+
public:
void deref()
{
void RefCountedLeakCounter::increment()
{
-#if ENABLE(JSC_MULTIPLE_THREADS)
+#if ENABLE(WTF_MULTIPLE_THREADS)
atomicIncrement(&m_count);
#else
++m_count;
void RefCountedLeakCounter::decrement()
{
-#if ENABLE(JSC_MULTIPLE_THREADS)
+#if ENABLE(WTF_MULTIPLE_THREADS)
atomicDecrement(&m_count);
#else
--m_count;
/*
- * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
#define WTF_RefPtr_h
#include <algorithm>
-#include "AlwaysInline.h"
#include "FastAllocBase.h"
#include "PassRefPtr.h"
enum PlacementNewAdoptType { PlacementNewAdopt };
- template <typename T> class PassRefPtr;
- template <typename T> class NonNullPassRefPtr;
+ template<typename T> class PassRefPtr;
+ template<typename T> class NonNullPassRefPtr;
enum HashTableDeletedValueType { HashTableDeletedValue };
- template <typename T> class RefPtr : public FastAllocBase {
+ template<typename T> class RefPtr {
+ WTF_MAKE_FAST_ALLOCATED;
public:
- RefPtr() : m_ptr(0) { }
- RefPtr(T* ptr) : m_ptr(ptr) { refIfNotNull(ptr); }
- RefPtr(const RefPtr& o) : m_ptr(o.m_ptr) { T* ptr = m_ptr; refIfNotNull(ptr); }
- // see comment in PassRefPtr.h for why this takes const reference
- template <typename U> RefPtr(const PassRefPtr<U>&);
- template <typename U> RefPtr(const NonNullPassRefPtr<U>&);
+ ALWAYS_INLINE RefPtr() : m_ptr(0) { }
+ ALWAYS_INLINE RefPtr(T* ptr) : m_ptr(ptr) { refIfNotNull(ptr); }
+ ALWAYS_INLINE RefPtr(const RefPtr& o) : m_ptr(o.m_ptr) { refIfNotNull(m_ptr); }
+ template<typename U> RefPtr(const RefPtr<U>& o) : m_ptr(o.get()) { refIfNotNull(m_ptr); }
+
+ // See comments in PassRefPtr.h for an explanation of why these takes const references.
+ template<typename U> RefPtr(const PassRefPtr<U>&);
+ template<typename U> RefPtr(const NonNullPassRefPtr<U>&);
// Special constructor for cases where we overwrite an object in place.
- RefPtr(PlacementNewAdoptType) { }
+ ALWAYS_INLINE RefPtr(PlacementNewAdoptType) { }
// Hash table deleted values, which are only constructed and never copied or destroyed.
RefPtr(HashTableDeletedValueType) : m_ptr(hashTableDeletedValue()) { }
bool isHashTableDeletedValue() const { return m_ptr == hashTableDeletedValue(); }
- ~RefPtr() { derefIfNotNull(m_ptr); }
-
- template <typename U> RefPtr(const RefPtr<U>& o) : m_ptr(o.get()) { T* ptr = m_ptr; refIfNotNull(ptr); }
-
+ ALWAYS_INLINE ~RefPtr() { derefIfNotNull(m_ptr); }
+
T* get() const { return m_ptr; }
- void clear() { derefIfNotNull(m_ptr); m_ptr = 0; }
+ void clear();
PassRefPtr<T> release() { PassRefPtr<T> tmp = adoptRef(m_ptr); m_ptr = 0; return tmp; }
T& operator*() const { return *m_ptr; }
RefPtr& operator=(T*);
RefPtr& operator=(const PassRefPtr<T>&);
RefPtr& operator=(const NonNullPassRefPtr<T>&);
- template <typename U> RefPtr& operator=(const RefPtr<U>&);
- template <typename U> RefPtr& operator=(const PassRefPtr<U>&);
- template <typename U> RefPtr& operator=(const NonNullPassRefPtr<U>&);
+#if !HAVE(NULLPTR)
+ RefPtr& operator=(std::nullptr_t) { clear(); return *this; }
+#endif
+ template<typename U> RefPtr& operator=(const RefPtr<U>&);
+ template<typename U> RefPtr& operator=(const PassRefPtr<U>&);
+ template<typename U> RefPtr& operator=(const NonNullPassRefPtr<U>&);
void swap(RefPtr&);
T* m_ptr;
};
- template <typename T> template <typename U> inline RefPtr<T>::RefPtr(const PassRefPtr<U>& o)
- : m_ptr(o.releaseRef())
+ template<typename T> template<typename U> inline RefPtr<T>::RefPtr(const PassRefPtr<U>& o)
+ : m_ptr(o.leakRef())
{
}
- template <typename T> template <typename U> inline RefPtr<T>::RefPtr(const NonNullPassRefPtr<U>& o)
- : m_ptr(o.releaseRef())
+ template<typename T> template<typename U> inline RefPtr<T>::RefPtr(const NonNullPassRefPtr<U>& o)
+ : m_ptr(o.leakRef())
{
}
- template <typename T> inline RefPtr<T>& RefPtr<T>::operator=(const RefPtr<T>& o)
+ template<typename T> inline void RefPtr<T>::clear()
+ {
+ T* ptr = m_ptr;
+ m_ptr = 0;
+ derefIfNotNull(ptr);
+ }
+
+ template<typename T> inline RefPtr<T>& RefPtr<T>::operator=(const RefPtr<T>& o)
{
T* optr = o.get();
refIfNotNull(optr);
return *this;
}
- template <typename T> template <typename U> inline RefPtr<T>& RefPtr<T>::operator=(const RefPtr<U>& o)
+ template<typename T> template<typename U> inline RefPtr<T>& RefPtr<T>::operator=(const RefPtr<U>& o)
{
T* optr = o.get();
refIfNotNull(optr);
return *this;
}
- template <typename T> inline RefPtr<T>& RefPtr<T>::operator=(T* optr)
+ template<typename T> inline RefPtr<T>& RefPtr<T>::operator=(T* optr)
{
refIfNotNull(optr);
T* ptr = m_ptr;
return *this;
}
- template <typename T> inline RefPtr<T>& RefPtr<T>::operator=(const PassRefPtr<T>& o)
+ template<typename T> inline RefPtr<T>& RefPtr<T>::operator=(const PassRefPtr<T>& o)
{
T* ptr = m_ptr;
- m_ptr = o.releaseRef();
+ m_ptr = o.leakRef();
derefIfNotNull(ptr);
return *this;
}
- template <typename T> inline RefPtr<T>& RefPtr<T>::operator=(const NonNullPassRefPtr<T>& o)
+ template<typename T> inline RefPtr<T>& RefPtr<T>::operator=(const NonNullPassRefPtr<T>& o)
{
T* ptr = m_ptr;
- m_ptr = o.releaseRef();
+ m_ptr = o.leakRef();
derefIfNotNull(ptr);
return *this;
}
- template <typename T> template <typename U> inline RefPtr<T>& RefPtr<T>::operator=(const PassRefPtr<U>& o)
+ template<typename T> template<typename U> inline RefPtr<T>& RefPtr<T>::operator=(const PassRefPtr<U>& o)
{
T* ptr = m_ptr;
- m_ptr = o.releaseRef();
+ m_ptr = o.leakRef();
derefIfNotNull(ptr);
return *this;
}
- template <typename T> template <typename U> inline RefPtr<T>& RefPtr<T>::operator=(const NonNullPassRefPtr<U>& o)
+ template<typename T> template<typename U> inline RefPtr<T>& RefPtr<T>::operator=(const NonNullPassRefPtr<U>& o)
{
T* ptr = m_ptr;
- m_ptr = o.releaseRef();
+ m_ptr = o.leakRef();
derefIfNotNull(ptr);
return *this;
}
- template <class T> inline void RefPtr<T>::swap(RefPtr<T>& o)
+ template<class T> inline void RefPtr<T>::swap(RefPtr<T>& o)
{
std::swap(m_ptr, o.m_ptr);
}
- template <class T> inline void swap(RefPtr<T>& a, RefPtr<T>& b)
+ template<class T> inline void swap(RefPtr<T>& a, RefPtr<T>& b)
{
a.swap(b);
}
- template <typename T, typename U> inline bool operator==(const RefPtr<T>& a, const RefPtr<U>& b)
+ template<typename T, typename U> inline bool operator==(const RefPtr<T>& a, const RefPtr<U>& b)
{
return a.get() == b.get();
}
- template <typename T, typename U> inline bool operator==(const RefPtr<T>& a, U* b)
+ template<typename T, typename U> inline bool operator==(const RefPtr<T>& a, U* b)
{
return a.get() == b;
}
- template <typename T, typename U> inline bool operator==(T* a, const RefPtr<U>& b)
+ template<typename T, typename U> inline bool operator==(T* a, const RefPtr<U>& b)
{
return a == b.get();
}
- template <typename T, typename U> inline bool operator!=(const RefPtr<T>& a, const RefPtr<U>& b)
+ template<typename T, typename U> inline bool operator!=(const RefPtr<T>& a, const RefPtr<U>& b)
{
return a.get() != b.get();
}
- template <typename T, typename U> inline bool operator!=(const RefPtr<T>& a, U* b)
+ template<typename T, typename U> inline bool operator!=(const RefPtr<T>& a, U* b)
{
return a.get() != b;
}
- template <typename T, typename U> inline bool operator!=(T* a, const RefPtr<U>& b)
+ template<typename T, typename U> inline bool operator!=(T* a, const RefPtr<U>& b)
{
return a != b.get();
}
- template <typename T, typename U> inline RefPtr<T> static_pointer_cast(const RefPtr<U>& p)
+ template<typename T, typename U> inline RefPtr<T> static_pointer_cast(const RefPtr<U>& p)
{
return RefPtr<T>(static_cast<T*>(p.get()));
}
- template <typename T, typename U> inline RefPtr<T> const_pointer_cast(const RefPtr<U>& p)
+ template<typename T, typename U> inline RefPtr<T> const_pointer_cast(const RefPtr<U>& p)
{
return RefPtr<T>(const_cast<T*>(p.get()));
}
- template <typename T> inline T* getPtr(const RefPtr<T>& p)
+ template<typename T> inline T* getPtr(const RefPtr<T>& p)
{
return p.get();
}
*
*/
+#ifndef RefPtrHashMap_h
+#define RefPtrHashMap_h
+
namespace WTF {
// This specialization is a direct copy of HashMap, with overloaded functions
};
template<typename T, typename MappedArg, typename HashArg, typename KeyTraitsArg, typename MappedTraitsArg>
- class HashMap<RefPtr<T>, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg> : public FastAllocBase {
+ class HashMap<RefPtr<T>, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg> {
+ WTF_MAKE_FAST_ALLOCATED;
private:
typedef KeyTraitsArg KeyTraits;
typedef MappedTraitsArg MappedTraits;
}
} // namespace WTF
+
+#endif // RefPtrHashMap_h
/*
- * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2005, 2006, 2007, 2008, 2010 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
#ifndef RetainPtr_h
#define RetainPtr_h
+#include "HashTraits.h"
+#include "NullPtr.h"
#include "TypeTraits.h"
#include <algorithm>
+
+#if USE(CF)
#include <CoreFoundation/CoreFoundation.h>
+#endif
#ifdef __OBJC__
#import <Foundation/Foundation.h>
}
#endif
- template <typename T> class RetainPtr {
+ template<typename T> class RetainPtr {
public:
typedef typename RemovePointer<T>::Type ValueType;
typedef ValueType* PtrType;
RetainPtr(const RetainPtr& o) : m_ptr(o.m_ptr) { if (PtrType ptr = m_ptr) CFRetain(ptr); }
+ // Hash table deleted values, which are only constructed and never copied or destroyed.
+ RetainPtr(HashTableDeletedValueType) : m_ptr(hashTableDeletedValue()) { }
+ bool isHashTableDeletedValue() const { return m_ptr == hashTableDeletedValue(); }
+
~RetainPtr() { if (PtrType ptr = m_ptr) CFRelease(ptr); }
- template <typename U> RetainPtr(const RetainPtr<U>& o) : m_ptr(o.get()) { if (PtrType ptr = m_ptr) CFRetain(ptr); }
+ template<typename U> RetainPtr(const RetainPtr<U>&);
PtrType get() const { return m_ptr; }
-
- PtrType releaseRef() { PtrType tmp = m_ptr; m_ptr = 0; return tmp; }
-
+
+ void clear();
+ PtrType leakRef() WARN_UNUSED_RETURN;
+
PtrType operator->() const { return m_ptr; }
bool operator!() const { return !m_ptr; }
operator UnspecifiedBoolType() const { return m_ptr ? &RetainPtr::m_ptr : 0; }
RetainPtr& operator=(const RetainPtr&);
- template <typename U> RetainPtr& operator=(const RetainPtr<U>&);
+ template<typename U> RetainPtr& operator=(const RetainPtr<U>&);
RetainPtr& operator=(PtrType);
- template <typename U> RetainPtr& operator=(U*);
+ template<typename U> RetainPtr& operator=(U*);
+#if !HAVE(NULLPTR)
+ RetainPtr& operator=(std::nullptr_t) { clear(); return *this; }
+#endif
void adoptCF(PtrType);
void adoptNS(PtrType);
void swap(RetainPtr&);
+ // FIXME: Remove releaseRef once we change all callers to call leakRef instead.
+ PtrType releaseRef() { return leakRef(); }
+
private:
+ static T* hashTableDeletedValue() { return reinterpret_cast<T*>(-1); }
+
PtrType m_ptr;
};
- template <typename T> inline RetainPtr<T>& RetainPtr<T>::operator=(const RetainPtr<T>& o)
+ template<typename T> template<typename U> inline RetainPtr<T>::RetainPtr(const RetainPtr<U>& o)
+ : m_ptr(o.get())
+ {
+ if (PtrType ptr = m_ptr)
+ CFRetain(ptr);
+ }
+
+ template<typename T> inline void RetainPtr<T>::clear()
+ {
+ if (PtrType ptr = m_ptr) {
+ m_ptr = 0;
+ CFRelease(ptr);
+ }
+ }
+
+ template<typename T> inline typename RetainPtr<T>::PtrType RetainPtr<T>::leakRef()
+ {
+ PtrType ptr = m_ptr;
+ m_ptr = 0;
+ return ptr;
+ }
+
+ template<typename T> inline RetainPtr<T>& RetainPtr<T>::operator=(const RetainPtr<T>& o)
{
PtrType optr = o.get();
if (optr)
return *this;
}
- template <typename T> template <typename U> inline RetainPtr<T>& RetainPtr<T>::operator=(const RetainPtr<U>& o)
+ template<typename T> template<typename U> inline RetainPtr<T>& RetainPtr<T>::operator=(const RetainPtr<U>& o)
{
PtrType optr = o.get();
if (optr)
return *this;
}
- template <typename T> inline RetainPtr<T>& RetainPtr<T>::operator=(PtrType optr)
+ template<typename T> inline RetainPtr<T>& RetainPtr<T>::operator=(PtrType optr)
{
if (optr)
CFRetain(optr);
return *this;
}
- template <typename T> inline void RetainPtr<T>::adoptCF(PtrType optr)
+ template<typename T> inline void RetainPtr<T>::adoptCF(PtrType optr)
{
PtrType ptr = m_ptr;
m_ptr = optr;
CFRelease(ptr);
}
- template <typename T> inline void RetainPtr<T>::adoptNS(PtrType optr)
+ template<typename T> inline void RetainPtr<T>::adoptNS(PtrType optr)
{
adoptNSReference(optr);
CFRelease(ptr);
}
- template <typename T> template <typename U> inline RetainPtr<T>& RetainPtr<T>::operator=(U* optr)
+ template<typename T> template<typename U> inline RetainPtr<T>& RetainPtr<T>::operator=(U* optr)
{
if (optr)
CFRetain(optr);
return *this;
}
- template <class T> inline void RetainPtr<T>::swap(RetainPtr<T>& o)
+ template<typename T> inline void RetainPtr<T>::swap(RetainPtr<T>& o)
{
std::swap(m_ptr, o.m_ptr);
}
- template <class T> inline void swap(RetainPtr<T>& a, RetainPtr<T>& b)
+ template<typename T> inline void swap(RetainPtr<T>& a, RetainPtr<T>& b)
{
a.swap(b);
}
- template <typename T, typename U> inline bool operator==(const RetainPtr<T>& a, const RetainPtr<U>& b)
+ template<typename T, typename U> inline bool operator==(const RetainPtr<T>& a, const RetainPtr<U>& b)
{
return a.get() == b.get();
}
- template <typename T, typename U> inline bool operator==(const RetainPtr<T>& a, U* b)
+ template<typename T, typename U> inline bool operator==(const RetainPtr<T>& a, U* b)
{
return a.get() == b;
}
- template <typename T, typename U> inline bool operator==(T* a, const RetainPtr<U>& b)
+ template<typename T, typename U> inline bool operator==(T* a, const RetainPtr<U>& b)
{
return a == b.get();
}
- template <typename T, typename U> inline bool operator!=(const RetainPtr<T>& a, const RetainPtr<U>& b)
+ template<typename T, typename U> inline bool operator!=(const RetainPtr<T>& a, const RetainPtr<U>& b)
{
return a.get() != b.get();
}
- template <typename T, typename U> inline bool operator!=(const RetainPtr<T>& a, U* b)
+ template<typename T, typename U> inline bool operator!=(const RetainPtr<T>& a, U* b)
{
return a.get() != b;
}
- template <typename T, typename U> inline bool operator!=(T* a, const RetainPtr<U>& b)
+ template<typename T, typename U> inline bool operator!=(T* a, const RetainPtr<U>& b)
{
return a != b.get();
}
+
+ template<typename P> struct HashTraits<RetainPtr<P> > : SimpleClassHashTraits<RetainPtr<P> > { };
+
+ template<typename P> struct PtrHash<RetainPtr<P> > : PtrHash<P*> {
+ using PtrHash<P*>::hash;
+ static unsigned hash(const RetainPtr<P>& key) { return hash(key.get()); }
+ using PtrHash<P*>::equal;
+ static bool equal(const RetainPtr<P>& a, const RetainPtr<P>& b) { return a == b; }
+ static bool equal(P* a, const RetainPtr<P>& b) { return a == b; }
+ static bool equal(const RetainPtr<P>& a, P* b) { return a == b; }
+ };
+
+ template<typename P> struct DefaultHash<RetainPtr<P> > { typedef PtrHash<RetainPtr<P> > Hash; };
} // namespace WTF
--- /dev/null
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// A straightforward SHA-1 implementation based on RFC 3174.
+// http://www.ietf.org/rfc/rfc3174.txt
+// The names of functions and variables (such as "a", "b", and "f") follow notations in RFC 3174.
+
+#include "config.h"
+#include "SHA1.h"
+
+#include "Assertions.h"
+#ifndef NDEBUG
+#include "StringExtras.h"
+#include "text/CString.h"
+#endif
+
+namespace WTF {
+
+#ifdef NDEBUG
+static inline void testSHA1() { }
+#else
+static bool isTestSHA1Done;
+
+static void expectSHA1(CString input, int repeat, CString expected)
+{
+ SHA1 sha1;
+ for (int i = 0; i < repeat; ++i)
+ sha1.addBytes(reinterpret_cast<const uint8_t*>(input.data()), input.length());
+ Vector<uint8_t, 20> digest;
+ sha1.computeHash(digest);
+ char* buffer = 0;
+ CString actual = CString::newUninitialized(40, buffer);
+ for (size_t i = 0; i < 20; ++i) {
+ snprintf(buffer, 3, "%02X", digest.at(i));
+ buffer += 2;
+ }
+ ASSERT_WITH_MESSAGE(actual == expected, "input: %s, repeat: %d, actual: %s, expected: %s", input.data(), repeat, actual.data(), expected.data());
+}
+
+static void testSHA1()
+{
+ if (isTestSHA1Done)
+ return;
+ isTestSHA1Done = true;
+
+ // Examples taken from sample code in RFC 3174.
+ expectSHA1("abc", 1, "A9993E364706816ABA3E25717850C26C9CD0D89D");
+ expectSHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 1, "84983E441C3BD26EBAAE4AA1F95129E5E54670F1");
+ expectSHA1("a", 1000000, "34AA973CD4C4DAA4F61EEB2BDBAD27316534016F");
+ expectSHA1("0123456701234567012345670123456701234567012345670123456701234567", 10, "DEA356A2CDDD90C7A7ECEDC5EBB563934F460452");
+}
+#endif
+
+static inline uint32_t f(int t, uint32_t b, uint32_t c, uint32_t d)
+{
+ ASSERT(t >= 0 && t < 80);
+ if (t < 20)
+ return (b & c) | ((~b) & d);
+ if (t < 40)
+ return b ^ c ^ d;
+ if (t < 60)
+ return (b & c) | (b & d) | (c & d);
+ return b ^ c ^ d;
+}
+
+static inline uint32_t k(int t)
+{
+ ASSERT(t >= 0 && t < 80);
+ if (t < 20)
+ return 0x5a827999;
+ if (t < 40)
+ return 0x6ed9eba1;
+ if (t < 60)
+ return 0x8f1bbcdc;
+ return 0xca62c1d6;
+}
+
+static inline uint32_t rotateLeft(int n, uint32_t x)
+{
+ ASSERT(n >= 0 && n < 32);
+ return (x << n) | (x >> (32 - n));
+}
+
+SHA1::SHA1()
+{
+ // FIXME: Move unit tests somewhere outside the constructor. See bug 55853.
+ testSHA1();
+ reset();
+}
+
+void SHA1::addBytes(const uint8_t* input, size_t length)
+{
+ while (length--) {
+ ASSERT(m_cursor < 64);
+ m_buffer[m_cursor++] = *input++;
+ ++m_totalBytes;
+ if (m_cursor == 64)
+ processBlock();
+ }
+}
+
+void SHA1::computeHash(Vector<uint8_t, 20>& digest)
+{
+ finalize();
+
+ digest.clear();
+ digest.resize(20);
+ for (size_t i = 0; i < 5; ++i) {
+ // Treat hashValue as a big-endian value.
+ uint32_t hashValue = m_hash[i];
+ for (int j = 0; j < 4; ++j) {
+ digest[4 * i + (3 - j)] = hashValue & 0xFF;
+ hashValue >>= 8;
+ }
+ }
+
+ reset();
+}
+
+void SHA1::finalize()
+{
+ ASSERT(m_cursor < 64);
+ m_buffer[m_cursor++] = 0x80;
+ if (m_cursor > 56) {
+ // Pad out to next block.
+ while (m_cursor < 64)
+ m_buffer[m_cursor++] = 0x00;
+ processBlock();
+ }
+
+ for (size_t i = m_cursor; i < 56; ++i)
+ m_buffer[i] = 0x00;
+
+ // Write the length as a big-endian 64-bit value.
+ uint64_t bits = m_totalBytes * 8;
+ for (int i = 0; i < 8; ++i) {
+ m_buffer[56 + (7 - i)] = bits & 0xFF;
+ bits >>= 8;
+ }
+ m_cursor = 64;
+ processBlock();
+}
+
+void SHA1::processBlock()
+{
+ ASSERT(m_cursor == 64);
+
+ uint32_t w[80] = { 0 };
+ for (int t = 0; t < 16; ++t)
+ w[t] = (m_buffer[t * 4] << 24) | (m_buffer[t * 4 + 1] << 16) | (m_buffer[t * 4 + 2] << 8) | m_buffer[t * 4 + 3];
+ for (int t = 16; t < 80; ++t)
+ w[t] = rotateLeft(1, w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16]);
+
+ uint32_t a = m_hash[0];
+ uint32_t b = m_hash[1];
+ uint32_t c = m_hash[2];
+ uint32_t d = m_hash[3];
+ uint32_t e = m_hash[4];
+
+ for (int t = 0; t < 80; ++t) {
+ uint32_t temp = rotateLeft(5, a) + f(t, b, c, d) + e + w[t] + k(t);
+ e = d;
+ d = c;
+ c = rotateLeft(30, b);
+ b = a;
+ a = temp;
+ }
+
+ m_hash[0] += a;
+ m_hash[1] += b;
+ m_hash[2] += c;
+ m_hash[3] += d;
+ m_hash[4] += e;
+
+ m_cursor = 0;
+}
+
+void SHA1::reset()
+{
+ m_cursor = 0;
+ m_totalBytes = 0;
+ m_hash[0] = 0x67452301;
+ m_hash[1] = 0xefcdab89;
+ m_hash[2] = 0x98badcfe;
+ m_hash[3] = 0x10325476;
+ m_hash[4] = 0xc3d2e1f0;
+
+ // Clear the buffer after use in case it's sensitive.
+ memset(m_buffer, 0, sizeof(m_buffer));
+}
+
+} // namespace WTF
--- /dev/null
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WTF_SHA1_h
+#define WTF_SHA1_h
+
+#include <wtf/Vector.h>
+
+namespace WTF {
+
+class SHA1 {
+public:
+ SHA1();
+
+ void addBytes(const Vector<uint8_t>& input)
+ {
+ addBytes(input.data(), input.size());
+ }
+ void addBytes(const uint8_t* input, size_t length);
+
+ // computeHash has a side effect of resetting the state of the object.
+ void computeHash(Vector<uint8_t, 20>&);
+
+private:
+ void finalize();
+ void processBlock();
+ void reset();
+
+ uint8_t m_buffer[64];
+ size_t m_cursor; // Number of bytes filled in m_buffer (0-64).
+ uint64_t m_totalBytes; // Number of bytes added so far.
+ uint32_t m_hash[5];
+};
+
+} // namespace WTF
+
+using WTF::SHA1;
+
+#endif // WTF_SHA1_h
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// A SentinelLinkedList is a linked list with dummy head and tail sentinels,
+// which allow for branch-less insertion and removal, and removal without a
+// pointer to the list.
+//
+// Requires: Node is a concrete class with:
+// Node(SentinelTag);
+// void setPrev(Node*);
+// Node* prev();
+// void setNext(Node*);
+// Node* next();
+
+#ifndef SentinelLinkedList_h
+#define SentinelLinkedList_h
+
+namespace WTF {
+
+enum SentinelTag { Sentinel };
+
+template <typename Node> class SentinelLinkedList {
+public:
+ typedef Node* iterator;
+
+ SentinelLinkedList();
+
+ void push(Node*);
+ static void remove(Node*);
+
+ iterator begin();
+ iterator end();
+
+private:
+ Node m_headSentinel;
+ Node m_tailSentinel;
+};
+
+template <typename Node> inline SentinelLinkedList<Node>::SentinelLinkedList()
+ : m_headSentinel(Sentinel)
+ , m_tailSentinel(Sentinel)
+{
+ m_headSentinel.setNext(&m_tailSentinel);
+ m_headSentinel.setPrev(0);
+
+ m_tailSentinel.setPrev(&m_headSentinel);
+ m_tailSentinel.setNext(0);
+}
+
+template <typename Node> inline typename SentinelLinkedList<Node>::iterator SentinelLinkedList<Node>::begin()
+{
+ return m_headSentinel.next();
+}
+
+template <typename Node> inline typename SentinelLinkedList<Node>::iterator SentinelLinkedList<Node>::end()
+{
+ return &m_tailSentinel;
+}
+
+template <typename Node> inline void SentinelLinkedList<Node>::push(Node* node)
+{
+ ASSERT(node);
+ Node* prev = &m_headSentinel;
+ Node* next = m_headSentinel.next();
+
+ node->setPrev(prev);
+ node->setNext(next);
+
+ prev->setNext(node);
+ next->setPrev(node);
+}
+
+template <typename Node> inline void SentinelLinkedList<Node>::remove(Node* node)
+{
+ Node* prev = node->prev();
+ Node* next = node->next();
+
+ prev->setNext(next);
+ next->setPrev(prev);
+}
+
+}
+
+using WTF::SentinelLinkedList;
+
+#endif
+
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SinglyLinkedList_h
+#define SinglyLinkedList_h
+
+namespace WTF {
+
+template <typename Node> class SinglyLinkedList {
+public:
+ SinglyLinkedList();
+
+ bool isEmpty();
+
+ void push(Node*);
+ Node* pop();
+
+private:
+ Node* m_head;
+};
+
+template <typename Node> inline SinglyLinkedList<Node>::SinglyLinkedList()
+ : m_head(0)
+{
+}
+
+template <typename Node> inline bool SinglyLinkedList<Node>::isEmpty()
+{
+ return !m_head;
+}
+
+template <typename Node> inline void SinglyLinkedList<Node>::push(Node* node)
+{
+ ASSERT(node);
+ node->setNext(m_head);
+ m_head = node;
+}
+
+template <typename Node> inline Node* SinglyLinkedList<Node>::pop()
+{
+ Node* tmp = m_head;
+ m_head = m_head->next();
+ return tmp;
+}
+
+}
+
+using WTF::SinglyLinkedList;
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <wtf/Assertions.h>
+#include <wtf/CrossThreadRefCounted.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
+
+namespace WTF {
+
+#ifndef NDEBUG
+struct StructWithIntAndTwoBools { int a; bool b; bool c; };
+static const size_t refCountedExtraDebugSize = sizeof(StructWithIntAndTwoBools) - sizeof(int);
+#else
+static const size_t refCountedExtraDebugSize = 0;
+#endif
+
+COMPILE_ASSERT(sizeof(OwnPtr<int>) == sizeof(int*), OwnPtr_should_stay_small);
+COMPILE_ASSERT(sizeof(PassRefPtr<RefCounted<int> >) == sizeof(int*), PassRefPtr_should_stay_small);
+COMPILE_ASSERT(sizeof(RefCounted<int>) == sizeof(int) + refCountedExtraDebugSize, RefCounted_should_stay_small);
+COMPILE_ASSERT(sizeof(RefCountedCustomAllocated<int>) == sizeof(int) + refCountedExtraDebugSize, RefCountedCustomAllocated_should_stay_small);
+COMPILE_ASSERT(sizeof(RefPtr<RefCounted<int> >) == sizeof(int*), RefPtr_should_stay_small);
+COMPILE_ASSERT(sizeof(Vector<int>) == 3 * sizeof(int*), Vector_should_stay_small);
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "config.h"
+#include "StackBounds.h"
+
+#if OS(DARWIN)
+
+#include <mach/task.h>
+#include <mach/thread_act.h>
+#include <pthread.h>
+
+#elif OS(WINDOWS)
+
+#include <windows.h>
+
+#elif OS(HAIKU)
+
+#include <OS.h>
+
+#elif OS(SOLARIS)
+
+#include <thread.h>
+
+#elif OS(QNX)
+
+#include <fcntl.h>
+#include <sys/procfs.h>
+#include <stdio.h>
+#include <errno.h>
+
+#elif OS(UNIX)
+
+#include <pthread.h>
+#if HAVE(PTHREAD_NP_H)
+#include <pthread_np.h>
+#endif
+
+#endif
+
+#include <WTFThreadData.h>
+
+namespace WTF {
+
+// Bug 26276 - Need a mechanism to determine stack extent
+//
+// These platforms should now be working correctly:
+// DARWIN, QNX, UNIX, SYMBIAN
+// These platforms are not:
+// WINDOWS, SOLARIS, OPENBSD, HAIKU, WINCE
+//
+// FIXME: remove this! - this code unsafely guesses at stack sizes!
+#if OS(WINDOWS) || OS(SOLARIS) || OS(OPENBSD) || OS(HAIKU)
+// Based on the current limit used by the JSC parser, guess the stack size.
+static const ptrdiff_t estimatedStackSize = 128 * sizeof(void*) * 1024;
+// This method assumes the stack is growing downwards.
+static void* estimateStackBound(void* origin)
+{
+ return static_cast<char*>(origin) - estimatedStackSize;
+}
+#endif
+
+#if OS(DARWIN)
+
+void StackBounds::initialize()
+{
+ pthread_t thread = pthread_self();
+ m_origin = pthread_get_stackaddr_np(thread);
+ m_bound = static_cast<char*>(m_origin) - pthread_get_stacksize_np(thread);
+}
+
+void StackBounds::checkConsistency() const
+{
+#if !ASSERT_DISABLED
+ // Skip consistency check if this StackBounds was initialized
+ // on a different thread than the current thread.
+ const StackBounds* stack = &wtfThreadData().stack();
+ if (stack != this)
+ return;
+
+ void* currentPosition = ¤tPosition;
+ ASSERT(m_origin != m_bound);
+ ASSERT(isGrowingDownward()
+ ? (currentPosition < m_origin && currentPosition > m_bound)
+ : (currentPosition > m_origin && currentPosition < m_bound));
+#endif
+}
+
+#elif OS(QNX)
+
+void StackBounds::initialize()
+{
+ void* stackBase = 0;
+ size_t stackSize = 0;
+ pthread_t thread = pthread_self();
+
+ struct _debug_thread_info threadInfo;
+ memset(&threadInfo, 0, sizeof(threadInfo));
+ threadInfo.tid = pthread_self();
+ int fd = open("/proc/self", O_RDONLY);
+ if (fd == -1) {
+ LOG_ERROR("Unable to open /proc/self (errno: %d)", errno);
+ CRASH();
+ }
+ devctl(fd, DCMD_PROC_TIDSTATUS, &threadInfo, sizeof(threadInfo), 0);
+ close(fd);
+ stackBase = reinterpret_cast<void*>(threadInfo.stkbase);
+ stackSize = threadInfo.stksize;
+ ASSERT(stackBase);
+
+ m_bound = stackBase;
+ m_origin = static_cast<char*>(stackBase) + stackSize;
+}
+
+#elif OS(SOLARIS)
+
+void StackBounds::initialize()
+{
+ stack_t s;
+ thr_stksegment(&s);
+ m_origin = s.ss_sp;
+ m_bound = estimateStackBound(m_origin);
+}
+
+#elif OS(OPENBSD)
+
+void StackBounds::initialize()
+{
+ pthread_t thread = pthread_self();
+ stack_t stack;
+ pthread_stackseg_np(thread, &stack);
+ m_origin = stack.ss_sp;
+ m_bound = estimateStackBound(m_origin);
+}
+
+#elif OS(SYMBIAN)
+
+void StackBounds::initialize()
+{
+ TThreadStackInfo info;
+ RThread thread;
+ thread.StackInfo(info);
+ m_origin = (void*)info.iBase;
+ m_bound = (void*)info.iLimit;
+}
+
+#elif OS(HAIKU)
+
+void StackBounds::initialize()
+{
+ thread_info threadInfo;
+ get_thread_info(find_thread(NULL), &threadInfo);
+ m_origin = threadInfo.stack_end;
+ m_bound = estimateStackBound(m_origin);
+}
+
+#elif OS(UNIX)
+
+void StackBounds::initialize()
+{
+ void* stackBase = 0;
+ size_t stackSize = 0;
+
+ pthread_t thread = pthread_self();
+ pthread_attr_t sattr;
+ pthread_attr_init(&sattr);
+#if HAVE(PTHREAD_NP_H) || OS(NETBSD)
+ // e.g. on FreeBSD 5.4, neundorf@kde.org
+ pthread_attr_get_np(thread, &sattr);
+#else
+ // FIXME: this function is non-portable; other POSIX systems may have different np alternatives
+ pthread_getattr_np(thread, &sattr);
+#endif
+ int rc = pthread_attr_getstack(&sattr, &stackBase, &stackSize);
+ (void)rc; // FIXME: Deal with error code somehow? Seems fatal.
+ ASSERT(stackBase);
+ pthread_attr_destroy(&sattr);
+ m_bound = stackBase;
+ m_origin = static_cast<char*>(stackBase) + stackSize;
+}
+
+#elif OS(WINCE)
+
+static bool detectGrowingDownward(void* previousFrame)
+{
+ // Find the address of this stack frame by taking the address of a local variable.
+ int thisFrame;
+ return previousFrame > &thisFrame;
+}
+
+static inline bool isPageWritable(void* page)
+{
+ MEMORY_BASIC_INFORMATION memoryInformation;
+ DWORD result = VirtualQuery(page, &memoryInformation, sizeof(memoryInformation));
+
+ // return false on error, including ptr outside memory
+ if (result != sizeof(memoryInformation))
+ return false;
+
+ DWORD protect = memoryInformation.Protect & ~(PAGE_GUARD | PAGE_NOCACHE);
+ return protect == PAGE_READWRITE
+ || protect == PAGE_WRITECOPY
+ || protect == PAGE_EXECUTE_READWRITE
+ || protect == PAGE_EXECUTE_WRITECOPY;
+}
+
+static inline void* getLowerStackBound(char* currentPage, DWORD pageSize)
+{
+ while (currentPage > 0) {
+ // check for underflow
+ if (currentPage >= reinterpret_cast<char*>(pageSize))
+ currentPage -= pageSize;
+ else
+ currentPage = 0;
+
+ if (!isPageWritable(currentPage))
+ return currentPage + pageSize;
+ }
+
+ return 0;
+}
+
+static inline void* getUpperStackBound(char* currentPage, DWORD pageSize)
+{
+ do {
+ // guaranteed to complete because isPageWritable returns false at end of memory
+ currentPage += pageSize;
+ } while (isPageWritable(currentPage));
+
+ return currentPage - pageSize;
+}
+
+void StackBounds::initialize()
+{
+ // find the address of this stack frame by taking the address of a local variable
+ void* thisFrame = &thisFrame;
+ bool isGrowingDownward = detectGrowingDownward(thisFrame);
+
+ SYSTEM_INFO systemInfo;
+ GetSystemInfo(&systemInfo);
+ DWORD pageSize = systemInfo.dwPageSize;
+
+ // scan all of memory starting from this frame, and return the last writeable page found
+ char* currentPage = reinterpret_cast<char*>(reinterpret_cast<DWORD>(thisFrame) & ~(pageSize - 1));
+ void* lowerStackBound = getLowerStackBound(currentPage, pageSize);
+ void* upperStackBound = getUpperStackBound(currentPage, pageSize);
+
+ m_origin = isGrowingDownward ? upperStackBound : lowerStackBound;
+ m_bound = isGrowingDownward ? lowerStackBound : upperStackBound;
+}
+
+#elif OS(WINDOWS)
+
+void StackBounds::initialize()
+{
+#if CPU(X86) && COMPILER(MSVC)
+ // offset 0x18 from the FS segment register gives a pointer to
+ // the thread information block for the current thread
+ NT_TIB* pTib;
+ __asm {
+ MOV EAX, FS:[18h]
+ MOV pTib, EAX
+ }
+ m_origin = static_cast<void*>(pTib->StackBase);
+#elif CPU(X86) && COMPILER(GCC)
+ // offset 0x18 from the FS segment register gives a pointer to
+ // the thread information block for the current thread
+ NT_TIB* pTib;
+ asm ( "movl %%fs:0x18, %0\n"
+ : "=r" (pTib)
+ );
+ m_origin = static_cast<void*>(pTib->StackBase);
+#elif CPU(X86_64)
+ PNT_TIB64 pTib = reinterpret_cast<PNT_TIB64>(NtCurrentTeb());
+ m_origin = reinterpret_cast<void*>(pTib->StackBase);
+#else
+#error Need a way to get the stack bounds on this platform (Windows)
+#endif
+ // Looks like we should be able to get pTib->StackLimit
+ m_bound = estimateStackBound(m_origin);
+}
+
+#else
+#error Need a way to get the stack bounds on this platform
+#endif
+
+} // namespace WTF
--- /dev/null
+/*
+ * Copyright (C) 2010 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef StackBounds_h
+#define StackBounds_h
+
+namespace WTF {
+
+class StackBounds {
+ // recursionCheck() / recursionLimit() tests (by default)
+ // that we are at least this far from the end of the stack.
+ const static size_t s_defaultAvailabilityDelta = 4096;
+
+public:
+ StackBounds()
+ : m_origin(0)
+ , m_bound(0)
+ {
+ }
+
+ static StackBounds currentThreadStackBounds()
+ {
+ StackBounds bounds;
+ bounds.initialize();
+ bounds.checkConsistency();
+ return bounds;
+ }
+
+ void* origin() const
+ {
+ ASSERT(m_origin);
+ return m_origin;
+ }
+
+ void* current() const
+ {
+ checkConsistency();
+ void* currentPosition = ¤tPosition;
+ return currentPosition;
+ }
+
+ void* recursionLimit(size_t minAvailableDelta = s_defaultAvailabilityDelta) const
+ {
+ checkConsistency();
+ return isGrowingDownward()
+ ? static_cast<char*>(m_bound) + minAvailableDelta
+ : static_cast<char*>(m_bound) - minAvailableDelta;
+ }
+
+ bool recursionCheck(size_t minAvailableDelta = s_defaultAvailabilityDelta) const
+ {
+ checkConsistency();
+ return isGrowingDownward()
+ ? current() >= recursionLimit(minAvailableDelta)
+ : current() <= recursionLimit(minAvailableDelta);
+ }
+
+private:
+ void initialize();
+
+
+ bool isGrowingDownward() const
+ {
+ ASSERT(m_origin && m_bound);
+#if OS(WINCE)
+ return m_origin > m_bound;
+#else
+ return true;
+#endif
+ }
+
+ void checkConsistency() const;
+
+ void* m_origin;
+ void* m_bound;
+};
+
+} // namespace WTF
+
+using WTF::StackBounds;
+
+#endif
#define STRINGIZE(exp) #exp
#define STRINGIZE_VALUE_OF(exp) STRINGIZE(exp)
+/*
+ * The reinterpret_cast<Type1*>([pointer to Type2]) expressions - where
+ * sizeof(Type1) > sizeof(Type2) - cause the following warning on ARM with GCC:
+ * increases required alignment of target type.
+ *
+ * An implicit or an extra static_cast<void*> bypasses the warning.
+ * For more info see the following bugzilla entries:
+ * - https://bugs.webkit.org/show_bug.cgi?id=38045
+ * - http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43976
+ */
+#if (CPU(ARM) || CPU(MIPS)) && COMPILER(GCC)
+template<typename Type>
+bool isPointerTypeAlignmentOkay(Type* ptr)
+{
+ return !(reinterpret_cast<intptr_t>(ptr) % __alignof__(Type));
+}
+
+template<typename TypePtr>
+TypePtr reinterpret_cast_ptr(void* ptr)
+{
+ ASSERT(isPointerTypeAlignmentOkay(reinterpret_cast<TypePtr>(ptr)));
+ return reinterpret_cast<TypePtr>(ptr);
+}
+
+template<typename TypePtr>
+TypePtr reinterpret_cast_ptr(const void* ptr)
+{
+ ASSERT(isPointerTypeAlignmentOkay(reinterpret_cast<TypePtr>(ptr)));
+ return reinterpret_cast<TypePtr>(ptr);
+}
+#else
+#define reinterpret_cast_ptr reinterpret_cast
+#endif
+
namespace WTF {
- /*
- * C++'s idea of a reinterpret_cast lacks sufficient cojones.
- */
- template<typename TO, typename FROM>
- TO bitwise_cast(FROM from)
- {
- COMPILE_ASSERT(sizeof(TO) == sizeof(FROM), WTF_bitwise_cast_sizeof_casted_types_is_equal);
- union {
- FROM from;
- TO to;
- } u;
- u.from = from;
- return u.to;
- }
+/*
+ * C++'s idea of a reinterpret_cast lacks sufficient cojones.
+ */
+template<typename TO, typename FROM>
+inline TO bitwise_cast(FROM from)
+{
+ COMPILE_ASSERT(sizeof(TO) == sizeof(FROM), WTF_bitwise_cast_sizeof_casted_types_is_equal);
+ union {
+ FROM from;
+ TO to;
+ } u;
+ u.from = from;
+ return u.to;
+}
+
+// Returns a count of the number of bits set in 'bits'.
+inline size_t bitCount(unsigned bits)
+{
+ bits = bits - ((bits >> 1) & 0x55555555);
+ bits = (bits & 0x33333333) + ((bits >> 2) & 0x33333333);
+ return (((bits + (bits >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24;
+}
+
+// Macro that returns a compile time constant with the length of an array, but gives an error if passed a non-array.
+template<typename T, size_t Size> char (&ArrayLengthHelperFunction(T (&)[Size]))[Size];
+#define WTF_ARRAY_LENGTH(array) sizeof(::WTF::ArrayLengthHelperFunction(array))
+
+// Efficient implementation that takes advantage of powers of two.
+template<size_t divisor> inline size_t roundUpToMultipleOf(size_t x)
+{
+ COMPILE_ASSERT(divisor && !(divisor & (divisor - 1)), divisor_is_a_power_of_two);
- // Returns a count of the number of bits set in 'bits'.
- inline size_t bitCount(unsigned bits)
- {
- bits = bits - ((bits >> 1) & 0x55555555);
- bits = (bits & 0x33333333) + ((bits >> 2) & 0x33333333);
- return (((bits + (bits >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24;
+ size_t remainderMask = divisor - 1;
+ return (x + remainderMask) & ~remainderMask;
+}
+
+// Binary search algorithm, calls extractKey on pre-sorted elements in array,
+// compares result with key (KeyTypes should be comparable with '--', '<', '>').
+// Optimized for cases where the array contains the key, checked by assertions.
+template<typename ArrayType, typename KeyType, KeyType(*extractKey)(ArrayType*)>
+inline ArrayType* binarySearch(ArrayType* array, size_t size, KeyType key)
+{
+ // The array must contain at least one element (pre-condition, array does conatin key).
+ // If the array only contains one element, no need to do the comparison.
+ while (size > 1) {
+ // Pick an element to check, half way through the array, and read the value.
+ int pos = (size - 1) >> 1;
+ KeyType val = extractKey(&array[pos]);
+
+ // If the key matches, success!
+ if (val == key)
+ return &array[pos];
+ // The item we are looking for is smaller than the item being check; reduce the value of 'size',
+ // chopping off the right hand half of the array.
+ else if (key < val)
+ size = pos;
+ // Discard all values in the left hand half of the array, up to and including the item at pos.
+ else {
+ size -= (pos + 1);
+ array += (pos + 1);
+ }
+
+ // 'size' should never reach zero.
+ ASSERT(size);
}
+
+ // If we reach this point we've chopped down to one element, no need to check it matches
+ ASSERT(size == 1);
+ ASSERT(key == extractKey(&array[0]));
+ return &array[0];
+}
} // namespace WTF
-#endif
+using WTF::binarySearch;
+using WTF::bitwise_cast;
+
+#endif // WTF_StdLibExtras_h
/*
- * Copyright (C) 2006 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2010 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
#include <stdarg.h>
#include <stdio.h>
+#include <string.h>
#if HAVE(STRINGS_H)
#include <strings.h>
va_start(args, format);
result = _vsnprintf(buffer, count, format, args);
va_end(args);
+
+ // In the case where the string entirely filled the buffer, _vsnprintf will not
+ // null-terminate it, but snprintf must.
+ if (count > 0)
+ buffer[count - 1] = '\0';
+
return result;
}
-#if COMPILER(MSVC7_OR_LOWER) || OS(WINCE)
-
-inline int vsnprintf(char* buffer, size_t count, const char* format, va_list args)
+inline double wtf_vsnprintf(char* buffer, size_t count, const char* format, va_list args)
{
- return _vsnprintf(buffer, count, format, args);
+ int result = _vsnprintf(buffer, count, format, args);
+
+ // In the case where the string entirely filled the buffer, _vsnprintf will not
+ // null-terminate it, but vsnprintf must.
+ if (count > 0)
+ buffer[count - 1] = '\0';
+
+ return result;
}
-#endif
+// Work around a difference in Microsoft's implementation of vsnprintf, where
+// vsnprintf does not null terminate the buffer. WebKit can rely on the null termination.
+#define vsnprintf(buffer, count, format, args) wtf_vsnprintf(buffer, count, format, args)
#if OS(WINCE)
#endif
-#if OS(WINDOWS) || OS(LINUX) || OS(SOLARIS)
-// FIXME: should check HAVE_STRNSTR
+#if !HAVE(STRNSTR)
inline char* strnstr(const char* buffer, const char* target, size_t bufferLength)
{
+++ /dev/null
-/*
- * Copyright (C) 2005, 2006, 2008, 2010 Apple Inc. All rights reserved.
- *
- * 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.
- *
- */
-#ifndef WTF_StringHashFunctions_h
-#define WTF_StringHashFunctions_h
-
-#include <wtf/unicode/Unicode.h>
-
-namespace WTF {
-
-// Golden ratio - arbitrary start value to avoid mapping all 0's to all 0's
-static const unsigned stringHashingStartValue = 0x9e3779b9U;
-
-// stringHash methods based on Paul Hsieh's SuperFastHash.
-// http://www.azillionmonkeys.com/qed/hash.html
-// char* data is interpreted as latin-encoded (zero extended to 16 bits).
-
-inline unsigned stringHash(const UChar* data, unsigned length)
-{
- unsigned hash = WTF::stringHashingStartValue;
- unsigned rem = length & 1;
- length >>= 1;
-
- // Main loop
- for (; length > 0; length--) {
- hash += data[0];
- unsigned tmp = (data[1] << 11) ^ hash;
- hash = (hash << 16) ^ tmp;
- data += 2;
- hash += hash >> 11;
- }
-
- // Handle end case
- if (rem) {
- hash += data[0];
- hash ^= hash << 11;
- hash += hash >> 17;
- }
-
- // Force "avalanching" of final 127 bits
- hash ^= hash << 3;
- hash += hash >> 5;
- hash ^= hash << 2;
- hash += hash >> 15;
- hash ^= hash << 10;
-
- hash &= 0x7fffffff;
-
- // this avoids ever returning a hash code of 0, since that is used to
- // signal "hash not computed yet", using a value that is likely to be
- // effectively the same as 0 when the low bits are masked
- if (hash == 0)
- hash = 0x40000000;
-
- return hash;
-}
-
-inline unsigned stringHash(const char* data, unsigned length)
-{
- unsigned hash = WTF::stringHashingStartValue;
- unsigned rem = length & 1;
- length >>= 1;
-
- // Main loop
- for (; length > 0; length--) {
- hash += static_cast<unsigned char>(data[0]);
- unsigned tmp = (static_cast<unsigned char>(data[1]) << 11) ^ hash;
- hash = (hash << 16) ^ tmp;
- data += 2;
- hash += hash >> 11;
- }
-
- // Handle end case
- if (rem) {
- hash += static_cast<unsigned char>(data[0]);
- hash ^= hash << 11;
- hash += hash >> 17;
- }
-
- // Force "avalanching" of final 127 bits
- hash ^= hash << 3;
- hash += hash >> 5;
- hash ^= hash << 2;
- hash += hash >> 15;
- hash ^= hash << 10;
-
- hash &= 0x7fffffff;
-
- // this avoids ever returning a hash code of 0, since that is used to
- // signal "hash not computed yet", using a value that is likely to be
- // effectively the same as 0 when the low bits are masked
- if (hash == 0)
- hash = 0x40000000;
-
- return hash;
-}
-
-inline unsigned stringHash(const char* data)
-{
- unsigned hash = WTF::stringHashingStartValue;
-
- // Main loop
- for (;;) {
- unsigned char b0 = data[0];
- if (!b0)
- break;
- unsigned char b1 = data[1];
- if (!b1) {
- hash += b0;
- hash ^= hash << 11;
- hash += hash >> 17;
- break;
- }
- hash += b0;
- unsigned tmp = (b1 << 11) ^ hash;
- hash = (hash << 16) ^ tmp;
- data += 2;
- hash += hash >> 11;
- }
-
- // Force "avalanching" of final 127 bits.
- hash ^= hash << 3;
- hash += hash >> 5;
- hash ^= hash << 2;
- hash += hash >> 15;
- hash ^= hash << 10;
-
- hash &= 0x7fffffff;
-
- // This avoids ever returning a hash code of 0, since that is used to
- // signal "hash not computed yet", using a value that is likely to be
- // effectively the same as 0 when the low bits are masked.
- if (hash == 0)
- hash = 0x40000000;
-
- return hash;
-}
-
-} // namespace WTF
-
-#endif // WTF_StringHashFunctions_h
--- /dev/null
+/*
+ * Copyright (C) 2005, 2006, 2008, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.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.
+ *
+ */
+#ifndef WTF_StringHasher_h
+#define WTF_StringHasher_h
+
+#include <wtf/unicode/Unicode.h>
+
+namespace WTF {
+
+// Golden ratio - arbitrary start value to avoid mapping all 0's to all 0's
+static const unsigned stringHashingStartValue = 0x9e3779b9U;
+
+// Paul Hsieh's SuperFastHash
+// http://www.azillionmonkeys.com/qed/hash.html
+// char* data is interpreted as latin-encoded (zero extended to 16 bits).
+class StringHasher {
+public:
+ inline StringHasher()
+ : m_hash(stringHashingStartValue)
+ , m_hasPendingCharacter(false)
+ , m_pendingCharacter(0)
+ {
+ }
+
+ inline void addCharacters(UChar a, UChar b)
+ {
+ ASSERT(!m_hasPendingCharacter);
+ addCharactersToHash(a, b);
+ }
+
+ inline void addCharacter(UChar ch)
+ {
+ if (m_hasPendingCharacter) {
+ addCharactersToHash(m_pendingCharacter, ch);
+ m_hasPendingCharacter = false;
+ return;
+ }
+
+ m_pendingCharacter = ch;
+ m_hasPendingCharacter = true;
+ }
+
+ inline unsigned hash() const
+ {
+ unsigned result = m_hash;
+
+ // Handle end case.
+ if (m_hasPendingCharacter) {
+ result += m_pendingCharacter;
+ result ^= result << 11;
+ result += result >> 17;
+ }
+
+ // Force "avalanching" of final 31 bits.
+ result ^= result << 3;
+ result += result >> 5;
+ result ^= result << 2;
+ result += result >> 15;
+ result ^= result << 10;
+
+ // First bit is used in UStringImpl for m_isIdentifier.
+ result &= 0x7fffffff;
+
+ // This avoids ever returning a hash code of 0, since that is used to
+ // signal "hash not computed yet", using a value that is likely to be
+ // effectively the same as 0 when the low bits are masked.
+ if (!result)
+ return 0x40000000;
+
+ return result;
+ }
+
+ template<typename T, UChar Converter(T)> static inline unsigned computeHash(const T* data, unsigned length)
+ {
+ StringHasher hasher;
+ bool rem = length & 1;
+ length >>= 1;
+
+ while (length--) {
+ hasher.addCharacters(Converter(data[0]), Converter(data[1]));
+ data += 2;
+ }
+
+ if (rem)
+ hasher.addCharacter(Converter(*data));
+
+ return hasher.hash();
+ }
+
+ template<typename T, UChar Converter(T)> static inline unsigned computeHash(const T* data)
+ {
+ StringHasher hasher;
+
+ while (true) {
+ UChar b0 = Converter(*data++);
+ if (!b0)
+ break;
+ UChar b1 = Converter(*data++);
+ if (!b1) {
+ hasher.addCharacter(b0);
+ break;
+ }
+
+ hasher.addCharacters(b0, b1);
+ }
+
+ return hasher.hash();
+ }
+
+ template<typename T> static inline unsigned computeHash(const T* data, unsigned length)
+ {
+ return computeHash<T, defaultCoverter>(data, length);
+ }
+
+ template<typename T> static inline unsigned computeHash(const T* data)
+ {
+ return computeHash<T, defaultCoverter>(data);
+ }
+
+ template<size_t length> static inline unsigned hashMemory(const void* data)
+ {
+ COMPILE_ASSERT(!(length % 4), length_must_be_a_multible_of_four);
+ return computeHash<UChar>(static_cast<const UChar*>(data), length / sizeof(UChar));
+ }
+
+ static inline unsigned hashMemory(const void* data, unsigned size)
+ {
+ ASSERT(!(size % 2));
+ return computeHash<UChar>(static_cast<const UChar*>(data), size / sizeof(UChar));
+ }
+
+private:
+ static inline UChar defaultCoverter(UChar ch)
+ {
+ return ch;
+ }
+
+ static inline UChar defaultCoverter(char ch)
+ {
+ return static_cast<unsigned char>(ch);
+ }
+
+ inline void addCharactersToHash(UChar a, UChar b)
+ {
+ m_hash += a;
+ unsigned tmp = (b << 11) ^ m_hash;
+ m_hash = (m_hash << 16) ^ tmp;
+ m_hash += m_hash >> 11;
+ }
+
+ unsigned m_hash;
+ bool m_hasPendingCharacter;
+ UChar m_pendingCharacter;
+};
+
+} // namespace WTF
+
+using WTF::StringHasher;
+
+#endif // WTF_StringHasher_h
// Ensure that the map contains initialized entries "x .. x+n-1".
// Returns true if successful, false if we could not allocate memory.
- bool Ensure(Number x, size_t n) {
+ bool Ensure(Number, size_t) {
// Nothing to do since flat array was allocate at start
return true;
}
// Copyright (c) 2005, 2006, Google Inc.
+// Copyright (c) 2010, Patrick Gansterer <paroga@paroga.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
#include <time.h> /* For nanosleep() */
-#include <sched.h> /* For sched_yield() */
-
#if HAVE(STDINT_H)
#include <stdint.h>
#elif HAVE(INTTYPES_H)
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
+#else
+#include <sched.h> /* For sched_yield() */
#endif
static void TCMalloc_SlowLock(volatile unsigned int* lockword);
#define SPINLOCK_INITIALIZER { 0 }
static void TCMalloc_SlowLock(volatile unsigned int* lockword) {
- sched_yield(); // Yield immediately since fast path failed
+// Yield immediately since fast path failed
+#if OS(WINDOWS)
+ Sleep(0);
+#else
+ sched_yield();
+#endif
while (true) {
int r;
#if COMPILER(GCC)
}
}
+#elif OS(WINDOWS)
+
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+
+static void TCMalloc_SlowLock(LPLONG lockword);
+
+// The following is a struct so that it can be initialized at compile time
+struct TCMalloc_SpinLock {
+
+ inline void Lock() {
+ if (InterlockedExchange(&m_lockword, 1))
+ TCMalloc_SlowLock(&m_lockword);
+ }
+
+ inline void Unlock() {
+ InterlockedExchange(&m_lockword, 0);
+ }
+
+ inline bool IsHeld() const {
+ return m_lockword != 0;
+ }
+
+ inline void Init() { m_lockword = 0; }
+
+ LONG m_lockword;
+};
+
+#define SPINLOCK_INITIALIZER { 0 }
+
+static void TCMalloc_SlowLock(LPLONG lockword) {
+ Sleep(0); // Yield immediately since fast path failed
+ while (InterlockedExchange(lockword, 1))
+ Sleep(2);
+}
+
#else
#include <pthread.h>
// Author: Sanjay Ghemawat
#include "config.h"
+#if !(defined(USE_SYSTEM_MALLOC) && USE_SYSTEM_MALLOC)
#include "TCSystemAlloc.h"
#include <algorithm>
-#include <fcntl.h>
#include "Assertions.h"
#include "TCSpinLock.h"
#include "UnusedParam.h"
// declared in TCSystemAlloc.h
#endif
+
+#endif // #if !(defined(USE_SYSTEM_MALLOC) && USE_SYSTEM_MALLOC)
+
--- /dev/null
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ThreadFunctionInvocation_h
+#define ThreadFunctionInvocation_h
+
+namespace WTF {
+
+typedef void* (*ThreadFunction)(void* argument);
+
+struct ThreadFunctionInvocation {
+ ThreadFunctionInvocation(ThreadFunction function, void* data)
+ : function(function)
+ , data(data)
+ {
+ }
+
+ ThreadFunction function;
+ void* data;
+};
+
+} // namespace WTF
+
+#endif // ThreadFunctionInvocation_h
#ifndef ThreadIdentifierDataPthreads_h
#define ThreadIdentifierDataPthreads_h
-#include <wtf/Noncopyable.h>
#include <wtf/Threading.h>
namespace WTF {
// Holds ThreadIdentifier in the thread-specific storage and employs pthreads-specific 2-pass destruction to reliably remove
// ThreadIdentifier from threadMap. It assumes regular ThreadSpecific types don't use multiple-pass destruction.
-class ThreadIdentifierData : public Noncopyable {
+class ThreadIdentifierData {
+ WTF_MAKE_NONCOPYABLE(ThreadIdentifierData);
public:
~ThreadIdentifierData();
--- /dev/null
+/*
+ * Copyright (C) 2007, 2008, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * Note: The implementations of InterlockedIncrement and InterlockedDecrement are based
+ * on atomic_increment and atomic_exchange_and_add from the Boost C++ Library. The license
+ * is virtually identical to the Apple license above but is included here for completeness.
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef ThreadSafeRefCounted_h
+#define ThreadSafeRefCounted_h
+
+#include "Platform.h"
+
+#include <wtf/Atomics.h>
+#include <wtf/DynamicAnnotations.h>
+#include <wtf/ThreadingPrimitives.h>
+
+namespace WTF {
+
+class ThreadSafeRefCountedBase {
+ WTF_MAKE_NONCOPYABLE(ThreadSafeRefCountedBase);
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ ThreadSafeRefCountedBase(int initialRefCount = 1)
+ : m_refCount(initialRefCount)
+ {
+ }
+
+ void ref()
+ {
+#if USE(LOCKFREE_THREADSAFEREFCOUNTED)
+ atomicIncrement(&m_refCount);
+#else
+ MutexLocker locker(m_mutex);
+ ++m_refCount;
+#endif
+ }
+
+ bool hasOneRef()
+ {
+ return refCount() == 1;
+ }
+
+ int refCount() const
+ {
+#if !USE(LOCKFREE_THREADSAFEREFCOUNTED)
+ MutexLocker locker(m_mutex);
+#endif
+ return static_cast<int const volatile &>(m_refCount);
+ }
+
+protected:
+ // Returns whether the pointer should be freed or not.
+ bool derefBase()
+ {
+#if USE(LOCKFREE_THREADSAFEREFCOUNTED)
+ WTF_ANNOTATE_HAPPENS_BEFORE(&m_refCount);
+ if (atomicDecrement(&m_refCount) <= 0) {
+ WTF_ANNOTATE_HAPPENS_AFTER(&m_refCount);
+ return true;
+ }
+#else
+ int refCount;
+ {
+ MutexLocker locker(m_mutex);
+ --m_refCount;
+ refCount = m_refCount;
+ }
+ if (refCount <= 0)
+ return true;
+#endif
+ return false;
+ }
+
+private:
+ template<class T>
+ friend class CrossThreadRefCounted;
+
+ int m_refCount;
+#if !USE(LOCKFREE_THREADSAFEREFCOUNTED)
+ mutable Mutex m_mutex;
+#endif
+};
+
+template<class T> class ThreadSafeRefCounted : public ThreadSafeRefCountedBase {
+public:
+ void deref()
+ {
+ if (derefBase())
+ delete static_cast<T*>(this);
+ }
+
+protected:
+ ThreadSafeRefCounted()
+ {
+ }
+};
+
+} // namespace WTF
+
+using WTF::ThreadSafeRefCounted;
+
+#endif // ThreadSafeRefCounted_h
+++ /dev/null
-/*
- * Copyright (C) 2007, 2008, 2010 Apple Inc. All rights reserved.
- * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *
- * Note: The implementations of InterlockedIncrement and InterlockedDecrement are based
- * on atomic_increment and atomic_exchange_and_add from the Boost C++ Library. The license
- * is virtually identical to the Apple license above but is included here for completeness.
- *
- * Boost Software License - Version 1.0 - August 17th, 2003
- *
- * Permission is hereby granted, free of charge, to any person or organization
- * obtaining a copy of the software and accompanying documentation covered by
- * this license (the "Software") to use, reproduce, display, distribute,
- * execute, and transmit the Software, and to prepare derivative works of the
- * Software, and to permit third-parties to whom the Software is furnished to
- * do so, all subject to the following:
- *
- * The copyright notices in the Software and this entire statement, including
- * the above license grant, this restriction and the following disclaimer,
- * must be included in all copies of the Software, in whole or in part, and
- * all derivative works of the Software, unless such copies or derivative
- * works are solely in the form of machine-executable object code generated by
- * a source language processor.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
- * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
- * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-#ifndef ThreadSafeShared_h
-#define ThreadSafeShared_h
-
-#include "Platform.h"
-
-#include <wtf/Atomics.h>
-#include <wtf/Noncopyable.h>
-#include <wtf/ThreadingPrimitives.h>
-
-namespace WTF {
-
-class ThreadSafeSharedBase : public Noncopyable {
-public:
- ThreadSafeSharedBase(int initialRefCount = 1)
- : m_refCount(initialRefCount)
- {
- }
-
- void ref()
- {
-#if USE(LOCKFREE_THREADSAFESHARED)
- atomicIncrement(&m_refCount);
-#else
- MutexLocker locker(m_mutex);
- ++m_refCount;
-#endif
- }
-
- bool hasOneRef()
- {
- return refCount() == 1;
- }
-
- int refCount() const
- {
-#if !USE(LOCKFREE_THREADSAFESHARED)
- MutexLocker locker(m_mutex);
-#endif
- return static_cast<int const volatile &>(m_refCount);
- }
-
-protected:
- // Returns whether the pointer should be freed or not.
- bool derefBase()
- {
-#if USE(LOCKFREE_THREADSAFESHARED)
- if (atomicDecrement(&m_refCount) <= 0)
- return true;
-#else
- int refCount;
- {
- MutexLocker locker(m_mutex);
- --m_refCount;
- refCount = m_refCount;
- }
- if (refCount <= 0)
- return true;
-#endif
- return false;
- }
-
-private:
- template<class T>
- friend class CrossThreadRefCounted;
-
- int m_refCount;
-#if !USE(LOCKFREE_THREADSAFESHARED)
- mutable Mutex m_mutex;
-#endif
-};
-
-template<class T> class ThreadSafeShared : public ThreadSafeSharedBase {
-public:
- ThreadSafeShared(int initialRefCount = 1)
- : ThreadSafeSharedBase(initialRefCount)
- {
- }
-
- void deref()
- {
- if (derefBase())
- delete static_cast<T*>(this);
- }
-};
-
-} // namespace WTF
-
-using WTF::ThreadSafeShared;
-
-#endif // ThreadSafeShared_h
#include <pthread.h>
#elif PLATFORM(QT)
#include <QThreadStorage>
+#elif PLATFORM(GTK)
+#include <glib.h>
#elif OS(WINDOWS)
#include <windows.h>
#endif
namespace WTF {
-#if !USE(PTHREADS) && !PLATFORM(QT) && OS(WINDOWS)
+#if !USE(PTHREADS) && !PLATFORM(QT) && !PLATFORM(GTK) && OS(WINDOWS)
// ThreadSpecificThreadExit should be called each time when a thread is detached.
// This is done automatically for threads created with WTF::createThread.
void ThreadSpecificThreadExit();
#endif
-template<typename T> class ThreadSpecific : public Noncopyable {
+template<typename T> class ThreadSpecific {
+ WTF_MAKE_NONCOPYABLE(ThreadSpecific);
public:
ThreadSpecific();
T* operator->();
operator T*();
T& operator*();
- ~ThreadSpecific();
+
+ void replace(T*);
private:
-#if !USE(PTHREADS) && !PLATFORM(QT) && OS(WINDOWS)
+#if !USE(PTHREADS) && !PLATFORM(QT) && !PLATFORM(GTK) && OS(WINDOWS)
friend void ThreadSpecificThreadExit();
#endif
+
+ // Not implemented. It's technically possible to destroy a thread specific key, but one would need
+ // to make sure that all values have been destroyed already (usually, that all threads that used it
+ // have exited). It's unlikely that any user of this call will be in that situation - and having
+ // a destructor defined can be confusing, given that it has such strong pre-requisites to work correctly.
+ ~ThreadSpecific();
T* get();
void set(T*);
void static destroy(void* ptr);
-#if USE(PTHREADS) || PLATFORM(QT) || OS(WINDOWS)
- struct Data : Noncopyable {
+#if USE(PTHREADS) || PLATFORM(QT) || PLATFORM(GTK) || OS(WINDOWS)
+ struct Data {
+ WTF_MAKE_NONCOPYABLE(Data);
+ public:
Data(T* value, ThreadSpecific<T>* owner) : value(value), owner(owner) {}
#if PLATFORM(QT)
~Data() { owner->destroy(this); }
T* value;
ThreadSpecific<T>* owner;
-#if !USE(PTHREADS) && !PLATFORM(QT)
+#if !USE(PTHREADS) && !PLATFORM(QT) && !PLATFORM(GTK)
void (*destructor)(void*);
#endif
};
pthread_key_t m_key;
#elif PLATFORM(QT)
QThreadStorage<Data*> m_key;
+#elif PLATFORM(GTK)
+ GStaticPrivate m_key;
#elif OS(WINDOWS)
int m_index;
#endif
{
}
-template<typename T>
-inline ThreadSpecific<T>::~ThreadSpecific()
-{
-}
-
template<typename T>
inline T* ThreadSpecific<T>::get()
{
CRASH();
}
-template<typename T>
-inline ThreadSpecific<T>::~ThreadSpecific()
-{
- pthread_key_delete(m_key); // Does not invoke destructor functions.
-}
-
template<typename T>
inline T* ThreadSpecific<T>::get()
{
}
template<typename T>
-inline ThreadSpecific<T>::~ThreadSpecific()
+inline T* ThreadSpecific<T>::get()
+{
+ Data* data = static_cast<Data*>(m_key.localData());
+ return data ? data->value : 0;
+}
+
+template<typename T>
+inline void ThreadSpecific<T>::set(T* ptr)
+{
+ ASSERT(!get());
+ Data* data = new Data(ptr, this);
+ m_key.setLocalData(data);
+}
+
+#elif PLATFORM(GTK)
+
+template<typename T>
+inline ThreadSpecific<T>::ThreadSpecific()
{
- // Does not invoke destructor functions. QThreadStorage will do it
+ g_static_private_init(&m_key);
}
template<typename T>
inline T* ThreadSpecific<T>::get()
{
- Data* data = static_cast<Data*>(m_key.localData());
+ Data* data = static_cast<Data*>(g_static_private_get(&m_key));
return data ? data->value : 0;
}
{
ASSERT(!get());
Data* data = new Data(ptr, this);
- m_key.setLocalData(data);
+ g_static_private_set(&m_key, data, destroy);
}
#elif OS(WINDOWS)
// We want get() to keep working while data destructor works, because it can be called indirectly by the destructor.
// Some pthreads implementations zero out the pointer before calling destroy(), so we temporarily reset it.
pthread_setspecific(data->owner->m_key, ptr);
+#elif PLATFORM(GTK)
+ // See comment as above
+ g_static_private_set(&data->owner->m_key, data, 0);
#endif
#if PLATFORM(QT)
// See comment as above
pthread_setspecific(data->owner->m_key, 0);
#elif PLATFORM(QT)
// Do nothing here
+#elif PLATFORM(GTK)
+ g_static_private_set(&data->owner->m_key, 0, 0);
#elif OS(WINDOWS)
TlsSetValue(tlsKeys()[data->owner->m_index], 0);
#else
if (!ptr) {
// Set up thread-specific value's memory pointer before invoking constructor, in case any function it calls
// needs to access the value, to avoid recursion.
- ptr = static_cast<T*>(fastMalloc(sizeof(T)));
+ ptr = static_cast<T*>(fastZeroedMalloc(sizeof(T)));
set(ptr);
new (ptr) T;
}
return *operator T*();
}
+template<typename T>
+inline void ThreadSpecific<T>::replace(T* newPtr)
+{
+ ASSERT(newPtr);
+ Data* data = static_cast<Data*>(pthread_getspecific(m_key));
+ ASSERT(data);
+ data->value->~T();
+ fastFree(data->value);
+ data->value = newPtr;
+}
+
}
#endif
#include "config.h"
#include "ThreadSpecific.h"
-#include <wtf/Noncopyable.h>
#if USE(PTHREADS)
#error This file should not be compiled by ports that do not use Windows native ThreadSpecific implementation.
namespace WTF {
-struct NewThreadContext : FastAllocBase {
+struct NewThreadContext {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
NewThreadContext(ThreadFunction entryPoint, void* data, const char* name)
: entryPoint(entryPoint)
, data(data)
#include <wtf/Locker.h>
#include <wtf/MainThread.h>
#include <wtf/Noncopyable.h>
-#include <wtf/ThreadSafeShared.h>
+#include <wtf/ThreadSafeRefCounted.h>
#include <wtf/ThreadingPrimitives.h>
// For portability, we do not use thread-safe statics natively supported by some compilers (e.g. gcc).
int waitForThreadCompletion(ThreadIdentifier, void**);
void detachThread(ThreadIdentifier);
+void yield();
void lockAtomicallyInitializedStaticMutex();
void unlockAtomicallyInitializedStaticMutex();
using WTF::currentThread;
using WTF::detachThread;
using WTF::waitForThreadCompletion;
+using WTF::yield;
#endif // Threading_h
#include "Platform.h"
#include <wtf/Assertions.h>
+#include <wtf/FastAllocBase.h>
#include <wtf/Locker.h>
#include <wtf/Noncopyable.h>
#include <pthread.h>
#elif PLATFORM(GTK)
#include "GOwnPtr.h"
-typedef struct _GMutex GMutex;
-typedef struct _GCond GCond;
#endif
#if PLATFORM(QT)
typedef void* PlatformCondition;
#endif
-class Mutex : public Noncopyable {
+class Mutex {
+ WTF_MAKE_NONCOPYABLE(Mutex); WTF_MAKE_FAST_ALLOCATED;
public:
Mutex();
~Mutex();
typedef Locker<Mutex> MutexLocker;
-class ReadWriteLock : public Noncopyable {
+class ReadWriteLock {
+ WTF_MAKE_NONCOPYABLE(ReadWriteLock);
public:
ReadWriteLock();
~ReadWriteLock();
PlatformReadWriteLock m_readWriteLock;
};
-class ThreadCondition : public Noncopyable {
+class ThreadCondition {
+ WTF_MAKE_NONCOPYABLE(ThreadCondition);
public:
ThreadCondition();
~ThreadCondition();
PlatformCondition m_condition;
};
+#if OS(WINDOWS)
+// The absoluteTime is in seconds, starting on January 1, 1970. The time is assumed to use the same time zone as WTF::currentTime().
+// Returns an interval in milliseconds suitable for passing to one of the Win32 wait functions (e.g., ::WaitForSingleObject).
+DWORD absoluteTimeToWaitTimeoutInterval(double absoluteTime);
+#endif
+
} // namespace WTF
using WTF::Mutex;
using WTF::MutexLocker;
using WTF::ThreadCondition;
+#if OS(WINDOWS)
+using WTF::absoluteTimeToWaitTimeoutInterval;
+#endif
+
#endif // ThreadingPrimitives_h
#if !COMPILER(MSVC)
#include <limits.h>
+#include <sched.h>
#include <sys/time.h>
#endif
#if OS(ANDROID)
-#include "jni_utility.h"
+#include "JNIUtility.h"
+#include "ThreadFunctionInvocation.h"
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+#endif
+
+#if OS(MAC_OS_X) && !defined(BUILDING_ON_LEOPARD)
+#include <objc/objc-auto.h>
#endif
namespace WTF {
}
#if OS(ANDROID)
-// On the Android platform, threads must be registered with the VM before they run.
-struct ThreadData {
- ThreadFunction entryPoint;
- void* arg;
-};
-
static void* runThreadWithRegistration(void* arg)
{
- ThreadData* data = static_cast<ThreadData*>(arg);
+ OwnPtr<ThreadFunctionInvocation> invocation = adoptPtr(static_cast<ThreadFunctionInvocation*>(arg));
JavaVM* vm = JSC::Bindings::getJavaVM();
JNIEnv* env;
void* ret = 0;
if (vm->AttachCurrentThread(&env, 0) == JNI_OK) {
- ret = data->entryPoint(data->arg);
+ ret = invocation->function(invocation->data);
vm->DetachCurrentThread();
}
- delete data;
return ret;
}
ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char*)
{
pthread_t threadHandle;
- ThreadData* threadData = new ThreadData();
- threadData->entryPoint = entryPoint;
- threadData->arg = data;
- if (pthread_create(&threadHandle, 0, runThreadWithRegistration, static_cast<void*>(threadData))) {
+ // On the Android platform, threads must be registered with the VM before they run.
+ OwnPtr<ThreadFunctionInvocation> invocation = adoptPtr(new ThreadFunctionInvocation(entryPoint, data));
+
+ if (pthread_create(&threadHandle, 0, runThreadWithRegistration, invocation.get())) {
LOG_ERROR("Failed to create pthread at entry point %p with data %p", entryPoint, data);
- delete threadData;
return 0;
}
+
+ // The thread will take ownership of invocation.
+ invocation.leakPtr();
+
return establishIdentifierForPthreadHandle(threadHandle);
}
#else
UNUSED_PARAM(threadName);
#endif
+#if OS(MAC_OS_X) && !defined(BUILDING_ON_LEOPARD)
+ // All threads that potentially use APIs above the BSD layer must be registered with the Objective-C
+ // garbage collector in case API implementations use garbage-collected memory.
+ objc_registerThreadWithCollector();
+#endif
+
ThreadIdentifier id = identifierByPthreadHandle(pthread_self());
ASSERT(id);
ThreadIdentifierData::initialize(id);
pthread_detach(pthreadHandle);
}
+void yield()
+{
+ sched_yield();
+}
+
ThreadIdentifier currentThread()
{
ThreadIdentifier id = ThreadIdentifierData::identifier();
Mutex::Mutex()
{
- pthread_mutex_init(&m_mutex, NULL);
+ pthread_mutexattr_t attr;
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
+
+ pthread_mutex_init(&m_mutex, &attr);
+
+ pthread_mutexattr_destroy(&attr);
}
Mutex::~Mutex()
#include "Threading.h"
#include "MainThread.h"
+#include "ThreadFunctionInvocation.h"
+#include <windows.h>
+#include <wtf/CurrentTime.h>
+#include <wtf/HashMap.h>
+#include <wtf/MathExtras.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/RandomNumberSeed.h>
+
#if !USE(PTHREADS) && OS(WINDOWS)
#include "ThreadSpecific.h"
#endif
+
#if !OS(WINCE)
#include <process.h>
#endif
+
#if HAVE(ERRNO_H)
#include <errno.h>
-#else
-#define NO_ERRNO
#endif
-#include <windows.h>
-#include <wtf/CurrentTime.h>
-#include <wtf/HashMap.h>
-#include <wtf/MathExtras.h>
-#include <wtf/RandomNumberSeed.h>
namespace WTF {
threadMap().remove(id);
}
-struct ThreadFunctionInvocation {
- ThreadFunctionInvocation(ThreadFunction function, void* data) : function(function), data(data) {}
-
- ThreadFunction function;
- void* data;
-};
-
static unsigned __stdcall wtfThreadEntryPoint(void* param)
{
- ThreadFunctionInvocation invocation = *static_cast<ThreadFunctionInvocation*>(param);
- delete static_cast<ThreadFunctionInvocation*>(param);
-
- void* result = invocation.function(invocation.data);
+ OwnPtr<ThreadFunctionInvocation> invocation = adoptPtr(static_cast<ThreadFunctionInvocation*>(param));
+ void* result = invocation->function(invocation->data);
#if !USE(PTHREADS) && OS(WINDOWS)
// Do the TLS cleanup.
{
unsigned threadIdentifier = 0;
ThreadIdentifier threadID = 0;
- ThreadFunctionInvocation* invocation = new ThreadFunctionInvocation(entryPoint, data);
+ OwnPtr<ThreadFunctionInvocation> invocation = adoptPtr(new ThreadFunctionInvocation(entryPoint, data));
#if OS(WINCE)
// This is safe on WINCE, since CRT is in the core and innately multithreaded.
// On desktop Windows, need to use _beginthreadex (not available on WinCE) if using any CRT functions
- HANDLE threadHandle = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)wtfThreadEntryPoint, invocation, 0, (LPDWORD)&threadIdentifier);
+ HANDLE threadHandle = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)wtfThreadEntryPoint, invocation.get(), 0, (LPDWORD)&threadIdentifier);
#else
- HANDLE threadHandle = reinterpret_cast<HANDLE>(_beginthreadex(0, 0, wtfThreadEntryPoint, invocation, 0, &threadIdentifier));
+ HANDLE threadHandle = reinterpret_cast<HANDLE>(_beginthreadex(0, 0, wtfThreadEntryPoint, invocation.get(), 0, &threadIdentifier));
#endif
if (!threadHandle) {
#if OS(WINCE)
LOG_ERROR("Failed to create thread at entry point %p with data %p: %ld", entryPoint, data, ::GetLastError());
-#elif defined(NO_ERRNO)
+#elif !HAVE(ERRNO_H)
LOG_ERROR("Failed to create thread at entry point %p with data %p.", entryPoint, data);
#else
LOG_ERROR("Failed to create thread at entry point %p with data %p: %ld", entryPoint, data, errno);
return 0;
}
+ // The thread will take ownership of invocation.
+ invocation.leakPtr();
+
threadID = static_cast<ThreadIdentifier>(threadIdentifier);
storeThreadHandleByIdentifier(threadIdentifier, threadHandle);
clearThreadHandleForIdentifier(threadID);
}
+void yield()
+{
+ ::Sleep(1);
+}
+
ThreadIdentifier currentThread()
{
return static_cast<ThreadIdentifier>(GetCurrentThreadId());
res = ReleaseSemaphore(m_blockLock, 1, 0);
ASSERT(res);
+ --mutex.m_recursionCount;
LeaveCriticalSection(&mutex.m_internalMutex);
// Main wait - use timeout.
}
EnterCriticalSection (&mutex.m_internalMutex);
+ ++mutex.m_recursionCount;
return !timedOut;
}
bool ThreadCondition::timedWait(Mutex& mutex, double absoluteTime)
{
- double currentTime = WTF::currentTime();
+ DWORD interval = absoluteTimeToWaitTimeoutInterval(absoluteTime);
- // Time is in the past - return immediately.
- if (absoluteTime < currentTime)
+ if (!interval) {
+ // Consider the wait to have timed out, even if our condition has already been signaled, to
+ // match the pthreads implementation.
return false;
-
- // Time is too far in the future (and would overflow unsigned long) - wait forever.
- if (absoluteTime - currentTime > static_cast<double>(INT_MAX) / 1000.0) {
- wait(mutex);
- return true;
}
- double intervalMilliseconds = (absoluteTime - currentTime) * 1000.0;
- return m_condition.timedWait(mutex.impl(), static_cast<unsigned long>(intervalMilliseconds));
+ return m_condition.timedWait(mutex.impl(), interval);
}
void ThreadCondition::signal()
m_condition.signal(true); // Unblock all threads.
}
+DWORD absoluteTimeToWaitTimeoutInterval(double absoluteTime)
+{
+ double currentTime = WTF::currentTime();
+
+ // Time is in the past - return immediately.
+ if (absoluteTime < currentTime)
+ return 0;
+
+ // Time is too far in the future (and would overflow unsigned long) - wait forever.
+ if (absoluteTime - currentTime > static_cast<double>(INT_MAX) / 1000.0)
+ return INFINITE;
+
+ return static_cast<DWORD>((absoluteTime - currentTime) * 1000.0);
+}
+
} // namespace WTF
COMPILE_ASSERT(!IsInteger<double>::value, WTF_IsInteger_double_false);
COMPILE_ASSERT(!IsInteger<float>::value, WTF_IsInteger_float_false);
+COMPILE_ASSERT(IsFloatingPoint<float>::value, WTF_IsFloatingPoint_float_true);
+COMPILE_ASSERT(IsFloatingPoint<double>::value, WTF_IsFloatingPoint_double_true);
+COMPILE_ASSERT(IsFloatingPoint<long double>::value, WTF_IsFloatingPoint_long_double_true);
+COMPILE_ASSERT(!IsFloatingPoint<int>::value, WTF_IsFloatingPoint_int_false);
+
COMPILE_ASSERT(IsPod<bool>::value, WTF_IsPod_bool_true);
COMPILE_ASSERT(IsPod<char>::value, WTF_IsPod_char_true);
COMPILE_ASSERT(IsPod<signed char>::value, WTF_IsPod_signed_char_true);
COMPILE_ASSERT((IsSameType<int, RemovePointer<int*>::Type>::value), WTF_Test_RemovePointer_int_pointer);
COMPILE_ASSERT((!IsSameType<int, RemovePointer<int**>::Type>::value), WTF_Test_RemovePointer_int_pointer_pointer);
+COMPILE_ASSERT((IsSameType<int, RemoveReference<int>::Type>::value), WTF_Test_RemoveReference_int);
+COMPILE_ASSERT((IsSameType<int, RemoveReference<int&>::Type>::value), WTF_Test_RemoveReference_int_reference);
+
} // namespace WTF
#if (defined(__GLIBCXX__) && (__GLIBCXX__ >= 20070724) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || (defined(_MSC_VER) && (_MSC_VER >= 1600))
#include <type_traits>
+#if defined(__GXX_EXPERIMENTAL_CXX0X__)
+#include <tr1/memory>
+#endif
#endif
namespace WTF {
// IsSameType<T, U>::value
//
// RemovePointer<T>::Type
+ // RemoveReference<T>::Type
// RemoveConst<T>::Type
// RemoveVolatile<T>::Type
// RemoveConstVolatile<T>::Type
template<> struct IsInteger<wchar_t> { static const bool value = true; };
#endif
+ template<typename T> struct IsFloatingPoint { static const bool value = false; };
+ template<> struct IsFloatingPoint<float> { static const bool value = true; };
+ template<> struct IsFloatingPoint<double> { static const bool value = true; };
+ template<> struct IsFloatingPoint<long double> { static const bool value = true; };
+
+ template<typename T> struct IsArithmetic { static const bool value = IsInteger<T>::value || IsFloatingPoint<T>::value; };
+
// IsPod is misnamed as it doesn't cover all plain old data (pod) types.
// Specifically, it doesn't allow for enums or for structs.
- template <typename T> struct IsPod { static const bool value = IsInteger<T>::value; };
- template <> struct IsPod<float> { static const bool value = true; };
- template <> struct IsPod<double> { static const bool value = true; };
- template <> struct IsPod<long double> { static const bool value = true; };
+ template <typename T> struct IsPod { static const bool value = IsArithmetic<T>::value; };
template <typename P> struct IsPod<P*> { static const bool value = true; };
template<typename T> class IsConvertibleToInteger {
typedef T Type;
};
+ template <typename T> struct RemoveReference {
+ typedef T Type;
+ };
+
+ template <typename T> struct RemoveReference<T&> {
+ typedef T Type;
+ };
+
#if (defined(__GLIBCXX__) && (__GLIBCXX__ >= 20070724) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || (defined(_MSC_VER) && (_MSC_VER >= 1600))
// GCC's libstdc++ 20070724 and later supports C++ TR1 type_traits in the std namespace.
/* don't use this for C++, it should only be used in plain C files or
ObjC methods, where leaving off the parameter name is not allowed. */
-#define UNUSED_PARAM(x) (void)x
+#include "Platform.h"
+
+#if COMPILER(INTEL) && !OS(WINDOWS) || COMPILER(RVCT)
+template<typename T>
+inline void unusedParam(T& x) { (void)x; }
+#define UNUSED_PARAM(variable) unusedParam(variable)
+#else
+#define UNUSED_PARAM(variable) (void)variable
+#endif
#endif /* WTF_UnusedParam_h */
#include <mach/vm_statistics.h>
-#if !defined(TARGETING_TIGER)
-
#if defined(VM_MEMORY_TCMALLOC)
#define VM_TAG_FOR_TCMALLOC_MEMORY VM_MAKE_TAG(VM_MEMORY_TCMALLOC)
#else
#define VM_TAG_FOR_REGISTERFILE_MEMORY VM_MAKE_TAG(65)
#endif // defined(VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE)
-#else // !defined(TARGETING_TIGER)
-
-// mmap on Tiger fails with tags that work on Leopard, so fall
-// back to Tiger-compatible tags (that also work on Leopard)
-// when targeting Tiger.
-#define VM_TAG_FOR_TCMALLOC_MEMORY -1
-#define VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY -1
-#define VM_TAG_FOR_REGISTERFILE_MEMORY -1
-
-#endif // !defined(TARGETING_TIGER)
-
-// Tags for vm_map and vm_allocate work on both Tiger and Leopard.
-
#if defined(VM_MEMORY_JAVASCRIPT_CORE)
#define VM_TAG_FOR_COLLECTOR_MEMORY VM_MAKE_TAG(VM_MEMORY_JAVASCRIPT_CORE)
#else
#include "FastAllocBase.h"
#include "Noncopyable.h"
#include "NotFound.h"
+#include "StdLibExtras.h"
#include "ValueCheck.h"
#include "VectorTraits.h"
#include <limits>
#include <utility>
+#include <wtf/Alignment.h>
#if PLATFORM(QT)
#include <QDataStream>
using std::min;
using std::max;
- // WTF_ALIGN_OF / WTF_ALIGNED
- #if COMPILER(GCC) || COMPILER(MINGW) || COMPILER(RVCT) || COMPILER(WINSCW)
- #define WTF_ALIGN_OF(type) __alignof__(type)
- #define WTF_ALIGNED(variable_type, variable, n) variable_type variable __attribute__((__aligned__(n)))
- #elif COMPILER(MSVC)
- #define WTF_ALIGN_OF(type) __alignof(type)
- #define WTF_ALIGNED(variable_type, variable, n) __declspec(align(n)) variable_type variable
- #else
- #error WTF_ALIGN macros need alignment control.
- #endif
-
- #if COMPILER(GCC) && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 303)
+ #if COMPILER(GCC) && !COMPILER(INTEL) && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 303)
typedef char __attribute__((__may_alias__)) AlignedBufferChar;
#else
typedef char AlignedBufferChar;
{
while (src != srcEnd) {
new (dst) T(*src);
+#if COMPILER(SUNCC) && __SUNPRO_CC <= 0x590
+ const_cast<T*>(src)->~T(); // Work around obscure SunCC 12 compiler bug.
+#else
src->~T();
+#endif
++dst;
++src;
}
};
template<typename T>
- class VectorBufferBase : public Noncopyable {
+ class VectorBufferBase {
+ WTF_MAKE_NONCOPYABLE(VectorBufferBase);
public:
void allocateBuffer(size_t newCapacity)
{
+ ASSERT(newCapacity);
m_capacity = newCapacity;
if (newCapacity > std::numeric_limits<size_t>::max() / sizeof(T))
CRASH();
bool tryAllocateBuffer(size_t newCapacity)
{
+ ASSERT(newCapacity);
if (newCapacity > std::numeric_limits<size_t>::max() / sizeof(T))
return false;
VectorBuffer(size_t capacity)
{
- allocateBuffer(capacity);
+ // Calling malloc(0) might take a lock and may actually do an
+ // allocation on some systems (e.g. Brew).
+ if (capacity)
+ allocateBuffer(capacity);
}
~VectorBuffer()
template<typename T, size_t inlineCapacity>
class VectorBuffer : private VectorBufferBase<T> {
+ WTF_MAKE_NONCOPYABLE(VectorBuffer);
private:
typedef VectorBufferBase<T> Base;
public:
void allocateBuffer(size_t newCapacity)
{
+ // FIXME: This should ASSERT(!m_buffer) to catch misuse/leaks.
if (newCapacity > inlineCapacity)
Base::allocateBuffer(newCapacity);
else {
using Base::m_capacity;
static const size_t m_inlineBufferSize = inlineCapacity * sizeof(T);
-#if PLATFORM(ARM)
- // FIXME: <rdar://problem/6546253&6546260>
- T* inlineBuffer() { return reinterpret_cast<T*>(static_cast<void*>(m_inlineBuffer.buffer)); }
-#else
- T* inlineBuffer() { return reinterpret_cast<T*>(m_inlineBuffer.buffer); }
-#endif
+ T* inlineBuffer() { return reinterpret_cast_ptr<T*>(m_inlineBuffer.buffer); }
AlignedBuffer<m_inlineBufferSize, WTF_ALIGN_OF(T)> m_inlineBuffer;
};
template<typename T, size_t inlineCapacity = 0>
- class Vector : public FastAllocBase {
+ class Vector {
+ WTF_MAKE_FAST_ALLOCATED;
private:
typedef VectorBuffer<T, inlineCapacity> Buffer;
typedef VectorTypeOperations<T> TypeOperations;
T& last() { return at(size() - 1); }
const T& last() const { return at(size() - 1); }
+ template<typename U> bool contains(const U&) const;
template<typename U> size_t find(const U&) const;
+ template<typename U> size_t reverseFind(const U&) const;
void shrink(size_t size);
void grow(size_t size);
m_buffer.swap(other.m_buffer);
}
+ void reverse();
+
void checkConsistency();
private:
return *this;
}
+// Works around an assert in VS2010. See https://connect.microsoft.com/VisualStudio/feedback/details/558044/std-copy-should-not-check-dest-when-first-last
+#if COMPILER(MSVC) && defined(_ITERATOR_DEBUG_LEVEL) && _ITERATOR_DEBUG_LEVEL
+ if (!begin())
+ return *this;
+#endif
+
std::copy(other.begin(), other.begin() + size(), begin());
TypeOperations::uninitializedCopy(other.begin() + size(), other.end(), end());
m_size = other.size();
return *this;
}
+ inline bool typelessPointersAreEqual(const void* a, const void* b) { return a == b; }
+
template<typename T, size_t inlineCapacity>
template<size_t otherCapacity>
Vector<T, inlineCapacity>& Vector<T, inlineCapacity>::operator=(const Vector<T, otherCapacity>& other)
{
- if (&other == this)
- return *this;
-
+ // If the inline capacities match, we should call the more specific
+ // template. If the inline capacities don't match, the two objects
+ // shouldn't be allocated the same address.
+ ASSERT(!typelessPointersAreEqual(&other, this));
+
if (size() > other.size())
shrink(other.size());
else if (other.size() > capacity()) {
return *this;
}
+// Works around an assert in VS2010. See https://connect.microsoft.com/VisualStudio/feedback/details/558044/std-copy-should-not-check-dest-when-first-last
+#if COMPILER(MSVC) && defined(_ITERATOR_DEBUG_LEVEL) && _ITERATOR_DEBUG_LEVEL
+ if (!begin())
+ return *this;
+#endif
+
std::copy(other.begin(), other.begin() + size(), begin());
TypeOperations::uninitializedCopy(other.begin() + size(), other.end(), end());
m_size = other.size();
return *this;
}
+ template<typename T, size_t inlineCapacity>
+ template<typename U>
+ bool Vector<T, inlineCapacity>::contains(const U& value) const
+ {
+ return find(value) != notFound;
+ }
+
template<typename T, size_t inlineCapacity>
template<typename U>
size_t Vector<T, inlineCapacity>::find(const U& value) const
return notFound;
}
+ template<typename T, size_t inlineCapacity>
+ template<typename U>
+ size_t Vector<T, inlineCapacity>::reverseFind(const U& value) const
+ {
+ for (size_t i = 1; i <= size(); ++i) {
+ const size_t index = size() - i;
+ if (at(index) == value)
+ return index;
+ }
+ return notFound;
+ }
+
template<typename T, size_t inlineCapacity>
void Vector<T, inlineCapacity>::fill(const T& val, size_t newSize)
{
m_size -= length;
}
+ template<typename T, size_t inlineCapacity>
+ inline void Vector<T, inlineCapacity>::reverse()
+ {
+ for (size_t i = 0; i < m_size / 2; ++i)
+ std::swap(at(i), at(m_size - 1 - i));
+ }
+
template<typename T, size_t inlineCapacity>
inline T* Vector<T, inlineCapacity>::releaseBuffer()
{
+++ /dev/null
-/*
- * Copyright (C) 2010 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef Vector3_h
-#define Vector3_h
-
-#include <math.h>
-
-namespace WebCore {
-
-class Vector3 {
-public:
- Vector3()
- : m_x(0.0)
- , m_y(0.0)
- , m_z(0.0)
- {
- }
-
- Vector3(double x, double y, double z)
- : m_x(x)
- , m_y(y)
- , m_z(z)
- {
- }
-
- Vector3(const float p[3])
- : m_x(p[0])
- , m_y(p[1])
- , m_z(p[2])
- {
- }
-
- Vector3(const double p[3])
- : m_x(p[0])
- , m_y(p[1])
- , m_z(p[2])
- {
- }
-
- double abs() const
- {
- return sqrt(m_x * m_x + m_y * m_y + m_z * m_z);
- }
-
- bool isZero() const
- {
- return !m_x && !m_y && !m_z;
- }
-
- void normalize()
- {
- double absValue = abs();
- if (!absValue)
- return;
-
- double k = 1.0 / absValue;
- m_x *= k;
- m_y *= k;
- m_z *= k;
- }
-
- double x() const { return m_x; }
- double y() const { return m_y; }
- double z() const { return m_z; }
-
-private:
- double m_x;
- double m_y;
- double m_z;
-};
-
-inline Vector3 operator+(const Vector3& v1, const Vector3& v2)
-{
- return Vector3(v1.x() + v2.x(), v1.y() + v2.y(), v1.z() + v2.z());
-}
-
-inline Vector3 operator-(const Vector3& v1, const Vector3& v2)
-{
- return Vector3(v1.x() - v2.x(), v1.y() - v2.y(), v1.z() - v2.z());
-}
-
-inline Vector3 operator*(double k, const Vector3& v)
-{
- return Vector3(k * v.x(), k * v.y(), k * v.z());
-}
-
-inline Vector3 operator*(const Vector3& v, double k)
-{
- return Vector3(k * v.x(), k * v.y(), k * v.z());
-}
-
-inline double dot(const Vector3& v1, const Vector3& v2)
-{
- return v1.x() * v2.x() + v1.y() * v2.y() + v1.z() * v2.z();
-}
-
-inline Vector3 cross(const Vector3& v1, const Vector3& v2)
-{
- double x3 = v1.y() * v2.z() - v1.z() * v2.y();
- double y3 = v1.z() * v2.x() - v1.x() * v2.z();
- double z3 = v1.x() * v2.y() - v1.y() * v2.x();
- return Vector3(x3, y3, z3);
-}
-
-inline double distance(const Vector3& v1, const Vector3& v2)
-{
- return (v1 - v2).abs();
-}
-
-} // WebCore
-
-#endif // Vector3_h
template<typename T>
struct VectorTraits : VectorTraitsBase<IsPod<T>::value, T> { };
- struct SimpleClassVectorTraits
+ struct SimpleClassVectorTraits : VectorTraitsBase<false, void>
{
- static const bool needsDestruction = true;
- static const bool needsInitialization = true;
static const bool canInitializeWithMemset = true;
static const bool canMoveWithMemcpy = true;
- static const bool canCopyWithMemcpy = false;
- static const bool canFillWithMemset = false;
static const bool canCompareWithMemcmp = true;
};
WTFThreadData::WTFThreadData()
: m_atomicStringTable(0)
, m_atomicStringTableDestructor(0)
+#if USE(JSC)
+ , m_stackBounds(StackBounds::currentThreadStackBounds())
+#endif
{
+#if USE(JSC)
static JSC::IdentifierTable* sharedIdentifierTable = new JSC::IdentifierTable();
if (pthread_main_np() || isWebThread())
m_defaultIdentifierTable = sharedIdentifierTable;
m_defaultIdentifierTable = new JSC::IdentifierTable();
m_currentIdentifierTable = m_defaultIdentifierTable;
+#endif
}
WTFThreadData::~WTFThreadData()
{
if (m_atomicStringTableDestructor)
m_atomicStringTableDestructor(m_atomicStringTable);
+#if USE(JSC)
delete m_defaultIdentifierTable;
+#endif
}
-} // namespace WebCore
+}
#include <wtf/HashMap.h>
#include <wtf/HashSet.h>
#include <wtf/Noncopyable.h>
+#include <wtf/StackBounds.h>
#include <wtf/text/StringHash.h>
// This was ENABLE(WORKERS) in WebCore, but this is not defined when compiling JSC.
#include <wtf/Threading.h>
#endif
-// FIXME: This is a temporary layering violation while we move more string code to WTF.
-namespace WebCore {
-class AtomicStringTable;
-class StringImpl;
-}
-using WebCore::StringImpl;
-
-typedef void (*AtomicStringTableDestructor)(WebCore::AtomicStringTable*);
-
#if USE(JSC)
// FIXME: This is a temporary layering violation while we move more string code to WTF.
namespace JSC {
typedef HashMap<const char*, RefPtr<StringImpl>, PtrHash<const char*> > LiteralIdentifierTable;
-class IdentifierTable : public FastAllocBase {
+class IdentifierTable {
+ WTF_MAKE_FAST_ALLOCATED;
public:
~IdentifierTable();
template<typename U, typename V>
std::pair<HashSet<StringImpl*>::iterator, bool> add(U value);
- void remove(StringImpl* r) { m_table.remove(r); }
+ bool remove(StringImpl* r)
+ {
+ HashSet<StringImpl*>::iterator iter = m_table.find(r);
+ if (iter == m_table.end())
+ return false;
+ m_table.remove(iter);
+ return true;
+ }
LiteralIdentifierTable& literalTable() { return m_literalTable; }
namespace WTF {
-class WTFThreadData : public Noncopyable {
+class AtomicStringTable;
+
+typedef void (*AtomicStringTableDestructor)(AtomicStringTable*);
+
+class WTFThreadData {
+ WTF_MAKE_NONCOPYABLE(WTFThreadData);
public:
WTFThreadData();
~WTFThreadData();
- WebCore::AtomicStringTable* atomicStringTable()
+ AtomicStringTable* atomicStringTable()
{
return m_atomicStringTable;
}
#if USE(JSC)
-
JSC::IdentifierTable* currentIdentifierTable()
{
return m_currentIdentifierTable;
{
m_currentIdentifierTable = m_defaultIdentifierTable;
}
+
+ const StackBounds& stack() const
+ {
+ return m_stackBounds;
+ }
#endif
private:
- WebCore::AtomicStringTable* m_atomicStringTable;
+ AtomicStringTable* m_atomicStringTable;
AtomicStringTableDestructor m_atomicStringTableDestructor;
#if USE(JSC)
JSC::IdentifierTable* m_defaultIdentifierTable;
JSC::IdentifierTable* m_currentIdentifierTable;
+ StackBounds m_stackBounds;
#endif
#if WTFTHREADDATA_MULTITHREADED
static JS_EXPORTDATA WTFThreadData* staticData;
#endif
friend WTFThreadData& wtfThreadData();
- friend class WebCore::AtomicStringTable;
+ friend class AtomicStringTable;
};
inline WTFThreadData& wtfThreadData()
#include <AEEBitmap.h>
#include <AEEFile.h>
+#include <AEEIMemGroup.h>
+#include <AEEIMemSpace.h>
+#include <AEENet.h>
+#include <AEESSL.h>
#include <AEEStdLib.h>
namespace WTF {
IBitmap_Release(ptr);
}
+void deleteOwnedPtr(ISSL* ptr)
+{
+ if (ptr)
+ ISSL_Release(ptr);
+}
+
+void deleteOwnedPtr(IMemGroup* ptr)
+{
+ if (ptr)
+ IMemGroup_Release(ptr);
+}
+
+void deleteOwnedPtr(IMemSpace* ptr)
+{
+ if (ptr)
+ IMemSpace_Release(ptr);
+}
+
+void deleteOwnedPtr(ISocket* ptr)
+{
+ if (ptr)
+ ISOCKET_Release(ptr);
+}
+
}
--- /dev/null
+/*
+ * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Collabora Ltd.
+ * Copyright (C) 2009 Martin Robinson
+ * Copyright (C) 2010 Company 100, Inc.
+ *
+ * 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.
+ *
+ */
+
+#ifndef RefPtrBrew_h
+#define RefPtrBrew_h
+
+#include "RefPtr.h"
+#include <AEEIBase.h>
+
+namespace WTF {
+
+// All Brew MP classes are derived from either IBase or IQI.
+template<> void refIfNotNull(IBase* ptr)
+{
+ if (LIKELY(ptr != 0))
+ IBase_AddRef(ptr);
+}
+
+template<> void derefIfNotNull(IBase* ptr)
+{
+ if (LIKELY(ptr != 0))
+ IBase_Release(ptr);
+}
+
+template<> void refIfNotNull(IQI* ptr)
+{
+ if (LIKELY(ptr != 0))
+ IQI_AddRef(ptr);
+}
+
+template<> void derefIfNotNull(IQI* ptr)
+{
+ if (LIKELY(ptr != 0))
+ IQI_Release(ptr);
+}
+
+} // namespace WTF
+
+#endif // RefPtrBrew_h
#include <wtf/Assertions.h>
#include <wtf/PassOwnPtr.h>
+#include <wtf/RefPtr.h>
namespace WTF {
return instance;
}
+template <typename T>
+static inline RefPtr<T> createRefPtrInstance(AEECLSID cls)
+{
+ T* instance = 0;
+
+ IShell* shell = reinterpret_cast<AEEApplet*>(GETAPPINSTANCE())->m_pIShell;
+ ISHELL_CreateInstance(shell, cls, reinterpret_cast<void**>(&instance));
+ ASSERT(instance);
+
+ return adoptRef(instance);
+}
+
} // namespace WTF
using WTF::createInstance;
+using WTF::createRefPtrInstance;
#endif // ShellBrew_h
--- /dev/null
+/*
+ * Copyright (C) 2010 Company 100, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "PlatformString.h"
+
+#include <AEEstd.h>
+
+namespace WTF {
+
+// String conversions
+String::String(const AECHAR* string)
+{
+ // It is safe to cast AECHAR to UChar as both of them use 16 bits representation.
+ const UChar* str = reinterpret_cast<const UChar*>(string);
+ const size_t len = std_wstrlen(string);
+
+ m_impl = StringImpl::create(str, len);
+}
+
+} // namespace WTF
* The author of this software is David M. Gay.
*
* Copyright (c) 1991, 2000, 2001 by Lucent Technologies.
- * Copyright (C) 2002, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2002, 2005, 2006, 2007, 2008, 2010 Apple Inc. All rights reserved.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
*
***************************************************************/
-/* Please send bug reports to
- David M. Gay
- Bell Laboratories, Room 2C-463
- 600 Mountain Avenue
- Murray Hill, NJ 07974-0636
- U.S.A.
- dmg@bell-labs.com
- */
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to "."). */
/* On a machine with IEEE extended-precision registers, it is
* necessary to specify double-precision (53-bit) rounding precision
*
* Modifications:
*
- * 1. We only require IEEE.
+ * 1. We only require IEEE double-precision arithmetic (not IEEE double-extended).
* 2. We get by with floating-point arithmetic in a case that
* Clinger missed -- when we're computing d * 10^n
* for a small integer d and the integer n is not too
* for 0 <= k <= 22).
*/
-/*
- * #define IEEE_8087 for IEEE-arithmetic machines where the least
- * significant byte has the lowest address.
- * #define IEEE_MC68k for IEEE-arithmetic machines where the most
- * significant byte has the lowest address.
- * #define No_leftright to omit left-right logic in fast floating-point
- * computation of dtoa.
- * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3
- * and Honor_FLT_ROUNDS is not #defined.
- * #define Inaccurate_Divide for IEEE-format with correctly rounded
- * products but inaccurate quotients, e.g., for Intel i860.
- * #define USE_LONG_LONG on machines that have a "long long"
- * integer type (of >= 64 bits), and performance testing shows that
- * it is faster than 32-bit fallback (which is often not the case
- * on 32-bit machines). On such machines, you can #define Just_16
- * to store 16 bits per 32-bit int32_t when doing high-precision integer
- * arithmetic. Whether this speeds things up or slows things down
- * depends on the machine and the number being converted.
- * #define Bad_float_h if your system lacks a float.h or if it does not
- * define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP,
- * FLT_RADIX, FLT_ROUNDS, and DBL_MAX.
- * #define INFNAN_CHECK on IEEE systems to cause strtod to check for
- * Infinity and NaN (case insensitively). On some systems (e.g.,
- * some HP systems), it may be necessary to #define NAN_WORD0
- * appropriately -- to the most significant word of a quiet NaN.
- * (On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.)
- * When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined,
- * strtod also accepts (case insensitively) strings of the form
- * NaN(x), where x is a string of hexadecimal digits and spaces;
- * if there is only one string of hexadecimal digits, it is taken
- * for the 52 fraction bits of the resulting NaN; if there are two
- * or more strings of hex digits, the first is for the high 20 bits,
- * the second and subsequent for the low 32 bits, with intervening
- * white space ignored; but if this results in none of the 52
- * fraction bits being on (an IEEE Infinity symbol), then NAN_WORD0
- * and NAN_WORD1 are used instead.
- * #define NO_IEEE_Scale to disable new (Feb. 1997) logic in strtod that
- * avoids underflows on inputs whose result does not underflow.
- * If you #define NO_IEEE_Scale on a machine that uses IEEE-format
- * floating-point numbers and flushes underflows to zero rather
- * than implementing gradual underflow, then you must also #define
- * Sudden_Underflow.
- * #define YES_ALIAS to permit aliasing certain double values with
- * arrays of ULongs. This leads to slightly better code with
- * some compilers and was always used prior to 19990916, but it
- * is not strictly legal and can cause trouble with aggressively
- * optimizing compilers (e.g., gcc 2.95.1 under -O2).
- * #define SET_INEXACT if IEEE arithmetic is being used and extra
- * computation should be done to set the inexact flag when the
- * result is inexact and avoid setting inexact when the result
- * is exact. In this case, dtoa.c must be compiled in
- * an environment, perhaps provided by #include "dtoa.c" in a
- * suitable wrapper, that defines two functions,
- * int get_inexact(void);
- * void clear_inexact(void);
- * such that get_inexact() returns a nonzero value if the
- * inexact bit is already set, and clear_inexact() sets the
- * inexact bit to 0. When SET_INEXACT is #defined, strtod
- * also does extra computations to set the underflow and overflow
- * flags when appropriate (i.e., when the result is tiny and
- * inexact or when it is a numeric value rounded to +-infinity).
- * #define NO_ERRNO if strtod should not assign errno = ERANGE when
- * the result overflows to +-Infinity or underflows to 0.
- */
-
#include "config.h"
#include "dtoa.h"
#if HAVE(ERRNO_H)
#include <errno.h>
-#else
-#define NO_ERRNO
#endif
+#include <float.h>
#include <math.h>
#include <stdint.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wtf/AlwaysInline.h>
#include <wtf/Assertions.h>
+#include <wtf/DecimalNumber.h>
#include <wtf/FastMalloc.h>
#include <wtf/MathExtras.h>
-#include <wtf/Vector.h>
#include <wtf/Threading.h>
-
-#include <stdio.h>
+#include <wtf/UnusedParam.h>
+#include <wtf/Vector.h>
#if COMPILER(MSVC)
#pragma warning(disable: 4244)
#pragma warning(disable: 4554)
#endif
-#if CPU(BIG_ENDIAN)
-#define IEEE_MC68k
-#elif CPU(MIDDLE_ENDIAN)
-#define IEEE_ARM
-#else
-#define IEEE_8087
-#endif
-
-#define INFNAN_CHECK
-#define No_Hex_NaN
-
-#if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(IEEE_ARM) != 1
-Exactly one of IEEE_8087, IEEE_ARM or IEEE_MC68k should be defined.
-#endif
-
namespace WTF {
-#if ENABLE(JSC_MULTIPLE_THREADS)
+#if ENABLE(WTF_MULTIPLE_THREADS)
Mutex* s_dtoaP5Mutex;
#endif
-typedef union { double d; uint32_t L[2]; } U;
+typedef union {
+ double d;
+ uint32_t L[2];
+} U;
-#ifdef YES_ALIAS
-#define dval(x) x
-#ifdef IEEE_8087
-#define word0(x) ((uint32_t*)&x)[1]
-#define word1(x) ((uint32_t*)&x)[0]
-#else
-#define word0(x) ((uint32_t*)&x)[0]
-#define word1(x) ((uint32_t*)&x)[1]
-#endif
+#if CPU(BIG_ENDIAN) || CPU(MIDDLE_ENDIAN)
+#define word0(x) (x)->L[0]
+#define word1(x) (x)->L[1]
#else
-#ifdef IEEE_8087
#define word0(x) (x)->L[1]
#define word1(x) (x)->L[0]
-#else
-#define word0(x) (x)->L[0]
-#define word1(x) (x)->L[1]
#endif
#define dval(x) (x)->d
-#endif
/* The following definition of Storeinc is appropriate for MIPS processors.
* An alternative that might be better on some machines is
- * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff)
+ * *p++ = high << 16 | low & 0xffff;
*/
-#if defined(IEEE_8087) || defined(IEEE_ARM)
-#define Storeinc(a,b,c) (((unsigned short*)a)[1] = (unsigned short)b, ((unsigned short*)a)[0] = (unsigned short)c, a++)
+static ALWAYS_INLINE uint32_t* storeInc(uint32_t* p, uint16_t high, uint16_t low)
+{
+ uint16_t* p16 = reinterpret_cast<uint16_t*>(p);
+#if CPU(BIG_ENDIAN)
+ p16[0] = high;
+ p16[1] = low;
#else
-#define Storeinc(a,b,c) (((unsigned short*)a)[0] = (unsigned short)b, ((unsigned short*)a)[1] = (unsigned short)c, a++)
+ p16[1] = high;
+ p16[0] = low;
#endif
+ return p + 1;
+}
#define Exp_shift 20
#define Exp_shift1 20
#define Quick_max 14
#define Int_max 14
-#if !defined(NO_IEEE_Scale)
-#undef Avoid_Underflow
-#define Avoid_Underflow
-#endif
-
-#if !defined(Flt_Rounds)
-#if defined(FLT_ROUNDS)
-#define Flt_Rounds FLT_ROUNDS
-#else
-#define Flt_Rounds 1
-#endif
-#endif /*Flt_Rounds*/
-
-
-#define rounded_product(a,b) a *= b
-#define rounded_quotient(a,b) a /= b
+#define rounded_product(a, b) a *= b
+#define rounded_quotient(a, b) a /= b
#define Big0 (Frac_mask1 | Exp_msk1 * (DBL_MAX_EXP + Bias - 1))
#define Big1 0xffffffff
-
-// FIXME: we should remove non-Pack_32 mode since it is unused and unmaintained
-#ifndef Pack_32
-#define Pack_32
-#endif
-
#if CPU(PPC64) || CPU(X86_64)
// FIXME: should we enable this on all 64-bit CPUs?
// 64-bit emulation provided by the compiler is likely to be slower than dtoa own code on 32-bit hardware.
#define USE_LONG_LONG
#endif
-#ifndef USE_LONG_LONG
-#ifdef Just_16
-#undef Pack_32
-/* When Pack_32 is not defined, we store 16 bits per 32-bit int32_t.
- * This makes some inner loops simpler and sometimes saves work
- * during multiplications, but it often seems to make things slightly
- * slower. Hence the default is now to store 32 bits per int32_t.
- */
-#endif
-#endif
-
-#define Kmax 15
-
struct BigInt {
BigInt() : sign(0) { }
int sign;
sign = 0;
m_words.clear();
}
-
+
size_t size() const
{
return m_words.size();
{
m_words.resize(s);
}
-
+
uint32_t* words()
{
return m_words.data();
{
return m_words.data();
}
-
+
void append(uint32_t w)
{
m_words.append(w);
}
-
+
Vector<uint32_t, 16> m_words;
};
carry = y >> 32;
*x++ = (uint32_t)y & 0xffffffffUL;
#else
-#ifdef Pack_32
uint32_t xi = *x;
uint32_t y = (xi & 0xffff) * m + carry;
uint32_t z = (xi >> 16) * m + (y >> 16);
carry = z >> 16;
*x++ = (z << 16) + (y & 0xffff);
-#else
- uint32_t y = *x * m + carry;
- carry = y >> 16;
- *x++ = y & 0xffff;
-#endif
#endif
} while (++i < wds);
static void s2b(BigInt& b, const char* s, int nd0, int nd, uint32_t y9)
{
- int k;
- int32_t y;
- int32_t x = (nd + 8) / 9;
-
- for (k = 0, y = 1; x > y; y <<= 1, k++) { }
-#ifdef Pack_32
b.sign = 0;
b.resize(1);
b.words()[0] = y9;
-#else
- b.sign = 0;
- b.resize((b->x[1] = y9 >> 16) ? 2 : 1);
- b.words()[0] = y9 & 0xffff;
-#endif
int i = 9;
if (9 < nd0) {
return k;
}
-static int lo0bits (uint32_t* y)
+static int lo0bits(uint32_t* y)
{
int k;
uint32_t x = *y;
if (!(x & 1)) {
k++;
x >>= 1;
- if (!x & 1)
+ if (!x)
return 32;
}
*y = x;
const BigInt* b = &bRef;
BigInt c;
int wa, wb, wc;
- const uint32_t *x = 0, *xa, *xb, *xae, *xbe;
- uint32_t *xc, *xc0;
+ const uint32_t* x = 0;
+ const uint32_t* xa;
+ const uint32_t* xb;
+ const uint32_t* xae;
+ const uint32_t* xbe;
+ uint32_t* xc;
+ uint32_t* xc0;
uint32_t y;
#ifdef USE_LONG_LONG
unsigned long long carry, z;
a = b;
b = tmp;
}
-
+
wa = a->size();
wb = b->size();
wc = wa + wb;
}
}
#else
-#ifdef Pack_32
for (; xb < xbe; xb++, xc0++) {
if ((y = *xb & 0xffff)) {
x = xa;
carry = z >> 16;
uint32_t z2 = (*x++ >> 16) * y + (*xc >> 16) + carry;
carry = z2 >> 16;
- Storeinc(xc, z2, z);
+ xc = storeInc(xc, z2, z);
} while (x < xae);
*xc = carry;
}
do {
z = (*x & 0xffff) * y + (*xc >> 16) + carry;
carry = z >> 16;
- Storeinc(xc, z, z2);
+ xc = storeInc(xc, z, z2);
z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry;
carry = z2 >> 16;
} while (x < xae);
*xc = z2;
}
}
-#else
- for(; xb < xbe; xc0++) {
- if ((y = *xb++)) {
- x = xa;
- xc = xc0;
- carry = 0;
- do {
- z = *x++ * y + *xc + carry;
- carry = z >> 16;
- *xc++ = z & 0xffff;
- } while (x < xae);
- *xc = carry;
- }
- }
-#endif
#endif
for (xc0 = c.words(), xc = xc0 + wc; wc > 0 && !*--xc; --wc) { }
c.resize(wc);
aRef = c;
}
-struct P5Node : Noncopyable {
+struct P5Node {
+ WTF_MAKE_NONCOPYABLE(P5Node); WTF_MAKE_FAST_ALLOCATED;
+public:
+ P5Node() { }
BigInt val;
P5Node* next;
};
-
+
static P5Node* p5s;
-static int p5s_count;
+static int p5sCount;
static ALWAYS_INLINE void pow5mult(BigInt& b, int k)
{
if (!(k >>= 2))
return;
-#if ENABLE(JSC_MULTIPLE_THREADS)
+#if ENABLE(WTF_MULTIPLE_THREADS)
s_dtoaP5Mutex->lock();
#endif
P5Node* p5 = p5s;
i2b(p5->val, 625);
p5->next = 0;
p5s = p5;
- p5s_count = 1;
+ p5sCount = 1;
}
- int p5s_count_local = p5s_count;
-#if ENABLE(JSC_MULTIPLE_THREADS)
+ int p5sCountLocal = p5sCount;
+#if ENABLE(WTF_MULTIPLE_THREADS)
s_dtoaP5Mutex->unlock();
#endif
- int p5s_used = 0;
+ int p5sUsed = 0;
for (;;) {
if (k & 1)
if (!(k >>= 1))
break;
- if (++p5s_used == p5s_count_local) {
-#if ENABLE(JSC_MULTIPLE_THREADS)
+ if (++p5sUsed == p5sCountLocal) {
+#if ENABLE(WTF_MULTIPLE_THREADS)
s_dtoaP5Mutex->lock();
#endif
- if (p5s_used == p5s_count) {
+ if (p5sUsed == p5sCount) {
ASSERT(!p5->next);
p5->next = new P5Node;
p5->next->next = 0;
p5->next->val = p5->val;
mult(p5->next->val, p5->next->val);
- ++p5s_count;
+ ++p5sCount;
}
-
- p5s_count_local = p5s_count;
-#if ENABLE(JSC_MULTIPLE_THREADS)
+
+ p5sCountLocal = p5sCount;
+#if ENABLE(WTF_MULTIPLE_THREADS)
s_dtoaP5Mutex->unlock();
#endif
}
static ALWAYS_INLINE void lshift(BigInt& b, int k)
{
-#ifdef Pack_32
int n = k >> 5;
-#else
- int n = k >> 4;
-#endif
int origSize = b.size();
int n1 = n + origSize + 1;
uint32_t* dstStart = b.words();
const uint32_t* src = srcStart + origSize - 1;
uint32_t* dst = dstStart + n1 - 1;
-#ifdef Pack_32
if (k) {
uint32_t hiSubword = 0;
int s = 32 - k;
*dst = hiSubword;
ASSERT(dst == dstStart + n);
- b.resize(origSize + n + (b.words()[n1 - 1] != 0));
+ b.resize(origSize + n + !!b.words()[n1 - 1]);
}
-#else
- if (k &= 0xf) {
- uint32_t hiSubword = 0;
- int s = 16 - k;
- for (; src >= srcStart; --src) {
- *dst-- = hiSubword | *src >> s;
- hiSubword = (*src << k) & 0xffff;
- }
- *dst = hiSubword;
- ASSERT(dst == dstStart + n);
- result->wds = b->wds + n + (result->x[n1 - 1] != 0);
- }
- #endif
else {
do {
*--dst = *src--;
const BigInt* a = &aRef;
const BigInt* b = &bRef;
int i, wa, wb;
- uint32_t *xc;
+ uint32_t* xc;
i = cmp(*a, *b);
if (!i) {
}
#else
uint32_t borrow = 0;
-#ifdef Pack_32
do {
uint32_t y = (*xa & 0xffff) - (*xb & 0xffff) - borrow;
borrow = (y & 0x10000) >> 16;
uint32_t z = (*xa++ >> 16) - (*xb++ >> 16) - borrow;
borrow = (z & 0x10000) >> 16;
- Storeinc(xc, z, y);
+ xc = storeInc(xc, z, y);
} while (xb < xbe);
while (xa < xae) {
uint32_t y = (*xa & 0xffff) - borrow;
borrow = (y & 0x10000) >> 16;
uint32_t z = (*xa++ >> 16) - borrow;
borrow = (z & 0x10000) >> 16;
- Storeinc(xc, z, y);
- }
-#else
- do {
- uint32_t y = *xa++ - *xb++ - borrow;
- borrow = (y & 0x10000) >> 16;
- *xc++ = y & 0xffff;
- } while (xb < xbe);
- while (xa < xae) {
- uint32_t y = *xa++ - borrow;
- borrow = (y & 0x10000) >> 16;
- *xc++ = y & 0xffff;
+ xc = storeInc(xc, z, y);
}
-#endif
#endif
while (!*--xc)
wa--;
U u;
L = (word0(x) & Exp_mask) - (P - 1) * Exp_msk1;
-#ifndef Avoid_Underflow
-#ifndef Sudden_Underflow
- if (L > 0) {
-#endif
-#endif
word0(&u) = L;
word1(&u) = 0;
-#ifndef Avoid_Underflow
-#ifndef Sudden_Underflow
- } else {
- L = -L >> Exp_shift;
- if (L < Exp_shift) {
- word0(&u) = 0x80000 >> L;
- word1(&u) = 0;
- } else {
- word0(&u) = 0;
- L -= Exp_shift;
- word1(&u) = L >= 31 ? 1 : 1 << 31 - L;
- }
- }
-#endif
-#endif
return dval(&u);
}
ASSERT(y);
k = hi0bits(y);
*e = 32 - k;
-#ifdef Pack_32
if (k < Ebits) {
d0 = Exp_1 | (y >> (Ebits - k));
w = xa > xa0 ? *--xa : 0;
d1 = (y << (32 - Ebits + k)) | (w >> (Ebits - k));
- goto ret_d;
+ goto returnD;
}
z = xa > xa0 ? *--xa : 0;
if (k -= Ebits) {
d0 = Exp_1 | y;
d1 = z;
}
-#else
- if (k < Ebits + 16) {
- z = xa > xa0 ? *--xa : 0;
- d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k;
- w = xa > xa0 ? *--xa : 0;
- y = xa > xa0 ? *--xa : 0;
- d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k;
- goto ret_d;
- }
- z = xa > xa0 ? *--xa : 0;
- w = xa > xa0 ? *--xa : 0;
- k -= Ebits + 16;
- d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k;
- y = xa > xa0 ? *--xa : 0;
- d1 = w << k + 16 | y << k;
-#endif
-ret_d:
+returnD:
#undef d0
#undef d1
return dval(&d);
static ALWAYS_INLINE void d2b(BigInt& b, U* d, int* e, int* bits)
{
int de, k;
- uint32_t *x, y, z;
-#ifndef Sudden_Underflow
+ uint32_t* x;
+ uint32_t y, z;
int i;
-#endif
#define d0 word0(d)
#define d1 word1(d)
b.sign = 0;
-#ifdef Pack_32
b.resize(1);
-#else
- b.resize(2);
-#endif
x = b.words();
z = d0 & Frac_mask;
d0 &= 0x7fffffff; /* clear sign bit, which we ignore */
-#ifdef Sudden_Underflow
- de = (int)(d0 >> Exp_shift);
-#else
if ((de = (int)(d0 >> Exp_shift)))
z |= Exp_msk1;
-#endif
-#ifdef Pack_32
if ((y = d1)) {
if ((k = lo0bits(&y))) {
x[0] = y | (z << (32 - k));
z >>= k;
} else
x[0] = y;
- if (z) {
- b.resize(2);
- x[1] = z;
- }
+ if (z) {
+ b.resize(2);
+ x[1] = z;
+ }
-#ifndef Sudden_Underflow
i = b.size();
-#endif
} else {
k = lo0bits(&z);
x[0] = z;
-#ifndef Sudden_Underflow
i = 1;
-#endif
b.resize(1);
k += 32;
}
-#else
- if ((y = d1)) {
- if ((k = lo0bits(&y))) {
- if (k >= 16) {
- x[0] = y | z << 32 - k & 0xffff;
- x[1] = z >> k - 16 & 0xffff;
- x[2] = z >> k;
- i = 2;
- } else {
- x[0] = y & 0xffff;
- x[1] = y >> 16 | z << 16 - k & 0xffff;
- x[2] = z >> k & 0xffff;
- x[3] = z >> k + 16;
- i = 3;
- }
- } else {
- x[0] = y & 0xffff;
- x[1] = y >> 16;
- x[2] = z & 0xffff;
- x[3] = z >> 16;
- i = 3;
- }
- } else {
- k = lo0bits(&z);
- if (k >= 16) {
- x[0] = z;
- i = 0;
- } else {
- x[0] = z & 0xffff;
- x[1] = z >> 16;
- i = 1;
- }
- k += 32;
- } while (!x[i])
- --i;
- b->resize(i + 1);
-#endif
-#ifndef Sudden_Underflow
if (de) {
-#endif
*e = de - Bias - (P - 1) + k;
*bits = P - k;
-#ifndef Sudden_Underflow
} else {
*e = de - Bias - (P - 1) + 1 + k;
-#ifdef Pack_32
*bits = (32 * i) - hi0bits(x[i - 1]);
-#else
- *bits = (i + 2) * 16 - hi0bits(x[i]);
-#endif
}
-#endif
}
#undef d0
#undef d1
dval(&da) = b2d(a, &ka);
dval(&db) = b2d(b, &kb);
-#ifdef Pack_32
k = ka - kb + 32 * (a.size() - b.size());
-#else
- k = ka - kb + 16 * (a.size() - b.size());
-#endif
if (k > 0)
word0(&da) += k * Exp_msk1;
else {
}
static const double tens[] = {
- 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
- 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
- 1e20, 1e21, 1e22
+ 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
+ 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
+ 1e20, 1e21, 1e22
};
static const double bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 };
static const double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128,
-#ifdef Avoid_Underflow
- 9007199254740992. * 9007199254740992.e-256
- /* = 2^106 * 1e-53 */
-#else
- 1e-256
-#endif
+ 9007199254740992. * 9007199254740992.e-256
+ /* = 2^106 * 1e-256 */
};
/* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */
#define Scale_Bit 0x10
#define n_bigtens 5
-#if defined(INFNAN_CHECK)
-
-#ifndef NAN_WORD0
-#define NAN_WORD0 0x7ff80000
-#endif
-
-#ifndef NAN_WORD1
-#define NAN_WORD1 0
-#endif
-
-static int match(const char** sp, const char* t)
-{
- int c, d;
- const char* s = *sp;
-
- while ((d = *t++)) {
- if ((c = *++s) >= 'A' && c <= 'Z')
- c += 'a' - 'A';
- if (c != d)
- return 0;
- }
- *sp = s + 1;
- return 1;
-}
-
-#ifndef No_Hex_NaN
-static void hexnan(U* rvp, const char** sp)
-{
- uint32_t c, x[2];
- const char* s;
- int havedig, udx0, xshift;
-
- x[0] = x[1] = 0;
- havedig = xshift = 0;
- udx0 = 1;
- s = *sp;
- while ((c = *(const unsigned char*)++s)) {
- if (c >= '0' && c <= '9')
- c -= '0';
- else if (c >= 'a' && c <= 'f')
- c += 10 - 'a';
- else if (c >= 'A' && c <= 'F')
- c += 10 - 'A';
- else if (c <= ' ') {
- if (udx0 && havedig) {
- udx0 = 0;
- xshift = 1;
- }
- continue;
- } else if (/*(*/ c == ')' && havedig) {
- *sp = s + 1;
- break;
- } else
- return; /* invalid form: don't change *sp */
- havedig = 1;
- if (xshift) {
- xshift = 0;
- x[0] = x[1];
- x[1] = 0;
- }
- if (udx0)
- x[0] = (x[0] << 4) | (x[1] >> 28);
- x[1] = (x[1] << 4) | c;
- }
- if ((x[0] &= 0xfffff) || x[1]) {
- word0(rvp) = Exp_mask | x[0];
- word1(rvp) = x[1];
- }
-}
-#endif /*No_Hex_NaN*/
-#endif /* INFNAN_CHECK */
-
double strtod(const char* s00, char** se)
{
-#ifdef Avoid_Underflow
int scale;
-#endif
int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign,
- e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign;
+ e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign;
const char *s, *s0, *s1;
double aadj, aadj1;
U aadj2, adj, rv, rv0;
int32_t L;
uint32_t y, z;
BigInt bb, bb1, bd, bd0, bs, delta;
-#ifdef SET_INEXACT
- int inexact, oldinexact;
-#endif
sign = nz0 = nz = 0;
dval(&rv) = 0;
- for (s = s00; ; s++)
+ for (s = s00; ; s++) {
switch (*s) {
- case '-':
- sign = 1;
- /* no break */
- case '+':
- if (*++s)
- goto break2;
- /* no break */
- case 0:
- goto ret0;
- case '\t':
- case '\n':
- case '\v':
- case '\f':
- case '\r':
- case ' ':
- continue;
- default:
+ case '-':
+ sign = 1;
+ /* no break */
+ case '+':
+ if (*++s)
goto break2;
+ /* no break */
+ case 0:
+ goto ret0;
+ case '\t':
+ case '\n':
+ case '\v':
+ case '\f':
+ case '\r':
+ case ' ':
+ continue;
+ default:
+ goto break2;
}
+ }
break2:
if (*s == '0') {
nz0 = 1;
s0 = s;
nf += nz;
nz = 0;
- goto have_dig;
+ goto haveDig;
}
- goto dig_done;
+ goto digDone;
}
for (; c >= '0' && c <= '9'; c = *++s) {
-have_dig:
+haveDig:
nz++;
if (c -= '0') {
nf += nz;
}
}
}
-dig_done:
+digDone:
e = 0;
if (c == 'e' || c == 'E') {
- if (!nd && !nz && !nz0) {
+ if (!nd && !nz && !nz0)
goto ret0;
- }
s00 = s;
esign = 0;
switch (c = *++s) {
- case '-':
- esign = 1;
- case '+':
- c = *++s;
+ case '-':
+ esign = 1;
+ case '+':
+ c = *++s;
}
if (c >= '0' && c <= '9') {
while (c == '0')
}
if (!nd) {
if (!nz && !nz0) {
-#ifdef INFNAN_CHECK
- /* Check for Nan and Infinity */
- switch(c) {
- case 'i':
- case 'I':
- if (match(&s,"nf")) {
- --s;
- if (!match(&s,"inity"))
- ++s;
- word0(&rv) = 0x7ff00000;
- word1(&rv) = 0;
- goto ret;
- }
- break;
- case 'n':
- case 'N':
- if (match(&s, "an")) {
- word0(&rv) = NAN_WORD0;
- word1(&rv) = NAN_WORD1;
-#ifndef No_Hex_NaN
- if (*s == '(') /*)*/
- hexnan(&rv, &s);
-#endif
- goto ret;
- }
- }
-#endif /* INFNAN_CHECK */
ret0:
s = s00;
sign = 0;
nd0 = nd;
k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1;
dval(&rv) = y;
- if (k > 9) {
-#ifdef SET_INEXACT
- if (k > DBL_DIG)
- oldinexact = get_inexact();
-#endif
+ if (k > 9)
dval(&rv) = tens[k - 9] * dval(&rv) + z;
- }
- if (nd <= DBL_DIG && Flt_Rounds == 1) {
+ if (nd <= DBL_DIG) {
if (!e)
goto ret;
if (e > 0) {
/* rv = */ rounded_product(dval(&rv), tens[e]);
goto ret;
}
- }
-#ifndef Inaccurate_Divide
- else if (e >= -Ten_pmax) {
+ } else if (e >= -Ten_pmax) {
/* rv = */ rounded_quotient(dval(&rv), tens[-e]);
goto ret;
}
-#endif
}
e1 += nd - k;
-#ifdef SET_INEXACT
- inexact = 1;
- if (k <= DBL_DIG)
- oldinexact = get_inexact();
-#endif
-#ifdef Avoid_Underflow
scale = 0;
-#endif
/* Get starting approximation = rv * 10**e1 */
if (e1 &= ~15) {
if (e1 > DBL_MAX_10_EXP) {
ovfl:
-#ifndef NO_ERRNO
+#if HAVE(ERRNO_H)
errno = ERANGE;
#endif
/* Can't trust HUGE_VAL */
word0(&rv) = Exp_mask;
word1(&rv) = 0;
-#ifdef SET_INEXACT
- /* set overflow bit */
- dval(&rv0) = 1e300;
- dval(&rv0) *= dval(&rv0);
-#endif
goto ret;
}
e1 >>= 4;
if (e1 >>= 4) {
if (e1 >= 1 << n_bigtens)
goto undfl;
-#ifdef Avoid_Underflow
if (e1 & Scale_Bit)
scale = 2 * P;
for (j = 0; e1 > 0; j++, e1 >>= 1)
if (e1 & 1)
dval(&rv) *= tinytens[j];
if (scale && (j = (2 * P) + 1 - ((word0(&rv) & Exp_mask) >> Exp_shift)) > 0) {
- /* scaled rv is denormal; zap j low bits */
+ /* scaled rv is denormal; clear j low bits */
if (j >= 32) {
word1(&rv) = 0;
if (j >= 53)
- word0(&rv) = (P + 2) * Exp_msk1;
+ word0(&rv) = (P + 2) * Exp_msk1;
else
- word0(&rv) &= 0xffffffff << (j - 32);
+ word0(&rv) &= 0xffffffff << (j - 32);
} else
word1(&rv) &= 0xffffffff << j;
}
-#else
- for (j = 0; e1 > 1; j++, e1 >>= 1)
- if (e1 & 1)
- dval(&rv) *= tinytens[j];
- /* The last multiplication could underflow. */
- dval(&rv0) = dval(&rv);
- dval(&rv) *= tinytens[j];
- if (!dval(&rv)) {
- dval(&rv) = 2. * dval(&rv0);
- dval(&rv) *= tinytens[j];
-#endif
if (!dval(&rv)) {
undfl:
dval(&rv) = 0.;
-#ifndef NO_ERRNO
+#if HAVE(ERRNO_H)
errno = ERANGE;
#endif
goto ret;
}
-#ifndef Avoid_Underflow
- word0(&rv) = Tiny0;
- word1(&rv) = Tiny1;
- /* The refinement below will clean
- * this approximation up.
- */
- }
-#endif
}
}
else
bd2 -= bbe;
bs2 = bb2;
-#ifdef Avoid_Underflow
j = bbe - scale;
i = j + bbbits - 1; /* logb(rv) */
if (i < Emin) /* denormal */
j += P - Emin;
else
j = P + 1 - bbbits;
-#else /*Avoid_Underflow*/
-#ifdef Sudden_Underflow
- j = P + 1 - bbbits;
-#else /*Sudden_Underflow*/
- j = bbe;
- i = j + bbbits - 1; /* logb(rv) */
- if (i < Emin) /* denormal */
- j += P - Emin;
- else
- j = P + 1 - bbbits;
-#endif /*Sudden_Underflow*/
-#endif /*Avoid_Underflow*/
bb2 += j;
bd2 += j;
-#ifdef Avoid_Underflow
bd2 += scale;
-#endif
i = bb2 < bd2 ? bb2 : bd2;
if (i > bs2)
i = bs2;
* special case of mantissa a power of two.
*/
if (dsign || word1(&rv) || word0(&rv) & Bndry_mask
-#ifdef Avoid_Underflow
|| (word0(&rv) & Exp_mask) <= (2 * P + 1) * Exp_msk1
-#else
- || (word0(&rv) & Exp_mask) <= Exp_msk1
-#endif
) {
-#ifdef SET_INEXACT
- if (!delta->words()[0] && delta->size() <= 1)
- inexact = 0;
-#endif
break;
}
if (!delta.words()[0] && delta.size() <= 1) {
/* exact result */
-#ifdef SET_INEXACT
- inexact = 0;
-#endif
break;
}
lshift(delta, Log2P);
if (cmp(delta, bs) > 0)
- goto drop_down;
+ goto dropDown;
break;
}
- if (i == 0) {
+ if (!i) {
/* exactly half-way between */
if (dsign) {
if ((word0(&rv) & Bndry_mask1) == Bndry_mask1
&& word1(&rv) == (
-#ifdef Avoid_Underflow
(scale && (y = word0(&rv) & Exp_mask) <= 2 * P * Exp_msk1)
? (0xffffffff & (0xffffffff << (2 * P + 1 - (y >> Exp_shift)))) :
-#endif
0xffffffff)) {
/*boundary case -- increment exponent*/
word0(&rv) = (word0(&rv) & Exp_mask) + Exp_msk1;
word1(&rv) = 0;
-#ifdef Avoid_Underflow
dsign = 0;
-#endif
break;
}
} else if (!(word0(&rv) & Bndry_mask) && !word1(&rv)) {
-drop_down:
+dropDown:
/* boundary case -- decrement exponent */
-#ifdef Sudden_Underflow /*{{*/
- L = word0(&rv) & Exp_mask;
-#ifdef Avoid_Underflow
- if (L <= (scale ? (2 * P + 1) * Exp_msk1 : Exp_msk1))
-#else
- if (L <= Exp_msk1)
-#endif /*Avoid_Underflow*/
- goto undfl;
- L -= Exp_msk1;
-#else /*Sudden_Underflow}{*/
-#ifdef Avoid_Underflow
if (scale) {
L = word0(&rv) & Exp_mask;
if (L <= (2 * P + 1) * Exp_msk1) {
goto undfl;
}
}
-#endif /*Avoid_Underflow*/
L = (word0(&rv) & Exp_mask) - Exp_msk1;
-#endif /*Sudden_Underflow}}*/
word0(&rv) = L | Bndry_mask1;
word1(&rv) = 0xffffffff;
break;
dval(&rv) += ulp(&rv);
else {
dval(&rv) -= ulp(&rv);
-#ifndef Sudden_Underflow
if (!dval(&rv))
goto undfl;
-#endif
}
-#ifdef Avoid_Underflow
dsign = 1 - dsign;
-#endif
break;
}
if ((aadj = ratio(delta, bs)) <= 2.) {
if (dsign)
aadj = aadj1 = 1.;
else if (word1(&rv) || word0(&rv) & Bndry_mask) {
-#ifndef Sudden_Underflow
if (word1(&rv) == Tiny1 && !word0(&rv))
goto undfl;
-#endif
aadj = 1.;
aadj1 = -1.;
} else {
} else {
aadj *= 0.5;
aadj1 = dsign ? aadj : -aadj;
-#ifdef Check_FLT_ROUNDS
- switch (Rounding) {
- case 2: /* towards +infinity */
- aadj1 -= 0.5;
- break;
- case 0: /* towards 0 */
- case 3: /* towards -infinity */
- aadj1 += 0.5;
- }
-#else
- if (Flt_Rounds == 0)
- aadj1 += 0.5;
-#endif /*Check_FLT_ROUNDS*/
}
y = word0(&rv) & Exp_mask;
word0(&rv) = Big0;
word1(&rv) = Big1;
goto cont;
- } else
- word0(&rv) += P * Exp_msk1;
+ }
+ word0(&rv) += P * Exp_msk1;
} else {
-#ifdef Avoid_Underflow
if (scale && y <= 2 * P * Exp_msk1) {
if (aadj <= 0x7fffffff) {
if ((z = (uint32_t)aadj) <= 0)
}
adj.d = aadj1 * ulp(&rv);
dval(&rv) += adj.d;
-#else
-#ifdef Sudden_Underflow
- if ((word0(&rv) & Exp_mask) <= P * Exp_msk1) {
- dval(&rv0) = dval(&rv);
- word0(&rv) += P * Exp_msk1;
- adj.d = aadj1 * ulp(&rv);
- dval(&rv) += adj.d;
- if ((word0(&rv) & Exp_mask) <= P * Exp_msk1)
- {
- if (word0(&rv0) == Tiny0 && word1(&rv0) == Tiny1)
- goto undfl;
- word0(&rv) = Tiny0;
- word1(&rv) = Tiny1;
- goto cont;
- }
- else
- word0(&rv) -= P * Exp_msk1;
- } else {
- adj.d = aadj1 * ulp(&rv);
- dval(&rv) += adj.d;
- }
-#else /*Sudden_Underflow*/
- /* Compute adj so that the IEEE rounding rules will
- * correctly round rv + adj in some half-way cases.
- * If rv * ulp(rv) is denormalized (i.e.,
- * y <= (P - 1) * Exp_msk1), we must adjust aadj to avoid
- * trouble from bits lost to denormalization;
- * example: 1.2e-307 .
- */
- if (y <= (P - 1) * Exp_msk1 && aadj > 1.) {
- aadj1 = (double)(int)(aadj + 0.5);
- if (!dsign)
- aadj1 = -aadj1;
- }
- adj.d = aadj1 * ulp(&rv);
- dval(&rv) += adj.d;
-#endif /*Sudden_Underflow*/
-#endif /*Avoid_Underflow*/
}
z = word0(&rv) & Exp_mask;
-#ifndef SET_INEXACT
-#ifdef Avoid_Underflow
- if (!scale)
-#endif
- if (y == z) {
+ if (!scale && y == z) {
/* Can we stop now? */
L = (int32_t)aadj;
aadj -= L;
} else if (aadj < .4999999 / FLT_RADIX)
break;
}
-#endif
cont:
- ;
- }
-#ifdef SET_INEXACT
- if (inexact) {
- if (!oldinexact) {
- word0(&rv0) = Exp_1 + (70 << Exp_shift);
- word1(&rv0) = 0;
- dval(&rv0) += 1.;
- }
- } else if (!oldinexact)
- clear_inexact();
-#endif
-#ifdef Avoid_Underflow
+ {}
+ }
if (scale) {
word0(&rv0) = Exp_1 - 2 * P * Exp_msk1;
word1(&rv0) = 0;
dval(&rv) *= dval(&rv0);
-#ifndef NO_ERRNO
+#if HAVE(ERRNO_H)
/* try to avoid the bug of testing an 8087 register value */
- if (word0(&rv) == 0 && word1(&rv) == 0)
+ if (!word0(&rv) && !word1(&rv))
errno = ERANGE;
#endif
}
-#endif /* Avoid_Underflow */
-#ifdef SET_INEXACT
- if (inexact && !(word0(&rv) & Exp_mask)) {
- /* set underflow bit */
- dval(&rv0) = 1e-300;
- dval(&rv0) *= dval(&rv0);
- }
-#endif
ret:
if (se)
*se = const_cast<char*>(s);
static ALWAYS_INLINE int quorem(BigInt& b, BigInt& S)
{
size_t n;
- uint32_t *bx, *bxe, q, *sx, *sxe;
+ uint32_t* bx;
+ uint32_t* bxe;
+ uint32_t q;
+ uint32_t* sx;
+ uint32_t* sxe;
#ifdef USE_LONG_LONG
unsigned long long borrow, carry, y, ys;
#else
uint32_t borrow, carry, y, ys;
-#ifdef Pack_32
uint32_t si, z, zs;
-#endif
#endif
ASSERT(b.size() <= 1 || b.words()[b.size() - 1]);
ASSERT(S.size() <= 1 || S.words()[S.size() - 1]);
borrow = y >> 32 & (uint32_t)1;
*bx++ = (uint32_t)y & 0xffffffffUL;
#else
-#ifdef Pack_32
si = *sx++;
ys = (si & 0xffff) * q + carry;
zs = (si >> 16) * q + (ys >> 16);
borrow = (y & 0x10000) >> 16;
z = (*bx >> 16) - (zs & 0xffff) - borrow;
borrow = (z & 0x10000) >> 16;
- Storeinc(bx, z, y);
-#else
- ys = *sx++ * q + carry;
- carry = ys >> 16;
- y = *bx - (ys & 0xffff) - borrow;
- borrow = (y & 0x10000) >> 16;
- *bx++ = y & 0xffff;
-#endif
+ bx = storeInc(bx, z, y);
#endif
} while (sx <= sxe);
if (!*bxe) {
borrow = y >> 32 & (uint32_t)1;
*bx++ = (uint32_t)y & 0xffffffffUL;
#else
-#ifdef Pack_32
si = *sx++;
ys = (si & 0xffff) + carry;
zs = (si >> 16) + (ys >> 16);
borrow = (y & 0x10000) >> 16;
z = (*bx >> 16) - (zs & 0xffff) - borrow;
borrow = (z & 0x10000) >> 16;
- Storeinc(bx, z, y);
-#else
- ys = *sx++ + carry;
- carry = ys >> 16;
- y = *bx - (ys & 0xffff) - borrow;
- borrow = (y & 0x10000) >> 16;
- *bx++ = y & 0xffff;
-#endif
+ bx = storeInc(bx, z, y);
#endif
} while (sx <= sxe);
bx = b.words();
/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.
*
* Inspired by "How to Print Floating-Point Numbers Accurately" by
- * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 92-101].
+ * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126].
*
* Modifications:
* 1. Rather than iterating, we use a simple numeric overestimate
* "uniformly" distributed input, the probability is
* something like 10^(k-15) that we must resort to the int32_t
* calculation.
+ *
+ * Note: 'leftright' translates to 'generate shortest possible string'.
*/
-
-void dtoa(DtoaBuffer result, double dd, int ndigits, int* decpt, int* sign, char** rve)
+template<bool roundingNone, bool roundingSignificantFigures, bool roundingDecimalPlaces, bool leftright>
+void dtoa(DtoaBuffer result, double dd, int ndigits, bool& signOut, int& exponentOut, unsigned& precisionOut)
{
- /*
- Arguments ndigits, decpt, sign are similar to those
- of ecvt and fcvt; trailing zeros are suppressed from
- the returned string. If not null, *rve is set to point
- to the end of the return value. If d is +-Infinity or NaN,
- then *decpt is set to 9999.
+ // Exactly one rounding mode must be specified.
+ ASSERT(roundingNone + roundingSignificantFigures + roundingDecimalPlaces == 1);
+ // roundingNone only allowed (only sensible?) with leftright set.
+ ASSERT(!roundingNone || leftright);
- */
+ ASSERT(!isnan(dd) && !isinf(dd));
int bbits, b2, b5, be, dig, i, ieps, ilim = 0, ilim0, ilim1 = 0,
- j, j1, k, k0, k_check, leftright, m2, m5, s2, s5,
- spec_case, try_quick;
+ j, j1, k, k0, k_check, m2, m5, s2, s5,
+ spec_case;
int32_t L;
-#ifndef Sudden_Underflow
int denorm;
uint32_t x;
-#endif
- BigInt b, b1, delta, mlo, mhi, S;
+ BigInt b, delta, mlo, mhi, S;
U d2, eps, u;
double ds;
- char *s, *s0;
-#ifdef SET_INEXACT
- int inexact, oldinexact;
-#endif
+ char* s;
+ char* s0;
u.d = dd;
- if (word0(&u) & Sign_bit) {
- /* set sign for everything, including 0's and NaNs */
- *sign = 1;
- word0(&u) &= ~Sign_bit; /* clear sign bit */
- } else
- *sign = 0;
- if ((word0(&u) & Exp_mask) == Exp_mask)
- {
- /* Infinity or NaN */
- *decpt = 9999;
- if (!word1(&u) && !(word0(&u) & 0xfffff)) {
- strcpy(result, "Infinity");
- if (rve)
- *rve = result + 8;
- } else {
- strcpy(result, "NaN");
- if (rve)
- *rve = result + 3;
- }
- return;
- }
+ /* Infinity or NaN */
+ ASSERT((word0(&u) & Exp_mask) != Exp_mask);
+
+ // JavaScript toString conversion treats -0 as 0.
if (!dval(&u)) {
- *decpt = 1;
+ signOut = false;
+ exponentOut = 0;
+ precisionOut = 1;
result[0] = '0';
result[1] = '\0';
- if (rve)
- *rve = result + 1;
return;
}
-#ifdef SET_INEXACT
- try_quick = oldinexact = get_inexact();
- inexact = 1;
-#endif
+ if (word0(&u) & Sign_bit) {
+ signOut = true;
+ word0(&u) &= ~Sign_bit; // clear sign bit
+ } else
+ signOut = false;
d2b(b, &u, &be, &bbits);
-#ifdef Sudden_Underflow
- i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask >> Exp_shift1));
-#else
if ((i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask >> Exp_shift1)))) {
-#endif
dval(&d2) = dval(&u);
word0(&d2) &= Frac_mask1;
word0(&d2) |= Exp_11;
*/
i -= Bias;
-#ifndef Sudden_Underflow
denorm = 0;
} else {
/* d is denormalized */
i -= (Bias + (P - 1) - 1) + 1;
denorm = 1;
}
-#endif
ds = (dval(&d2) - 1.5) * 0.289529654602168 + 0.1760912590558 + (i * 0.301029995663981);
k = (int)ds;
if (ds < 0. && ds != k)
s5 = 0;
}
-#ifndef SET_INEXACT
-#ifdef Check_FLT_ROUNDS
- try_quick = Rounding == 1;
-#else
- try_quick = 1;
-#endif
-#endif /*SET_INEXACT*/
+ if (roundingNone) {
+ ilim = ilim1 = -1;
+ i = 18;
+ ndigits = 0;
+ }
+ if (roundingSignificantFigures) {
+ if (ndigits <= 0)
+ ndigits = 1;
+ ilim = ilim1 = i = ndigits;
+ }
+ if (roundingDecimalPlaces) {
+ i = ndigits + k + 1;
+ ilim = i;
+ ilim1 = i - 1;
+ if (i <= 0)
+ i = 1;
+ }
- leftright = 1;
- ilim = ilim1 = -1;
- i = 18;
- ndigits = 0;
s = s0 = result;
- if (ilim >= 0 && ilim <= Quick_max && try_quick) {
-
+ if (ilim >= 0 && ilim <= Quick_max) {
/* Try to get by with floating-point arithmetic. */
i = 0;
}
if (k_check && dval(&u) < 1. && ilim > 0) {
if (ilim1 <= 0)
- goto fast_failed;
+ goto fastFailed;
ilim = ilim1;
k--;
dval(&u) *= 10.;
}
dval(&eps) = (ieps * dval(&u)) + 7.;
word0(&eps) -= (P - 1) * Exp_msk1;
- if (ilim == 0) {
+ if (!ilim) {
S.clear();
mhi.clear();
dval(&u) -= 5.;
if (dval(&u) > dval(&eps))
- goto one_digit;
+ goto oneDigit;
if (dval(&u) < -dval(&eps))
- goto no_digits;
- goto fast_failed;
+ goto noDigits;
+ goto fastFailed;
}
-#ifndef No_leftright
if (leftright) {
/* Use Steele & White method of only
* generating digits needed.
if (dval(&u) < dval(&eps))
goto ret;
if (1. - dval(&u) < dval(&eps))
- goto bump_up;
+ goto bumpUp;
if (++i >= ilim)
break;
dval(&eps) *= 10.;
dval(&u) *= 10.;
}
} else {
-#endif
/* Generate ilim digits, then fix them up. */
dval(&eps) *= tens[ilim - 1];
for (i = 1;; i++, dval(&u) *= 10.) {
*s++ = '0' + (int)L;
if (i == ilim) {
if (dval(&u) > 0.5 + dval(&eps))
- goto bump_up;
- else if (dval(&u) < 0.5 - dval(&eps)) {
+ goto bumpUp;
+ if (dval(&u) < 0.5 - dval(&eps)) {
while (*--s == '0') { }
s++;
goto ret;
break;
}
}
-#ifndef No_leftright
}
-#endif
-fast_failed:
+fastFailed:
s = s0;
dval(&u) = dval(&d2);
k = k0;
S.clear();
mhi.clear();
if (ilim < 0 || dval(&u) <= 5 * ds)
- goto no_digits;
- goto one_digit;
+ goto noDigits;
+ goto oneDigit;
}
for (i = 1;; i++, dval(&u) *= 10.) {
L = (int32_t)(dval(&u) / ds);
dval(&u) -= L * ds;
-#ifdef Check_FLT_ROUNDS
- /* If FLT_ROUNDS == 2, L will usually be high by 1 */
- if (dval(&u) < 0) {
- L--;
- dval(&u) += ds;
- }
-#endif
*s++ = '0' + (int)L;
if (!dval(&u)) {
-#ifdef SET_INEXACT
- inexact = 0;
-#endif
break;
}
if (i == ilim) {
dval(&u) += dval(&u);
if (dval(&u) > ds || (dval(&u) == ds && (L & 1))) {
-bump_up:
+bumpUp:
while (*--s == '9')
if (s == s0) {
k++;
mhi.clear();
mlo.clear();
if (leftright) {
- i =
-#ifndef Sudden_Underflow
- denorm ? be + (Bias + (P - 1) - 1 + 1) :
-#endif
- 1 + P - bbits;
+ i = denorm ? be + (Bias + (P - 1) - 1 + 1) : 1 + P - bbits;
b2 += i;
s2 += i;
i2b(mhi, 1);
pow5mult(b, j);
} else
pow5mult(b, b5);
- }
+ }
i2b(S, 1);
if (s5 > 0)
pow5mult(S, s5);
/* Check for special case that d is a normalized power of 2. */
spec_case = 0;
- if (!word1(&u) && !(word0(&u) & Bndry_mask)
-#ifndef Sudden_Underflow
- && word0(&u) & (Exp_mask & ~Exp_msk1)
-#endif
- ) {
+ if ((roundingNone || leftright) && (!word1(&u) && !(word0(&u) & Bndry_mask) && word0(&u) & (Exp_mask & ~Exp_msk1))) {
/* The special case */
b2 += Log2P;
s2 += Log2P;
* and for all and pass them and a shift to quorem, so it
* can do shifts and ors to compute the numerator for q.
*/
-#ifdef Pack_32
if ((i = ((s5 ? 32 - hi0bits(S.words()[S.size() - 1]) : 1) + s2) & 0x1f))
i = 32 - i;
-#else
- if ((i = ((s5 ? 32 - hi0bits(S.words()[S.size() - 1]) : 1) + s2) & 0xf))
- i = 16 - i;
-#endif
if (i > 4) {
i -= 4;
b2 += i;
if (s2 > 0)
lshift(S, s2);
if (k_check) {
- if (cmp(b,S) < 0) {
+ if (cmp(b, S) < 0) {
k--;
multadd(b, 10, 0); /* we botched the k estimate */
if (leftright)
ilim = ilim1;
}
}
-
+ if (ilim <= 0 && roundingDecimalPlaces) {
+ if (ilim < 0)
+ goto noDigits;
+ multadd(S, 5, 0);
+ // For IEEE-754 unbiased rounding this check should be <=, such that 0.5 would flush to zero.
+ if (cmp(b, S) < 0)
+ goto noDigits;
+ goto oneDigit;
+ }
if (leftright) {
if (m2 > 0)
lshift(mhi, m2);
*/
mlo = mhi;
- if (spec_case) {
- mhi = mlo;
+ if (spec_case)
lshift(mhi, Log2P);
- }
for (i = 1;;i++) {
- dig = quorem(b,S) + '0';
+ dig = quorem(b, S) + '0';
/* Do we yet have the shortest decimal string
* that will round to d?
*/
j = cmp(b, mlo);
diff(delta, S, mhi);
j1 = delta.sign ? 1 : cmp(b, delta);
- if (j1 == 0 && !(word1(&u) & 1)) {
+#ifdef DTOA_ROUND_BIASED
+ if (j < 0 || !j) {
+#else
+ // FIXME: ECMA-262 specifies that equidistant results round away from
+ // zero, which probably means we shouldn't be on the unbiased code path
+ // (the (word1(&u) & 1) clause is looking highly suspicious). I haven't
+ // yet understood this code well enough to make the call, but we should
+ // probably be enabling DTOA_ROUND_BIASED. I think the interesting corner
+ // case to understand is probably "Math.pow(0.5, 24).toString()".
+ // I believe this value is interesting because I think it is precisely
+ // representable in binary floating point, and its decimal representation
+ // has a single digit that Steele & White reduction can remove, with the
+ // value 5 (thus equidistant from the next numbers above and below).
+ // We produce the correct answer using either codepath, and I don't as
+ // yet understand why. :-)
+ if (!j1 && !(word1(&u) & 1)) {
if (dig == '9')
- goto round_9_up;
+ goto round9up;
if (j > 0)
dig++;
-#ifdef SET_INEXACT
- else if (!b->x[0] && b->wds <= 1)
- inexact = 0;
-#endif
*s++ = dig;
goto ret;
}
- if (j < 0 || (j == 0 && !(word1(&u) & 1))) {
- if (!b.words()[0] && b.size() <= 1) {
-#ifdef SET_INEXACT
- inexact = 0;
+ if (j < 0 || (!j && !(word1(&u) & 1))) {
#endif
- goto accept_dig;
- }
- if (j1 > 0) {
+ if ((b.words()[0] || b.size() > 1) && (j1 > 0)) {
lshift(b, 1);
j1 = cmp(b, S);
- if ((j1 > 0 || (j1 == 0 && (dig & 1))) && dig++ == '9')
- goto round_9_up;
+ // For IEEE-754 round-to-even, this check should be (j1 > 0 || (!j1 && (dig & 1))),
+ // but ECMA-262 specifies that equidistant values (e.g. (.5).toFixed()) should
+ // be rounded away from zero.
+ if (j1 >= 0) {
+ if (dig == '9')
+ goto round9up;
+ dig++;
+ }
}
-accept_dig:
*s++ = dig;
goto ret;
}
if (j1 > 0) {
if (dig == '9') { /* possible if i == 1 */
-round_9_up:
+round9up:
*s++ = '9';
goto roundoff;
}
multadd(mlo, 10, 0);
multadd(mhi, 10, 0);
}
- } else
+ } else {
for (i = 1;; i++) {
- *s++ = dig = quorem(b,S) + '0';
- if (!b.words()[0] && b.size() <= 1) {
-#ifdef SET_INEXACT
- inexact = 0;
-#endif
+ *s++ = dig = quorem(b, S) + '0';
+ if (!b.words()[0] && b.size() <= 1)
goto ret;
- }
if (i >= ilim)
break;
multadd(b, 10, 0);
}
+ }
/* Round off last digit */
lshift(b, 1);
j = cmp(b, S);
- if (j > 0 || (j == 0 && (dig & 1))) {
+ // For IEEE-754 round-to-even, this check should be (j > 0 || (!j && (dig & 1))),
+ // but ECMA-262 specifies that equidistant values (e.g. (.5).toFixed()) should
+ // be rounded away from zero.
+ if (j >= 0) {
roundoff:
while (*--s == '9')
if (s == s0) {
s++;
}
goto ret;
-no_digits:
- k = -1 - ndigits;
- goto ret;
-one_digit:
+noDigits:
+ exponentOut = 0;
+ precisionOut = 1;
+ result[0] = '0';
+ result[1] = '\0';
+ return;
+oneDigit:
*s++ = '1';
k++;
goto ret;
ret:
-#ifdef SET_INEXACT
- if (inexact) {
- if (!oldinexact) {
- word0(&u) = Exp_1 + (70 << Exp_shift);
- word1(&u) = 0;
- dval(&u) += 1.;
- }
- } else if (!oldinexact)
- clear_inexact();
-#endif
+ ASSERT(s > result);
*s = 0;
- *decpt = k + 1;
- if (rve)
- *rve = s;
+ exponentOut = k;
+ precisionOut = s - result;
}
-static ALWAYS_INLINE void append(char*& next, const char* src, unsigned size)
+void dtoa(DtoaBuffer result, double dd, bool& sign, int& exponent, unsigned& precision)
{
- for (unsigned i = 0; i < size; ++i)
- *next++ = *src++;
+ // flags are roundingNone, leftright.
+ dtoa<true, false, false, true>(result, dd, 0, sign, exponent, precision);
}
-void doubleToStringInJavaScriptFormat(double d, DtoaBuffer buffer, unsigned* resultLength)
+void dtoaRoundSF(DtoaBuffer result, double dd, int ndigits, bool& sign, int& exponent, unsigned& precision)
{
- ASSERT(buffer);
+ // flag is roundingSignificantFigures.
+ dtoa<false, true, false, false>(result, dd, ndigits, sign, exponent, precision);
+}
- // avoid ever printing -NaN, in JS conceptually there is only one NaN value
- if (isnan(d)) {
- append(buffer, "NaN", 3);
- if (resultLength)
- *resultLength = 3;
- return;
- }
- // -0 -> "0"
- if (!d) {
- buffer[0] = '0';
- if (resultLength)
- *resultLength = 1;
- return;
- }
+void dtoaRoundDP(DtoaBuffer result, double dd, int ndigits, bool& sign, int& exponent, unsigned& precision)
+{
+ // flag is roundingDecimalPlaces.
+ dtoa<false, false, true, false>(result, dd, ndigits, sign, exponent, precision);
+}
- int decimalPoint;
- int sign;
+static ALWAYS_INLINE void copyAsciiToUTF16(UChar* next, const char* src, unsigned size)
+{
+ for (unsigned i = 0; i < size; ++i)
+ *next++ = *src++;
+}
- DtoaBuffer result;
- char* resultEnd = 0;
- WTF::dtoa(result, d, 0, &decimalPoint, &sign, &resultEnd);
- int length = resultEnd - result;
-
- char* next = buffer;
- if (sign)
- *next++ = '-';
-
- if (decimalPoint <= 0 && decimalPoint > -6) {
- *next++ = '0';
- *next++ = '.';
- for (int j = decimalPoint; j < 0; j++)
- *next++ = '0';
- append(next, result, length);
- } else if (decimalPoint <= 21 && decimalPoint > 0) {
- if (length <= decimalPoint) {
- append(next, result, length);
- for (int j = 0; j < decimalPoint - length; j++)
- *next++ = '0';
- } else {
- append(next, result, decimalPoint);
- *next++ = '.';
- append(next, result + decimalPoint, length - decimalPoint);
+unsigned numberToString(double d, NumberToStringBuffer buffer)
+{
+ // Handle NaN and Infinity.
+ if (isnan(d) || isinf(d)) {
+ if (isnan(d)) {
+ copyAsciiToUTF16(buffer, "NaN", 3);
+ return 3;
}
- } else if (result[0] < '0' || result[0] > '9')
- append(next, result, length);
- else {
- *next++ = result[0];
- if (length > 1) {
- *next++ = '.';
- append(next, result + 1, length - 1);
+ if (d > 0) {
+ copyAsciiToUTF16(buffer, "Infinity", 8);
+ return 8;
}
+ copyAsciiToUTF16(buffer, "-Infinity", 9);
+ return 9;
+ }
- *next++ = 'e';
- *next++ = (decimalPoint >= 0) ? '+' : '-';
- // decimalPoint can't be more than 3 digits decimal given the
- // nature of float representation
- int exponential = decimalPoint - 1;
- if (exponential < 0)
- exponential = -exponential;
- if (exponential >= 100)
- *next++ = static_cast<char>('0' + exponential / 100);
- if (exponential >= 10)
- *next++ = static_cast<char>('0' + (exponential % 100) / 10);
- *next++ = static_cast<char>('0' + exponential % 10);
- }
- if (resultLength)
- *resultLength = next - buffer;
+ // Convert to decimal with rounding.
+ DecimalNumber number(d);
+ return number.exponent() >= -6 && number.exponent() < 21
+ ? number.toStringDecimal(buffer, NumberToStringBufferLength)
+ : number.toStringExponential(buffer, NumberToStringBufferLength);
}
} // namespace WTF
#ifndef WTF_dtoa_h
#define WTF_dtoa_h
-namespace WTF {
- class Mutex;
-}
+#include <wtf/unicode/Unicode.h>
namespace WTF {
+class Mutex;
+
+extern WTF::Mutex* s_dtoaP5Mutex;
- extern WTF::Mutex* s_dtoaP5Mutex;
+// s00: input string. Must not be 0 and must be terminated by 0.
+// se: *se will have the last consumed character position + 1.
+double strtod(const char* s00, char** se);
- double strtod(const char* s00, char** se);
+typedef char DtoaBuffer[80];
- typedef char DtoaBuffer[80];
- void dtoa(DtoaBuffer result, double d, int ndigits, int* decpt, int* sign, char** rve);
+void dtoa(DtoaBuffer result, double dd, bool& sign, int& exponent, unsigned& precision);
+void dtoaRoundSF(DtoaBuffer result, double dd, int ndigits, bool& sign, int& exponent, unsigned& precision);
+void dtoaRoundDP(DtoaBuffer result, double dd, int ndigits, bool& sign, int& exponent, unsigned& precision);
- // dtoa() for ECMA-262 'ToString Applied to the Number Type.'
- // The *resultLength will have the length of the resultant string in bufer.
- // The resultant string isn't terminated by 0.
- void doubleToStringInJavaScriptFormat(double, DtoaBuffer, unsigned* resultLength);
+// Size = 80 for sizeof(DtoaBuffer) + some sign bits, decimal point, 'e', exponent digits.
+const unsigned NumberToStringBufferLength = 96;
+typedef UChar NumberToStringBuffer[NumberToStringBufferLength];
+unsigned numberToString(double, NumberToStringBuffer);
} // namespace WTF
-using WTF::DtoaBuffer;
-using WTF::doubleToStringInJavaScriptFormat;
+using WTF::NumberToStringBuffer;
+using WTF::numberToString;
#endif // WTF_dtoa_h
{
}
-static int timeoutFired(void*)
+static Eina_Bool timeoutFired(void*)
{
dispatchFunctionsFromMainThread();
return ECORE_CALLBACK_CANCEL;
#include "config.h"
#include "GOwnPtr.h"
+#if ENABLE(GLIB_SUPPORT)
+
#include <gio/gio.h>
#include <glib.h>
g_dir_close(ptr);
}
-template <> void freeOwnedGPtr<GFile>(GFile* ptr)
-{
- if (ptr)
- g_object_unref(ptr);
-}
} // namespace WTF
+
+#endif // ENABLE(GLIB_SUPPORT)
#ifndef GOwnPtr_h
#define GOwnPtr_h
+#if ENABLE(GLIB_SUPPORT)
+
#include <algorithm>
#include <wtf/Assertions.h>
#include <wtf/Noncopyable.h>
-// Forward delcarations at this point avoid the need to include GLib includes
-// in WTF headers.
-typedef struct _GError GError;
-typedef struct _GList GList;
-typedef struct _GCond GCond;
-typedef struct _GMutex GMutex;
-typedef struct _GPatternSpec GPatternSpec;
-typedef struct _GDir GDir;
-typedef struct _GHashTable GHashTable;
-typedef struct _GFile GFile;
extern "C" void g_free(void*);
namespace WTF {
template<> void freeOwnedGPtr<GMutex>(GMutex*);
template<> void freeOwnedGPtr<GPatternSpec>(GPatternSpec*);
template<> void freeOwnedGPtr<GDir>(GDir*);
-template<> void freeOwnedGPtr<GHashTable>(GHashTable*);
-template<> void freeOwnedGPtr<GFile>(GFile*);
-template <typename T> class GOwnPtr : public Noncopyable {
+template <typename T> class GOwnPtr {
+ WTF_MAKE_NONCOPYABLE(GOwnPtr);
public:
explicit GOwnPtr(T* ptr = 0) : m_ptr(ptr) { }
~GOwnPtr() { freeOwnedGPtr(m_ptr); }
void clear()
{
- freeOwnedGPtr(m_ptr);
+ T* ptr = m_ptr;
m_ptr = 0;
+ freeOwnedGPtr(ptr);
}
T& operator*() const
using WTF::GOwnPtr;
+#endif // ENABLE(GLIB_SUPPORT)
+
#endif // GOwnPtr_h
+
#include "config.h"
#include "GRefPtr.h"
+#if ENABLE(GLIB_SUPPORT)
+
#include <glib.h>
namespace WTF {
g_hash_table_unref(ptr);
}
+#if GLIB_CHECK_VERSION(2, 24, 0)
+template <> GVariant* refGPtr(GVariant* ptr)
+{
+ if (ptr)
+ g_variant_ref(ptr);
+ return ptr;
+}
+
+template <> void derefGPtr(GVariant* ptr)
+{
+ g_variant_unref(ptr);
+}
+
+#else
+
+// We do this so that we can avoid including the glib.h header in GRefPtr.h.
+typedef struct _GVariant {
+ bool fake;
+} GVariant;
+
+template <> GVariant* refGPtr(GVariant* ptr)
+{
+ return ptr;
+}
+
+template <> void derefGPtr(GVariant* ptr)
+{
+}
+
+#endif
+
+template <> GSource* refGPtr(GSource* ptr)
+{
+ if (ptr)
+ g_source_ref(ptr);
+ return ptr;
+}
+
+template <> void derefGPtr(GSource* ptr)
+{
+ if (ptr)
+ g_source_unref(ptr);
+}
+
} // namespace WTF
+
+#endif // ENABLE(GLIB_SUPPORT)
#ifndef WTF_GRefPtr_h
#define WTF_GRefPtr_h
+#if ENABLE(GLIB_SUPPORT)
+
#include "AlwaysInline.h"
+#include "GRefPtr.h"
+#include "RefPtr.h"
#include <algorithm>
-typedef struct _GHashTable GHashTable;
-typedef void* gpointer;
-extern "C" void g_object_unref(gpointer object);
-extern "C" gpointer g_object_ref_sink(gpointer object);
+extern "C" void g_object_unref(gpointer);
+extern "C" gpointer g_object_ref_sink(gpointer);
namespace WTF {
template <typename T> inline void derefGPtr(T*);
template <typename T> class GRefPtr;
template <typename T> GRefPtr<T> adoptGRef(T*);
-template <> GHashTable* refGPtr(GHashTable* ptr);
-template <> void derefGPtr(GHashTable* ptr);
template <typename T> class GRefPtr {
public:
GRefPtr() : m_ptr(0) { }
- GRefPtr(T* ptr) : m_ptr(ptr) { if (ptr) refGPtr(ptr); }
- GRefPtr(const GRefPtr& o) : m_ptr(o.m_ptr) { if (T* ptr = m_ptr) refGPtr(ptr); }
- template <typename U> GRefPtr(const GRefPtr<U>& o) : m_ptr(o.get()) { if (T* ptr = m_ptr) refGPtr(ptr); }
- ~GRefPtr() { if (T* ptr = m_ptr) derefGPtr(ptr); }
+ GRefPtr(T* ptr)
+ : m_ptr(ptr)
+ {
+ if (ptr)
+ refGPtr(ptr);
+ }
- void clear()
+ GRefPtr(const GRefPtr& o)
+ : m_ptr(o.m_ptr)
+ {
+ if (T* ptr = m_ptr)
+ refGPtr(ptr);
+ }
+
+ template <typename U> GRefPtr(const GRefPtr<U>& o)
+ : m_ptr(o.get())
+ {
+ if (T* ptr = m_ptr)
+ refGPtr(ptr);
+ }
+
+ ~GRefPtr()
{
if (T* ptr = m_ptr)
derefGPtr(ptr);
+ }
+
+ void clear()
+ {
+ T* ptr = m_ptr;
+ m_ptr = 0;
+ if (ptr)
+ derefGPtr(ptr);
+ }
+
+ T* leakRef() WARN_UNUSED_RETURN
+ {
+ T* ptr = m_ptr;
m_ptr = 0;
+ return ptr;
}
+ // Hash table deleted values, which are only constructed and never copied or destroyed.
+ GRefPtr(HashTableDeletedValueType) : m_ptr(hashTableDeletedValue()) { }
+ bool isHashTableDeletedValue() const { return m_ptr == hashTableDeletedValue(); }
+
T* get() const { return m_ptr; }
T& operator*() const { return *m_ptr; }
ALWAYS_INLINE T* operator->() const { return m_ptr; }
return GRefPtr<T>(p, GRefPtrAdopt);
}
+template <> GHashTable* refGPtr(GHashTable* ptr);
+template <> void derefGPtr(GHashTable* ptr);
+template <> GVariant* refGPtr(GVariant* ptr);
+template <> void derefGPtr(GVariant* ptr);
+template <> GSource* refGPtr(GSource* ptr);
+template <> void derefGPtr(GSource* ptr);
+
template <typename T> inline T* refGPtr(T* ptr)
{
if (ptr)
} // namespace WTF
using WTF::GRefPtr;
-using WTF::refGPtr;
-using WTF::derefGPtr;
using WTF::adoptGRef;
-using WTF::static_pointer_cast;
-using WTF::const_pointer_cast;
+
+#endif // ENABLE(GLIB_SUPPORT)
#endif // WTF_GRefPtr_h
--- /dev/null
+/*
+ * Copyright (C) 2010 Igalia, S.L.
+ *
+ * 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.
+ */
+
+#ifndef GtkTypedefs_h
+#define GtkTypedefs_h
+
+/* Vanilla C code does not seem to be able to handle forward-declaration typedefs. */
+#ifdef __cplusplus
+
+typedef char gchar;
+typedef double gdouble;
+typedef float gfloat;
+typedef int gint;
+typedef gint gboolean;
+typedef long glong;
+typedef short gshort;
+typedef unsigned char guchar;
+typedef unsigned int guint;
+typedef unsigned long gulong;
+typedef unsigned short gushort;
+typedef void* gpointer;
+
+typedef struct _GAsyncResult GAsyncResult;
+typedef struct _GCancellable GCancellable;
+typedef struct _GCharsetConverter GCharsetConverter;
+typedef struct _GCond GCond;
+typedef struct _GDir GDir;
+typedef struct _GdkAtom* GdkAtom;
+typedef struct _GdkCursor GdkCursor;
+typedef struct _GdkDragContext GdkDragContext;
+typedef struct _GdkEventConfigure GdkEventConfigure;
+typedef struct _GdkEventExpose GdkEventExpose;
+typedef struct _GdkPixbuf GdkPixbuf;
+typedef struct _GError GError;
+typedef struct _GFile GFile;
+typedef struct _GHashTable GHashTable;
+typedef struct _GInputStream GInputStream;
+typedef struct _GList GList;
+typedef struct _GMutex GMutex;
+typedef struct _GPatternSpec GPatternSpec;
+typedef struct _GPollableOutputStream GPollableOutputStream;
+typedef struct _GSocketClient GSocketClient;
+typedef struct _GSocketConnection GSocketConnection;
+typedef struct _GSource GSource;
+typedef struct _GVariant GVariant;
+typedef union _GdkEvent GdkEvent;
+
+#if USE(CAIRO)
+typedef struct _cairo_surface cairo_surface_t;
+#endif
+
+#if PLATFORM(GTK)
+typedef struct _GtkAction GtkAction;
+typedef struct _GtkAdjustment GtkAdjustment;
+typedef struct _GtkBorder GtkBorder;
+typedef struct _GtkClipboard GtkClipboard;
+typedef struct _GtkContainer GtkContainer;
+typedef struct _GtkIconInfo GtkIconInfo;
+typedef struct _GtkMenu GtkMenu;
+typedef struct _GtkMenuItem GtkMenuItem;
+typedef struct _GtkObject GtkObject;
+typedef struct _GtkSelectionData GtkSelectionData;
+typedef struct _GtkStyle GtkStyle;
+typedef struct _GtkTargetList GtkTargetList;
+typedef struct _GtkThemeParts GtkThemeParts;
+typedef struct _GtkWidget GtkWidget;
+typedef struct _GtkWindow GtkWindow;
+
+#ifdef GTK_API_VERSION_2
+typedef struct _GdkRectangle GdkRectangle;
+typedef struct _GdkDrawable GdkWindow;
+#else
+typedef struct _GdkWindow GdkWindow;
+typedef struct _cairo_rectangle_int cairo_rectangle_int_t;
+typedef cairo_rectangle_int_t GdkRectangle;
+typedef struct _GtkStyleContext GtkStyleContext;
+#endif
+
+#endif
+
+#endif
+#endif /* GtkTypedefs_h */
#include "HashMap.h"
#include "MainThread.h"
#include "RandomNumberSeed.h"
+#include <wtf/StdLibExtras.h>
#include <glib.h>
#include <limits.h>
namespace WTF {
+typedef HashMap<ThreadIdentifier, GThread*> ThreadMap;
+
static Mutex* atomicallyInitializedStaticMutex;
static Mutex& threadMapMutex()
{
- static Mutex mutex;
+ DEFINE_STATIC_LOCAL(Mutex, mutex, ());
return mutex;
}
atomicallyInitializedStaticMutex->unlock();
}
-static HashMap<ThreadIdentifier, GThread*>& threadMap()
+static ThreadMap& threadMap()
{
- static HashMap<ThreadIdentifier, GThread*> map;
+ DEFINE_STATIC_LOCAL(ThreadMap, map, ());
return map;
}
{
MutexLocker locker(threadMapMutex());
- HashMap<ThreadIdentifier, GThread*>::iterator i = threadMap().begin();
+ ThreadMap::iterator i = threadMap().begin();
for (; i != threadMap().end(); ++i) {
if (i->second == thread)
return i->first;
return establishIdentifierForThread(currentThread);
}
+void yield()
+{
+ g_thread_yield();
+}
+
Mutex::Mutex()
: m_mutex(g_mutex_new())
{
--- /dev/null
+/*
+ * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "PlatformString.h"
+
+#include <String.h>
+#include <wtf/text/CString.h>
+
+namespace WTF {
+
+// String conversions
+String::String(const BString& string)
+{
+ if (string.Length())
+ m_impl = String::fromUTF8(string.String(), string.Length()).impl();
+ else
+ m_impl = StringImpl::empty();
+}
+
+String::operator BString() const
+{
+ BString string;
+ string.SetTo(utf8().data());
+
+ return string;
+}
+
+} // namespace WTF
void initializeMainThreadPlatform()
{
-#if !defined(BUILDING_ON_TIGER)
ASSERT(!staticMainThreadCaller);
staticMainThreadCaller = [[WTFMainThreadCaller alloc] init];
mainThreadEstablishedAsPthreadMain = false;
mainThreadPthread = pthread_self();
mainThreadNSThread = [[NSThread currentThread] retain];
-#else
- ASSERT_NOT_REACHED();
-#endif
}
void initializeMainThreadToProcessMainThreadPlatform()
return;
}
-#if !defined(BUILDING_ON_TIGER)
ASSERT(mainThreadNSThread);
[staticMainThreadCaller performSelector:@selector(call) onThread:mainThreadNSThread withObject:nil waitUntilDone:NO];
-#else
- ASSERT_NOT_REACHED();
-#endif
}
bool isMainThread()
return pthread_main_np();
}
-#if !defined(BUILDING_ON_TIGER)
ASSERT(mainThreadPthread);
return pthread_equal(pthread_self(), mainThreadPthread);
-#else
- ASSERT_NOT_REACHED();
- return false;
-#endif
}
// This function is the same as isMainThread() above except that it does not do
#include "config.h"
+#include <wtf/StdLibExtras.h>
#include <wtf/text/WTFString.h>
#include <QString>
-namespace WebCore {
+namespace WTF {
// String conversions
String::String(const QString& qstr)
{
if (qstr.isNull())
return;
- m_impl = StringImpl::create(reinterpret_cast<const UChar*>(qstr.constData()), qstr.length());
+ m_impl = StringImpl::create(reinterpret_cast_ptr<const UChar*>(qstr.constData()), qstr.length());
}
String::String(const QStringRef& ref)
{
if (!ref.string())
return;
- m_impl = StringImpl::create(reinterpret_cast<const UChar*>(ref.unicode()), ref.length());
+ m_impl = StringImpl::create(reinterpret_cast_ptr<const UChar*>(ref.unicode()), ref.length());
}
String::operator QString() const
return establishIdentifierForThread(currentThread);
}
+void yield()
+{
+ QThread::yieldCurrentThread();
+}
+
Mutex::Mutex()
: m_mutex(new QMutex())
{
+++ /dev/null
-/*
- * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-
-#if OS(SYMBIAN)
-
-#include "BlockAllocatorSymbian.h"
-
-
-namespace WTF {
-
-/** Efficiently allocates blocks of size blockSize with blockSize alignment.
- * Primarly designed for JSC Collector's needs.
- * Not thread-safe.
- */
-AlignedBlockAllocator::AlignedBlockAllocator(TUint32 reservationSize, TUint32 blockSize )
- : m_reservation(reservationSize),
- m_blockSize(blockSize)
-{
-
- // Get system's page size value.
- SYMBIAN_PAGESIZE(m_pageSize);
-
- // We only accept multiples of system page size for both initial reservation and the alignment/block size
- m_reservation = SYMBIAN_ROUNDUPTOMULTIPLE(m_reservation, m_pageSize);
- __ASSERT_ALWAYS(SYMBIAN_ROUNDUPTOMULTIPLE(m_blockSize, m_pageSize), User::Panic(_L("AlignedBlockAllocator1"), KErrArgument));
-
- // Calculate max. bit flags we need to carve a reservationSize range into blockSize-sized blocks
- m_map.numBits = m_reservation / m_blockSize;
- const TUint32 bitsPerWord = 8*sizeof(TUint32);
- const TUint32 numWords = (m_map.numBits + bitsPerWord -1) / bitsPerWord;
-
- m_map.bits = new TUint32[numWords];
- __ASSERT_ALWAYS(m_map.bits, User::Panic(_L("AlignedBlockAllocator2"), KErrNoMemory));
- m_map.clearAll();
-
- // Open a Symbian RChunk, and reserve requested virtual address range
- // Any thread in this process can operate this rchunk due to EOwnerProcess access rights.
- TInt ret = m_chunk.CreateDisconnectedLocal(0 , 0, (TInt)m_reservation , EOwnerProcess);
- if (ret != KErrNone)
- User::Panic(_L("AlignedBlockAllocator3"), ret);
-
- // This is the offset to m_chunk.Base() required to make it m_blockSize-aligned
- m_offset = SYMBIAN_ROUNDUPTOMULTIPLE(TUint32(m_chunk.Base()), m_blockSize) - TUint(m_chunk.Base());
-
-}
-
-void* AlignedBlockAllocator::alloc()
-{
-
- TInt freeRam = 0;
- void* address = 0;
-
- // Look up first free slot in bit map
- const TInt freeIdx = m_map.findFree();
-
- // Pseudo OOM: We ate up the address space we reserved..
- // ..even though the device may have free RAM left
- if (freeIdx < 0)
- return 0;
-
- TInt ret = m_chunk.Commit(m_offset + (m_blockSize * freeIdx), m_blockSize);
- if (ret != KErrNone)
- return 0; // True OOM: Device didn't have physical RAM to spare
-
- // Updated bit to mark region as in use.
- m_map.set(freeIdx);
-
- // Calculate address of committed region (block)
- address = (void*)( (m_chunk.Base() + m_offset) + (TUint)(m_blockSize * freeIdx) );
-
- return address;
-}
-
-void AlignedBlockAllocator::free(void* block)
-{
- // Calculate index of block to be freed
- TInt idx = TUint(static_cast<TUint8*>(block) - m_chunk.Base() - m_offset) / m_blockSize;
-
- __ASSERT_DEBUG(idx >= 0 && idx < m_map.numBits, User::Panic(_L("AlignedBlockAllocator4"), KErrCorrupt)); // valid index check
- __ASSERT_DEBUG(m_map.get(idx), User::Panic(_L("AlignedBlockAllocator5"), KErrCorrupt)); // in-use flag check
-
- // Return committed region to system RAM pool (the physical RAM becomes usable by others)
- TInt ret = m_chunk.Decommit(m_offset + m_blockSize * idx, m_blockSize);
-
- // mark this available again
- m_map.clear(idx);
-}
-
-void AlignedBlockAllocator::destroy()
-{
- // release everything!
- m_chunk.Decommit(0, m_chunk.MaxSize());
- m_map.clearAll();
-}
-
-AlignedBlockAllocator::~AlignedBlockAllocator()
-{
- destroy();
- m_chunk.Close();
- delete [] m_map.bits;
-}
-
-} // end of namespace
-
-#endif // SYMBIAN
+++ /dev/null
-/*
- * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef BlockAllocatorSymbian_h
-#define BlockAllocatorSymbian_h
-
-#include <e32cmn.h>
-#include <e32std.h>
-#include <hal.h>
-
-
-#define SYMBIAN_PAGESIZE(x) (HAL::Get(HALData::EMemoryPageSize, x));
-#define SYMBIAN_FREERAM(x) (HAL::Get(HALData::EMemoryRAMFree, x));
-#define SYMBIAN_ROUNDUPTOMULTIPLE(x, multipleof) ( (x + multipleof - 1) & ~(multipleof - 1) )
-
-// Set sane defaults if -D<flagname=value> wasn't provided via compiler args
-#ifndef JSCCOLLECTOR_VIRTUALMEM_RESERVATION
-#if defined(__WINS__)
- // Emulator has limited virtual address space
- #define JSCCOLLECTOR_VIRTUALMEM_RESERVATION (4*1024*1024)
-#else
- // HW has plenty of virtual addresses
- #define JSCCOLLECTOR_VIRTUALMEM_RESERVATION (128*1024*1024)
-#endif
-#endif
-
-namespace WTF {
-
-/**
- * Allocates contiguous region of size blockSize with blockSize-aligned address.
- * blockSize must be a multiple of system page size (typically 4K on Symbian/ARM)
- *
- * @param reservationSize Virtual address range to be reserved upon creation of chunk (bytes).
- * @param blockSize Size of a single allocation. Returned address will also be blockSize-aligned.
- */
-class AlignedBlockAllocator {
- public:
- AlignedBlockAllocator(TUint32 reservationSize, TUint32 blockSize);
- ~AlignedBlockAllocator();
- void destroy();
- void* alloc();
- void free(void* data);
-
- private:
- RChunk m_chunk; // Symbian chunk that lets us reserve/commit/decommit
- TUint m_offset; // offset of first committed region from base
- TInt m_pageSize; // cached value of system page size, typically 4K on Symbian
- TUint32 m_reservation;
- TUint32 m_blockSize;
-
- // Tracks comitted/decommitted state of a blockSize region
- struct {
-
- TUint32 *bits; // array of bit flags
- TUint32 numBits; // number of regions to keep track of
-
- bool get(TUint32 n) const
- {
- return !!(bits[n >> 5] & (1 << (n & 0x1F)));
- }
-
- void set(TUint32 n)
- {
- bits[n >> 5] |= (1 << (n & 0x1F));
- }
-
- void clear(TUint32 n)
- {
- bits[n >> 5] &= ~(1 << (n & 0x1F));
- }
-
- void clearAll()
- {
- for (TUint32 i = 0; i < numBits; i++)
- clear(i);
- }
-
- TInt findFree() const
- {
- for (TUint32 i = 0; i < numBits; i++) {
- if (!get(i))
- return i;
- }
- return -1;
- }
-
- } m_map;
-
-};
-
-}
-
-#endif // end of BlockAllocatorSymbian_h
-
-
/*
* Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
#include "config.h"
-#include <libkern/OSAtomic.h>
-
#include "AtomicString.h"
#include "StringHash.h"
#include <wtf/HashSet.h>
#include <wtf/Threading.h>
#include <wtf/WTFThreadData.h>
+#include <wtf/unicode/UTF8.h>
+
+#include <libkern/OSAtomic.h>
-namespace WebCore {
+namespace WTF {
+
+using namespace Unicode;
COMPILE_ASSERT(sizeof(AtomicString) == sizeof(String), atomic_string_and_string_must_be_same_size);
return table->table();
}
+template<typename T, typename HashTranslator>
+static inline PassRefPtr<StringImpl> addToStringTable(const T& value)
+{
+ pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable().add<T, HashTranslator>(value);
+
+ // If the string is newly-translated, then we need to adopt it.
+ // The boolean in the pair tells us if that is so.
+ return addResult.second ? adoptRef(*addResult.first) : *addResult.first;
+}
+
struct CStringTranslator {
static unsigned hash(const char* c)
{
- return StringImpl::computeHash(c);
+ return StringHasher::computeHash(c);
}
static bool equal(StringImpl* r, const char* s)
if (d[i] != c)
return false;
}
- return s[length] == 0;
+ return !s[length];
}
static void translate(StringImpl*& location, const char* const& c, unsigned hash)
{
- location = StringImpl::create(c).releaseRef();
+ location = StringImpl::create(c).leakRef();
location->setHash(hash);
location->setIsAtomic(true);
}
if (!c)
return 0;
if (!*c)
- return StringImpl::empty();
+ return StringImpl::empty();
+
AtomicStringTableLocker locker;
- pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable().add<const char*, CStringTranslator>(c);
- if (!addResult.second)
- return *addResult.first;
- return adoptRef(*addResult.first);
+ return addToStringTable<const char*, CStringTranslator>(c);
}
struct UCharBuffer {
// FIXME: perhaps we should have a more abstract macro that indicates when
// going 4 bytes at a time is unsafe
-#if CPU(ARM) || CPU(SH4)
+#if CPU(ARM) || CPU(SH4) || CPU(MIPS) || CPU(SPARC)
const UChar* stringCharacters = string->characters();
for (unsigned i = 0; i != length; ++i) {
if (*stringCharacters++ != *characters++)
#endif
}
+bool operator==(const AtomicString& string, const Vector<UChar>& vector)
+{
+ return string.impl() && equal(string.impl(), vector.data(), vector.size());
+}
+
struct UCharBufferTranslator {
static unsigned hash(const UCharBuffer& buf)
{
- return StringImpl::computeHash(buf.s, buf.length);
+ return StringHasher::computeHash(buf.s, buf.length);
}
static bool equal(StringImpl* const& str, const UCharBuffer& buf)
{
- return WebCore::equal(str, buf.s, buf.length);
+ return WTF::equal(str, buf.s, buf.length);
}
static void translate(StringImpl*& location, const UCharBuffer& buf, unsigned hash)
{
- location = StringImpl::create(buf.s, buf.length).releaseRef();
+ location = StringImpl::create(buf.s, buf.length).leakRef();
location->setHash(hash);
location->setIsAtomic(true);
}
struct HashAndCharactersTranslator {
static unsigned hash(const HashAndCharacters& buffer)
{
- ASSERT(buffer.hash == StringImpl::computeHash(buffer.characters, buffer.length));
+ ASSERT(buffer.hash == StringHasher::computeHash(buffer.characters, buffer.length));
return buffer.hash;
}
static bool equal(StringImpl* const& string, const HashAndCharacters& buffer)
{
- return WebCore::equal(string, buffer.characters, buffer.length);
+ return WTF::equal(string, buffer.characters, buffer.length);
}
static void translate(StringImpl*& location, const HashAndCharacters& buffer, unsigned hash)
{
- location = StringImpl::create(buffer.characters, buffer.length).releaseRef();
+ location = StringImpl::create(buffer.characters, buffer.length).leakRef();
+ location->setHash(hash);
+ location->setIsAtomic(true);
+ }
+};
+
+struct HashAndUTF8Characters {
+ unsigned hash;
+ const char* characters;
+ unsigned length;
+ unsigned utf16Length;
+};
+
+struct HashAndUTF8CharactersTranslator {
+ static unsigned hash(const HashAndUTF8Characters& buffer)
+ {
+ return buffer.hash;
+ }
+
+ static bool equal(StringImpl* const& string, const HashAndUTF8Characters& buffer)
+ {
+ if (buffer.utf16Length != string->length())
+ return false;
+
+ const UChar* stringCharacters = string->characters();
+
+ // If buffer contains only ASCII characters UTF-8 and UTF16 length are the same.
+ if (buffer.utf16Length != buffer.length)
+ return equalUTF16WithUTF8(stringCharacters, stringCharacters + string->length(), buffer.characters, buffer.characters + buffer.length);
+
+ for (unsigned i = 0; i < buffer.length; ++i) {
+ ASSERT(isASCII(buffer.characters[i]));
+ if (stringCharacters[i] != buffer.characters[i])
+ return false;
+ }
+
+ return true;
+ }
+
+ static void translate(StringImpl*& location, const HashAndUTF8Characters& buffer, unsigned hash)
+ {
+ UChar* target;
+ location = StringImpl::createUninitialized(buffer.utf16Length, target).releaseRef();
+
+ const char* source = buffer.characters;
+ if (convertUTF8ToUTF16(&source, source + buffer.length, &target, target + buffer.utf16Length) != conversionOK)
+ ASSERT_NOT_REACHED();
+
location->setHash(hash);
location->setIsAtomic(true);
}
if (!s)
return 0;
- if (length == 0)
+ if (!length)
return StringImpl::empty();
- UCharBuffer buf = { s, length };
+ UCharBuffer buffer = { s, length };
AtomicStringTableLocker locker;
- pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable().add<UCharBuffer, UCharBufferTranslator>(buf);
-
- // If the string is newly-translated, then we need to adopt it.
- // The boolean in the pair tells us if that is so.
- return addResult.second ? adoptRef(*addResult.first) : *addResult.first;
+ return addToStringTable<UCharBuffer, UCharBufferTranslator>(buffer);
}
PassRefPtr<StringImpl> AtomicString::add(const UChar* s, unsigned length, unsigned existingHash)
ASSERT(s);
ASSERT(existingHash);
- if (length == 0)
+ if (!length)
return StringImpl::empty();
-
- HashAndCharacters buffer = { existingHash, s, length };
+
+ HashAndCharacters buffer = { existingHash, s, length };
AtomicStringTableLocker locker;
- pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable().add<HashAndCharacters, HashAndCharactersTranslator>(buffer);
- if (!addResult.second)
- return *addResult.first;
- return adoptRef(*addResult.first);
+ return addToStringTable<HashAndCharacters, HashAndCharactersTranslator>(buffer);
}
PassRefPtr<StringImpl> AtomicString::add(const UChar* s)
while (s[length] != UChar(0))
length++;
- if (length == 0)
+ if (!length)
return StringImpl::empty();
- UCharBuffer buf = {s, length};
+ UCharBuffer buffer = { s, length };
AtomicStringTableLocker locker;
- pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable().add<UCharBuffer, UCharBufferTranslator>(buf);
-
- // If the string is newly-translated, then we need to adopt it.
- // The boolean in the pair tells us if that is so.
- return addResult.second ? adoptRef(*addResult.first) : *addResult.first;
+ return addToStringTable<UCharBuffer, UCharBufferTranslator>(buffer);
}
PassRefPtr<StringImpl> AtomicString::addSlowCase(StringImpl* r)
if (!r || r->isAtomic())
return r;
- if (r->length() == 0)
+ if (!r->length())
return StringImpl::empty();
AtomicStringTableLocker locker;
ASSERT(s);
ASSERT(existingHash);
- if (length == 0)
+ if (!length)
return static_cast<AtomicStringImpl*>(StringImpl::empty());
HashAndCharacters buffer = { existingHash, s, length };
AtomicStringTableLocker locker;
stringTable().remove(r);
}
-
+
AtomicString AtomicString::lower() const
{
// Note: This is a hot function in the Dromaeo benchmark.
StringImpl* impl = this->impl();
+ if (UNLIKELY(!impl))
+ return *this;
RefPtr<StringImpl> newImpl = impl->lower();
if (LIKELY(newImpl == impl))
return *this;
return AtomicString(newImpl);
}
+AtomicString AtomicString::fromUTF8Internal(const char* charactersStart, const char* charactersEnd)
+{
+ HashAndUTF8Characters buffer;
+ buffer.characters = charactersStart;
+ buffer.hash = calculateStringHashAndLengthFromUTF8(charactersStart, charactersEnd, buffer.length, buffer.utf16Length);
+
+ if (!buffer.hash)
+ return nullAtom;
+
+ AtomicString atomicString;
+ AtomicStringTableLocker locker;
+ atomicString.m_string = addToStringTable<HashAndUTF8Characters, HashAndUTF8CharactersTranslator>(buffer);
+ return atomicString;
}
+
+} // namespace WTF
#define ATOMICSTRING_CONVERSION
#endif
-// FIXME: This is a temporary layering violation while we move string code to WTF.
-// Landing the file moves in one patch, will follow on with patches to change the namespaces.
-namespace WebCore {
+namespace WTF {
struct AtomicStringHash;
bool contains(const String& s, bool caseSensitive = true) const
{ return m_string.contains(s, caseSensitive); }
- int find(UChar c, int start = 0) const { return m_string.find(c, start); }
- int find(const char* s, int start = 0, bool caseSentitive = true) const
+ size_t find(UChar c, size_t start = 0) const { return m_string.find(c, start); }
+ size_t find(const char* s, size_t start = 0, bool caseSentitive = true) const
{ return m_string.find(s, start, caseSentitive); }
- int find(const String& s, int start = 0, bool caseSentitive = true) const
+ size_t find(const String& s, size_t start = 0, bool caseSentitive = true) const
{ return m_string.find(s, start, caseSentitive); }
bool startsWith(const String& s, bool caseSensitive = true) const
static void remove(StringImpl*);
-#if PLATFORM(CF)
+#if USE(CF)
AtomicString(CFStringRef s) : m_string(add(String(s).impl())) { }
CFStringRef createCFString() const { return m_string.createCFString(); }
#endif
operator QString() const { return m_string; }
#endif
+ // AtomicString::fromUTF8 will return a null string if
+ // the input data contains invalid UTF-8 sequences.
+ static AtomicString fromUTF8(const char*, size_t);
+ static AtomicString fromUTF8(const char*);
+
private:
String m_string;
return addSlowCase(r);
}
static PassRefPtr<StringImpl> addSlowCase(StringImpl*);
+ static AtomicString fromUTF8Internal(const char*, const char*);
};
inline bool operator==(const AtomicString& a, const AtomicString& b) { return a.impl() == b.impl(); }
bool operator==(const AtomicString& a, const char* b);
+bool operator==(const AtomicString& a, const Vector<UChar>& b);
inline bool operator==(const AtomicString& a, const String& b) { return equal(a.impl(), b.impl()); }
inline bool operator==(const char* a, const AtomicString& b) { return b == a; }
inline bool operator==(const String& a, const AtomicString& b) { return equal(a.impl(), b.impl()); }
+inline bool operator==(const Vector<UChar>& a, const AtomicString& b) { return b == a; }
inline bool operator!=(const AtomicString& a, const AtomicString& b) { return a.impl() != b.impl(); }
inline bool operator!=(const AtomicString& a, const char *b) { return !(a == b); }
inline bool operator!=(const AtomicString& a, const String& b) { return !equal(a.impl(), b.impl()); }
+inline bool operator!=(const AtomicString& a, const Vector<UChar>& b) { return !(a == b); }
inline bool operator!=(const char* a, const AtomicString& b) { return !(b == a); }
inline bool operator!=(const String& a, const AtomicString& b) { return !equal(a.impl(), b.impl()); }
+inline bool operator!=(const Vector<UChar>& a, const AtomicString& b) { return !(a == b); }
inline bool equalIgnoringCase(const AtomicString& a, const AtomicString& b) { return equalIgnoringCase(a.impl(), b.impl()); }
inline bool equalIgnoringCase(const AtomicString& a, const char* b) { return equalIgnoringCase(a.impl(), b); }
// Define external global variables for the commonly used atomic strings.
// These are only usable from the main thread.
#ifndef ATOMICSTRING_HIDE_GLOBALS
- extern const JS_EXPORTDATA AtomicString nullAtom;
- extern const JS_EXPORTDATA AtomicString emptyAtom;
- extern const JS_EXPORTDATA AtomicString textAtom;
- extern const JS_EXPORTDATA AtomicString commentAtom;
- extern const JS_EXPORTDATA AtomicString starAtom;
- extern const JS_EXPORTDATA AtomicString xmlAtom;
- extern const JS_EXPORTDATA AtomicString xmlnsAtom;
+extern const JS_EXPORTDATA AtomicString nullAtom;
+extern const JS_EXPORTDATA AtomicString emptyAtom;
+extern const JS_EXPORTDATA AtomicString textAtom;
+extern const JS_EXPORTDATA AtomicString commentAtom;
+extern const JS_EXPORTDATA AtomicString starAtom;
+extern const JS_EXPORTDATA AtomicString xmlAtom;
+extern const JS_EXPORTDATA AtomicString xmlnsAtom;
+
+inline AtomicString AtomicString::fromUTF8(const char* characters, size_t length)
+{
+ if (!characters)
+ return nullAtom;
+ if (!length)
+ return emptyAtom;
+ return fromUTF8Internal(characters, characters + length);
+}
+
+inline AtomicString AtomicString::fromUTF8(const char* characters)
+{
+ if (!characters)
+ return nullAtom;
+ if (!*characters)
+ return emptyAtom;
+ return fromUTF8Internal(characters, 0);
+}
#endif
-} // namespace WebCore
-
-
-namespace WTF {
-
- // AtomicStringHash is the default hash for AtomicString
- template<typename T> struct DefaultHash;
- template<> struct DefaultHash<WebCore::AtomicString> {
- typedef WebCore::AtomicStringHash Hash;
- };
+// AtomicStringHash is the default hash for AtomicString
+template<typename T> struct DefaultHash;
+template<> struct DefaultHash<AtomicString> {
+ typedef AtomicStringHash Hash;
+};
} // namespace WTF
+#ifndef ATOMICSTRING_HIDE_GLOBALS
+using WTF::AtomicString;
+using WTF::nullAtom;
+using WTF::emptyAtom;
+using WTF::textAtom;
+using WTF::commentAtom;
+using WTF::starAtom;
+using WTF::xmlAtom;
+using WTF::xmlnsAtom;
+#endif
+
+#include "StringConcatenate.h"
#endif // AtomicString_h
--- /dev/null
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef AtomicStringHash_h
+#define AtomicStringHash_h
+
+#include <wtf/text/AtomicString.h>
+#include <wtf/HashTraits.h>
+
+namespace WTF {
+
+ struct AtomicStringHash {
+ static unsigned hash(const AtomicString& key)
+ {
+ return key.impl()->existingHash();
+ }
+
+ static bool equal(const AtomicString& a, const AtomicString& b)
+ {
+ return a == b;
+ }
+
+ static const bool safeToCompareToEmptyOrDeleted = false;
+ };
+
+ // AtomicStringHash is the default hash for AtomicString
+ template<> struct HashTraits<WTF::AtomicString> : GenericHashTraits<WTF::AtomicString> {
+ static const bool emptyValueIsZero = true;
+ static void constructDeletedValue(WTF::AtomicString& slot) { new (&slot) WTF::AtomicString(HashTableDeletedValue); }
+ static bool isDeletedValue(const WTF::AtomicString& slot) { return slot.isHashTableDeletedValue(); }
+ };
+
+}
+
+using WTF::AtomicStringHash;
+
+#endif
#include "StringImpl.h"
-// FIXME: This is a temporary layering violation while we move string code to WTF.
-// Landing the file moves in one patch, will follow on with patches to change the namespaces.
-namespace WebCore {
+namespace WTF {
class AtomicStringImpl : public StringImpl
{
}
+using WTF::AtomicStringImpl;
+
#endif
CString::CString(const char* str)
{
+ if (!str)
+ return;
+
init(str, strlen(str));
}
-CString::CString(const char* str, unsigned length)
+CString::CString(const char* str, size_t length)
{
init(str, length);
}
-void CString::init(const char* str, unsigned length)
+void CString::init(const char* str, size_t length)
{
if (!str)
return;
- if (length >= numeric_limits<size_t>::max())
- CRASH();
+ // We need to be sure we can add 1 to length without overflowing.
+ // Since the passed-in length is the length of an actual existing
+ // string, and we know the string doesn't occupy the entire address
+ // space, we can assert here and there's no need for a runtime check.
+ ASSERT(length < numeric_limits<size_t>::max());
m_buffer = CStringBuffer::create(length + 1);
memcpy(m_buffer->mutableData(), str, length);
private:
friend class CString;
- static PassRefPtr<CStringBuffer> create(unsigned length) { return adoptRef(new CStringBuffer(length)); }
- CStringBuffer(unsigned length) : m_vector(length) { }
+ static PassRefPtr<CStringBuffer> create(size_t length) { return adoptRef(new CStringBuffer(length)); }
+ CStringBuffer(size_t length) : m_vector(length) { }
char* mutableData() { return m_vector.data(); }
Vector<char> m_vector;
public:
CString() { }
CString(const char*);
- CString(const char*, unsigned length);
+ CString(const char*, size_t length);
CString(CStringBuffer* buffer) : m_buffer(buffer) { }
static CString newUninitialized(size_t length, char*& characterBuffer);
return m_buffer ? m_buffer->data() : 0;
}
char* mutableData();
- unsigned length() const
+ size_t length() const
{
return m_buffer ? m_buffer->length() - 1 : 0;
}
private:
void copyBufferIfNeeded();
- void init(const char*, unsigned length);
+ void init(const char*, size_t length);
RefPtr<CStringBuffer> m_buffer;
};
#define StringBuffer_h
#include <wtf/Assertions.h>
-#include <wtf/Noncopyable.h>
#include <wtf/unicode/Unicode.h>
#include <limits>
-namespace WebCore {
+namespace WTF {
-class StringBuffer : public Noncopyable {
+class StringBuffer {
+ WTF_MAKE_NONCOPYABLE(StringBuffer);
public:
explicit StringBuffer(unsigned length)
: m_length(length)
} // namespace WTF
+using WTF::StringBuffer;
+
#endif // StringBuffer_h
--- /dev/null
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "StringBuilder.h"
+
+#include "WTFString.h"
+
+namespace WTF {
+
+void StringBuilder::reifyString()
+{
+ // Check if the string already exists.
+ if (!m_string.isNull()) {
+ ASSERT(m_string.length() == m_length);
+ return;
+ }
+
+ // Check for empty.
+ if (!m_length) {
+ m_string = StringImpl::empty();
+ return;
+ }
+
+ // Must be valid in the buffer, take a substring (unless string fills the buffer).
+ ASSERT(m_buffer && m_length <= m_buffer->length());
+ m_string = (m_length == m_buffer->length())
+ ? m_buffer.get()
+ : StringImpl::create(m_buffer, 0, m_length);
+}
+
+void StringBuilder::resize(unsigned newSize)
+{
+ // Check newSize < m_length, hence m_length > 0.
+ ASSERT(newSize <= m_length);
+ if (newSize == m_length)
+ return;
+ ASSERT(m_length);
+
+ // If there is a buffer, we only need to duplicate it if it has more than one ref.
+ if (m_buffer) {
+ if (!m_buffer->hasOneRef())
+ allocateBuffer(m_buffer->characters(), m_buffer->length());
+ m_length = newSize;
+ m_string = String();
+ return;
+ }
+
+ // Since m_length && !m_buffer, the string must be valid in m_string, and m_string.length() > 0.
+ ASSERT(!m_string.isEmpty());
+ ASSERT(m_length == m_string.length());
+ ASSERT(newSize < m_string.length());
+ m_length = newSize;
+ m_string = StringImpl::create(m_string.impl(), 0, newSize);
+}
+
+void StringBuilder::reserveCapacity(unsigned newCapacity)
+{
+ if (m_buffer) {
+ // If there is already a buffer, then grow if necessary.
+ if (newCapacity > m_buffer->length())
+ allocateBuffer(m_buffer->characters(), newCapacity);
+ } else {
+ // Grow the string, if necessary.
+ if (newCapacity > m_length)
+ allocateBuffer(m_string.characters(), newCapacity);
+ }
+}
+
+// Allocate a new buffer, copying in currentCharacters (these may come from either m_string
+// or m_buffer, neither will be reassigned until the copy has completed).
+void StringBuilder::allocateBuffer(const UChar* currentCharacters, unsigned requiredLength)
+{
+ // Copy the existing data into a new buffer, set result to point to the end of the existing data.
+ RefPtr<StringImpl> buffer = StringImpl::createUninitialized(requiredLength, m_bufferCharacters);
+ memcpy(m_bufferCharacters, currentCharacters, static_cast<size_t>(m_length) * sizeof(UChar)); // This can't overflow.
+
+ // Update the builder state.
+ m_buffer = buffer.release();
+ m_string = String();
+}
+
+// Make 'length' additional capacity be available in m_buffer, update m_string & m_length,
+// return a pointer to the newly allocated storage.
+UChar* StringBuilder::appendUninitialized(unsigned length)
+{
+ ASSERT(length);
+
+ // Calcuate the new size of the builder after appending.
+ unsigned requiredLength = length + m_length;
+ if (requiredLength < length)
+ CRASH();
+
+ if (m_buffer) {
+ // If the buffer is valid it must be at least as long as the current builder contents!
+ ASSERT(m_buffer->length() >= m_length);
+
+ // Check if the buffer already has sufficient capacity.
+ if (requiredLength <= m_buffer->length()) {
+ unsigned currentLength = m_length;
+ m_string = String();
+ m_length = requiredLength;
+ return m_bufferCharacters + currentLength;
+ }
+
+ // We need to realloc the buffer.
+ allocateBuffer(m_buffer->characters(), std::max(requiredLength, m_buffer->length() * 2));
+ } else {
+ ASSERT(m_string.length() == m_length);
+ allocateBuffer(m_string.characters(), std::max(requiredLength, requiredLength * 2));
+ }
+
+ UChar* result = m_bufferCharacters + m_length;
+ m_length = requiredLength;
+ return result;
+}
+
+void StringBuilder::append(const UChar* characters, unsigned length)
+{
+ if (!length)
+ return;
+ ASSERT(characters);
+
+ memcpy(appendUninitialized(length), characters, static_cast<size_t>(length) * 2);
+}
+
+void StringBuilder::append(const char* characters, unsigned length)
+{
+ if (!length)
+ return;
+ ASSERT(characters);
+
+ UChar* dest = appendUninitialized(length);
+ const char* end = characters + length;
+ while (characters < end)
+ *(dest++) = *(const unsigned char*)(characters++);
+}
+
+void StringBuilder::shrinkToFit()
+{
+ // If the buffer is at least 80% full, don't bother copying. Need to tune this heuristic!
+ if (m_buffer && m_buffer->length() > (m_length + (m_length >> 2))) {
+ UChar* result;
+ m_string = StringImpl::createUninitialized(m_length, result);
+ memcpy(result, m_buffer->characters(), static_cast<size_t>(m_length) * 2); // This can't overflow.
+ m_buffer = 0;
+ }
+}
+
+} // namespace WTF
--- /dev/null
+/*
+ * Copyright (C) 2009, 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef StringBuilder_h
+#define StringBuilder_h
+
+#include <wtf/Vector.h>
+#include <wtf/text/WTFString.h>
+
+namespace WTF {
+
+class StringBuilder {
+public:
+ StringBuilder()
+ : m_length(0)
+ {
+ }
+
+ void append(const UChar*, unsigned);
+ void append(const char*, unsigned);
+
+ void append(const String& string)
+ {
+ // If we're appending to an empty string, and there is not buffer
+ // (in case reserveCapacity has been called) then just retain the
+ // string.
+ if (!m_length && !m_buffer) {
+ m_string = string;
+ m_length = string.length();
+ return;
+ }
+ append(string.characters(), string.length());
+ }
+
+ void append(const char* characters)
+ {
+ if (characters)
+ append(characters, strlen(characters));
+ }
+
+ void append(UChar c)
+ {
+ if (m_buffer && m_length < m_buffer->length() && m_string.isNull())
+ m_bufferCharacters[m_length++] = c;
+ else
+ append(&c, 1);
+ }
+
+ void append(char c)
+ {
+ if (m_buffer && m_length < m_buffer->length() && m_string.isNull())
+ m_bufferCharacters[m_length++] = (unsigned char)c;
+ else
+ append(&c, 1);
+ }
+
+ String toString()
+ {
+ if (m_string.isNull()) {
+ shrinkToFit();
+ reifyString();
+ }
+ return m_string;
+ }
+
+ String toStringPreserveCapacity()
+ {
+ if (m_string.isNull())
+ reifyString();
+ return m_string;
+ }
+
+ unsigned length() const
+ {
+ return m_length;
+ }
+
+ bool isEmpty() const { return !length(); }
+
+ void reserveCapacity(unsigned newCapacity);
+
+ void resize(unsigned newSize);
+
+ void shrinkToFit();
+
+ UChar operator[](unsigned i) const
+ {
+ ASSERT(i < m_length);
+ if (!m_string.isNull())
+ return m_string[i];
+ ASSERT(m_buffer);
+ return m_buffer->characters()[i];
+ }
+
+ void clear()
+ {
+ m_length = 0;
+ m_string = String();
+ m_buffer = 0;
+ }
+
+private:
+ void allocateBuffer(const UChar* currentCharacters, unsigned requiredLength);
+ UChar* appendUninitialized(unsigned length);
+ void reifyString();
+
+ unsigned m_length;
+ String m_string;
+ RefPtr<StringImpl> m_buffer;
+ UChar* m_bufferCharacters;
+};
+
+} // namespace WTF
+
+using WTF::StringBuilder;
+
+#endif // StringBuilder_h
--- /dev/null
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef StringConcatenate_h
+#define StringConcatenate_h
+
+#ifndef WTFString_h
+#include "AtomicString.h"
+#endif
+
+namespace WTF {
+
+template<typename StringType>
+class StringTypeAdapter {
+};
+
+template<>
+class StringTypeAdapter<char> {
+public:
+ StringTypeAdapter<char>(char buffer)
+ : m_buffer(buffer)
+ {
+ }
+
+ unsigned length() { return 1; }
+ void writeTo(UChar* destination) { *destination = m_buffer; }
+
+private:
+ unsigned char m_buffer;
+};
+
+template<>
+class StringTypeAdapter<UChar> {
+public:
+ StringTypeAdapter<UChar>(UChar buffer)
+ : m_buffer(buffer)
+ {
+ }
+
+ unsigned length() { return 1; }
+ void writeTo(UChar* destination) { *destination = m_buffer; }
+
+private:
+ UChar m_buffer;
+};
+
+template<>
+class StringTypeAdapter<char*> {
+public:
+ StringTypeAdapter<char*>(char* buffer)
+ : m_buffer(buffer)
+ , m_length(strlen(buffer))
+ {
+ }
+
+ unsigned length() { return m_length; }
+
+ void writeTo(UChar* destination)
+ {
+ for (unsigned i = 0; i < m_length; ++i) {
+ unsigned char c = m_buffer[i];
+ destination[i] = c;
+ }
+ }
+
+private:
+ const char* m_buffer;
+ unsigned m_length;
+};
+
+template<>
+class StringTypeAdapter<const UChar*> {
+public:
+ StringTypeAdapter<const UChar*>(const UChar* buffer)
+ : m_buffer(buffer)
+ {
+ size_t len = 0;
+ while (m_buffer[len] != UChar(0))
+ len++;
+
+ if (len > std::numeric_limits<unsigned>::max())
+ CRASH();
+
+ m_length = len;
+ }
+
+ unsigned length() { return m_length; }
+
+ void writeTo(UChar* destination)
+ {
+ memcpy(destination, m_buffer, static_cast<size_t>(m_length) * sizeof(UChar));
+ }
+
+private:
+ const UChar* m_buffer;
+ unsigned m_length;
+};
+
+template<>
+class StringTypeAdapter<const char*> {
+public:
+ StringTypeAdapter<const char*>(const char* buffer)
+ : m_buffer(buffer)
+ , m_length(strlen(buffer))
+ {
+ }
+
+ unsigned length() { return m_length; }
+
+ void writeTo(UChar* destination)
+ {
+ for (unsigned i = 0; i < m_length; ++i) {
+ unsigned char c = m_buffer[i];
+ destination[i] = c;
+ }
+ }
+
+private:
+ const char* m_buffer;
+ unsigned m_length;
+};
+
+template<>
+class StringTypeAdapter<Vector<char> > {
+public:
+ StringTypeAdapter<Vector<char> >(const Vector<char>& buffer)
+ : m_buffer(buffer)
+ {
+ }
+
+ size_t length() { return m_buffer.size(); }
+
+ void writeTo(UChar* destination)
+ {
+ for (size_t i = 0; i < m_buffer.size(); ++i) {
+ unsigned char c = m_buffer[i];
+ destination[i] = c;
+ }
+ }
+
+private:
+ const Vector<char>& m_buffer;
+};
+
+template<>
+class StringTypeAdapter<String> {
+public:
+ StringTypeAdapter<String>(const String& string)
+ : m_buffer(string)
+ {
+ }
+
+ unsigned length() { return m_buffer.length(); }
+
+ void writeTo(UChar* destination)
+ {
+ const UChar* data = m_buffer.characters();
+ unsigned length = m_buffer.length();
+ for (unsigned i = 0; i < length; ++i)
+ destination[i] = data[i];
+ }
+
+private:
+ const String& m_buffer;
+};
+
+template<>
+class StringTypeAdapter<AtomicString> {
+public:
+ StringTypeAdapter<AtomicString>(const AtomicString& string)
+ : m_adapter(string.string())
+ {
+ }
+
+ unsigned length() { return m_adapter.length(); }
+ void writeTo(UChar* destination) { m_adapter.writeTo(destination); }
+
+private:
+ StringTypeAdapter<String> m_adapter;
+};
+
+inline void sumWithOverflow(unsigned& total, unsigned addend, bool& overflow)
+{
+ unsigned oldTotal = total;
+ total = oldTotal + addend;
+ if (total < oldTotal)
+ overflow = true;
+}
+
+template<typename StringType1, typename StringType2>
+PassRefPtr<StringImpl> tryMakeString(StringType1 string1, StringType2 string2)
+{
+ StringTypeAdapter<StringType1> adapter1(string1);
+ StringTypeAdapter<StringType2> adapter2(string2);
+
+ UChar* buffer;
+ bool overflow = false;
+ unsigned length = adapter1.length();
+ sumWithOverflow(length, adapter2.length(), overflow);
+ if (overflow)
+ return 0;
+ RefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer);
+ if (!resultImpl)
+ return 0;
+
+ UChar* result = buffer;
+ adapter1.writeTo(result);
+ result += adapter1.length();
+ adapter2.writeTo(result);
+
+ return resultImpl.release();
+}
+
+template<typename StringType1, typename StringType2, typename StringType3>
+PassRefPtr<StringImpl> tryMakeString(StringType1 string1, StringType2 string2, StringType3 string3)
+{
+ StringTypeAdapter<StringType1> adapter1(string1);
+ StringTypeAdapter<StringType2> adapter2(string2);
+ StringTypeAdapter<StringType3> adapter3(string3);
+
+ UChar* buffer = 0;
+ bool overflow = false;
+ unsigned length = adapter1.length();
+ sumWithOverflow(length, adapter2.length(), overflow);
+ sumWithOverflow(length, adapter3.length(), overflow);
+ if (overflow)
+ return 0;
+ RefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer);
+ if (!resultImpl)
+ return 0;
+
+ UChar* result = buffer;
+ adapter1.writeTo(result);
+ result += adapter1.length();
+ adapter2.writeTo(result);
+ result += adapter2.length();
+ adapter3.writeTo(result);
+
+ return resultImpl.release();
+}
+
+template<typename StringType1, typename StringType2, typename StringType3, typename StringType4>
+PassRefPtr<StringImpl> tryMakeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4)
+{
+ StringTypeAdapter<StringType1> adapter1(string1);
+ StringTypeAdapter<StringType2> adapter2(string2);
+ StringTypeAdapter<StringType3> adapter3(string3);
+ StringTypeAdapter<StringType4> adapter4(string4);
+
+ UChar* buffer;
+ bool overflow = false;
+ unsigned length = adapter1.length();
+ sumWithOverflow(length, adapter2.length(), overflow);
+ sumWithOverflow(length, adapter3.length(), overflow);
+ sumWithOverflow(length, adapter4.length(), overflow);
+ if (overflow)
+ return 0;
+ RefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer);
+ if (!resultImpl)
+ return 0;
+
+ UChar* result = buffer;
+ adapter1.writeTo(result);
+ result += adapter1.length();
+ adapter2.writeTo(result);
+ result += adapter2.length();
+ adapter3.writeTo(result);
+ result += adapter3.length();
+ adapter4.writeTo(result);
+
+ return resultImpl.release();
+}
+
+template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5>
+PassRefPtr<StringImpl> tryMakeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5)
+{
+ StringTypeAdapter<StringType1> adapter1(string1);
+ StringTypeAdapter<StringType2> adapter2(string2);
+ StringTypeAdapter<StringType3> adapter3(string3);
+ StringTypeAdapter<StringType4> adapter4(string4);
+ StringTypeAdapter<StringType5> adapter5(string5);
+
+ UChar* buffer;
+ bool overflow = false;
+ unsigned length = adapter1.length();
+ sumWithOverflow(length, adapter2.length(), overflow);
+ sumWithOverflow(length, adapter3.length(), overflow);
+ sumWithOverflow(length, adapter4.length(), overflow);
+ sumWithOverflow(length, adapter5.length(), overflow);
+ if (overflow)
+ return 0;
+ RefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer);
+ if (!resultImpl)
+ return 0;
+
+ UChar* result = buffer;
+ adapter1.writeTo(result);
+ result += adapter1.length();
+ adapter2.writeTo(result);
+ result += adapter2.length();
+ adapter3.writeTo(result);
+ result += adapter3.length();
+ adapter4.writeTo(result);
+ result += adapter4.length();
+ adapter5.writeTo(result);
+
+ return resultImpl.release();
+}
+
+template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6>
+PassRefPtr<StringImpl> tryMakeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6)
+{
+ StringTypeAdapter<StringType1> adapter1(string1);
+ StringTypeAdapter<StringType2> adapter2(string2);
+ StringTypeAdapter<StringType3> adapter3(string3);
+ StringTypeAdapter<StringType4> adapter4(string4);
+ StringTypeAdapter<StringType5> adapter5(string5);
+ StringTypeAdapter<StringType6> adapter6(string6);
+
+ UChar* buffer;
+ bool overflow = false;
+ unsigned length = adapter1.length();
+ sumWithOverflow(length, adapter2.length(), overflow);
+ sumWithOverflow(length, adapter3.length(), overflow);
+ sumWithOverflow(length, adapter4.length(), overflow);
+ sumWithOverflow(length, adapter5.length(), overflow);
+ sumWithOverflow(length, adapter6.length(), overflow);
+ if (overflow)
+ return 0;
+ RefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer);
+ if (!resultImpl)
+ return 0;
+
+ UChar* result = buffer;
+ adapter1.writeTo(result);
+ result += adapter1.length();
+ adapter2.writeTo(result);
+ result += adapter2.length();
+ adapter3.writeTo(result);
+ result += adapter3.length();
+ adapter4.writeTo(result);
+ result += adapter4.length();
+ adapter5.writeTo(result);
+ result += adapter5.length();
+ adapter6.writeTo(result);
+
+ return resultImpl.release();
+}
+
+template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7>
+PassRefPtr<StringImpl> tryMakeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7)
+{
+ StringTypeAdapter<StringType1> adapter1(string1);
+ StringTypeAdapter<StringType2> adapter2(string2);
+ StringTypeAdapter<StringType3> adapter3(string3);
+ StringTypeAdapter<StringType4> adapter4(string4);
+ StringTypeAdapter<StringType5> adapter5(string5);
+ StringTypeAdapter<StringType6> adapter6(string6);
+ StringTypeAdapter<StringType7> adapter7(string7);
+
+ UChar* buffer;
+ bool overflow = false;
+ unsigned length = adapter1.length();
+ sumWithOverflow(length, adapter2.length(), overflow);
+ sumWithOverflow(length, adapter3.length(), overflow);
+ sumWithOverflow(length, adapter4.length(), overflow);
+ sumWithOverflow(length, adapter5.length(), overflow);
+ sumWithOverflow(length, adapter6.length(), overflow);
+ sumWithOverflow(length, adapter7.length(), overflow);
+ if (overflow)
+ return 0;
+ RefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer);
+ if (!resultImpl)
+ return 0;
+
+ UChar* result = buffer;
+ adapter1.writeTo(result);
+ result += adapter1.length();
+ adapter2.writeTo(result);
+ result += adapter2.length();
+ adapter3.writeTo(result);
+ result += adapter3.length();
+ adapter4.writeTo(result);
+ result += adapter4.length();
+ adapter5.writeTo(result);
+ result += adapter5.length();
+ adapter6.writeTo(result);
+ result += adapter6.length();
+ adapter7.writeTo(result);
+
+ return resultImpl.release();
+}
+
+template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7, typename StringType8>
+PassRefPtr<StringImpl> tryMakeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7, StringType8 string8)
+{
+ StringTypeAdapter<StringType1> adapter1(string1);
+ StringTypeAdapter<StringType2> adapter2(string2);
+ StringTypeAdapter<StringType3> adapter3(string3);
+ StringTypeAdapter<StringType4> adapter4(string4);
+ StringTypeAdapter<StringType5> adapter5(string5);
+ StringTypeAdapter<StringType6> adapter6(string6);
+ StringTypeAdapter<StringType7> adapter7(string7);
+ StringTypeAdapter<StringType8> adapter8(string8);
+
+ UChar* buffer;
+ bool overflow = false;
+ unsigned length = adapter1.length();
+ sumWithOverflow(length, adapter2.length(), overflow);
+ sumWithOverflow(length, adapter3.length(), overflow);
+ sumWithOverflow(length, adapter4.length(), overflow);
+ sumWithOverflow(length, adapter5.length(), overflow);
+ sumWithOverflow(length, adapter6.length(), overflow);
+ sumWithOverflow(length, adapter7.length(), overflow);
+ sumWithOverflow(length, adapter8.length(), overflow);
+ if (overflow)
+ return 0;
+ RefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer);
+ if (!resultImpl)
+ return 0;
+
+ UChar* result = buffer;
+ adapter1.writeTo(result);
+ result += adapter1.length();
+ adapter2.writeTo(result);
+ result += adapter2.length();
+ adapter3.writeTo(result);
+ result += adapter3.length();
+ adapter4.writeTo(result);
+ result += adapter4.length();
+ adapter5.writeTo(result);
+ result += adapter5.length();
+ adapter6.writeTo(result);
+ result += adapter6.length();
+ adapter7.writeTo(result);
+ result += adapter7.length();
+ adapter8.writeTo(result);
+
+ return resultImpl.release();
+}
+
+template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7, typename StringType8, typename StringType9>
+PassRefPtr<StringImpl> tryMakeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7, StringType8 string8, StringType9 string9)
+{
+ StringTypeAdapter<StringType1> adapter1(string1);
+ StringTypeAdapter<StringType2> adapter2(string2);
+ StringTypeAdapter<StringType3> adapter3(string3);
+ StringTypeAdapter<StringType4> adapter4(string4);
+ StringTypeAdapter<StringType5> adapter5(string5);
+ StringTypeAdapter<StringType6> adapter6(string6);
+ StringTypeAdapter<StringType7> adapter7(string7);
+ StringTypeAdapter<StringType8> adapter8(string8);
+ StringTypeAdapter<StringType9> adapter9(string9);
+
+ UChar* buffer;
+ bool overflow = false;
+ unsigned length = adapter1.length();
+ sumWithOverflow(length, adapter2.length(), overflow);
+ sumWithOverflow(length, adapter3.length(), overflow);
+ sumWithOverflow(length, adapter4.length(), overflow);
+ sumWithOverflow(length, adapter5.length(), overflow);
+ sumWithOverflow(length, adapter6.length(), overflow);
+ sumWithOverflow(length, adapter7.length(), overflow);
+ sumWithOverflow(length, adapter8.length(), overflow);
+ sumWithOverflow(length, adapter9.length(), overflow);
+ if (overflow)
+ return 0;
+ RefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer);
+ if (!resultImpl)
+ return 0;
+
+ UChar* result = buffer;
+ adapter1.writeTo(result);
+ result += adapter1.length();
+ adapter2.writeTo(result);
+ result += adapter2.length();
+ adapter3.writeTo(result);
+ result += adapter3.length();
+ adapter4.writeTo(result);
+ result += adapter4.length();
+ adapter5.writeTo(result);
+ result += adapter5.length();
+ adapter6.writeTo(result);
+ result += adapter6.length();
+ adapter7.writeTo(result);
+ result += adapter7.length();
+ adapter8.writeTo(result);
+ result += adapter8.length();
+ adapter9.writeTo(result);
+
+ return resultImpl.release();
+}
+
+
+// Convenience only.
+template<typename StringType1>
+String makeString(StringType1 string1)
+{
+ return String(string1);
+}
+
+template<typename StringType1, typename StringType2>
+String makeString(StringType1 string1, StringType2 string2)
+{
+ RefPtr<StringImpl> resultImpl = tryMakeString(string1, string2);
+ if (!resultImpl)
+ CRASH();
+ return resultImpl.release();
+}
+
+template<typename StringType1, typename StringType2, typename StringType3>
+String makeString(StringType1 string1, StringType2 string2, StringType3 string3)
+{
+ RefPtr<StringImpl> resultImpl = tryMakeString(string1, string2, string3);
+ if (!resultImpl)
+ CRASH();
+ return resultImpl.release();
+}
+
+template<typename StringType1, typename StringType2, typename StringType3, typename StringType4>
+String makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4)
+{
+ RefPtr<StringImpl> resultImpl = tryMakeString(string1, string2, string3, string4);
+ if (!resultImpl)
+ CRASH();
+ return resultImpl.release();
+}
+
+template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5>
+String makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5)
+{
+ RefPtr<StringImpl> resultImpl = tryMakeString(string1, string2, string3, string4, string5);
+ if (!resultImpl)
+ CRASH();
+ return resultImpl.release();
+}
+
+template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6>
+String makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6)
+{
+ RefPtr<StringImpl> resultImpl = tryMakeString(string1, string2, string3, string4, string5, string6);
+ if (!resultImpl)
+ CRASH();
+ return resultImpl.release();
+}
+
+template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7>
+String makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7)
+{
+ RefPtr<StringImpl> resultImpl = tryMakeString(string1, string2, string3, string4, string5, string6, string7);
+ if (!resultImpl)
+ CRASH();
+ return resultImpl.release();
+}
+
+template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7, typename StringType8>
+String makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7, StringType8 string8)
+{
+ RefPtr<StringImpl> resultImpl = tryMakeString(string1, string2, string3, string4, string5, string6, string7, string8);
+ if (!resultImpl)
+ CRASH();
+ return resultImpl.release();
+}
+
+template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7, typename StringType8, typename StringType9>
+String makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7, StringType8 string8, StringType9 string9)
+{
+ RefPtr<StringImpl> resultImpl = tryMakeString(string1, string2, string3, string4, string5, string6, string7, string8, string9);
+ if (!resultImpl)
+ CRASH();
+ return resultImpl.release();
+}
+
+} // namespace WTF
+
+using WTF::makeString;
+
+#include "StringOperators.h"
+#endif
#include "AtomicString.h"
#include "WTFString.h"
+#include <wtf/Forward.h>
#include <wtf/HashTraits.h>
-#include <wtf/StringHashFunctions.h>
+#include <wtf/StringHasher.h>
#include <wtf/unicode/Unicode.h>
-// FIXME: This is a temporary layering violation while we move string code to WTF.
-// Landing the file moves in one patch, will follow on with patches to change the namespaces.
-namespace WebCore {
+namespace WTF {
// The hash() functions on StringHash and CaseFoldingHash do not support
// null strings. get(), contains(), and add() on HashMap<String,..., StringHash>
// FIXME: perhaps we should have a more abstract macro that indicates when
// going 4 bytes at a time is unsafe
-#if CPU(ARM) || CPU(SH4)
+#if CPU(ARM) || CPU(SH4) || CPU(MIPS)
const UChar* aChars = a->characters();
const UChar* bChars = b->characters();
for (unsigned i = 0; i != aLength; ++i) {
class CaseFoldingHash {
public:
- // Paul Hsieh's SuperFastHash
- // http://www.azillionmonkeys.com/qed/hash.html
+ template<typename T> static inline UChar foldCase(T ch)
+ {
+ return WTF::Unicode::foldCase(ch);
+ }
+
static unsigned hash(const UChar* data, unsigned length)
{
- unsigned l = length;
- const UChar* s = data;
- uint32_t hash = WTF::stringHashingStartValue;
- uint32_t tmp;
-
- int rem = l & 1;
- l >>= 1;
-
- // Main loop.
- for (; l > 0; l--) {
- hash += WTF::Unicode::foldCase(s[0]);
- tmp = (WTF::Unicode::foldCase(s[1]) << 11) ^ hash;
- hash = (hash << 16) ^ tmp;
- s += 2;
- hash += hash >> 11;
- }
-
- // Handle end case.
- if (rem) {
- hash += WTF::Unicode::foldCase(s[0]);
- hash ^= hash << 11;
- hash += hash >> 17;
- }
-
- // Force "avalanching" of final 127 bits.
- hash ^= hash << 3;
- hash += hash >> 5;
- hash ^= hash << 2;
- hash += hash >> 15;
- hash ^= hash << 10;
-
- // This avoids ever returning a hash code of 0, since that is used to
- // signal "hash not computed yet", using a value that is likely to be
- // effectively the same as 0 when the low bits are masked.
- hash |= !hash << 31;
-
- return hash;
+ return StringHasher::computeHash<UChar, foldCase<UChar> >(data, length);
}
static unsigned hash(StringImpl* str)
{
return hash(str->characters(), str->length());
}
-
- static unsigned hash(const char* str, unsigned length)
- {
- // This hash is designed to work on 16-bit chunks at a time. But since the normal case
- // (above) is to hash UTF-16 characters, we just treat the 8-bit chars as if they
- // were 16-bit chunks, which will give matching results.
- unsigned l = length;
- const char* s = str;
- uint32_t hash = WTF::stringHashingStartValue;
- uint32_t tmp;
-
- int rem = l & 1;
- l >>= 1;
-
- // Main loop
- for (; l > 0; l--) {
- hash += WTF::Unicode::foldCase(s[0]);
- tmp = (WTF::Unicode::foldCase(s[1]) << 11) ^ hash;
- hash = (hash << 16) ^ tmp;
- s += 2;
- hash += hash >> 11;
- }
-
- // Handle end case
- if (rem) {
- hash += WTF::Unicode::foldCase(s[0]);
- hash ^= hash << 11;
- hash += hash >> 17;
- }
-
- // Force "avalanching" of final 127 bits
- hash ^= hash << 3;
- hash += hash >> 5;
- hash ^= hash << 2;
- hash += hash >> 15;
- hash ^= hash << 10;
-
- // this avoids ever returning a hash code of 0, since that is used to
- // signal "hash not computed yet", using a value that is likely to be
- // effectively the same as 0 when the low bits are masked
- hash |= !hash << 31;
-
- return hash;
+ static unsigned hash(const char* data, unsigned length)
+ {
+ return StringHasher::computeHash<char, foldCase<char> >(data, length);
}
-
+
static bool equal(const StringImpl* a, const StringImpl* b)
{
if (a == b)
}
};
-}
-
-namespace WTF {
-
- template<> struct HashTraits<WebCore::String> : GenericHashTraits<WebCore::String> {
- static const bool emptyValueIsZero = true;
- static void constructDeletedValue(WebCore::String& slot) { new (&slot) WebCore::String(HashTableDeletedValue); }
- static bool isDeletedValue(const WebCore::String& slot) { return slot.isHashTableDeletedValue(); }
- };
+ template<> struct HashTraits<String> : SimpleClassHashTraits<String> { };
}
+using WTF::StringHash;
+using WTF::CaseFoldingHash;
+using WTF::AlreadyHashed;
+
#endif
#include <wtf/StdLibExtras.h>
#include <wtf/WTFThreadData.h>
-using namespace WTF;
-using namespace Unicode;
using namespace std;
-namespace WebCore {
+namespace WTF {
+
+using namespace Unicode;
static const unsigned minLengthToShare = 20;
+COMPILE_ASSERT(sizeof(StringImpl) == 2 * sizeof(int) + 3 * sizeof(void*), StringImpl_should_stay_small);
+
StringImpl::~StringImpl()
{
ASSERT(!isStatic());
if (isAtomic())
AtomicString::remove(this);
#if USE(JSC)
- if (isIdentifier())
- wtfThreadData().currentIdentifierTable()->remove(this);
+ if (isIdentifier()) {
+ if (!wtfThreadData().currentIdentifierTable()->remove(this))
+ CRASH();
+ }
#endif
BufferOwnership ownership = bufferOwnership();
return m_substringBuffer->sharedBuffer();
if (ownership == BufferOwned) {
ASSERT(!m_sharedBuffer);
- m_sharedBuffer = SharedUChar::create(new SharableUChar(m_data)).releaseRef();
+ m_sharedBuffer = SharedUChar::create(new SharableUChar(m_data)).leakRef();
m_refCountAndFlags = (m_refCountAndFlags & ~s_refCountMaskBufferOwnership) | BufferShared;
}
return newImpl.release();
}
-PassRefPtr<StringImpl> StringImpl::secure(UChar character, bool hideLastCharacter)
+PassRefPtr<StringImpl> StringImpl::secure(UChar character, LastCharacterBehavior behavior)
{
+ if (!m_length)
+ return this;
+
UChar* data;
RefPtr<StringImpl> newImpl = createUninitialized(m_length, data);
- if (m_length) {
- const unsigned lastCharacterIndex = m_length - 1;
- for (unsigned i = 0; i < lastCharacterIndex; ++i)
- data[i] = character;
- data[lastCharacterIndex] = hideLastCharacter ? character : m_data[lastCharacterIndex];
- }
+ unsigned lastCharacterIndex = m_length - 1;
+ for (unsigned i = 0; i < lastCharacterIndex; ++i)
+ data[i] = character;
+ data[lastCharacterIndex] = (behavior == ObscureLastCharacter) ? character : m_data[lastCharacterIndex];
return newImpl.release();
}
return charactersToIntPtr(m_data, m_length, ok);
}
-double StringImpl::toDouble(bool* ok)
+double StringImpl::toDouble(bool* ok, bool* didReadNumber)
{
- return charactersToDouble(m_data, m_length, ok);
+ return charactersToDouble(m_data, m_length, ok, didReadNumber);
}
-float StringImpl::toFloat(bool* ok)
+float StringImpl::toFloat(bool* ok, bool* didReadNumber)
{
- return charactersToFloat(m_data, m_length, ok);
+ return charactersToFloat(m_data, m_length, ok, didReadNumber);
}
static bool equal(const UChar* a, const char* b, int length)
return umemcasecmp(a, b, length) == 0;
}
-int StringImpl::find(const char* chs, int index, bool caseSensitive)
+int codePointCompare(const StringImpl* s1, const StringImpl* s2)
{
- if (!chs || index < 0)
- return -1;
+ const unsigned l1 = s1 ? s1->length() : 0;
+ const unsigned l2 = s2 ? s2->length() : 0;
+ const unsigned lmin = l1 < l2 ? l1 : l2;
+ const UChar* c1 = s1 ? s1->characters() : 0;
+ const UChar* c2 = s2 ? s2->characters() : 0;
+ unsigned pos = 0;
+ while (pos < lmin && *c1 == *c2) {
+ c1++;
+ c2++;
+ pos++;
+ }
+
+ if (pos < lmin)
+ return (c1[0] > c2[0]) ? 1 : -1;
+
+ if (l1 == l2)
+ return 0;
- size_t matchStringLength = strlen(chs);
- if (matchStringLength > static_cast<unsigned>(numeric_limits<int>::max()))
+ return (l1 > l2) ? 1 : -1;
+}
+
+size_t StringImpl::find(UChar c, unsigned start)
+{
+ return WTF::find(m_data, m_length, c, start);
+}
+
+size_t StringImpl::find(CharacterMatchFunctionPtr matchFunction, unsigned start)
+{
+ return WTF::find(m_data, m_length, matchFunction, start);
+}
+
+size_t StringImpl::find(const char* matchString, unsigned index)
+{
+ // Check for null or empty string to match against
+ if (!matchString)
+ return notFound;
+ size_t matchStringLength = strlen(matchString);
+ if (matchStringLength > numeric_limits<unsigned>::max())
CRASH();
- int chsLength = matchStringLength;
- int n = m_length - index;
- if (n < 0)
- return -1;
- n -= chsLength - 1;
- if (n <= 0)
- return -1;
-
- const char* chsPlusOne = chs + 1;
- int chsLengthMinusOne = chsLength - 1;
-
- const UChar* ptr = m_data + index - 1;
- if (caseSensitive) {
- UChar c = *chs;
- do {
- if (*++ptr == c && equal(ptr + 1, chsPlusOne, chsLengthMinusOne))
- return m_length - chsLength - n + 1;
- } while (--n);
- } else {
- UChar lc = Unicode::foldCase(*chs);
- do {
- if (Unicode::foldCase(*++ptr) == lc && equalIgnoringCase(ptr + 1, chsPlusOne, chsLengthMinusOne))
- return m_length - chsLength - n + 1;
- } while (--n);
- }
-
- return -1;
-}
-
-int StringImpl::find(UChar c, int start)
-{
- return WebCore::find(m_data, m_length, c, start);
-}
-
-int StringImpl::find(CharacterMatchFunctionPtr matchFunction, int start)
-{
- return WebCore::find(m_data, m_length, matchFunction, start);
-}
-
-int StringImpl::find(StringImpl* str, int index, bool caseSensitive)
-{
- /*
- We use a simple trick for efficiency's sake. Instead of
- comparing strings, we compare the sum of str with that of
- a part of this string. Only if that matches, we call memcmp
- or ucstrnicmp.
- */
- ASSERT(str);
- if (index < 0)
- index += m_length;
- int lstr = str->m_length;
- int lthis = m_length - index;
- if ((unsigned)lthis > m_length)
- return -1;
- int delta = lthis - lstr;
- if (delta < 0)
- return -1;
-
- const UChar* uthis = m_data + index;
- const UChar* ustr = str->m_data;
- unsigned hthis = 0;
- unsigned hstr = 0;
- if (caseSensitive) {
- for (int i = 0; i < lstr; i++) {
- hthis += uthis[i];
- hstr += ustr[i];
- }
- int i = 0;
- while (1) {
- if (hthis == hstr && memcmp(uthis + i, ustr, lstr * sizeof(UChar)) == 0)
- return index + i;
- if (i == delta)
- return -1;
- hthis += uthis[i + lstr];
- hthis -= uthis[i];
- i++;
- }
- } else {
- for (int i = 0; i < lstr; i++ ) {
- hthis += toASCIILower(uthis[i]);
- hstr += toASCIILower(ustr[i]);
- }
- int i = 0;
- while (1) {
- if (hthis == hstr && equalIgnoringCase(uthis + i, ustr, lstr))
- return index + i;
- if (i == delta)
- return -1;
- hthis += toASCIILower(uthis[i + lstr]);
- hthis -= toASCIILower(uthis[i]);
- i++;
- }
+ unsigned matchLength = matchStringLength;
+ if (!matchLength)
+ return min(index, length());
+
+ // Optimization 1: fast case for strings of length 1.
+ if (matchLength == 1)
+ return WTF::find(characters(), length(), *(const unsigned char*)matchString, index);
+
+ // Check index & matchLength are in range.
+ if (index > length())
+ return notFound;
+ unsigned searchLength = length() - index;
+ if (matchLength > searchLength)
+ return notFound;
+ // delta is the number of additional times to test; delta == 0 means test only once.
+ unsigned delta = searchLength - matchLength;
+
+ const UChar* searchCharacters = characters() + index;
+ const unsigned char* matchCharacters = (const unsigned char*)matchString;
+
+ // Optimization 2: keep a running hash of the strings,
+ // only call memcmp if the hashes match.
+ unsigned searchHash = 0;
+ unsigned matchHash = 0;
+ for (unsigned i = 0; i < matchLength; ++i) {
+ searchHash += searchCharacters[i];
+ matchHash += matchCharacters[i];
+ }
+
+ unsigned i = 0;
+ // keep looping until we match
+ while (searchHash != matchHash || !equal(searchCharacters + i, matchString, matchLength)) {
+ if (i == delta)
+ return notFound;
+ searchHash += searchCharacters[i + matchLength];
+ searchHash -= searchCharacters[i];
+ ++i;
}
+ return index + i;
}
-int StringImpl::reverseFind(UChar c, int index)
+size_t StringImpl::findIgnoringCase(const char* matchString, unsigned index)
{
- return WebCore::reverseFind(m_data, m_length, c, index);
+ // Check for null or empty string to match against
+ if (!matchString)
+ return notFound;
+ size_t matchStringLength = strlen(matchString);
+ if (matchStringLength > numeric_limits<unsigned>::max())
+ CRASH();
+ unsigned matchLength = matchStringLength;
+ if (!matchLength)
+ return min(index, length());
+
+ // Check index & matchLength are in range.
+ if (index > length())
+ return notFound;
+ unsigned searchLength = length() - index;
+ if (matchLength > searchLength)
+ return notFound;
+ // delta is the number of additional times to test; delta == 0 means test only once.
+ unsigned delta = searchLength - matchLength;
+
+ const UChar* searchCharacters = characters() + index;
+
+ unsigned i = 0;
+ // keep looping until we match
+ while (!equalIgnoringCase(searchCharacters + i, matchString, matchLength)) {
+ if (i == delta)
+ return notFound;
+ ++i;
+ }
+ return index + i;
}
-int StringImpl::reverseFind(StringImpl* str, int index, bool caseSensitive)
+size_t StringImpl::find(StringImpl* matchString, unsigned index)
{
- /*
- See StringImpl::find() for explanations.
- */
- ASSERT(str);
- int lthis = m_length;
- if (index < 0)
- index += lthis;
-
- int lstr = str->m_length;
- int delta = lthis - lstr;
- if ( index < 0 || index > lthis || delta < 0 )
- return -1;
- if ( index > delta )
- index = delta;
-
- const UChar *uthis = m_data;
- const UChar *ustr = str->m_data;
- unsigned hthis = 0;
- unsigned hstr = 0;
- int i;
- if (caseSensitive) {
- for ( i = 0; i < lstr; i++ ) {
- hthis += uthis[index + i];
- hstr += ustr[i];
- }
- i = index;
- while (1) {
- if (hthis == hstr && memcmp(uthis + i, ustr, lstr * sizeof(UChar)) == 0)
- return i;
- if (i == 0)
- return -1;
- i--;
- hthis -= uthis[i + lstr];
- hthis += uthis[i];
- }
- } else {
- for (i = 0; i < lstr; i++) {
- hthis += toASCIILower(uthis[index + i]);
- hstr += toASCIILower(ustr[i]);
- }
- i = index;
- while (1) {
- if (hthis == hstr && equalIgnoringCase(uthis + i, ustr, lstr) )
- return i;
- if (i == 0)
- return -1;
- i--;
- hthis -= toASCIILower(uthis[i + lstr]);
- hthis += toASCIILower(uthis[i]);
- }
+ // Check for null or empty string to match against
+ if (!matchString)
+ return notFound;
+ unsigned matchLength = matchString->length();
+ if (!matchLength)
+ return min(index, length());
+
+ // Optimization 1: fast case for strings of length 1.
+ if (matchLength == 1)
+ return WTF::find(characters(), length(), matchString->characters()[0], index);
+
+ // Check index & matchLength are in range.
+ if (index > length())
+ return notFound;
+ unsigned searchLength = length() - index;
+ if (matchLength > searchLength)
+ return notFound;
+ // delta is the number of additional times to test; delta == 0 means test only once.
+ unsigned delta = searchLength - matchLength;
+
+ const UChar* searchCharacters = characters() + index;
+ const UChar* matchCharacters = matchString->characters();
+
+ // Optimization 2: keep a running hash of the strings,
+ // only call memcmp if the hashes match.
+ unsigned searchHash = 0;
+ unsigned matchHash = 0;
+ for (unsigned i = 0; i < matchLength; ++i) {
+ searchHash += searchCharacters[i];
+ matchHash += matchCharacters[i];
+ }
+
+ unsigned i = 0;
+ // keep looping until we match
+ while (searchHash != matchHash || memcmp(searchCharacters + i, matchCharacters, matchLength * sizeof(UChar))) {
+ if (i == delta)
+ return notFound;
+ searchHash += searchCharacters[i + matchLength];
+ searchHash -= searchCharacters[i];
+ ++i;
+ }
+ return index + i;
+}
+
+size_t StringImpl::findIgnoringCase(StringImpl* matchString, unsigned index)
+{
+ // Check for null or empty string to match against
+ if (!matchString)
+ return notFound;
+ unsigned matchLength = matchString->length();
+ if (!matchLength)
+ return min(index, length());
+
+ // Check index & matchLength are in range.
+ if (index > length())
+ return notFound;
+ unsigned searchLength = length() - index;
+ if (matchLength > searchLength)
+ return notFound;
+ // delta is the number of additional times to test; delta == 0 means test only once.
+ unsigned delta = searchLength - matchLength;
+
+ const UChar* searchCharacters = characters() + index;
+ const UChar* matchCharacters = matchString->characters();
+
+ unsigned i = 0;
+ // keep looping until we match
+ while (!equalIgnoringCase(searchCharacters + i, matchCharacters, matchLength)) {
+ if (i == delta)
+ return notFound;
+ ++i;
+ }
+ return index + i;
+}
+
+size_t StringImpl::reverseFind(UChar c, unsigned index)
+{
+ return WTF::reverseFind(m_data, m_length, c, index);
+}
+
+size_t StringImpl::reverseFind(StringImpl* matchString, unsigned index)
+{
+ // Check for null or empty string to match against
+ if (!matchString)
+ return notFound;
+ unsigned matchLength = matchString->length();
+ if (!matchLength)
+ return min(index, length());
+
+ // Optimization 1: fast case for strings of length 1.
+ if (matchLength == 1)
+ return WTF::reverseFind(characters(), length(), matchString->characters()[0], index);
+
+ // Check index & matchLength are in range.
+ if (matchLength > length())
+ return notFound;
+ // delta is the number of additional times to test; delta == 0 means test only once.
+ unsigned delta = min(index, length() - matchLength);
+
+ const UChar *searchCharacters = characters();
+ const UChar *matchCharacters = matchString->characters();
+
+ // Optimization 2: keep a running hash of the strings,
+ // only call memcmp if the hashes match.
+ unsigned searchHash = 0;
+ unsigned matchHash = 0;
+ for (unsigned i = 0; i < matchLength; ++i) {
+ searchHash += searchCharacters[delta + i];
+ matchHash += matchCharacters[i];
+ }
+
+ // keep looping until we match
+ while (searchHash != matchHash || memcmp(searchCharacters + delta, matchCharacters, matchLength * sizeof(UChar))) {
+ if (!delta)
+ return notFound;
+ delta--;
+ searchHash -= searchCharacters[delta + matchLength];
+ searchHash += searchCharacters[delta];
}
+ return delta;
+}
+
+size_t StringImpl::reverseFindIgnoringCase(StringImpl* matchString, unsigned index)
+{
+ // Check for null or empty string to match against
+ if (!matchString)
+ return notFound;
+ unsigned matchLength = matchString->length();
+ if (!matchLength)
+ return min(index, length());
+
+ // Check index & matchLength are in range.
+ if (matchLength > length())
+ return notFound;
+ // delta is the number of additional times to test; delta == 0 means test only once.
+ unsigned delta = min(index, length() - matchLength);
- // Should never get here.
- return -1;
+ const UChar *searchCharacters = characters();
+ const UChar *matchCharacters = matchString->characters();
+
+ // keep looping until we match
+ while (!equalIgnoringCase(searchCharacters + delta, matchCharacters, matchLength)) {
+ if (!delta)
+ return notFound;
+ delta--;
+ }
+ return delta;
}
-bool StringImpl::endsWith(StringImpl* m_data, bool caseSensitive)
+bool StringImpl::endsWith(StringImpl* matchString, bool caseSensitive)
{
- ASSERT(m_data);
- int start = m_length - m_data->m_length;
- if (start >= 0)
- return (find(m_data, start, caseSensitive) == start);
+ ASSERT(matchString);
+ if (m_length >= matchString->m_length) {
+ unsigned start = m_length - matchString->m_length;
+ return (caseSensitive ? find(matchString, start) : findIgnoringCase(matchString, start)) == start;
+ }
return false;
}
if (!replacement)
return this;
- int repStrLength = replacement->length();
- int srcSegmentStart = 0;
+ unsigned repStrLength = replacement->length();
+ size_t srcSegmentStart = 0;
unsigned matchCount = 0;
// Count the matches
- while ((srcSegmentStart = find(pattern, srcSegmentStart)) >= 0) {
+ while ((srcSegmentStart = find(pattern, srcSegmentStart)) != notFound) {
++matchCount;
++srcSegmentStart;
}
RefPtr<StringImpl> newImpl = createUninitialized(newSize, data);
// Construct the new data
- int srcSegmentEnd;
- int srcSegmentLength;
+ size_t srcSegmentEnd;
+ unsigned srcSegmentLength;
srcSegmentStart = 0;
- int dstOffset = 0;
+ unsigned dstOffset = 0;
- while ((srcSegmentEnd = find(pattern, srcSegmentStart)) >= 0) {
+ while ((srcSegmentEnd = find(pattern, srcSegmentStart)) != notFound) {
srcSegmentLength = srcSegmentEnd - srcSegmentStart;
memcpy(data + dstOffset, m_data + srcSegmentStart, srcSegmentLength * sizeof(UChar));
dstOffset += srcSegmentLength;
srcSegmentLength = m_length - srcSegmentStart;
memcpy(data + dstOffset, m_data + srcSegmentStart, srcSegmentLength * sizeof(UChar));
- ASSERT(dstOffset + srcSegmentLength == static_cast<int>(newImpl->length()));
+ ASSERT(dstOffset + srcSegmentLength == newImpl->length());
return newImpl.release();
}
if (!pattern || !replacement)
return this;
- int patternLength = pattern->length();
+ unsigned patternLength = pattern->length();
if (!patternLength)
return this;
- int repStrLength = replacement->length();
- int srcSegmentStart = 0;
+ unsigned repStrLength = replacement->length();
+ size_t srcSegmentStart = 0;
unsigned matchCount = 0;
// Count the matches
- while ((srcSegmentStart = find(pattern, srcSegmentStart)) >= 0) {
+ while ((srcSegmentStart = find(pattern, srcSegmentStart)) != notFound) {
++matchCount;
srcSegmentStart += patternLength;
}
RefPtr<StringImpl> newImpl = createUninitialized(newSize, data);
// Construct the new data
- int srcSegmentEnd;
- int srcSegmentLength;
+ size_t srcSegmentEnd;
+ unsigned srcSegmentLength;
srcSegmentStart = 0;
- int dstOffset = 0;
+ unsigned dstOffset = 0;
- while ((srcSegmentEnd = find(pattern, srcSegmentStart)) >= 0) {
+ while ((srcSegmentEnd = find(pattern, srcSegmentStart)) != notFound) {
srcSegmentLength = srcSegmentEnd - srcSegmentStart;
memcpy(data + dstOffset, m_data + srcSegmentStart, srcSegmentLength * sizeof(UChar));
dstOffset += srcSegmentLength;
srcSegmentLength = m_length - srcSegmentStart;
memcpy(data + dstOffset, m_data + srcSegmentStart, srcSegmentLength * sizeof(UChar));
- ASSERT(dstOffset + srcSegmentLength == static_cast<int>(newImpl->length()));
+ ASSERT(dstOffset + srcSegmentLength == newImpl->length());
return newImpl.release();
}
return false;
}
-Vector<char> StringImpl::ascii()
-{
- Vector<char> buffer(m_length + 1);
- for (unsigned i = 0; i != m_length; ++i) {
- UChar c = m_data[i];
- if ((c >= 0x20 && c < 0x7F) || c == 0x00)
- buffer[i] = static_cast<char>(c);
- else
- buffer[i] = '?';
- }
- buffer[m_length] = '\0';
- return buffer;
-}
-
-WTF::Unicode::Direction StringImpl::defaultWritingDirection()
+WTF::Unicode::Direction StringImpl::defaultWritingDirection(bool* hasStrongDirectionality)
{
for (unsigned i = 0; i < m_length; ++i) {
WTF::Unicode::Direction charDirection = WTF::Unicode::direction(m_data[i]);
- if (charDirection == WTF::Unicode::LeftToRight)
+ if (charDirection == WTF::Unicode::LeftToRight) {
+ if (hasStrongDirectionality)
+ *hasStrongDirectionality = true;
return WTF::Unicode::LeftToRight;
- if (charDirection == WTF::Unicode::RightToLeft || charDirection == WTF::Unicode::RightToLeftArabic)
+ }
+ if (charDirection == WTF::Unicode::RightToLeft || charDirection == WTF::Unicode::RightToLeftArabic) {
+ if (hasStrongDirectionality)
+ *hasStrongDirectionality = true;
return WTF::Unicode::RightToLeft;
+ }
}
+ if (hasStrongDirectionality)
+ *hasStrongDirectionality = false;
return WTF::Unicode::LeftToRight;
}
return threadsafeCopy();
}
-} // namespace WebCore
+} // namespace WTF
#include <limits.h>
#include <wtf/ASCIICType.h>
#include <wtf/CrossThreadRefCounted.h>
+#include <wtf/Forward.h>
#include <wtf/OwnFastMallocPtr.h>
#include <wtf/StdLibExtras.h>
-#include <wtf/StringHashFunctions.h>
+#include <wtf/StringHasher.h>
#include <wtf/Vector.h>
#include <wtf/text/StringImplBase.h>
#include <wtf/unicode/Unicode.h>
-#if PLATFORM(CF)
+#if USE(CF)
typedef const struct __CFString * CFStringRef;
#endif
// FIXME: This is a temporary layering violation while we move string code to WTF.
// Landing the file moves in one patch, will follow on with patches to change the namespaces.
namespace JSC {
-
struct IdentifierCStringTranslator;
struct IdentifierUCharBufferTranslator;
-
}
-// FIXME: This is a temporary layering violation while we move string code to WTF.
-// Landing the file moves in one patch, will follow on with patches to change the namespaces.
-namespace WebCore {
-
-class StringBuffer;
+namespace WTF {
struct CStringTranslator;
struct HashAndCharactersTranslator;
-struct StringHash;
+struct HashAndUTF8CharactersTranslator;
struct UCharBufferTranslator;
enum TextCaseSensitivity { TextCaseSensitive, TextCaseInsensitive };
class StringImpl : public StringImplBase {
friend struct JSC::IdentifierCStringTranslator;
friend struct JSC::IdentifierUCharBufferTranslator;
- friend struct CStringTranslator;
- friend struct HashAndCharactersTranslator;
- friend struct UCharBufferTranslator;
+ friend struct WTF::CStringTranslator;
+ friend struct WTF::HashAndCharactersTranslator;
+ friend struct WTF::HashAndUTF8CharactersTranslator;
+ friend struct WTF::UCharBufferTranslator;
friend class AtomicStringImpl;
private:
// Used to construct static strings, which have an special refCount that can never hit zero.
StringImpl(const UChar* characters, unsigned length, PassRefPtr<StringImpl> base)
: StringImplBase(length, BufferSubstring)
, m_data(characters)
- , m_substringBuffer(base.releaseRef())
+ , m_substringBuffer(base.leakRef())
, m_hash(0)
{
ASSERT(m_data);
StringImpl(const UChar* characters, unsigned length, PassRefPtr<SharedUChar> sharedBuffer)
: StringImplBase(length, BufferShared)
, m_data(characters)
- , m_sharedBuffer(sharedBuffer.releaseRef())
+ , m_sharedBuffer(sharedBuffer.leakRef())
, m_hash(0)
{
ASSERT(m_data);
{
ASSERT(!isStatic());
ASSERT(!m_hash);
- ASSERT(hash == computeHash(m_data, m_length));
+ ASSERT(hash == StringHasher::computeHash(m_data, m_length));
m_hash = hash;
}
static PassRefPtr<StringImpl> create(const char*, unsigned length);
static PassRefPtr<StringImpl> create(const char*);
static PassRefPtr<StringImpl> create(const UChar*, unsigned length, PassRefPtr<SharedUChar> sharedBuffer);
- static PassRefPtr<StringImpl> create(PassRefPtr<StringImpl> rep, unsigned offset, unsigned length)
+ static ALWAYS_INLINE PassRefPtr<StringImpl> create(PassRefPtr<StringImpl> rep, unsigned offset, unsigned length)
{
ASSERT(rep);
ASSERT(length <= rep->length());
}
static PassRefPtr<StringImpl> createUninitialized(unsigned length, UChar*& data);
- static PassRefPtr<StringImpl> tryCreateUninitialized(unsigned length, UChar*& output)
+ static ALWAYS_INLINE PassRefPtr<StringImpl> tryCreateUninitialized(unsigned length, UChar*& output)
{
if (!length) {
output = 0;
m_refCountAndFlags &= ~s_refCountFlagIsAtomic;
}
- unsigned hash() const { if (!m_hash) m_hash = computeHash(m_data, m_length); return m_hash; }
+ unsigned hash() const { if (!m_hash) m_hash = StringHasher::computeHash(m_data, m_length); return m_hash; }
unsigned existingHash() const { ASSERT(m_hash); return m_hash; }
- static unsigned computeHash(const UChar* data, unsigned length) { return WTF::stringHash(data, length); }
- static unsigned computeHash(const char* data, unsigned length) { return WTF::stringHash(data, length); }
- static unsigned computeHash(const char* data) { return WTF::stringHash(data); }
ALWAYS_INLINE void deref() { m_refCountAndFlags -= s_refCountIncrement; if (!(m_refCountAndFlags & (s_refCountMask | s_refCountFlagStatic))) delete this; }
ALWAYS_INLINE bool hasOneRef() const { return (m_refCountAndFlags & (s_refCountMask | s_refCountFlagStatic)) == s_refCountIncrement; }
uint64_t toUInt64(bool* ok = 0); // ignores trailing garbage
intptr_t toIntPtr(bool* ok = 0); // ignores trailing garbage
- double toDouble(bool* ok = 0);
- float toFloat(bool* ok = 0);
+ double toDouble(bool* ok = 0, bool* didReadNumber = 0);
+ float toFloat(bool* ok = 0, bool* didReadNumber = 0);
PassRefPtr<StringImpl> lower();
PassRefPtr<StringImpl> upper();
- PassRefPtr<StringImpl> secure(UChar, bool hideLastCharacter = true);
+
+ enum LastCharacterBehavior { ObscureLastCharacter, DisplayLastCharacter };
+
+ PassRefPtr<StringImpl> secure(UChar, LastCharacterBehavior = ObscureLastCharacter);
PassRefPtr<StringImpl> foldCase();
PassRefPtr<StringImpl> stripWhiteSpace();
PassRefPtr<StringImpl> removeCharacters(CharacterMatchFunctionPtr);
- int find(const char*, int index = 0, bool caseSensitive = true);
- int find(UChar, int index = 0);
- int find(CharacterMatchFunctionPtr, int index = 0);
- int find(StringImpl*, int index, bool caseSensitive = true);
+ size_t find(UChar, unsigned index = 0);
+ size_t find(CharacterMatchFunctionPtr, unsigned index = 0);
+ size_t find(const char*, unsigned index = 0);
+ size_t find(StringImpl*, unsigned index = 0);
+ size_t findIgnoringCase(const char*, unsigned index = 0);
+ size_t findIgnoringCase(StringImpl*, unsigned index = 0);
- int reverseFind(UChar, int index);
- int reverseFind(StringImpl*, int index, bool caseSensitive = true);
-
- bool startsWith(StringImpl* str, bool caseSensitive = true) { return reverseFind(str, 0, caseSensitive) == 0; }
+ size_t reverseFind(UChar, unsigned index = UINT_MAX);
+ size_t reverseFind(StringImpl*, unsigned index = UINT_MAX);
+ size_t reverseFindIgnoringCase(StringImpl*, unsigned index = UINT_MAX);
+
+ bool startsWith(StringImpl* str, bool caseSensitive = true) { return (caseSensitive ? reverseFind(str, 0) : reverseFindIgnoringCase(str, 0)) == 0; }
bool endsWith(StringImpl*, bool caseSensitive = true);
PassRefPtr<StringImpl> replace(UChar, UChar);
PassRefPtr<StringImpl> replace(StringImpl*, StringImpl*);
PassRefPtr<StringImpl> replace(unsigned index, unsigned len, StringImpl*);
- Vector<char> ascii();
int wordCount(int maxWordsToCount = INT_MAX);
- WTF::Unicode::Direction defaultWritingDirection();
+ WTF::Unicode::Direction defaultWritingDirection(bool* hasStrongDirectionality = 0);
-#if PLATFORM(CF)
+#if USE(CF)
CFStringRef createCFString();
#endif
#ifdef __OBJC__
bool equalIgnoringNullity(StringImpl*, StringImpl*);
+template<size_t inlineCapacity>
+bool equalIgnoringNullity(const Vector<UChar, inlineCapacity>& a, StringImpl* b)
+{
+ if (!b)
+ return !a.size();
+ if (a.size() != b->length())
+ return false;
+ return !memcmp(a.data(), b->characters(), b->length());
+}
+
+int codePointCompare(const StringImpl*, const StringImpl*);
+
static inline bool isSpaceOrNewline(UChar c)
{
// Use isASCIISpace() for basic Latin-1.
return StringImpl::createStrippingNullCharactersSlowCase(characters, length);
}
-}
-
-using WebCore::equal;
-
-namespace WTF {
+struct StringHash;
- // WebCore::StringHash is the default hash for StringImpl* and RefPtr<StringImpl>
- template<typename T> struct DefaultHash;
- template<> struct DefaultHash<WebCore::StringImpl*> {
- typedef WebCore::StringHash Hash;
- };
- template<> struct DefaultHash<RefPtr<WebCore::StringImpl> > {
- typedef WebCore::StringHash Hash;
- };
+// StringHash is the default hash for StringImpl* and RefPtr<StringImpl>
+template<typename T> struct DefaultHash;
+template<> struct DefaultHash<StringImpl*> {
+ typedef StringHash Hash;
+};
+template<> struct DefaultHash<RefPtr<StringImpl> > {
+ typedef StringHash Hash;
+};
}
+using WTF::StringImpl;
+using WTF::equal;
+using WTF::TextCaseSensitivity;
+using WTF::TextCaseSensitive;
+using WTF::TextCaseInsensitive;
+
#endif
#ifndef StringImplBase_h
#define StringImplBase_h
-#include <wtf/Noncopyable.h>
#include <wtf/unicode/Unicode.h>
namespace WTF {
-class StringImplBase : public Noncopyable {
+class StringImplBase {
+ WTF_MAKE_NONCOPYABLE(StringImplBase); WTF_MAKE_FAST_ALLOCATED;
public:
bool isStringImpl() { return (m_refCountAndFlags & s_refCountInvalidForStringImpl) != s_refCountInvalidForStringImpl; }
unsigned length() const { return m_length; }
BufferShared,
};
- using Noncopyable::operator new;
- void* operator new(size_t, void* inPlace) { ASSERT(inPlace); return inPlace; }
-
// For SmallStringStorage, which allocates an array and uses an in-place new.
StringImplBase() { }
--- /dev/null
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) Research In Motion Limited 2011. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+#ifndef StringOperators_h
+#define StringOperators_h
+
+namespace WTF {
+
+template<typename StringType1, typename StringType2>
+class StringAppend {
+public:
+ StringAppend(StringType1 string1, StringType2 string2)
+ : m_string1(string1)
+ , m_string2(string2)
+ {
+ }
+
+ operator String() const
+ {
+ RefPtr<StringImpl> resultImpl = tryMakeString(m_string1, m_string2);
+ if (!resultImpl)
+ CRASH();
+ return resultImpl.release();
+ }
+
+ operator AtomicString() const
+ {
+ return operator String();
+ }
+
+ void writeTo(UChar* destination)
+ {
+ StringTypeAdapter<StringType1> adapter1(m_string1);
+ StringTypeAdapter<StringType2> adapter2(m_string2);
+ adapter1.writeTo(destination);
+ adapter2.writeTo(destination + adapter1.length());
+ }
+
+ unsigned length()
+ {
+ StringTypeAdapter<StringType1> adapter1(m_string1);
+ StringTypeAdapter<StringType2> adapter2(m_string2);
+ return adapter1.length() + adapter2.length();
+ }
+
+private:
+ StringType1 m_string1;
+ StringType2 m_string2;
+};
+
+template<typename StringType1, typename StringType2>
+class StringTypeAdapter<StringAppend<StringType1, StringType2> > {
+public:
+ StringTypeAdapter<StringAppend<StringType1, StringType2> >(StringAppend<StringType1, StringType2>& buffer)
+ : m_buffer(buffer)
+ {
+ }
+
+ unsigned length() { return m_buffer.length(); }
+ void writeTo(UChar* destination) { m_buffer.writeTo(destination); }
+
+private:
+ StringAppend<StringType1, StringType2>& m_buffer;
+};
+
+inline StringAppend<const char*, String> operator+(const char* string1, const String& string2)
+{
+ return StringAppend<const char*, String>(string1, string2);
+}
+
+inline StringAppend<const char*, AtomicString> operator+(const char* string1, const AtomicString& string2)
+{
+ return StringAppend<const char*, AtomicString>(string1, string2);
+}
+
+template<typename T>
+StringAppend<String, T> operator+(const String& string1, T string2)
+{
+ return StringAppend<String, T>(string1, string2);
+}
+
+template<typename U, typename V, typename W>
+StringAppend<U, StringAppend<V, W> > operator+(U string1, const StringAppend<V, W>& string2)
+{
+ return StringAppend<U, StringAppend<V, W> >(string1, string2);
+}
+
+} // namespace WTF
+
+#endif // StringOperators_h
#endif
#include "AtomicString.h"
+#include "DynamicAnnotations.h"
#include "StaticConstructors.h"
#include "StringImpl.h"
-namespace WebCore {
+namespace WTF {
StringImpl* StringImpl::empty()
{
// PCRE goes away.
static UChar emptyUCharData = 0;
DEFINE_STATIC_LOCAL(StringImpl, emptyString, (&emptyUCharData, 0, ConstructStaticString));
+ WTF_ANNOTATE_BENIGN_RACE(&emptyString, "Benign race on StringImpl::emptyString reference counter");
return &emptyString;
}
--- /dev/null
+/*
+ * Copyright (C) 2010, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TextPosition_h
+#define TextPosition_h
+
+#include <wtf/Assertions.h>
+
+namespace WTF {
+
+/*
+ * Text Position
+ *
+ * TextPosition structure specifies coordinates within an text resource. It is used mostly
+ * for saving script source position.
+ *
+ * Later TextPosition0 and TextPosition1 and both number types can be merged together quite easily.
+ *
+ * 0-based and 1-based
+ *
+ * Line and column numbers could be interpreted as zero-based or 1-based. Since
+ * both practices coexist in WebKit source base, 'int' type should be replaced with
+ * a dedicated wrapper types, so that compiler helped us with this ambiguity.
+ *
+ * Here we introduce 2 types of numbers: ZeroBasedNumber and OneBasedNumber and
+ * 2 corresponding types of TextPosition structure. While only one type ought to be enough,
+ * this is done to keep transition to the new types as transparent as possible:
+ * e.g. in areas where 0-based integers are used, TextPosition0 should be introduced. This
+ * way all changes will remain trackable.
+ *
+ * Later both number types can be merged in one type quite easily.
+ *
+ * For type safety and for the future type merge it is important that all operations in API
+ * that accept or return integer have a name explicitly defining base of integer. For this reason
+ * int-receiving constructors are hidden from API.
+ */
+
+template<typename NUMBER>
+class TextPosition {
+public:
+ TextPosition(NUMBER line, NUMBER column)
+ : m_line(line)
+ , m_column(column)
+ {
+ }
+ TextPosition() {}
+
+ bool operator==(const TextPosition& other) { return m_line == other.m_line && m_column == other.m_column; }
+ bool operator!=(const TextPosition& other) { return !((*this) == other); }
+
+ // A 'minimum' value of position, used as a default value.
+ static TextPosition<NUMBER> minimumPosition() { return TextPosition<NUMBER>(NUMBER::base(), NUMBER::base()); }
+
+ // A value with line value less than a minimum; used as an impossible position.
+ static TextPosition<NUMBER> belowRangePosition() { return TextPosition<NUMBER>(NUMBER::belowBase(), NUMBER::belowBase()); }
+
+ NUMBER m_line;
+ NUMBER m_column;
+};
+
+class OneBasedNumber;
+
+// An int wrapper that always reminds you that the number should be 0-based
+class ZeroBasedNumber {
+public:
+ static ZeroBasedNumber fromZeroBasedInt(int zeroBasedInt) { return ZeroBasedNumber(zeroBasedInt); }
+
+ ZeroBasedNumber() {}
+
+ int zeroBasedInt() const { return m_value; }
+ int convertAsOneBasedInt() const { return m_value + 1; }
+ OneBasedNumber convertToOneBased() const;
+
+ bool operator==(ZeroBasedNumber other) { return m_value == other.m_value; }
+ bool operator!=(ZeroBasedNumber other) { return !((*this) == other); }
+
+ static ZeroBasedNumber base() { return 0; }
+ static ZeroBasedNumber belowBase() { return -1; }
+
+private:
+ ZeroBasedNumber(int value) : m_value(value) {}
+ int m_value;
+};
+
+// An int wrapper that always reminds you that the number should be 1-based
+class OneBasedNumber {
+public:
+ static OneBasedNumber fromOneBasedInt(int oneBasedInt) { return OneBasedNumber(oneBasedInt); }
+ OneBasedNumber() {}
+
+ int oneBasedInt() const { return m_value; }
+ int convertAsZeroBasedInt() const { return m_value - 1; }
+ ZeroBasedNumber convertToZeroBased() const { return ZeroBasedNumber::fromZeroBasedInt(m_value - 1); }
+
+ bool operator==(OneBasedNumber other) { return m_value == other.m_value; }
+ bool operator!=(OneBasedNumber other) { return !((*this) == other); }
+
+ static OneBasedNumber base() { return 1; }
+ static OneBasedNumber belowBase() { return 0; }
+
+private:
+ OneBasedNumber(int value) : m_value(value) {}
+ int m_value;
+};
+
+typedef TextPosition<ZeroBasedNumber> TextPosition0;
+typedef TextPosition<OneBasedNumber> TextPosition1;
+
+inline TextPosition0 toZeroBasedTextPosition(const TextPosition1& position)
+{
+ return TextPosition0(position.m_line.convertToZeroBased(), position.m_column.convertToZeroBased());
+}
+
+inline TextPosition1 toOneBasedTextPosition(const TextPosition0& position)
+{
+ return TextPosition1(position.m_line.convertToOneBased(), position.m_column.convertToOneBased());
+}
+
+inline OneBasedNumber ZeroBasedNumber::convertToOneBased() const
+{
+ return OneBasedNumber::fromOneBasedInt(m_value + 1);
+}
+
+}
+
+using WTF::TextPosition0;
+using WTF::TextPosition1;
+
+#endif // TextPosition_h
#include <wtf/unicode/UTF8.h>
#include <wtf/unicode/Unicode.h>
-using namespace WTF;
-using namespace WTF::Unicode;
using namespace std;
-namespace WebCore {
+namespace WTF {
+using namespace Unicode;
+using namespace std;
+
+// Construct a string with UTF-16 data.
+String::String(const UChar* characters, unsigned length)
+ : m_impl(characters ? StringImpl::create(characters, length) : 0)
+{
+}
+
+// Construct a string with UTF-16 data, from a null-terminated source.
String::String(const UChar* str)
{
if (!str)
m_impl = StringImpl::create(str, len);
}
+// Construct a string with latin1 data.
+String::String(const char* characters, unsigned length)
+ : m_impl(characters ? StringImpl::create(characters, length) : 0)
+{
+}
+
+// Construct a string with latin1 data, from a null-terminated source.
+String::String(const char* characters)
+ : m_impl(characters ? StringImpl::create(characters) : 0)
+{
+}
+
void String::append(const String& str)
{
if (str.isEmpty())
m_impl = StringImpl::create(&c, 1);
}
-String operator+(const String& a, const String& b)
+int codePointCompare(const String& a, const String& b)
{
- if (a.isEmpty())
- return b;
- if (b.isEmpty())
- return a;
- String c = a;
- c += b;
- return c;
-}
-
-String operator+(const String& s, const char* cs)
-{
- return s + String(cs);
-}
-
-String operator+(const char* cs, const String& s)
-{
- return String(cs) + s;
+ return codePointCompare(a.impl(), b.impl());
}
void String::insert(const String& str, unsigned pos)
return m_impl->substring(pos, len);
}
+String String::substringSharingImpl(unsigned offset, unsigned length) const
+{
+ // FIXME: We used to check against a limit of Heap::minExtraCost / sizeof(UChar).
+
+ unsigned stringLength = this->length();
+ offset = min(offset, stringLength);
+ length = min(length, stringLength - offset);
+
+ if (!offset && length == stringLength)
+ return *this;
+ return String(StringImpl::create(m_impl, offset, length));
+}
+
String String::lower() const
{
if (!m_impl)
va_end(args);
- return buffer;
+ QByteArray ba = buffer.toUtf8();
+ return StringImpl::create(ba.constData(), ba.length());
#elif OS(WINCE)
va_list args;
return m_impl->toIntPtr(ok);
}
-double String::toDouble(bool* ok) const
+double String::toDouble(bool* ok, bool* didReadNumber) const
{
if (!m_impl) {
if (ok)
*ok = false;
+ if (didReadNumber)
+ *didReadNumber = false;
return 0.0;
}
- return m_impl->toDouble(ok);
+ return m_impl->toDouble(ok, didReadNumber);
}
-float String::toFloat(bool* ok) const
+float String::toFloat(bool* ok, bool* didReadNumber) const
{
if (!m_impl) {
if (ok)
*ok = false;
+ if (didReadNumber)
+ *didReadNumber = false;
return 0.0f;
}
- return m_impl->toFloat(ok);
+ return m_impl->toFloat(ok, didReadNumber);
}
String String::threadsafeCopy() const
{
result.clear();
- int startPos = 0;
- int endPos;
- while ((endPos = find(separator, startPos)) != -1) {
+ unsigned startPos = 0;
+ size_t endPos;
+ while ((endPos = find(separator, startPos)) != notFound) {
if (allowEmptyEntries || startPos != endPos)
result.append(substring(startPos, endPos - startPos));
startPos = endPos + separator.length();
}
- if (allowEmptyEntries || startPos != static_cast<int>(length()))
+ if (allowEmptyEntries || startPos != length())
result.append(substring(startPos));
}
void String::split(const String& separator, Vector<String>& result) const
{
- return split(separator, false, result);
+ split(separator, false, result);
}
void String::split(UChar separator, bool allowEmptyEntries, Vector<String>& result) const
{
result.clear();
- int startPos = 0;
- int endPos;
- while ((endPos = find(separator, startPos)) != -1) {
+ unsigned startPos = 0;
+ size_t endPos;
+ while ((endPos = find(separator, startPos)) != notFound) {
if (allowEmptyEntries || startPos != endPos)
result.append(substring(startPos, endPos - startPos));
startPos = endPos + 1;
}
- if (allowEmptyEntries || startPos != static_cast<int>(length()))
+ if (allowEmptyEntries || startPos != length())
result.append(substring(startPos));
}
void String::split(UChar separator, Vector<String>& result) const
{
- return split(String(&separator, 1), false, result);
+ split(String(&separator, 1), false, result);
}
-Vector<char> String::ascii() const
+CString String::ascii() const
{
- if (m_impl)
- return m_impl->ascii();
-
- const char* nullMsg = "(null impl)";
- Vector<char, 2048> buffer;
- for (int i = 0; nullMsg[i]; ++i)
- buffer.append(nullMsg[i]);
-
- buffer.append('\0');
- return buffer;
+ // Printable ASCII characters 32..127 and the null character are
+ // preserved, characters outside of this range are converted to '?'.
+
+ unsigned length = this->length();
+ const UChar* characters = this->characters();
+
+ char* characterBuffer;
+ CString result = CString::newUninitialized(length, characterBuffer);
+
+ for (unsigned i = 0; i < length; ++i) {
+ UChar ch = characters[i];
+ characterBuffer[i] = ch && (ch < 0x20 || ch > 0x7f) ? '?' : ch;
+ }
+
+ return result;
}
CString String::latin1() const
for (unsigned i = 0; i < length; ++i) {
UChar ch = characters[i];
- characterBuffer[i] = ch > 255 ? '?' : ch;
+ characterBuffer[i] = ch > 0xff ? '?' : ch;
}
return result;
*buffer++ = static_cast<char>((ch & 0x3F) | 0x80);
}
-CString String::utf8() const
+CString String::utf8(bool strict) const
{
unsigned length = this->length();
const UChar* characters = this->characters();
Vector<char, 1024> bufferVector(length * 3);
char* buffer = bufferVector.data();
- ConversionResult result = convertUTF16ToUTF8(&characters, characters + length, &buffer, buffer + bufferVector.size(), false);
- ASSERT(result != sourceIllegal); // Only produced from strict conversion.
+ ConversionResult result = convertUTF16ToUTF8(&characters, characters + length, &buffer, buffer + bufferVector.size(), strict);
ASSERT(result != targetExhausted); // (length * 3) should be sufficient for any conversion
- // If a high surrogate is left unconverted, treat it the same was as an unpaired high surrogate
- // would have been handled in the middle of a string with non-strict conversion - which is to say,
- // simply encode it to UTF-8.
+ // Only produced from strict conversion.
+ if (result == sourceIllegal)
+ return CString();
+
+ // Check for an unconverted high surrogate.
if (result == sourceExhausted) {
- // This should be one unpaired high surrogate.
- ASSERT((characters + 1) == (characters + length));
+ if (strict)
+ return CString();
+ // This should be one unpaired high surrogate. Treat it the same
+ // was as an unpaired high surrogate would have been handled in
+ // the middle of a string with non-strict conversion - which is
+ // to say, simply encode it to UTF-8.
+ ASSERT((characters + 1) == (this->characters() + length));
ASSERT((*characters >= 0xD800) && (*characters <= 0xDBFF));
// There should be room left, since one UChar hasn't been converted.
ASSERT((buffer + 3) <= (buffer + bufferVector.size()));
return toIntegralType<intptr_t>(data, lengthOfCharactersAsInteger(data, length), ok, 10);
}
-double charactersToDouble(const UChar* data, size_t length, bool* ok)
+double charactersToDouble(const UChar* data, size_t length, bool* ok, bool* didReadNumber)
{
if (!length) {
if (ok)
*ok = false;
+ if (didReadNumber)
+ *didReadNumber = false;
return 0.0;
}
for (unsigned i = 0; i < length; ++i)
bytes[i] = data[i] < 0x7F ? data[i] : '?';
bytes[length] = '\0';
+ char* start = bytes.data();
char* end;
- double val = WTF::strtod(bytes.data(), &end);
+ double val = WTF::strtod(start, &end);
if (ok)
*ok = (end == 0 || *end == '\0');
+ if (didReadNumber)
+ *didReadNumber = end - start;
return val;
}
-float charactersToFloat(const UChar* data, size_t length, bool* ok)
+float charactersToFloat(const UChar* data, size_t length, bool* ok, bool* didReadNumber)
{
// FIXME: This will return ok even when the string fits into a double but not a float.
- return static_cast<float>(charactersToDouble(data, length, ok));
+ return static_cast<float>(charactersToDouble(data, length, ok, didReadNumber));
+}
+
+const String& emptyString()
+{
+ DEFINE_STATIC_LOCAL(String, emptyString, (StringImpl::empty()));
+ return emptyString;
}
-} // namespace WebCore
+} // namespace WTF
#ifndef NDEBUG
-// For use in the debugger - leaks memory
-WebCore::String* string(const char*);
+// For use in the debugger
+String* string(const char*);
+Vector<char> asciiDebug(StringImpl* impl);
+Vector<char> asciiDebug(String& string);
-WebCore::String* string(const char* s)
+String* string(const char* s)
{
- return new WebCore::String(s);
+ // leaks memory!
+ return new String(s);
}
+
+Vector<char> asciiDebug(StringImpl* impl)
+{
+ if (!impl)
+ return asciiDebug(String("[null]").impl());
+
+ Vector<char> buffer;
+ unsigned length = impl->length();
+ const UChar* characters = impl->characters();
+
+ buffer.resize(length + 1);
+ for (unsigned i = 0; i < length; ++i) {
+ UChar ch = characters[i];
+ buffer[i] = ch && (ch < 0x20 || ch > 0x7f) ? '?' : ch;
+ }
+ buffer[length] = '\0';
+
+ return buffer;
+}
+
+Vector<char> asciiDebug(String& string)
+{
+ return asciiDebug(string.impl());
+}
+
#endif
/*
* (C) 1999 Lars Knoll (knoll@kde.org)
- * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
#include <objc/objc.h>
#endif
-#if PLATFORM(CF)
+#if USE(CF)
typedef const struct __CFString * CFStringRef;
#endif
class BString;
#endif
-namespace WTF {
-class CString;
-}
-using WTF::CString;
+#if PLATFORM(BREWMP)
+// AECHAR is defined in AEEStdDef.h, but don't include it here to avoid conflicts.
+#ifndef _AECHAR_DEFINED
+typedef uint16 AECHAR;
+#define _AECHAR_DEFINED
+#endif
+#endif
-// FIXME: This is a temporary layering violation while we move string code to WTF.
-// Landing the file moves in one patch, will follow on with patches to change the namespaces.
-namespace WebCore {
+namespace WTF {
-class SharedBuffer;
+class CString;
struct StringHash;
// Declarations of string operations
bool charactersAreAllASCII(const UChar*, size_t);
+bool charactersAreAllLatin1(const UChar*, size_t);
int charactersToIntStrict(const UChar*, size_t, bool* ok = 0, int base = 10);
unsigned charactersToUIntStrict(const UChar*, size_t, bool* ok = 0, int base = 10);
int64_t charactersToInt64Strict(const UChar*, size_t, bool* ok = 0, int base = 10);
uint64_t charactersToUInt64(const UChar*, size_t, bool* ok = 0); // ignores trailing garbage
intptr_t charactersToIntPtr(const UChar*, size_t, bool* ok = 0); // ignores trailing garbage
-double charactersToDouble(const UChar*, size_t, bool* ok = 0);
-float charactersToFloat(const UChar*, size_t, bool* ok = 0);
+double charactersToDouble(const UChar*, size_t, bool* ok = 0, bool* didReadNumber = 0);
+float charactersToFloat(const UChar*, size_t, bool* ok = 0, bool* didReadNumber = 0);
-int find(const UChar*, size_t, UChar, int startPosition = 0);
-int reverseFind(const UChar*, size_t, UChar, int startPosition = -1);
+template<bool isSpecialCharacter(UChar)> bool isAllSpecialCharacters(const UChar*, size_t);
class String {
public:
- String() { } // gives null string, distinguishable from an empty string
- String(const UChar* str, unsigned len)
- {
- if (!str)
- return;
- m_impl = StringImpl::create(str, len);
- }
- String(const char* str)
- {
- if (!str)
- return;
- m_impl = StringImpl::create(str);
- }
- String(const char* str, unsigned length)
- {
- if (!str)
- return;
- m_impl = StringImpl::create(str, length);
- }
- String(const UChar*); // Specifically for null terminated UTF-16
- String(StringImpl* i) : m_impl(i) { }
- String(PassRefPtr<StringImpl> i) : m_impl(i) { }
- String(RefPtr<StringImpl> i) : m_impl(i) { }
+ // Construct a null string, distinguishable from an empty string.
+ String() { }
- void swap(String& o) { m_impl.swap(o.m_impl); }
+ // Construct a string with UTF-16 data.
+ String(const UChar* characters, unsigned length);
- // Hash table deleted values, which are only constructed and never copied or destroyed.
- String(WTF::HashTableDeletedValueType) : m_impl(WTF::HashTableDeletedValue) { }
- bool isHashTableDeletedValue() const { return m_impl.isHashTableDeletedValue(); }
+ // Construct a string by copying the contents of a vector. To avoid
+ // copying, consider using String::adopt instead.
+ template<size_t inlineCapacity>
+ explicit String(const Vector<UChar, inlineCapacity>&);
+
+ // Construct a string with UTF-16 data, from a null-terminated source.
+ String(const UChar*);
+
+ // Construct a string with latin1 data.
+ String(const char* characters, unsigned length);
+
+ // Construct a string with latin1 data, from a null-terminated source.
+ String(const char* characters);
+
+ // Construct a string referencing an existing StringImpl.
+ String(StringImpl* impl) : m_impl(impl) { }
+ String(PassRefPtr<StringImpl> impl) : m_impl(impl) { }
+ String(RefPtr<StringImpl> impl) : m_impl(impl) { }
+
+ // Inline the destructor.
+ ALWAYS_INLINE ~String() { }
+
+ void swap(String& o) { m_impl.swap(o.m_impl); }
static String adopt(StringBuffer& buffer) { return StringImpl::adopt(buffer); }
- static String adopt(Vector<UChar>& vector) { return StringImpl::adopt(vector); }
+ template<size_t inlineCapacity>
+ static String adopt(Vector<UChar, inlineCapacity>& vector) { return StringImpl::adopt(vector); }
+
+ bool isNull() const { return !m_impl; }
+ bool isEmpty() const { return !m_impl || !m_impl->length(); }
- ALWAYS_INLINE unsigned length() const
+ StringImpl* impl() const { return m_impl.get(); }
+
+ unsigned length() const
{
if (!m_impl)
return 0;
return m_impl->characters();
}
- const UChar* charactersWithNullTermination();
-
- UChar operator[](unsigned i) const // if i >= length(), returns 0
+ CString ascii() const;
+ CString latin1() const;
+ CString utf8(bool strict = false) const;
+
+ UChar operator[](unsigned index) const
{
- if (!m_impl || i >= m_impl->length())
+ if (!m_impl || index >= m_impl->length())
return 0;
- return m_impl->characters()[i];
+ return m_impl->characters()[index];
}
- UChar32 characterStartingAt(unsigned) const; // Ditto.
+
+ static String number(short);
+ static String number(unsigned short);
+ static String number(int);
+ static String number(unsigned);
+ static String number(long);
+ static String number(unsigned long);
+ static String number(long long);
+ static String number(unsigned long long);
+ static String number(double);
+
+ // Find a single character or string, also with match function & latin1 forms.
+ size_t find(UChar c, unsigned start = 0) const
+ { return m_impl ? m_impl->find(c, start) : notFound; }
+ size_t find(const String& str, unsigned start = 0) const
+ { return m_impl ? m_impl->find(str.impl(), start) : notFound; }
+ size_t find(CharacterMatchFunctionPtr matchFunction, unsigned start = 0) const
+ { return m_impl ? m_impl->find(matchFunction, start) : notFound; }
+ size_t find(const char* str, unsigned start = 0) const
+ { return m_impl ? m_impl->find(str, start) : notFound; }
+
+ // Find the last instance of a single character or string.
+ size_t reverseFind(UChar c, unsigned start = UINT_MAX) const
+ { return m_impl ? m_impl->reverseFind(c, start) : notFound; }
+ size_t reverseFind(const String& str, unsigned start = UINT_MAX) const
+ { return m_impl ? m_impl->reverseFind(str.impl(), start) : notFound; }
+
+ // Case insensitive string matching.
+ size_t findIgnoringCase(const char* str, unsigned start = 0) const
+ { return m_impl ? m_impl->findIgnoringCase(str, start) : notFound; }
+ size_t findIgnoringCase(const String& str, unsigned start = 0) const
+ { return m_impl ? m_impl->findIgnoringCase(str.impl(), start) : notFound; }
+ size_t reverseFindIgnoringCase(const String& str, unsigned start = UINT_MAX) const
+ { return m_impl ? m_impl->reverseFindIgnoringCase(str.impl(), start) : notFound; }
+
+ // Wrappers for find & reverseFind adding dynamic sensitivity check.
+ size_t find(const char* str, unsigned start, bool caseSensitive) const
+ { return caseSensitive ? find(str, start) : findIgnoringCase(str, start); }
+ size_t find(const String& str, unsigned start, bool caseSensitive) const
+ { return caseSensitive ? find(str, start) : findIgnoringCase(str, start); }
+ size_t reverseFind(const String& str, unsigned start, bool caseSensitive) const
+ { return caseSensitive ? reverseFind(str, start) : reverseFindIgnoringCase(str, start); }
+
+ const UChar* charactersWithNullTermination();
- bool contains(UChar c) const { return find(c) != -1; }
- bool contains(const char* str, bool caseSensitive = true) const { return find(str, 0, caseSensitive) != -1; }
- bool contains(const String& str, bool caseSensitive = true) const { return find(str, 0, caseSensitive) != -1; }
-
- int find(UChar c, int start = 0) const
- { return m_impl ? m_impl->find(c, start) : -1; }
- int find(CharacterMatchFunctionPtr matchFunction, int start = 0) const
- { return m_impl ? m_impl->find(matchFunction, start) : -1; }
- int find(const char* str, int start = 0, bool caseSensitive = true) const
- { return m_impl ? m_impl->find(str, start, caseSensitive) : -1; }
- int find(const String& str, int start = 0, bool caseSensitive = true) const
- { return m_impl ? m_impl->find(str.impl(), start, caseSensitive) : -1; }
-
- int reverseFind(UChar c, int start = -1) const
- { return m_impl ? m_impl->reverseFind(c, start) : -1; }
- int reverseFind(const String& str, int start = -1, bool caseSensitive = true) const
- { return m_impl ? m_impl->reverseFind(str.impl(), start, caseSensitive) : -1; }
+ UChar32 characterStartingAt(unsigned) const; // Ditto.
+ bool contains(UChar c) const { return find(c) != notFound; }
+ bool contains(const char* str, bool caseSensitive = true) const { return find(str, 0, caseSensitive) != notFound; }
+ bool contains(const String& str, bool caseSensitive = true) const { return find(str, 0, caseSensitive) != notFound; }
+
bool startsWith(const String& s, bool caseSensitive = true) const
{ return m_impl ? m_impl->startsWith(s.impl(), caseSensitive) : s.isEmpty(); }
bool endsWith(const String& s, bool caseSensitive = true) const
void makeLower() { if (m_impl) m_impl = m_impl->lower(); }
void makeUpper() { if (m_impl) m_impl = m_impl->upper(); }
- void makeSecure(UChar aChar, bool last = true) { if (m_impl) m_impl = m_impl->secure(aChar, last); }
+ void makeSecure(UChar aChar, StringImpl::LastCharacterBehavior behavior = StringImpl::ObscureLastCharacter)
+ {
+ if (m_impl)
+ m_impl = m_impl->secure(aChar, behavior);
+ }
void truncate(unsigned len);
void remove(unsigned pos, int len = 1);
String substring(unsigned pos, unsigned len = UINT_MAX) const;
+ String substringSharingImpl(unsigned pos, unsigned len = UINT_MAX) const;
String left(unsigned len) const { return substring(0, len); }
String right(unsigned len) const { return substring(length() - len, len); }
String simplifyWhiteSpace() const;
String removeCharacters(CharacterMatchFunctionPtr) const;
+ template<bool isSpecialCharacter(UChar)> bool isAllSpecialCharacters() const;
// Return the string with case folded for case insensitive comparison.
String foldCase() const;
- static String number(short);
- static String number(unsigned short);
- static String number(int);
- static String number(unsigned);
- static String number(long);
- static String number(unsigned long);
- static String number(long long);
- static String number(unsigned long long);
- static String number(double);
-
+#if !PLATFORM(QT)
static String format(const char *, ...) WTF_ATTRIBUTE_PRINTF(1, 2);
+#else
+ static String format(const char *, ...);
+#endif
// Returns an uninitialized string. The characters needs to be written
// into the buffer returned in data before the returned string is used.
int64_t toInt64(bool* ok = 0) const;
uint64_t toUInt64(bool* ok = 0) const;
intptr_t toIntPtr(bool* ok = 0) const;
- double toDouble(bool* ok = 0) const;
- float toFloat(bool* ok = 0) const;
+ double toDouble(bool* ok = 0, bool* didReadNumber = 0) const;
+ float toFloat(bool* ok = 0, bool* didReadNumber = 0) const;
bool percentage(int& percentage) const;
// to ever prefer copy() over plain old assignment.
String threadsafeCopy() const;
- bool isNull() const { return !m_impl; }
- ALWAYS_INLINE bool isEmpty() const { return !m_impl || !m_impl->length(); }
-
- StringImpl* impl() const { return m_impl.get(); }
+ // Prevent Strings from being implicitly convertable to bool as it will be ambiguous on any platform that
+ // allows implicit conversion to another pointer type (e.g., Mac allows implicit conversion to NSString*).
+ typedef struct ImplicitConversionFromWTFStringToBoolDisallowedA* (String::*UnspecifiedBoolTypeA);
+ typedef struct ImplicitConversionFromWTFStringToBoolDisallowedB* (String::*UnspecifiedBoolTypeB);
+ operator UnspecifiedBoolTypeA() const;
+ operator UnspecifiedBoolTypeB() const;
-#if PLATFORM(CF)
+#if USE(CF)
String(CFStringRef);
CFStringRef createCFString() const;
#endif
operator BString() const;
#endif
- Vector<char> ascii() const;
-
- CString latin1() const;
- CString utf8() const;
+#if PLATFORM(BREWMP)
+ String(const AECHAR*);
+#endif
+ // String::fromUTF8 will return a null string if
+ // the input data contains invalid UTF-8 sequences.
static String fromUTF8(const char*, size_t);
static String fromUTF8(const char*);
static String fromUTF8WithLatin1Fallback(const char*, size_t);
// Determines the writing direction using the Unicode Bidi Algorithm rules P2 and P3.
- WTF::Unicode::Direction defaultWritingDirection() const { return m_impl ? m_impl->defaultWritingDirection() : WTF::Unicode::LeftToRight; }
+ WTF::Unicode::Direction defaultWritingDirection(bool* hasStrongDirectionality = 0) const
+ {
+ if (m_impl)
+ return m_impl->defaultWritingDirection(hasStrongDirectionality);
+ if (hasStrongDirectionality)
+ *hasStrongDirectionality = false;
+ return WTF::Unicode::LeftToRight;
+ }
bool containsOnlyASCII() const { return charactersAreAllASCII(characters(), length()); }
+ bool containsOnlyLatin1() const { return charactersAreAllLatin1(characters(), length()); }
+
+ // Hash table deleted values, which are only constructed and never copied or destroyed.
+ String(WTF::HashTableDeletedValueType) : m_impl(WTF::HashTableDeletedValue) { }
+ bool isHashTableDeletedValue() const { return m_impl.isHashTableDeletedValue(); }
private:
RefPtr<StringImpl> m_impl;
QDataStream& operator>>(QDataStream& stream, String& str);
#endif
-String operator+(const String&, const String&);
-String operator+(const String&, const char*);
-String operator+(const char*, const String&);
-
inline String& operator+=(String& a, const String& b) { a.append(b); return a; }
inline bool operator==(const String& a, const String& b) { return equal(a.impl(), b.impl()); }
inline bool equalIgnoringNullity(const String& a, const String& b) { return equalIgnoringNullity(a.impl(), b.impl()); }
+template<size_t inlineCapacity>
+inline bool equalIgnoringNullity(const Vector<UChar, inlineCapacity>& a, const String& b) { return equalIgnoringNullity(a, b.impl()); }
+
inline bool operator!(const String& str) { return str.isNull(); }
inline void swap(String& a, String& b) { a.swap(b); }
// Definitions of string operations
+template<size_t inlineCapacity>
+String::String(const Vector<UChar, inlineCapacity>& vector)
+ : m_impl(vector.size() ? StringImpl::create(vector.data(), vector.size()) : 0)
+{
+}
+
#ifdef __OBJC__
// This is for situations in WebKit where the long standing behavior has been
// "nil if empty", so we try to maintain longstanding behavior for the sake of
return !(ored & 0xFF80);
}
-inline int find(const UChar* characters, size_t length, UChar character, int startPosition)
+inline bool charactersAreAllLatin1(const UChar* characters, size_t length)
+{
+ UChar ored = 0;
+ for (size_t i = 0; i < length; ++i)
+ ored |= characters[i];
+ return !(ored & 0xFF00);
+}
+
+int codePointCompare(const String&, const String&);
+
+inline size_t find(const UChar* characters, unsigned length, UChar matchCharacter, unsigned index = 0)
{
- if (startPosition >= static_cast<int>(length))
- return -1;
- for (size_t i = startPosition; i < length; ++i) {
- if (characters[i] == character)
- return static_cast<int>(i);
+ while (index < length) {
+ if (characters[index] == matchCharacter)
+ return index;
+ ++index;
}
- return -1;
+ return notFound;
}
-inline int find(const UChar* characters, size_t length, CharacterMatchFunctionPtr matchFunction, int startPosition)
+inline size_t find(const UChar* characters, unsigned length, CharacterMatchFunctionPtr matchFunction, unsigned index = 0)
{
- if (startPosition >= static_cast<int>(length))
- return -1;
- for (size_t i = startPosition; i < length; ++i) {
- if (matchFunction(characters[i]))
- return static_cast<int>(i);
+ while (index < length) {
+ if (matchFunction(characters[index]))
+ return index;
+ ++index;
}
- return -1;
+ return notFound;
}
-inline int reverseFind(const UChar* characters, size_t length, UChar character, int startPosition)
+inline size_t reverseFind(const UChar* characters, unsigned length, UChar matchCharacter, unsigned index = UINT_MAX)
{
- if (startPosition >= static_cast<int>(length) || !length)
- return -1;
- if (startPosition < 0)
- startPosition += static_cast<int>(length);
- while (true) {
- if (characters[startPosition] == character)
- return startPosition;
- if (!startPosition)
- return -1;
- startPosition--;
+ if (!length)
+ return notFound;
+ if (index >= length)
+ index = length - 1;
+ while (characters[index] != matchCharacter) {
+ if (!index--)
+ return notFound;
}
- ASSERT_NOT_REACHED();
- return -1;
+ return index;
}
inline void append(Vector<UChar>& vector, const String& string)
}
}
-} // namespace WebCore
+template<bool isSpecialCharacter(UChar)> inline bool isAllSpecialCharacters(const UChar* characters, size_t length)
+{
+ for (size_t i = 0; i < length; ++i) {
+ if (!isSpecialCharacter(characters[i]))
+ return false;
+ }
+ return true;
+}
-namespace WTF {
+template<bool isSpecialCharacter(UChar)> inline bool String::isAllSpecialCharacters() const
+{
+ return WTF::isAllSpecialCharacters<isSpecialCharacter>(characters(), length());
+}
+
+// StringHash is the default hash for String
+template<typename T> struct DefaultHash;
+template<> struct DefaultHash<String> {
+ typedef StringHash Hash;
+};
+
+template <> struct VectorTraits<String> : SimpleClassVectorTraits { };
- // StringHash is the default hash for String
- template<typename T> struct DefaultHash;
- template<> struct DefaultHash<WebCore::String> {
- typedef WebCore::StringHash Hash;
- };
+// Shared global empty string.
+const String& emptyString();
}
+using WTF::CString;
+using WTF::String;
+using WTF::emptyString;
+using WTF::append;
+using WTF::appendNumber;
+using WTF::charactersAreAllASCII;
+using WTF::charactersAreAllLatin1;
+using WTF::charactersToIntStrict;
+using WTF::charactersToUIntStrict;
+using WTF::charactersToInt64Strict;
+using WTF::charactersToUInt64Strict;
+using WTF::charactersToIntPtrStrict;
+using WTF::charactersToInt;
+using WTF::charactersToUInt;
+using WTF::charactersToInt64;
+using WTF::charactersToUInt64;
+using WTF::charactersToIntPtr;
+using WTF::charactersToDouble;
+using WTF::charactersToFloat;
+using WTF::equal;
+using WTF::equalIgnoringCase;
+using WTF::find;
+using WTF::isAllSpecialCharacters;
+using WTF::isSpaceOrNewline;
+using WTF::reverseFind;
+
+#include "AtomicString.h"
#endif
--- /dev/null
+/*
+ * Copyright (C) 2007, 2009, 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef CharacterNames_h
+#define CharacterNames_h
+
+#include "Unicode.h"
+
+namespace WTF {
+namespace Unicode {
+
+// Names here are taken from the Unicode standard.
+
+// Most of these are UChar constants, not UChar32, which makes them
+// more convenient for WebCore code that mostly uses UTF-16.
+
+const UChar32 aegeanWordSeparatorLine = 0x10100;
+const UChar32 aegeanWordSeparatorDot = 0x10101;
+const UChar blackCircle = 0x25CF;
+const UChar blackSquare = 0x25A0;
+const UChar blackUpPointingTriangle = 0x25B2;
+const UChar bullet = 0x2022;
+const UChar bullseye = 0x25CE;
+const UChar carriageReturn = 0x000D;
+const UChar combiningEnclosingKeycap = 0x20E3;
+const UChar ethiopicPrefaceColon = 0x1366;
+const UChar ethiopicWordspace = 0x1361;
+const UChar fisheye = 0x25C9;
+const UChar hebrewPunctuationGeresh = 0x05F3;
+const UChar hebrewPunctuationGershayim = 0x05F4;
+const UChar horizontalEllipsis = 0x2026;
+const UChar hyphen = 0x2010;
+const UChar hyphenMinus = 0x002D;
+const UChar ideographicComma = 0x3001;
+const UChar ideographicFullStop = 0x3002;
+const UChar ideographicSpace = 0x3000;
+const UChar leftDoubleQuotationMark = 0x201C;
+const UChar leftSingleQuotationMark = 0x2018;
+const UChar leftToRightEmbed = 0x202A;
+const UChar leftToRightMark = 0x200E;
+const UChar leftToRightOverride = 0x202D;
+const UChar minusSign = 0x2212;
+const UChar newlineCharacter = 0x000A;
+const UChar noBreakSpace = 0x00A0;
+const UChar objectReplacementCharacter = 0xFFFC;
+const UChar popDirectionalFormatting = 0x202C;
+const UChar replacementCharacter = 0xFFFD;
+const UChar rightDoubleQuotationMark = 0x201D;
+const UChar rightSingleQuotationMark = 0x2019;
+const UChar rightToLeftEmbed = 0x202B;
+const UChar rightToLeftMark = 0x200F;
+const UChar rightToLeftOverride = 0x202E;
+const UChar sesameDot = 0xFE45;
+const UChar softHyphen = 0x00AD;
+const UChar space = 0x0020;
+const UChar tibetanMarkIntersyllabicTsheg = 0x0F0B;
+const UChar tibetanMarkDelimiterTshegBstar = 0x0F0C;
+const UChar32 ugariticWordDivider = 0x1039F;
+const UChar whiteBullet = 0x25E6;
+const UChar whiteCircle = 0x25CB;
+const UChar whiteSesameDot = 0xFE46;
+const UChar whiteUpPointingTriangle = 0x25B3;
+const UChar yenSign = 0x00A5;
+const UChar zeroWidthJoiner = 0x200D;
+const UChar zeroWidthNonJoiner = 0x200C;
+const UChar zeroWidthSpace = 0x200B;
+const UChar zeroWidthNoBreakSpace = 0xFEFF;
+
+const UChar AppleLogo = 0xF8FF;
+const UChar BigDot = 0x25CF;
+
+} // namespace Unicode
+} // namespace WTF
+
+using WTF::Unicode::aegeanWordSeparatorLine;
+using WTF::Unicode::aegeanWordSeparatorDot;
+using WTF::Unicode::blackCircle;
+using WTF::Unicode::blackSquare;
+using WTF::Unicode::blackUpPointingTriangle;
+using WTF::Unicode::bullet;
+using WTF::Unicode::bullseye;
+using WTF::Unicode::carriageReturn;
+using WTF::Unicode::combiningEnclosingKeycap;
+using WTF::Unicode::ethiopicPrefaceColon;
+using WTF::Unicode::ethiopicWordspace;
+using WTF::Unicode::fisheye;
+using WTF::Unicode::hebrewPunctuationGeresh;
+using WTF::Unicode::hebrewPunctuationGershayim;
+using WTF::Unicode::horizontalEllipsis;
+using WTF::Unicode::hyphen;
+using WTF::Unicode::hyphenMinus;
+using WTF::Unicode::ideographicComma;
+using WTF::Unicode::ideographicFullStop;
+using WTF::Unicode::ideographicSpace;
+using WTF::Unicode::leftDoubleQuotationMark;
+using WTF::Unicode::leftSingleQuotationMark;
+using WTF::Unicode::leftToRightEmbed;
+using WTF::Unicode::leftToRightMark;
+using WTF::Unicode::leftToRightOverride;
+using WTF::Unicode::minusSign;
+using WTF::Unicode::newlineCharacter;
+using WTF::Unicode::noBreakSpace;
+using WTF::Unicode::objectReplacementCharacter;
+using WTF::Unicode::popDirectionalFormatting;
+using WTF::Unicode::replacementCharacter;
+using WTF::Unicode::rightDoubleQuotationMark;
+using WTF::Unicode::rightSingleQuotationMark;
+using WTF::Unicode::rightToLeftEmbed;
+using WTF::Unicode::rightToLeftMark;
+using WTF::Unicode::rightToLeftOverride;
+using WTF::Unicode::sesameDot;
+using WTF::Unicode::softHyphen;
+using WTF::Unicode::space;
+using WTF::Unicode::tibetanMarkIntersyllabicTsheg;
+using WTF::Unicode::tibetanMarkDelimiterTshegBstar;
+using WTF::Unicode::ugariticWordDivider;
+using WTF::Unicode::whiteBullet;
+using WTF::Unicode::whiteCircle;
+using WTF::Unicode::whiteSesameDot;
+using WTF::Unicode::whiteUpPointingTriangle;
+using WTF::Unicode::yenSign;
+using WTF::Unicode::zeroWidthJoiner;
+using WTF::Unicode::zeroWidthNonJoiner;
+using WTF::Unicode::zeroWidthSpace;
+using WTF::Unicode::zeroWidthNoBreakSpace;
+
+using WTF::Unicode::AppleLogo;
+using WTF::Unicode::BigDot;
+
+#endif // CharacterNames_h
#ifndef WTF_Collator_h
#define WTF_Collator_h
+#include <wtf/FastAllocBase.h>
#include <wtf/Noncopyable.h>
#include <wtf/PassOwnPtr.h>
#include <wtf/unicode/Unicode.h>
namespace WTF {
- class Collator : public Noncopyable {
+ class Collator {
+ WTF_MAKE_NONCOPYABLE(Collator); WTF_MAKE_FAST_ALLOCATED;
public:
enum Result { Equal = 0, Greater = 1, Less = -1 };
PassOwnPtr<Collator> Collator::userDefault()
{
- return new Collator(0);
+ return adoptPtr(new Collator(0));
}
// A default implementation for platforms that lack Unicode-aware collation.
/*
* Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
#include "config.h"
#include "UTF8.h"
+#include "ASCIICType.h"
+#include <wtf/StringHasher.h>
+#include <wtf/unicode/CharacterNames.h>
+
namespace WTF {
namespace Unicode {
inline int inlineUTF8SequenceLength(char b0)
{
- return (b0 & 0x80) == 0 ? 1 : inlineUTF8SequenceLengthNonASCII(b0);
+ return isASCII(b0) ? 1 : inlineUTF8SequenceLengthNonASCII(b0);
}
int UTF8SequenceLength(char b0)
{
- return (b0 & 0x80) == 0 ? 1 : inlineUTF8SequenceLengthNonASCII(b0);
+ return isASCII(b0) ? 1 : inlineUTF8SequenceLengthNonASCII(b0);
}
int decodeUTF8Sequence(const char* sequence)
bytesToWrite = 4;
} else {
bytesToWrite = 3;
- ch = 0xFFFD;
+ ch = replacementCharacter;
}
target += bytesToWrite;
static const UChar32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL,
0x03C82080UL, 0xFA082080UL, 0x82082080UL };
+static inline UChar32 readUTF8Sequence(const char*& sequence, unsigned length)
+{
+ UChar32 character = 0;
+
+ // The cases all fall through.
+ switch (length) {
+ case 6: character += static_cast<unsigned char>(*sequence++); character <<= 6;
+ case 5: character += static_cast<unsigned char>(*sequence++); character <<= 6;
+ case 4: character += static_cast<unsigned char>(*sequence++); character <<= 6;
+ case 3: character += static_cast<unsigned char>(*sequence++); character <<= 6;
+ case 2: character += static_cast<unsigned char>(*sequence++); character <<= 6;
+ case 1: character += static_cast<unsigned char>(*sequence++);
+ }
+
+ return character - offsetsFromUTF8[length - 1];
+}
+
ConversionResult convertUTF8ToUTF16(
const char** sourceStart, const char* sourceEnd,
UChar** targetStart, UChar* targetEnd, bool strict)
const char* source = *sourceStart;
UChar* target = *targetStart;
while (source < sourceEnd) {
- UChar32 ch = 0;
- int extraBytesToRead = UTF8SequenceLength(*source) - 1;
- if (source + extraBytesToRead >= sourceEnd) {
+ int utf8SequenceLength = inlineUTF8SequenceLength(*source);
+ if (sourceEnd - source < utf8SequenceLength) {
result = sourceExhausted;
break;
}
// Do this check whether lenient or strict
- if (!isLegalUTF8(reinterpret_cast<const unsigned char*>(source), extraBytesToRead + 1)) {
+ if (!isLegalUTF8(reinterpret_cast<const unsigned char*>(source), utf8SequenceLength)) {
result = sourceIllegal;
break;
}
- // The cases all fall through.
- switch (extraBytesToRead) {
- case 5: ch += static_cast<unsigned char>(*source++); ch <<= 6; // remember, illegal UTF-8
- case 4: ch += static_cast<unsigned char>(*source++); ch <<= 6; // remember, illegal UTF-8
- case 3: ch += static_cast<unsigned char>(*source++); ch <<= 6;
- case 2: ch += static_cast<unsigned char>(*source++); ch <<= 6;
- case 1: ch += static_cast<unsigned char>(*source++); ch <<= 6;
- case 0: ch += static_cast<unsigned char>(*source++);
- }
- ch -= offsetsFromUTF8[extraBytesToRead];
+
+ UChar32 character = readUTF8Sequence(source, utf8SequenceLength);
if (target >= targetEnd) {
- source -= (extraBytesToRead + 1); // Back up source pointer!
- result = targetExhausted; break;
+ source -= utf8SequenceLength; // Back up source pointer!
+ result = targetExhausted;
+ break;
}
- if (ch <= 0xFFFF) {
+
+ if (U_IS_BMP(character)) {
// UTF-16 surrogate values are illegal in UTF-32
- if (ch >= 0xD800 && ch <= 0xDFFF) {
+ if (U_IS_SURROGATE(character)) {
if (strict) {
- source -= (extraBytesToRead + 1); // return to the illegal value itself
+ source -= utf8SequenceLength; // return to the illegal value itself
result = sourceIllegal;
break;
} else
- *target++ = 0xFFFD;
+ *target++ = replacementCharacter;
} else
- *target++ = (UChar)ch; // normal case
- } else if (ch > 0x10FFFF) {
- if (strict) {
- result = sourceIllegal;
- source -= (extraBytesToRead + 1); // return to the start
- break; // Bail out; shouldn't continue
- } else
- *target++ = 0xFFFD;
- } else {
+ *target++ = character; // normal case
+ } else if (U_IS_SUPPLEMENTARY(character)) {
// target is a character in range 0xFFFF - 0x10FFFF
if (target + 1 >= targetEnd) {
- source -= (extraBytesToRead + 1); // Back up source pointer!
+ source -= utf8SequenceLength; // Back up source pointer!
result = targetExhausted;
break;
}
- ch -= 0x0010000UL;
- *target++ = (UChar)((ch >> 10) + 0xD800);
- *target++ = (UChar)((ch & 0x03FF) + 0xDC00);
+ *target++ = U16_LEAD(character);
+ *target++ = U16_TRAIL(character);
+ } else {
+ if (strict) {
+ source -= utf8SequenceLength; // return to the start
+ result = sourceIllegal;
+ break; // Bail out; shouldn't continue
+ } else
+ *target++ = replacementCharacter;
}
}
*sourceStart = source;
return result;
}
+unsigned calculateStringHashAndLengthFromUTF8(const char* data, const char* dataEnd, unsigned& dataLength, unsigned& utf16Length)
+{
+ if (!data)
+ return 0;
+
+ StringHasher stringHasher;
+ dataLength = 0;
+ utf16Length = 0;
+
+ while (data < dataEnd || (!dataEnd && *data)) {
+ if (isASCII(*data)) {
+ stringHasher.addCharacter(*data++);
+ dataLength++;
+ utf16Length++;
+ continue;
+ }
+
+ int utf8SequenceLength = inlineUTF8SequenceLengthNonASCII(*data);
+ dataLength += utf8SequenceLength;
+
+ if (!dataEnd) {
+ for (int i = 1; i < utf8SequenceLength; ++i) {
+ if (!data[i])
+ return 0;
+ }
+ } else if (dataEnd - data < utf8SequenceLength)
+ return 0;
+
+ if (!isLegalUTF8(reinterpret_cast<const unsigned char*>(data), utf8SequenceLength))
+ return 0;
+
+ UChar32 character = readUTF8Sequence(data, utf8SequenceLength);
+ ASSERT(!isASCII(character));
+
+ if (U_IS_BMP(character)) {
+ // UTF-16 surrogate values are illegal in UTF-32
+ if (U_IS_SURROGATE(character))
+ return 0;
+ stringHasher.addCharacter(static_cast<UChar>(character)); // normal case
+ utf16Length++;
+ } else if (U_IS_SUPPLEMENTARY(character)) {
+ stringHasher.addCharacters(static_cast<UChar>(U16_LEAD(character)),
+ static_cast<UChar>(U16_TRAIL(character)));
+ utf16Length += 2;
+ } else
+ return 0;
+ }
+
+ return stringHasher.hash();
}
+
+bool equalUTF16WithUTF8(const UChar* a, const UChar* aEnd, const char* b, const char* bEnd)
+{
+ while (b < bEnd) {
+ if (isASCII(*b)) {
+ if (*a++ != *b++)
+ return false;
+ continue;
+ }
+
+ int utf8SequenceLength = inlineUTF8SequenceLengthNonASCII(*b);
+
+ if (bEnd - b < utf8SequenceLength)
+ return false;
+
+ if (!isLegalUTF8(reinterpret_cast<const unsigned char*>(b), utf8SequenceLength))
+ return 0;
+
+ UChar32 character = readUTF8Sequence(b, utf8SequenceLength);
+ ASSERT(!isASCII(character));
+
+ if (U_IS_BMP(character)) {
+ // UTF-16 surrogate values are illegal in UTF-32
+ if (U_IS_SURROGATE(character))
+ return false;
+ if (*a++ != character)
+ return false;
+ } else if (U_IS_SUPPLEMENTARY(character)) {
+ if (*a++ != U16_LEAD(character))
+ return false;
+ if (*a++ != U16_TRAIL(character))
+ return false;
+ } else
+ return false;
+ }
+
+ return a == aEnd;
}
+
+} // namespace Unicode
+} // namespace WTF
#include "Unicode.h"
namespace WTF {
- namespace Unicode {
+namespace Unicode {
// Given a first byte, gives the length of the UTF-8 sequence it begins.
// Returns 0 for bytes that are not legal starts of UTF-8 sequences.
ConversionResult convertUTF16ToUTF8(
const UChar** sourceStart, const UChar* sourceEnd,
char** targetStart, char* targetEnd, bool strict = true);
- }
-}
+
+ unsigned calculateStringHashAndLengthFromUTF8(const char* data, const char* dataEnd, unsigned& dataLength, unsigned& utf16Length);
+
+ bool equalUTF16WithUTF8(const UChar* a, const UChar* aEnd, const char* b, const char* bEnd);
+
+} // namespace Unicode
+} // namespace WTF
#endif // WTF_UTF8_h
#elif USE(GLIB_UNICODE)
#include <wtf/unicode/glib/UnicodeGLib.h>
#elif USE(WINCE_UNICODE)
-#include <wtf/unicode/wince/UnicodeWince.h>
+#include <wtf/unicode/wince/UnicodeWinCE.h>
+#elif USE(BREWMP_UNICODE)
+#include <wtf/unicode/brew/UnicodeBrew.h>
#else
#error "Unknown Unicode implementation"
#endif
--- /dev/null
+/*
+ * Copyright (C) 1999-2004, International Business Machines Corporation and others. All Rights Reserved.
+ *
+ */
+
+#ifndef UnicodeMacrosFromICU_h
+#define UnicodeMacrosFromICU_h
+
+// some defines from ICU
+
+#define U_IS_BMP(c) ((UChar32)(c)<=0xffff)
+#define U16_IS_LEAD(c) (((c)&0xfffffc00)==0xd800)
+#define U16_IS_TRAIL(c) (((c)&0xfffffc00)==0xdc00)
+#define U16_SURROGATE_OFFSET ((0xd800<<10UL)+0xdc00-0x10000)
+#define U16_GET_SUPPLEMENTARY(lead, trail) \
+ (((UChar32)(lead)<<10UL)+(UChar32)(trail)-U16_SURROGATE_OFFSET)
+
+#define U16_LEAD(supplementary) (UChar)(((supplementary)>>10)+0xd7c0)
+#define U16_TRAIL(supplementary) (UChar)(((supplementary)&0x3ff)|0xdc00)
+#define U16_LENGTH(c) ((uint32_t)(c) <= 0xffff ? 1 : 2)
+
+#define U_IS_SUPPLEMENTARY(c) ((UChar32)((c)-0x10000)<=0xfffff)
+#define U_IS_SURROGATE(c) (((c)&0xfffff800)==0xd800)
+#define U16_IS_SINGLE(c) !U_IS_SURROGATE(c)
+#define U16_IS_SURROGATE(c) U_IS_SURROGATE(c)
+#define U16_IS_SURROGATE_LEAD(c) (((c)&0x400)==0)
+
+#define U16_GET(s, start, i, length, c) { \
+ (c)=(s)[i]; \
+ if(U16_IS_SURROGATE(c)) { \
+ uint16_t __c2; \
+ if(U16_IS_SURROGATE_LEAD(c)) { \
+ if((i)+1<(length) && U16_IS_TRAIL(__c2=(s)[(i)+1])) { \
+ (c)=U16_GET_SUPPLEMENTARY((c), __c2); \
+ } \
+ } else { \
+ if((i)-1>=(start) && U16_IS_LEAD(__c2=(s)[(i)-1])) { \
+ (c)=U16_GET_SUPPLEMENTARY(__c2, (c)); \
+ } \
+ } \
+ } \
+}
+
+#define U16_PREV(s, start, i, c) { \
+ (c)=(s)[--(i)]; \
+ if(U16_IS_TRAIL(c)) { \
+ uint16_t __c2; \
+ if((i)>(start) && U16_IS_LEAD(__c2=(s)[(i)-1])) { \
+ --(i); \
+ (c)=U16_GET_SUPPLEMENTARY(__c2, (c)); \
+ } \
+ } \
+}
+
+#define U16_BACK_1(s, start, i) { \
+ if(U16_IS_TRAIL((s)[--(i)]) && (i)>(start) && U16_IS_LEAD((s)[(i)-1])) { \
+ --(i); \
+ } \
+}
+
+#define U16_NEXT(s, i, length, c) { \
+ (c)=(s)[(i)++]; \
+ if(U16_IS_LEAD(c)) { \
+ uint16_t __c2; \
+ if((i)<(length) && U16_IS_TRAIL(__c2=(s)[(i)])) { \
+ ++(i); \
+ (c)=U16_GET_SUPPLEMENTARY((c), __c2); \
+ } \
+ } \
+}
+
+#define U16_FWD_1(s, i, length) { \
+ if(U16_IS_LEAD((s)[(i)++]) && (i)<(length) && U16_IS_TRAIL((s)[i])) { \
+ ++(i); \
+ } \
+}
+
+#define U_MASK(x) ((uint32_t)1<<(x))
+
+#define U8_MAX_LENGTH 4
+
+#define U8_APPEND_UNSAFE(s, i, c) { \
+ if((uint32_t)(c)<=0x7f) { \
+ (s)[(i)++]=(uint8_t)(c); \
+ } else { \
+ if((uint32_t)(c)<=0x7ff) { \
+ (s)[(i)++]=(uint8_t)(((c)>>6)|0xc0); \
+ } else { \
+ if((uint32_t)(c)<=0xffff) { \
+ (s)[(i)++]=(uint8_t)(((c)>>12)|0xe0); \
+ } else { \
+ (s)[(i)++]=(uint8_t)(((c)>>18)|0xf0); \
+ (s)[(i)++]=(uint8_t)((((c)>>12)&0x3f)|0x80); \
+ } \
+ (s)[(i)++]=(uint8_t)((((c)>>6)&0x3f)|0x80); \
+ } \
+ (s)[(i)++]=(uint8_t)(((c)&0x3f)|0x80); \
+ } \
+}
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2006 George Staikos <staikos@kde.org>
+ * Copyright (C) 2006 Alexey Proskuryakov <ap@nypop.com>
+ * Copyright (C) 2007-2009 Torch Mobile, Inc.
+ * Copyright (C) 2010 Company 100, Inc.
+ *
+ * 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 "UnicodeBrew.h"
+
+#include <wchar.h>
+#include <wctype.h>
+
+namespace WTF {
+namespace Unicode {
+
+UChar toLower(UChar c)
+{
+ return towlower(c);
+}
+
+UChar toUpper(UChar c)
+{
+ return towupper(c);
+}
+
+UChar foldCase(UChar c)
+{
+ return towlower(c);
+}
+
+bool isPrintableChar(UChar c)
+{
+ return !!iswprint(c);
+}
+
+bool isUpper(UChar c)
+{
+ return !!iswupper(c);
+}
+
+bool isLower(UChar c)
+{
+ return !!iswlower(c);
+}
+
+bool isDigit(UChar c)
+{
+ return !!iswdigit(c);
+}
+
+bool isPunct(UChar c)
+{
+ return !!iswpunct(c);
+}
+
+bool isAlphanumeric(UChar c)
+{
+ return !!iswalnum(c);
+}
+
+int toLower(UChar* result, int resultLength, const UChar* source, int sourceLength, bool* isError)
+{
+ const UChar* sourceIterator = source;
+ const UChar* sourceEnd = source + sourceLength;
+ UChar* resultIterator = result;
+ UChar* resultEnd = result + resultLength;
+
+ if (sourceLength <= resultLength) {
+ while (sourceIterator < sourceEnd)
+ *resultIterator++ = towlower(*sourceIterator++);
+ } else {
+ while (resultIterator < resultEnd)
+ *resultIterator++ = towlower(*sourceIterator++);
+ }
+
+ int remainingCharacters = sourceIterator < sourceEnd ? sourceEnd - sourceIterator : 0;
+ *isError = !!remainingCharacters;
+ if (resultIterator < resultEnd)
+ *resultIterator = 0;
+
+ return (resultIterator - result) + remainingCharacters;
+}
+
+int toUpper(UChar* result, int resultLength, const UChar* source, int sourceLength, bool* isError)
+{
+ const UChar* sourceIterator = source;
+ const UChar* sourceEnd = source + sourceLength;
+ UChar* resultIterator = result;
+ UChar* resultEnd = result + resultLength;
+
+ if (sourceLength <= resultLength) {
+ while (sourceIterator < sourceEnd)
+ *resultIterator++ = towupper(*sourceIterator++);
+ } else {
+ while (resultIterator < resultEnd)
+ *resultIterator++ = towupper(*sourceIterator++);
+ }
+
+ int remainingCharacters = sourceIterator < sourceEnd ? sourceEnd - sourceIterator : 0;
+ *isError = !!remainingCharacters;
+ if (resultIterator < resultEnd)
+ *resultIterator = 0;
+
+ return (resultIterator - result) + remainingCharacters;
+}
+
+int foldCase(UChar* result, int resultLength, const UChar* source, int sourceLength, bool* isError)
+{
+ *isError = false;
+ if (resultLength < sourceLength) {
+ *isError = true;
+ return sourceLength;
+ }
+ for (int i = 0; i < sourceLength; ++i)
+ result[i] = foldCase(source[i]);
+ return sourceLength;
+}
+
+UChar toTitleCase(UChar c)
+{
+ return towupper(c);
+}
+
+Direction direction(UChar32 c)
+{
+ return static_cast<Direction>(ICU::direction(c));
+}
+
+CharCategory category(unsigned int c)
+{
+ return static_cast<CharCategory>(TO_MASK((int8_t) ICU::category(c)));
+}
+
+DecompositionType decompositionType(UChar32 c)
+{
+ return static_cast<DecompositionType>(ICU::decompositionType(c));
+}
+
+unsigned char combiningClass(UChar32 c)
+{
+ return ICU::combiningClass(c);
+}
+
+UChar mirroredChar(UChar32 c)
+{
+ return ICU::mirroredChar(c);
+}
+
+int digitValue(UChar c)
+{
+ return ICU::digitValue(c);
+}
+
+bool isSpace(UChar c)
+{
+ return !!iswspace(c);
+}
+
+bool isLetter(UChar c)
+{
+ return !!iswalpha(c);
+}
+
+} // namespace Unicode
+} // namespace WTF
--- /dev/null
+/*
+ * Copyright (C) 2006 George Staikos <staikos@kde.org>
+ * Copyright (C) 2006 Alexey Proskuryakov <ap@nypop.com>
+ * Copyright (C) 2007 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2007-2009 Torch Mobile, Inc.
+ * Copyright (C) 2010 Company 100, Inc.
+ *
+ * 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.
+ *
+ */
+
+#ifndef UnicodeBrew_h
+#define UnicodeBrew_h
+
+#include "UnicodeFromICU.h"
+#include "UnicodeMacrosFromICU.h"
+
+namespace WTF {
+namespace Unicode {
+
+enum Direction {
+ LeftToRight = ICU::U_LEFT_TO_RIGHT,
+ RightToLeft = ICU::U_RIGHT_TO_LEFT,
+ EuropeanNumber = ICU::U_EUROPEAN_NUMBER,
+ EuropeanNumberSeparator = ICU::U_EUROPEAN_NUMBER_SEPARATOR,
+ EuropeanNumberTerminator = ICU::U_EUROPEAN_NUMBER_TERMINATOR,
+ ArabicNumber = ICU::U_ARABIC_NUMBER,
+ CommonNumberSeparator = ICU::U_COMMON_NUMBER_SEPARATOR,
+ BlockSeparator = ICU::U_BLOCK_SEPARATOR,
+ SegmentSeparator = ICU::U_SEGMENT_SEPARATOR,
+ WhiteSpaceNeutral = ICU::U_WHITE_SPACE_NEUTRAL,
+ OtherNeutral = ICU::U_OTHER_NEUTRAL,
+ LeftToRightEmbedding = ICU::U_LEFT_TO_RIGHT_EMBEDDING,
+ LeftToRightOverride = ICU::U_LEFT_TO_RIGHT_OVERRIDE,
+ RightToLeftArabic = ICU::U_RIGHT_TO_LEFT_ARABIC,
+ RightToLeftEmbedding = ICU::U_RIGHT_TO_LEFT_EMBEDDING,
+ RightToLeftOverride = ICU::U_RIGHT_TO_LEFT_OVERRIDE,
+ PopDirectionalFormat = ICU::U_POP_DIRECTIONAL_FORMAT,
+ NonSpacingMark = ICU::U_DIR_NON_SPACING_MARK,
+ BoundaryNeutral = ICU::U_BOUNDARY_NEUTRAL
+};
+
+enum DecompositionType {
+ DecompositionNone = ICU::U_DT_NONE,
+ DecompositionCanonical = ICU::U_DT_CANONICAL,
+ DecompositionCompat = ICU::U_DT_COMPAT,
+ DecompositionCircle = ICU::U_DT_CIRCLE,
+ DecompositionFinal = ICU::U_DT_FINAL,
+ DecompositionFont = ICU::U_DT_FONT,
+ DecompositionFraction = ICU::U_DT_FRACTION,
+ DecompositionInitial = ICU::U_DT_INITIAL,
+ DecompositionIsolated = ICU::U_DT_ISOLATED,
+ DecompositionMedial = ICU::U_DT_MEDIAL,
+ DecompositionNarrow = ICU::U_DT_NARROW,
+ DecompositionNoBreak = ICU::U_DT_NOBREAK,
+ DecompositionSmall = ICU::U_DT_SMALL,
+ DecompositionSquare = ICU::U_DT_SQUARE,
+ DecompositionSub = ICU::U_DT_SUB,
+ DecompositionSuper = ICU::U_DT_SUPER,
+ DecompositionVertical = ICU::U_DT_VERTICAL,
+ DecompositionWide = ICU::U_DT_WIDE,
+};
+
+enum CharCategory {
+ NoCategory = 0,
+ Other_NotAssigned = TO_MASK(ICU::U_GENERAL_OTHER_TYPES),
+ Letter_Uppercase = TO_MASK(ICU::U_UPPERCASE_LETTER),
+ Letter_Lowercase = TO_MASK(ICU::U_LOWERCASE_LETTER),
+ Letter_Titlecase = TO_MASK(ICU::U_TITLECASE_LETTER),
+ Letter_Modifier = TO_MASK(ICU::U_MODIFIER_LETTER),
+ Letter_Other = TO_MASK(ICU::U_OTHER_LETTER),
+
+ Mark_NonSpacing = TO_MASK(ICU::U_NON_SPACING_MARK),
+ Mark_Enclosing = TO_MASK(ICU::U_ENCLOSING_MARK),
+ Mark_SpacingCombining = TO_MASK(ICU::U_COMBINING_SPACING_MARK),
+
+ Number_DecimalDigit = TO_MASK(ICU::U_DECIMAL_DIGIT_NUMBER),
+ Number_Letter = TO_MASK(ICU::U_LETTER_NUMBER),
+ Number_Other = TO_MASK(ICU::U_OTHER_NUMBER),
+
+ Separator_Space = TO_MASK(ICU::U_SPACE_SEPARATOR),
+ Separator_Line = TO_MASK(ICU::U_LINE_SEPARATOR),
+ Separator_Paragraph = TO_MASK(ICU::U_PARAGRAPH_SEPARATOR),
+
+ Other_Control = TO_MASK(ICU::U_CONTROL_CHAR),
+ Other_Format = TO_MASK(ICU::U_FORMAT_CHAR),
+ Other_PrivateUse = TO_MASK(ICU::U_PRIVATE_USE_CHAR),
+ Other_Surrogate = TO_MASK(ICU::U_SURROGATE),
+
+ Punctuation_Dash = TO_MASK(ICU::U_DASH_PUNCTUATION),
+ Punctuation_Open = TO_MASK(ICU::U_START_PUNCTUATION),
+ Punctuation_Close = TO_MASK(ICU::U_END_PUNCTUATION),
+ Punctuation_Connector = TO_MASK(ICU::U_CONNECTOR_PUNCTUATION),
+ Punctuation_Other = TO_MASK(ICU::U_OTHER_PUNCTUATION),
+
+ Symbol_Math = TO_MASK(ICU::U_MATH_SYMBOL),
+ Symbol_Currency = TO_MASK(ICU::U_CURRENCY_SYMBOL),
+ Symbol_Modifier = TO_MASK(ICU::U_MODIFIER_SYMBOL),
+ Symbol_Other = TO_MASK(ICU::U_OTHER_SYMBOL),
+
+ Punctuation_InitialQuote = TO_MASK(ICU::U_INITIAL_PUNCTUATION),
+ Punctuation_FinalQuote = TO_MASK(ICU::U_FINAL_PUNCTUATION)
+};
+
+UChar foldCase(UChar);
+
+int foldCase(UChar* result, int resultLength, const UChar* source, int sourceLength, bool* isError);
+
+int toLower(UChar* result, int resultLength, const UChar* source, int sourceLength, bool* isError);
+
+UChar toUpper(UChar);
+UChar toLower(UChar);
+
+bool isUpper(UChar);
+
+int toUpper(UChar* result, int resultLength, const UChar* source, int sourceLength, bool* isError);
+
+UChar toTitleCase(UChar);
+
+inline bool isArabicChar(UChar32 c)
+{
+ return c >= 0x0600 && c <= 0x06FF;
+}
+
+bool isAlphanumeric(UChar);
+
+CharCategory category(unsigned int);
+
+inline bool isSeparatorSpace(UChar c)
+{
+ return category(c) == Separator_Space;
+}
+
+bool isPrintableChar(UChar);
+
+bool isDigit(UChar);
+
+bool isPunct(UChar);
+
+inline bool hasLineBreakingPropertyComplexContext(UChar32)
+{
+ // FIXME: implement!
+ return false;
+}
+
+inline bool hasLineBreakingPropertyComplexContextOrIdeographic(UChar32 c)
+{
+ // FIXME
+ return false;
+}
+
+UChar mirroredChar(UChar32);
+
+Direction direction(UChar32);
+
+bool isLower(UChar);
+
+int digitValue(UChar);
+
+unsigned char combiningClass(UChar32);
+
+DecompositionType decompositionType(UChar32);
+
+inline int umemcasecmp(const UChar* a, const UChar* b, int len)
+{
+ for (int i = 0; i < len; ++i) {
+ UChar c1 = foldCase(a[i]);
+ UChar c2 = foldCase(b[i]);
+ if (c1 != c2)
+ return c1 - c2;
+ }
+ return 0;
+}
+
+bool isSpace(UChar);
+bool isLetter(UChar);
+
+} // namespace Unicode
+} // namespace WTF
+
+#endif
/*
* Copyright (C) 2008 Jürg Billeter <j@bitron.ch>
* Copyright (C) 2008 Dominik Röttsches <dominik.roettsches@access-company.com>
+ * Copyright (C) 2010 Igalia S.L.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
#include "config.h"
#include "UnicodeGLib.h"
+#include <wtf/Vector.h>
+#include <wtf/unicode/UTF8.h>
+
+#define UTF8_IS_SURROGATE(character) (character >= 0x10000 && character <= 0x10FFFF)
+
namespace WTF {
namespace Unicode {
return *ucs4Result;
}
-int foldCase(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error)
+static int getUTF16LengthFromUTF8(const gchar* utf8String, int length)
{
- *error = false;
- GOwnPtr<GError> gerror;
+ int utf16Length = 0;
+ const gchar* inputString = utf8String;
- GOwnPtr<char> utf8src;
- utf8src.set(g_utf16_to_utf8(src, srcLength, 0, 0, &gerror.outPtr()));
- if (gerror) {
- *error = true;
- return -1;
- }
-
- GOwnPtr<char> utf8result;
- utf8result.set(g_utf8_casefold(utf8src.get(), -1));
+ while ((utf8String + length - inputString > 0) && *inputString) {
+ gunichar character = g_utf8_get_char(inputString);
- long utf16resultLength = -1;
- GOwnPtr<UChar> utf16result;
- utf16result.set(g_utf8_to_utf16(utf8result.get(), -1, 0, &utf16resultLength, &gerror.outPtr()));
- if (gerror) {
- *error = true;
- return -1;
+ utf16Length += UTF8_IS_SURROGATE(character) ? 2 : 1;
+ inputString = g_utf8_next_char(inputString);
}
- if (utf16resultLength > resultLength) {
- *error = true;
- return utf16resultLength;
- }
- memcpy(result, utf16result.get(), utf16resultLength * sizeof(UChar));
-
- return utf16resultLength;
+ return utf16Length;
}
-int toLower(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error)
+typedef gchar* (*UTF8CaseFunction)(const gchar*, gssize length);
+
+static int convertCase(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error, UTF8CaseFunction caseFunction)
{
*error = false;
- GOwnPtr<GError> gerror;
- GOwnPtr<char> utf8src;
- utf8src.set(g_utf16_to_utf8(src, srcLength, 0, 0, &gerror.outPtr()));
- if (gerror) {
+ // Allocate a buffer big enough to hold all the characters.
+ Vector<char> buffer(srcLength * 3);
+ char* utf8Target = buffer.data();
+ const UChar* utf16Source = src;
+ ConversionResult conversionResult = convertUTF16ToUTF8(&utf16Source, utf16Source + srcLength, &utf8Target, utf8Target + buffer.size(), true);
+ if (conversionResult != conversionOK) {
*error = true;
return -1;
}
+ buffer.shrink(utf8Target - buffer.data());
- GOwnPtr<char> utf8result;
- utf8result.set(g_utf8_strdown(utf8src.get(), -1));
+ GOwnPtr<char> utf8Result(caseFunction(buffer.data(), buffer.size()));
+ long utf8ResultLength = strlen(utf8Result.get());
- long utf16resultLength = -1;
- GOwnPtr<UChar> utf16result;
- utf16result.set(g_utf8_to_utf16(utf8result.get(), -1, 0, &utf16resultLength, &gerror.outPtr()));
- if (gerror) {
+ // Calculate the destination buffer size.
+ int realLength = getUTF16LengthFromUTF8(utf8Result.get(), utf8ResultLength);
+ if (realLength > resultLength) {
*error = true;
- return -1;
+ return realLength;
}
- if (utf16resultLength > resultLength) {
+ // Convert the result to UTF-16.
+ UChar* utf16Target = result;
+ const char* utf8Source = utf8Result.get();
+ conversionResult = convertUTF8ToUTF16(&utf8Source, utf8Source + utf8ResultLength, &utf16Target, utf16Target + resultLength, true);
+ long utf16ResultLength = utf16Target - result;
+ if (conversionResult != conversionOK)
*error = true;
- return utf16resultLength;
- }
- memcpy(result, utf16result.get(), utf16resultLength * sizeof(UChar));
- return utf16resultLength;
+ return utf16ResultLength <= 0 ? -1 : utf16ResultLength;
}
-
-int toUpper(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error)
+int foldCase(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error)
{
- *error = false;
- GOwnPtr<GError> gerror;
-
- GOwnPtr<char> utf8src;
- utf8src.set(g_utf16_to_utf8(src, srcLength, 0, 0, &gerror.outPtr()));
- if (gerror) {
- *error = true;
- return -1;
- }
-
- GOwnPtr<char> utf8result;
- utf8result.set(g_utf8_strup(utf8src.get(), -1));
-
- long utf16resultLength = -1;
- GOwnPtr<UChar> utf16result;
- utf16result.set(g_utf8_to_utf16(utf8result.get(), -1, 0, &utf16resultLength, &gerror.outPtr()));
- if (gerror) {
- *error = true;
- return -1;
- }
+ return convertCase(result, resultLength, src, srcLength, error, g_utf8_casefold);
+}
- if (utf16resultLength > resultLength) {
- *error = true;
- return utf16resultLength;
- }
- memcpy(result, utf16result.get(), utf16resultLength * sizeof(UChar));
+int toLower(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error)
+{
+ return convertCase(result, resultLength, src, srcLength, error, g_utf8_strdown);
+}
- return utf16resultLength;
+int toUpper(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error)
+{
+ return convertCase(result, resultLength, src, srcLength, error, g_utf8_strup);
}
Direction direction(UChar32 c)
+++ /dev/null
-/*
- * Copyright (C) 2006 George Staikos <staikos@kde.org>
- * Copyright (C) 2006 Alexey Proskuryakov <ap@nypop.com>
- * Copyright (C) 2007 Apple Computer, Inc. All rights reserved.
- * Copyright (C) 2008 Jürg Billeter <j@bitron.ch>
- * Copyright (C) 2008 Dominik Röttsches <dominik.roettsches@access-company.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.
- *
- */
-
-#ifndef UnicodeMacrosFromICU_h
-#define UnicodeMacrosFromICU_h
-
-// some defines from ICU
-
-#define U16_IS_LEAD(c) (((c)&0xfffffc00)==0xd800)
-#define U16_IS_TRAIL(c) (((c)&0xfffffc00)==0xdc00)
-#define U16_SURROGATE_OFFSET ((0xd800<<10UL)+0xdc00-0x10000)
-#define U16_GET_SUPPLEMENTARY(lead, trail) \
- (((UChar32)(lead)<<10UL)+(UChar32)(trail)-U16_SURROGATE_OFFSET)
-
-#define U16_LEAD(supplementary) (UChar)(((supplementary)>>10)+0xd7c0)
-#define U16_TRAIL(supplementary) (UChar)(((supplementary)&0x3ff)|0xdc00)
-
-#define U_IS_SURROGATE(c) (((c)&0xfffff800)==0xd800)
-#define U16_IS_SINGLE(c) !U_IS_SURROGATE(c)
-#define U16_IS_SURROGATE(c) U_IS_SURROGATE(c)
-#define U16_IS_SURROGATE_LEAD(c) (((c)&0x400)==0)
-
-#define U16_PREV(s, start, i, c) { \
- (c)=(s)[--(i)]; \
- if(U16_IS_TRAIL(c)) { \
- uint16_t __c2; \
- if((i)>(start) && U16_IS_LEAD(__c2=(s)[(i)-1])) { \
- --(i); \
- (c)=U16_GET_SUPPLEMENTARY(__c2, (c)); \
- } \
- } \
-}
-
-#define U16_NEXT(s, i, length, c) { \
- (c)=(s)[(i)++]; \
- if(U16_IS_LEAD(c)) { \
- uint16_t __c2; \
- if((i)<(length) && U16_IS_TRAIL(__c2=(s)[(i)])) { \
- ++(i); \
- (c)=U16_GET_SUPPLEMENTARY((c), __c2); \
- } \
- } \
-}
-
-#define U_MASK(x) ((uint32_t)1<<(x))
-
-#endif
-
PassOwnPtr<Collator> Collator::userDefault()
{
-#if OS(DARWIN) && PLATFORM(CF)
+#if OS(DARWIN) && USE(CF)
// Mac OS X doesn't set UNIX locale to match user-selected one, so ICU default doesn't work.
-#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !OS(IPHONE_OS)
+#if !defined(BUILDING_ON_LEOPARD) && !OS(IOS)
RetainPtr<CFLocaleRef> currentLocale(AdoptCF, CFLocaleCopyCurrent());
CFStringRef collationOrder = (CFStringRef)CFLocaleGetValue(currentLocale.get(), kCFLocaleCollatorIdentifier);
#else
CFStringRef collationOrder = collationOrderRetainer.get();
#endif
char buf[256];
- if (collationOrder) {
- CFStringGetCString(collationOrder, buf, sizeof(buf), kCFStringEncodingASCII);
- return new Collator(buf);
- } else
- return new Collator("");
+ if (!collationOrder)
+ return adoptPtr(new Collator(""));
+ CFStringGetCString(collationOrder, buf, sizeof(buf), kCFStringEncodingASCII);
+ return adoptPtr(new Collator(buf));
#else
- return new Collator(0);
+ return adoptPtr(new Collator(0));
#endif
}
#ifndef WTF_UNICODE_QT4_H
#define WTF_UNICODE_QT4_H
+#include "UnicodeMacrosFromICU.h"
+
#include <QChar>
#include <QString>
#include <config.h>
#include <stdint.h>
+#if USE(QT_ICU_TEXT_BREAKING)
+#include <unicode/ubrk.h>
+#endif
QT_BEGIN_NAMESPACE
namespace QUnicodeTables {
QT_END_NAMESPACE
// ugly hack to make UChar compatible with JSChar in API/JSStringRef.h
-#if defined(Q_OS_WIN) || COMPILER(WINSCW) || (COMPILER(RVCT) && OS(SYMBIAN))
+#if defined(Q_OS_WIN) || COMPILER(WINSCW) || (COMPILER(RVCT) && !OS(LINUX))
typedef wchar_t UChar;
#else
typedef uint16_t UChar;
#endif
-typedef uint32_t UChar32;
-
-// some defines from ICU
-
-#define U16_IS_LEAD(c) (((c)&0xfffffc00)==0xd800)
-#define U16_IS_TRAIL(c) (((c)&0xfffffc00)==0xdc00)
-#define U16_SURROGATE_OFFSET ((0xd800<<10UL)+0xdc00-0x10000)
-#define U16_GET_SUPPLEMENTARY(lead, trail) \
- (((UChar32)(lead)<<10UL)+(UChar32)(trail)-U16_SURROGATE_OFFSET)
-
-#define U16_LEAD(supplementary) (UChar)(((supplementary)>>10)+0xd7c0)
-#define U16_TRAIL(supplementary) (UChar)(((supplementary)&0x3ff)|0xdc00)
-
-#define U_IS_SURROGATE(c) (((c)&0xfffff800)==0xd800)
-#define U16_IS_SINGLE(c) !U_IS_SURROGATE(c)
-#define U16_IS_SURROGATE(c) U_IS_SURROGATE(c)
-#define U16_IS_SURROGATE_LEAD(c) (((c)&0x400)==0)
-
-#define U16_NEXT(s, i, length, c) { \
- (c)=(s)[(i)++]; \
- if(U16_IS_LEAD(c)) { \
- uint16_t __c2; \
- if((i)<(length) && U16_IS_TRAIL(__c2=(s)[(i)])) { \
- ++(i); \
- (c)=U16_GET_SUPPLEMENTARY((c), __c2); \
- } \
- } \
-}
-#define U16_PREV(s, start, i, c) { \
- (c)=(s)[--(i)]; \
- if(U16_IS_TRAIL(c)) { \
- uint16_t __c2; \
- if((i)>(start) && U16_IS_LEAD(__c2=(s)[(i)-1])) { \
- --(i); \
- (c)=U16_GET_SUPPLEMENTARY(__c2, (c)); \
- } \
- } \
-}
-
-#define U_MASK(x) ((uint32_t)1<<(x))
+#if !USE(QT_ICU_TEXT_BREAKING)
+typedef uint32_t UChar32;
+#endif
namespace WTF {
namespace Unicode {
inline UChar32 toLower(UChar32 ch)
{
- return QChar::toLower(ch);
+ return QChar::toLower(uint32_t(ch));
}
inline int toLower(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error)
return rindex + needed;
}
-inline UChar32 toUpper(UChar32 ch)
+inline UChar32 toUpper(UChar32 c)
{
- return QChar::toUpper(ch);
+ return QChar::toUpper(uint32_t(c));
}
inline int toUpper(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error)
inline int toTitleCase(UChar32 c)
{
- return QChar::toTitleCase(c);
+ return QChar::toTitleCase(uint32_t(c));
}
inline UChar32 foldCase(UChar32 c)
{
- return QChar::toCaseFolded(c);
+ return QChar::toCaseFolded(uint32_t(c));
}
inline int foldCase(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error)
{
const uint test = U_MASK(QChar::Other_Control) |
U_MASK(QChar::Other_NotAssigned);
- return !(U_MASK(QChar::category(c)) & test);
+ return !(U_MASK(QChar::category(uint32_t(c))) & test);
}
inline bool isSeparatorSpace(UChar32 c)
{
- return QChar::category(c) == QChar::Separator_Space;
+ return QChar::category(uint32_t(c)) == QChar::Separator_Space;
}
inline bool isPunct(UChar32 c)
U_MASK(QChar::Punctuation_InitialQuote) |
U_MASK(QChar::Punctuation_FinalQuote) |
U_MASK(QChar::Punctuation_Other);
- return U_MASK(QChar::category(c)) & test;
+ return U_MASK(QChar::category(uint32_t(c))) & test;
}
inline bool isLower(UChar32 c)
{
- return QChar::category(c) == QChar::Letter_Lowercase;
+ return QChar::category(uint32_t(c)) == QChar::Letter_Lowercase;
}
inline bool hasLineBreakingPropertyComplexContext(UChar32)
inline UChar32 mirroredChar(UChar32 c)
{
- return QChar::mirroredChar(c);
+ return QChar::mirroredChar(uint32_t(c));
}
inline uint8_t combiningClass(UChar32 c)
{
- return QChar::combiningClass(c);
+ return QChar::combiningClass(uint32_t(c));
}
inline DecompositionType decompositionType(UChar32 c)
inline Direction direction(UChar32 c)
{
- return (Direction)QChar::direction(c);
+ return (Direction)QChar::direction(uint32_t(c));
}
inline CharCategory category(UChar32 c)
{
- return (CharCategory) U_MASK(QChar::category(c));
+ return (CharCategory) U_MASK(QChar::category(uint32_t(c)));
}
} }
--- /dev/null
+/*
+ * Copyright (C) 2006 George Staikos <staikos@kde.org>
+ * Copyright (C) 2006 Alexey Proskuryakov <ap@nypop.com>
+ * Copyright (C) 2007-2009 Torch Mobile, Inc.
+ *
+ * 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 "UnicodeWinCE.h"
+
+#include <wchar.h>
+
+namespace WTF {
+namespace Unicode {
+
+UChar toLower(UChar c)
+{
+ return towlower(c);
+}
+
+UChar toUpper(UChar c)
+{
+ return towupper(c);
+}
+
+UChar foldCase(UChar c)
+{
+ return towlower(c);
+}
+
+bool isPrintableChar(UChar c)
+{
+ return !!iswprint(c);
+}
+
+bool isSpace(UChar c)
+{
+ return !!iswspace(c);
+}
+
+bool isLetter(UChar c)
+{
+ return !!iswalpha(c);
+}
+
+bool isUpper(UChar c)
+{
+ return !!iswupper(c);
+}
+
+bool isLower(UChar c)
+{
+ return !!iswlower(c);
+}
+
+bool isDigit(UChar c)
+{
+ return !!iswdigit(c);
+}
+
+bool isPunct(UChar c)
+{
+ return !!iswpunct(c);
+}
+
+bool isAlphanumeric(UChar c)
+{
+ return !!iswalnum(c);
+}
+
+int toLower(UChar* result, int resultLength, const UChar* source, int sourceLength, bool* isError)
+{
+ const UChar* sourceIterator = source;
+ const UChar* sourceEnd = source + sourceLength;
+ UChar* resultIterator = result;
+ UChar* resultEnd = result + resultLength;
+
+ int remainingCharacters = 0;
+ if (sourceLength <= resultLength)
+ while (sourceIterator < sourceEnd)
+ *resultIterator++ = towlower(*sourceIterator++);
+ else
+ while (resultIterator < resultEnd)
+ *resultIterator++ = towlower(*sourceIterator++);
+
+ if (sourceIterator < sourceEnd)
+ remainingCharacters += sourceEnd - sourceIterator;
+ *isError = !!remainingCharacters;
+ if (resultIterator < resultEnd)
+ *resultIterator = 0;
+
+ return (resultIterator - result) + remainingCharacters;
+}
+
+int toUpper(UChar* result, int resultLength, const UChar* source, int sourceLength, bool* isError)
+{
+ const UChar* sourceIterator = source;
+ const UChar* sourceEnd = source + sourceLength;
+ UChar* resultIterator = result;
+ UChar* resultEnd = result + resultLength;
+
+ int remainingCharacters = 0;
+ if (sourceLength <= resultLength)
+ while (sourceIterator < sourceEnd)
+ *resultIterator++ = towupper(*sourceIterator++);
+ else
+ while (resultIterator < resultEnd)
+ *resultIterator++ = towupper(*sourceIterator++);
+
+ if (sourceIterator < sourceEnd)
+ remainingCharacters += sourceEnd - sourceIterator;
+ *isError = !!remainingCharacters;
+ if (resultIterator < resultEnd)
+ *resultIterator = 0;
+
+ return (resultIterator - result) + remainingCharacters;
+}
+
+int foldCase(UChar* result, int resultLength, const UChar* source, int sourceLength, bool* isError)
+{
+ *isError = false;
+ if (resultLength < sourceLength) {
+ *isError = true;
+ return sourceLength;
+ }
+ for (int i = 0; i < sourceLength; ++i)
+ result[i] = foldCase(source[i]);
+ return sourceLength;
+}
+
+UChar toTitleCase(UChar c)
+{
+ return towupper(c);
+}
+
+Direction direction(UChar32 c)
+{
+ return static_cast<Direction>(UnicodeCE::direction(c));
+}
+
+CharCategory category(unsigned int c)
+{
+ return static_cast<CharCategory>(TO_MASK((__int8) UnicodeCE::category(c)));
+}
+
+DecompositionType decompositionType(UChar32 c)
+{
+ return static_cast<DecompositionType>(UnicodeCE::decompositionType(c));
+}
+
+unsigned char combiningClass(UChar32 c)
+{
+ return UnicodeCE::combiningClass(c);
+}
+
+UChar mirroredChar(UChar32 c)
+{
+ return UnicodeCE::mirroredChar(c);
+}
+
+int digitValue(UChar c)
+{
+ return UnicodeCE::digitValue(c);
+}
+
+} // namespace Unicode
+} // namespace WTF
--- /dev/null
+/*
+ * Copyright (C) 2006 George Staikos <staikos@kde.org>
+ * Copyright (C) 2006 Alexey Proskuryakov <ap@nypop.com>
+ * Copyright (C) 2007 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2007-2009 Torch Mobile, Inc.
+ *
+ * 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.
+ *
+ */
+
+#ifndef WTF_UnicodeWinCE_h
+#define WTF_UnicodeWinCE_h
+
+#include "UnicodeMacrosFromICU.h"
+
+#include "ce_unicode.h"
+
+#define TO_MASK(x) (1 << (x))
+
+namespace WTF {
+namespace Unicode {
+
+enum Direction {
+ LeftToRight = UnicodeCE::U_LEFT_TO_RIGHT,
+ RightToLeft = UnicodeCE::U_RIGHT_TO_LEFT,
+ EuropeanNumber = UnicodeCE::U_EUROPEAN_NUMBER,
+ EuropeanNumberSeparator = UnicodeCE::U_EUROPEAN_NUMBER_SEPARATOR,
+ EuropeanNumberTerminator = UnicodeCE::U_EUROPEAN_NUMBER_TERMINATOR,
+ ArabicNumber = UnicodeCE::U_ARABIC_NUMBER,
+ CommonNumberSeparator = UnicodeCE::U_COMMON_NUMBER_SEPARATOR,
+ BlockSeparator = UnicodeCE::U_BLOCK_SEPARATOR,
+ SegmentSeparator = UnicodeCE::U_SEGMENT_SEPARATOR,
+ WhiteSpaceNeutral = UnicodeCE::U_WHITE_SPACE_NEUTRAL,
+ OtherNeutral = UnicodeCE::U_OTHER_NEUTRAL,
+ LeftToRightEmbedding = UnicodeCE::U_LEFT_TO_RIGHT_EMBEDDING,
+ LeftToRightOverride = UnicodeCE::U_LEFT_TO_RIGHT_OVERRIDE,
+ RightToLeftArabic = UnicodeCE::U_RIGHT_TO_LEFT_ARABIC,
+ RightToLeftEmbedding = UnicodeCE::U_RIGHT_TO_LEFT_EMBEDDING,
+ RightToLeftOverride = UnicodeCE::U_RIGHT_TO_LEFT_OVERRIDE,
+ PopDirectionalFormat = UnicodeCE::U_POP_DIRECTIONAL_FORMAT,
+ NonSpacingMark = UnicodeCE::U_DIR_NON_SPACING_MARK,
+ BoundaryNeutral = UnicodeCE::U_BOUNDARY_NEUTRAL
+};
+
+enum DecompositionType {
+ DecompositionNone = UnicodeCE::U_DT_NONE,
+ DecompositionCanonical = UnicodeCE::U_DT_CANONICAL,
+ DecompositionCompat = UnicodeCE::U_DT_COMPAT,
+ DecompositionCircle = UnicodeCE::U_DT_CIRCLE,
+ DecompositionFinal = UnicodeCE::U_DT_FINAL,
+ DecompositionFont = UnicodeCE::U_DT_FONT,
+ DecompositionFraction = UnicodeCE::U_DT_FRACTION,
+ DecompositionInitial = UnicodeCE::U_DT_INITIAL,
+ DecompositionIsolated = UnicodeCE::U_DT_ISOLATED,
+ DecompositionMedial = UnicodeCE::U_DT_MEDIAL,
+ DecompositionNarrow = UnicodeCE::U_DT_NARROW,
+ DecompositionNoBreak = UnicodeCE::U_DT_NOBREAK,
+ DecompositionSmall = UnicodeCE::U_DT_SMALL,
+ DecompositionSquare = UnicodeCE::U_DT_SQUARE,
+ DecompositionSub = UnicodeCE::U_DT_SUB,
+ DecompositionSuper = UnicodeCE::U_DT_SUPER,
+ DecompositionVertical = UnicodeCE::U_DT_VERTICAL,
+ DecompositionWide = UnicodeCE::U_DT_WIDE
+};
+
+enum CharCategory {
+ NoCategory = 0,
+ Other_NotAssigned = TO_MASK(UnicodeCE::U_GENERAL_OTHER_TYPES),
+ Letter_Uppercase = TO_MASK(UnicodeCE::U_UPPERCASE_LETTER),
+ Letter_Lowercase = TO_MASK(UnicodeCE::U_LOWERCASE_LETTER),
+ Letter_Titlecase = TO_MASK(UnicodeCE::U_TITLECASE_LETTER),
+ Letter_Modifier = TO_MASK(UnicodeCE::U_MODIFIER_LETTER),
+ Letter_Other = TO_MASK(UnicodeCE::U_OTHER_LETTER),
+
+ Mark_NonSpacing = TO_MASK(UnicodeCE::U_NON_SPACING_MARK),
+ Mark_Enclosing = TO_MASK(UnicodeCE::U_ENCLOSING_MARK),
+ Mark_SpacingCombining = TO_MASK(UnicodeCE::U_COMBINING_SPACING_MARK),
+
+ Number_DecimalDigit = TO_MASK(UnicodeCE::U_DECIMAL_DIGIT_NUMBER),
+ Number_Letter = TO_MASK(UnicodeCE::U_LETTER_NUMBER),
+ Number_Other = TO_MASK(UnicodeCE::U_OTHER_NUMBER),
+
+ Separator_Space = TO_MASK(UnicodeCE::U_SPACE_SEPARATOR),
+ Separator_Line = TO_MASK(UnicodeCE::U_LINE_SEPARATOR),
+ Separator_Paragraph = TO_MASK(UnicodeCE::U_PARAGRAPH_SEPARATOR),
+
+ Other_Control = TO_MASK(UnicodeCE::U_CONTROL_CHAR),
+ Other_Format = TO_MASK(UnicodeCE::U_FORMAT_CHAR),
+ Other_PrivateUse = TO_MASK(UnicodeCE::U_PRIVATE_USE_CHAR),
+ Other_Surrogate = TO_MASK(UnicodeCE::U_SURROGATE),
+
+ Punctuation_Dash = TO_MASK(UnicodeCE::U_DASH_PUNCTUATION),
+ Punctuation_Open = TO_MASK(UnicodeCE::U_START_PUNCTUATION),
+ Punctuation_Close = TO_MASK(UnicodeCE::U_END_PUNCTUATION),
+ Punctuation_Connector = TO_MASK(UnicodeCE::U_CONNECTOR_PUNCTUATION),
+ Punctuation_Other = TO_MASK(UnicodeCE::U_OTHER_PUNCTUATION),
+
+ Symbol_Math = TO_MASK(UnicodeCE::U_MATH_SYMBOL),
+ Symbol_Currency = TO_MASK(UnicodeCE::U_CURRENCY_SYMBOL),
+ Symbol_Modifier = TO_MASK(UnicodeCE::U_MODIFIER_SYMBOL),
+ Symbol_Other = TO_MASK(UnicodeCE::U_OTHER_SYMBOL),
+
+ Punctuation_InitialQuote = TO_MASK(UnicodeCE::U_INITIAL_PUNCTUATION),
+ Punctuation_FinalQuote = TO_MASK(UnicodeCE::U_FINAL_PUNCTUATION)
+};
+
+CharCategory category(unsigned int);
+
+bool isSpace(UChar);
+bool isLetter(UChar);
+bool isPrintableChar(UChar);
+bool isUpper(UChar);
+bool isLower(UChar);
+bool isPunct(UChar);
+bool isDigit(UChar);
+bool isAlphanumeric(UChar);
+inline bool isSeparatorSpace(UChar c) { return category(c) == Separator_Space; }
+inline bool isHighSurrogate(UChar c) { return (c & 0xfc00) == 0xd800; }
+inline bool isLowSurrogate(UChar c) { return (c & 0xfc00) == 0xdc00; }
+
+UChar toLower(UChar);
+UChar toUpper(UChar);
+UChar foldCase(UChar);
+UChar toTitleCase(UChar);
+int toLower(UChar* result, int resultLength, const UChar* source, int sourceLength, bool* isError);
+int toUpper(UChar* result, int resultLength, const UChar* source, int sourceLength, bool* isError);
+int foldCase(UChar* result, int resultLength, const UChar* source, int sourceLength, bool* isError);
+
+int digitValue(UChar);
+
+UChar mirroredChar(UChar32);
+unsigned char combiningClass(UChar32);
+DecompositionType decompositionType(UChar32);
+Direction direction(UChar32);
+inline bool isArabicChar(UChar32 c)
+{
+ return c >= 0x0600 && c <= 0x06FF;
+}
+
+inline bool hasLineBreakingPropertyComplexContext(UChar32)
+{
+ return false; // FIXME: implement!
+}
+
+inline int umemcasecmp(const UChar* a, const UChar* b, int len)
+{
+ for (int i = 0; i < len; ++i) {
+ UChar c1 = foldCase(a[i]);
+ UChar c2 = foldCase(b[i]);
+ if (c1 != c2)
+ return c1 - c2;
+ }
+ return 0;
+}
+
+inline UChar32 surrogateToUcs4(UChar high, UChar low)
+{
+ return (UChar32(high) << 10) + low - 0x35fdc00;
+}
+
+} // namespace Unicode
+} // namespace WTF
+
+#endif // WTF_UnicodeWinCE_h
+++ /dev/null
-/*
- * Copyright (C) 2006 George Staikos <staikos@kde.org>
- * Copyright (C) 2006 Alexey Proskuryakov <ap@nypop.com>
- * Copyright (C) 2007-2009 Torch Mobile, Inc.
- *
- * 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 "UnicodeWince.h"
-
-#include <wchar.h>
-
-namespace WTF {
-namespace Unicode {
-
-wchar_t toLower(wchar_t c)
-{
- return towlower(c);
-}
-
-wchar_t toUpper(wchar_t c)
-{
- return towupper(c);
-}
-
-wchar_t foldCase(wchar_t c)
-{
- return towlower(c);
-}
-
-bool isPrintableChar(wchar_t c)
-{
- return !!iswprint(c);
-}
-
-bool isSpace(wchar_t c)
-{
- return !!iswspace(c);
-}
-
-bool isLetter(wchar_t c)
-{
- return !!iswalpha(c);
-}
-
-bool isUpper(wchar_t c)
-{
- return !!iswupper(c);
-}
-
-bool isLower(wchar_t c)
-{
- return !!iswlower(c);
-}
-
-bool isDigit(wchar_t c)
-{
- return !!iswdigit(c);
-}
-
-bool isPunct(wchar_t c)
-{
- return !!iswpunct(c);
-}
-
-int toLower(wchar_t* result, int resultLength, const wchar_t* source, int sourceLength, bool* isError)
-{
- const UChar* sourceIterator = source;
- const UChar* sourceEnd = source + sourceLength;
- UChar* resultIterator = result;
- UChar* resultEnd = result + resultLength;
-
- int remainingCharacters = 0;
- if (sourceLength <= resultLength)
- while (sourceIterator < sourceEnd)
- *resultIterator++ = towlower(*sourceIterator++);
- else
- while (resultIterator < resultEnd)
- *resultIterator++ = towlower(*sourceIterator++);
-
- if (sourceIterator < sourceEnd)
- remainingCharacters += sourceEnd - sourceIterator;
- *isError = (remainingCharacters != 0);
- if (resultIterator < resultEnd)
- *resultIterator = 0;
-
- return (resultIterator - result) + remainingCharacters;
-}
-
-int toUpper(wchar_t* result, int resultLength, const wchar_t* source, int sourceLength, bool* isError)
-{
- const UChar* sourceIterator = source;
- const UChar* sourceEnd = source + sourceLength;
- UChar* resultIterator = result;
- UChar* resultEnd = result + resultLength;
-
- int remainingCharacters = 0;
- if (sourceLength <= resultLength)
- while (sourceIterator < sourceEnd)
- *resultIterator++ = towupper(*sourceIterator++);
- else
- while (resultIterator < resultEnd)
- *resultIterator++ = towupper(*sourceIterator++);
-
- if (sourceIterator < sourceEnd)
- remainingCharacters += sourceEnd - sourceIterator;
- *isError = (remainingCharacters != 0);
- if (resultIterator < resultEnd)
- *resultIterator = 0;
-
- return (resultIterator - result) + remainingCharacters;
-}
-
-int foldCase(wchar_t* result, int resultLength, const wchar_t* source, int sourceLength, bool* isError)
-{
- *isError = false;
- if (resultLength < sourceLength) {
- *isError = true;
- return sourceLength;
- }
- for (int i = 0; i < sourceLength; ++i)
- result[i] = foldCase(source[i]);
- return sourceLength;
-}
-
-wchar_t toTitleCase(wchar_t c)
-{
- return towupper(c);
-}
-
-Direction direction(UChar32 c)
-{
- return static_cast<Direction>(UnicodeCE::direction(c));
-}
-
-CharCategory category(unsigned int c)
-{
- return static_cast<CharCategory>(TO_MASK((__int8) UnicodeCE::category(c)));
-}
-
-DecompositionType decompositionType(UChar32 c)
-{
- return static_cast<DecompositionType>(UnicodeCE::decompositionType(c));
-}
-
-unsigned char combiningClass(UChar32 c)
-{
- return UnicodeCE::combiningClass(c);
-}
-
-wchar_t mirroredChar(UChar32 c)
-{
- return UnicodeCE::mirroredChar(c);
-}
-
-int digitValue(wchar_t c)
-{
- return UnicodeCE::digitValue(c);
-}
-
-} // namespace Unicode
-} // namespace WTF
+++ /dev/null
-/*
- * Copyright (C) 2006 George Staikos <staikos@kde.org>
- * Copyright (C) 2006 Alexey Proskuryakov <ap@nypop.com>
- * Copyright (C) 2007 Apple Computer, Inc. All rights reserved.
- * Copyright (C) 2007-2009 Torch Mobile, Inc.
- *
- * 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.
- *
- */
-
-#ifndef UNICODE_WINCE_H
-#define UNICODE_WINCE_H
-
-#include "ce_unicode.h"
-
-#define TO_MASK(x) (1 << (x))
-
-// some defines from ICU needed one or two places
-
-#define U16_IS_LEAD(c) (((c) & 0xfffffc00) == 0xd800)
-#define U16_IS_TRAIL(c) (((c) & 0xfffffc00) == 0xdc00)
-#define U16_SURROGATE_OFFSET ((0xd800 << 10UL) + 0xdc00 - 0x10000)
-#define U16_GET_SUPPLEMENTARY(lead, trail) \
- (((UChar32)(lead) << 10UL) + (UChar32)(trail) - U16_SURROGATE_OFFSET)
-
-#define U16_LEAD(supplementary) (UChar)(((supplementary) >> 10) + 0xd7c0)
-#define U16_TRAIL(supplementary) (UChar)(((supplementary) & 0x3ff) | 0xdc00)
-
-#define U_IS_SURROGATE(c) (((c) & 0xfffff800) == 0xd800)
-#define U16_IS_SURROGATE(c) U_IS_SURROGATE(c)
-#define U16_IS_SURROGATE_LEAD(c) (((c) & 0x400) == 0)
-
-#define U16_NEXT(s, i, length, c) { \
- (c)=(s)[(i)++]; \
- if (U16_IS_LEAD(c)) { \
- uint16_t __c2; \
- if ((i) < (length) && U16_IS_TRAIL(__c2 = (s)[(i)])) { \
- ++(i); \
- (c) = U16_GET_SUPPLEMENTARY((c), __c2); \
- } \
- } \
-}
-
-#define U16_PREV(s, start, i, c) { \
- (c)=(s)[--(i)]; \
- if (U16_IS_TRAIL(c)) { \
- uint16_t __c2; \
- if ((i) > (start) && U16_IS_LEAD(__c2 = (s)[(i) - 1])) { \
- --(i); \
- (c) = U16_GET_SUPPLEMENTARY(__c2, (c)); \
- } \
- } \
-}
-
-#define U16_IS_SINGLE(c) !U_IS_SURROGATE(c)
-
-namespace WTF {
-
- namespace Unicode {
-
- enum Direction {
- LeftToRight = UnicodeCE::U_LEFT_TO_RIGHT,
- RightToLeft = UnicodeCE::U_RIGHT_TO_LEFT,
- EuropeanNumber = UnicodeCE::U_EUROPEAN_NUMBER,
- EuropeanNumberSeparator = UnicodeCE::U_EUROPEAN_NUMBER_SEPARATOR,
- EuropeanNumberTerminator = UnicodeCE::U_EUROPEAN_NUMBER_TERMINATOR,
- ArabicNumber = UnicodeCE::U_ARABIC_NUMBER,
- CommonNumberSeparator = UnicodeCE::U_COMMON_NUMBER_SEPARATOR,
- BlockSeparator = UnicodeCE::U_BLOCK_SEPARATOR,
- SegmentSeparator = UnicodeCE::U_SEGMENT_SEPARATOR,
- WhiteSpaceNeutral = UnicodeCE::U_WHITE_SPACE_NEUTRAL,
- OtherNeutral = UnicodeCE::U_OTHER_NEUTRAL,
- LeftToRightEmbedding = UnicodeCE::U_LEFT_TO_RIGHT_EMBEDDING,
- LeftToRightOverride = UnicodeCE::U_LEFT_TO_RIGHT_OVERRIDE,
- RightToLeftArabic = UnicodeCE::U_RIGHT_TO_LEFT_ARABIC,
- RightToLeftEmbedding = UnicodeCE::U_RIGHT_TO_LEFT_EMBEDDING,
- RightToLeftOverride = UnicodeCE::U_RIGHT_TO_LEFT_OVERRIDE,
- PopDirectionalFormat = UnicodeCE::U_POP_DIRECTIONAL_FORMAT,
- NonSpacingMark = UnicodeCE::U_DIR_NON_SPACING_MARK,
- BoundaryNeutral = UnicodeCE::U_BOUNDARY_NEUTRAL
- };
-
- enum DecompositionType {
- DecompositionNone = UnicodeCE::U_DT_NONE,
- DecompositionCanonical = UnicodeCE::U_DT_CANONICAL,
- DecompositionCompat = UnicodeCE::U_DT_COMPAT,
- DecompositionCircle = UnicodeCE::U_DT_CIRCLE,
- DecompositionFinal = UnicodeCE::U_DT_FINAL,
- DecompositionFont = UnicodeCE::U_DT_FONT,
- DecompositionFraction = UnicodeCE::U_DT_FRACTION,
- DecompositionInitial = UnicodeCE::U_DT_INITIAL,
- DecompositionIsolated = UnicodeCE::U_DT_ISOLATED,
- DecompositionMedial = UnicodeCE::U_DT_MEDIAL,
- DecompositionNarrow = UnicodeCE::U_DT_NARROW,
- DecompositionNoBreak = UnicodeCE::U_DT_NOBREAK,
- DecompositionSmall = UnicodeCE::U_DT_SMALL,
- DecompositionSquare = UnicodeCE::U_DT_SQUARE,
- DecompositionSub = UnicodeCE::U_DT_SUB,
- DecompositionSuper = UnicodeCE::U_DT_SUPER,
- DecompositionVertical = UnicodeCE::U_DT_VERTICAL,
- DecompositionWide = UnicodeCE::U_DT_WIDE,
- };
-
- enum CharCategory {
- NoCategory = 0,
- Other_NotAssigned = TO_MASK(UnicodeCE::U_GENERAL_OTHER_TYPES),
- Letter_Uppercase = TO_MASK(UnicodeCE::U_UPPERCASE_LETTER),
- Letter_Lowercase = TO_MASK(UnicodeCE::U_LOWERCASE_LETTER),
- Letter_Titlecase = TO_MASK(UnicodeCE::U_TITLECASE_LETTER),
- Letter_Modifier = TO_MASK(UnicodeCE::U_MODIFIER_LETTER),
- Letter_Other = TO_MASK(UnicodeCE::U_OTHER_LETTER),
-
- Mark_NonSpacing = TO_MASK(UnicodeCE::U_NON_SPACING_MARK),
- Mark_Enclosing = TO_MASK(UnicodeCE::U_ENCLOSING_MARK),
- Mark_SpacingCombining = TO_MASK(UnicodeCE::U_COMBINING_SPACING_MARK),
-
- Number_DecimalDigit = TO_MASK(UnicodeCE::U_DECIMAL_DIGIT_NUMBER),
- Number_Letter = TO_MASK(UnicodeCE::U_LETTER_NUMBER),
- Number_Other = TO_MASK(UnicodeCE::U_OTHER_NUMBER),
-
- Separator_Space = TO_MASK(UnicodeCE::U_SPACE_SEPARATOR),
- Separator_Line = TO_MASK(UnicodeCE::U_LINE_SEPARATOR),
- Separator_Paragraph = TO_MASK(UnicodeCE::U_PARAGRAPH_SEPARATOR),
-
- Other_Control = TO_MASK(UnicodeCE::U_CONTROL_CHAR),
- Other_Format = TO_MASK(UnicodeCE::U_FORMAT_CHAR),
- Other_PrivateUse = TO_MASK(UnicodeCE::U_PRIVATE_USE_CHAR),
- Other_Surrogate = TO_MASK(UnicodeCE::U_SURROGATE),
-
- Punctuation_Dash = TO_MASK(UnicodeCE::U_DASH_PUNCTUATION),
- Punctuation_Open = TO_MASK(UnicodeCE::U_START_PUNCTUATION),
- Punctuation_Close = TO_MASK(UnicodeCE::U_END_PUNCTUATION),
- Punctuation_Connector = TO_MASK(UnicodeCE::U_CONNECTOR_PUNCTUATION),
- Punctuation_Other = TO_MASK(UnicodeCE::U_OTHER_PUNCTUATION),
-
- Symbol_Math = TO_MASK(UnicodeCE::U_MATH_SYMBOL),
- Symbol_Currency = TO_MASK(UnicodeCE::U_CURRENCY_SYMBOL),
- Symbol_Modifier = TO_MASK(UnicodeCE::U_MODIFIER_SYMBOL),
- Symbol_Other = TO_MASK(UnicodeCE::U_OTHER_SYMBOL),
-
- Punctuation_InitialQuote = TO_MASK(UnicodeCE::U_INITIAL_PUNCTUATION),
- Punctuation_FinalQuote = TO_MASK(UnicodeCE::U_FINAL_PUNCTUATION)
- };
-
- CharCategory category(unsigned int);
-
- bool isSpace(wchar_t);
- bool isLetter(wchar_t);
- bool isPrintableChar(wchar_t);
- bool isUpper(wchar_t);
- bool isLower(wchar_t);
- bool isPunct(wchar_t);
- bool isDigit(wchar_t);
- inline bool isSeparatorSpace(wchar_t c) { return category(c) == Separator_Space; }
- inline bool isHighSurrogate(wchar_t c) { return (c & 0xfc00) == 0xd800; }
- inline bool isLowSurrogate(wchar_t c) { return (c & 0xfc00) == 0xdc00; }
-
- wchar_t toLower(wchar_t);
- wchar_t toUpper(wchar_t);
- wchar_t foldCase(wchar_t);
- wchar_t toTitleCase(wchar_t);
- int toLower(wchar_t* result, int resultLength, const wchar_t* source, int sourceLength, bool* isError);
- int toUpper(wchar_t* result, int resultLength, const wchar_t* source, int sourceLength, bool* isError);
- int foldCase(UChar* result, int resultLength, const wchar_t* source, int sourceLength, bool* isError);
-
- int digitValue(wchar_t);
-
- wchar_t mirroredChar(UChar32);
- unsigned char combiningClass(UChar32);
- DecompositionType decompositionType(UChar32);
- Direction direction(UChar32);
- inline bool isArabicChar(UChar32)
- {
- return false; // FIXME: implement!
- }
-
- inline bool hasLineBreakingPropertyComplexContext(UChar32)
- {
- return false; // FIXME: implement!
- }
-
- inline int umemcasecmp(const wchar_t* a, const wchar_t* b, int len)
- {
- for (int i = 0; i < len; ++i) {
- wchar_t c1 = foldCase(a[i]);
- wchar_t c2 = foldCase(b[i]);
- if (c1 != c2)
- return c1 - c2;
- }
- return 0;
- }
-
- inline UChar32 surrogateToUcs4(wchar_t high, wchar_t low)
- {
- return (UChar32(high) << 10) + low - 0x35fdc00;
- }
-
- } // namespace Unicode
-
-} // namespace WTF
-
-#endif
-// vim: ts=2 sw=2 et
--- /dev/null
+/*
+ * Copyright (C) 2010 Google, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ParsedURL.h"
+
+#include "URLComponent.h"
+#include "URLParser.h"
+
+namespace WTF {
+
+ParsedURL::ParsedURL(const URLString& spec)
+ : m_spec(spec)
+{
+ // FIXME: Handle non-standard URLs.
+ if (spec.string().isEmpty())
+ return;
+ URLParser<UChar>::parseStandardURL(spec.string().characters(), spec.string().length(), m_segments);
+}
+
+String ParsedURL::scheme() const
+{
+ return segment(m_segments.scheme);
+}
+
+String ParsedURL::username() const
+{
+ return segment(m_segments.username);
+}
+
+String ParsedURL::password() const
+{
+ return segment(m_segments.password);
+}
+
+String ParsedURL::host() const
+{
+ return segment(m_segments.host);
+}
+
+String ParsedURL::port() const
+{
+ return segment(m_segments.port);
+}
+
+String ParsedURL::path() const
+{
+ return segment(m_segments.path);
+}
+
+String ParsedURL::query() const
+{
+ return segment(m_segments.query);
+}
+
+String ParsedURL::fragment() const
+{
+ return segment(m_segments.fragment);
+}
+
+String ParsedURL::segment(const URLComponent& component) const
+{
+ if (!component.isValid())
+ return String();
+ return m_spec.string().substring(component.begin(), component.length());
+}
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2010 Google, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ParsedURL_h
+#define ParsedURL_h
+
+#include "URLSegments.h"
+#include "URLString.h"
+
+namespace WTF {
+
+class URLComponent;
+
+class ParsedURL {
+public:
+ explicit ParsedURL(const URLString&);
+
+ // FIXME: Add a method for parsing non-canonicalized URLs.
+
+ String scheme() const;
+ String username() const;
+ String password() const;
+ String host() const;
+ String port() const;
+ String path() const;
+ String query() const;
+ String fragment() const;
+
+ URLString spec() { return m_spec; }
+
+private:
+ inline String segment(const URLComponent&) const;
+
+ URLString m_spec;
+ URLSegments m_segments;
+};
+
+}
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2010 Google, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef URLString_h
+#define URLString_h
+
+#include "WTFString.h"
+
+namespace WTF {
+
+// URLString represents a string that's a canonicalized URL.
+class URLString {
+public:
+ URLString() { }
+
+ const String& string() const { return m_string;}
+
+private:
+ friend class ParsedURL;
+
+ // URLString can only be constructed by a ParsedURL.
+ explicit URLString(const String& string)
+ : m_string(string)
+ {
+ }
+
+ String m_string;
+};
+
+}
+
+#endif
+
--- /dev/null
+// Copyright 2010, Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef RawURLBuffer_h
+#define RawURLBuffer_h
+
+#include "URLBuffer.h"
+#include <stdlib.h>
+
+namespace WTF {
+
+// Simple implementation of the URLBuffer using new[]. This class
+// also supports a static buffer so if it is allocated on the stack, most
+// URLs can be canonicalized with no heap allocations.
+template<typename CHAR, int inlineCapacity = 1024>
+class RawURLBuffer : public URLBuffer<CHAR> {
+public:
+ RawURLBuffer() : URLBuffer<CHAR>()
+ {
+ this->m_buffer = m_inlineBuffer;
+ this->m_capacity = inlineCapacity;
+ }
+
+ virtual ~RawURLBuffer()
+ {
+ if (this->m_buffer != m_inlineBuffer)
+ delete[] this->m_buffer;
+ }
+
+ virtual void resize(int size)
+ {
+ CHAR* newBuffer = new CHAR[size];
+ memcpy(newBuffer, this->m_buffer, sizeof(CHAR) * (this->m_length < size ? this->m_length : size));
+ if (this->m_buffer != m_inlineBuffer)
+ delete[] this->m_buffer;
+ this->m_buffer = newBuffer;
+ this->m_capacity = size;
+ }
+
+protected:
+ CHAR m_inlineBuffer[inlineCapacity];
+};
+
+} // namespace WTF
+
+#endif // RawURLBuffer_h
--- /dev/null
+// Copyright 2010, Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef URLBuffer_h
+#define URLBuffer_h
+
+namespace WTF {
+
+// Base class for the canonicalizer output, this maintains a buffer and
+// supports simple resizing and append operations on it.
+//
+// It is VERY IMPORTANT that no virtual function calls be made on the common
+// code path. We only have two virtual function calls, the destructor and a
+// resize function that is called when the existing buffer is not big enough.
+// The derived class is then in charge of setting up our buffer which we will
+// manage.
+template<typename CHAR>
+class URLBuffer {
+public:
+ URLBuffer() : m_buffer(0), m_capacity(0), m_length(0) { }
+ virtual ~URLBuffer() { }
+
+ // Implemented to resize the buffer. This function should update the buffer
+ // pointer to point to the new buffer, and any old data up to |m_length| in
+ // the buffer must be copied over.
+ //
+ // The new size must be larger than m_capacity.
+ virtual void resize(int) = 0;
+
+ inline char at(int offset) const { return m_buffer[offset]; }
+ inline void set(int offset, CHAR ch)
+ {
+ // FIXME: Add ASSERT(offset < length());
+ m_buffer[offset] = ch;
+ }
+
+ // Returns the current capacity of the buffer. The length() is the number of
+ // characters that have been declared to be written, but the capacity() is
+ // the number that can be written without reallocation. If the caller must
+ // write many characters at once, it can make sure there is enough capacity,
+ // write the data, then use setLength() to declare the new length().
+ int capacity() const { return m_capacity; }
+ int length() const { return m_length; }
+
+ // The output will NOT be 0-terminated. Call length() to get the length.
+ const CHAR* data() const { return m_buffer; }
+ CHAR* data() { return m_buffer; }
+
+ // Shortens the URL to the new length. Used for "backing up" when processing
+ // relative paths. This can also be used if an external function writes a lot
+ // of data to the buffer (when using the "Raw" version below) beyond the end,
+ // to declare the new length.
+ void setLength(int length)
+ {
+ // FIXME: Add ASSERT(length < capacity());
+ m_length = length;
+ }
+
+ // This is the most performance critical function, since it is called for
+ // every character.
+ void append(CHAR ch)
+ {
+ // In VC2005, putting this common case first speeds up execution
+ // dramatically because this branch is predicted as taken.
+ if (m_length < m_capacity) {
+ m_buffer[m_length] = ch;
+ ++m_length;
+ return;
+ }
+
+ if (!grow(1))
+ return;
+
+ m_buffer[m_length] = ch;
+ ++m_length;
+ }
+
+ void append(const CHAR* str, int strLength)
+ {
+ if (m_length + strLength > m_capacity) {
+ if (!grow(m_length + strLength - m_capacity))
+ return;
+ }
+ for (int i = 0; i < strLength; i++)
+ m_buffer[m_length + i] = str[i];
+ m_length += strLength;
+ }
+
+protected:
+ // Returns true if the buffer could be resized, false on OOM.
+ bool grow(int minimumAdditionalCapacity)
+ {
+ static const int minimumCapacity = 16;
+ int newCapacity = m_capacity ? m_capacity : minimumCapacity;
+ do {
+ if (newCapacity >= (1 << 30)) // Prevent overflow below.
+ return false;
+ newCapacity *= 2;
+ } while (newCapacity < m_capacity + minimumAdditionalCapacity);
+ resize(newCapacity);
+ return true;
+ }
+
+ CHAR* m_buffer;
+ int m_capacity;
+ int m_length; // Used characters in the buffer.
+};
+
+} // namespace WTF
+
+#endif // URLBuffer_h
--- /dev/null
+// Copyright 2010, Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "config.h"
+#include "URLCharacterTypes.h"
+
+namespace WTF {
+
+const unsigned char URLCharacterTypes::characterTypeTable[0x100] = {
+ InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter,
+ InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter,
+ InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter,
+ InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, // 0x00 - 0x0f
+ InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter,
+ InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter,
+ InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter,
+ InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, // 0x10 - 0x1f
+ InvalidCharacter, // 0x20 ' ' (escape spaces in queries)
+ QueryCharacter | UserInfoCharacter, // 0x21 !
+ InvalidCharacter, // 0x22 "
+ InvalidCharacter, // 0x23 # (invalid in query since it marks the ref)
+ QueryCharacter | UserInfoCharacter, // 0x24 $
+ QueryCharacter | UserInfoCharacter, // 0x25 %
+ QueryCharacter | UserInfoCharacter, // 0x26 &
+ QueryCharacter | UserInfoCharacter, // 0x27 '
+ QueryCharacter | UserInfoCharacter, // 0x28 (
+ QueryCharacter | UserInfoCharacter, // 0x29 )
+ QueryCharacter | UserInfoCharacter, // 0x2a *
+ QueryCharacter | UserInfoCharacter, // 0x2b +
+ QueryCharacter | UserInfoCharacter, // 0x2c ,
+ QueryCharacter | UserInfoCharacter, // 0x2d -
+ QueryCharacter | UserInfoCharacter | IPv4Character, // 0x2e .
+ QueryCharacter, // 0x2f /
+ QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter | DecimalCharacter | OctalCharacter, // 0x30 0
+ QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter | DecimalCharacter | OctalCharacter, // 0x31 1
+ QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter | DecimalCharacter | OctalCharacter, // 0x32 2
+ QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter | DecimalCharacter | OctalCharacter, // 0x33 3
+ QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter | DecimalCharacter | OctalCharacter, // 0x34 4
+ QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter | DecimalCharacter | OctalCharacter, // 0x35 5
+ QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter | DecimalCharacter | OctalCharacter, // 0x36 6
+ QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter | DecimalCharacter | OctalCharacter, // 0x37 7
+ QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter | DecimalCharacter, // 0x38 8
+ QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter | DecimalCharacter, // 0x39 9
+ QueryCharacter, // 0x3a :
+ QueryCharacter, // 0x3b ;
+ InvalidCharacter, // 0x3c <
+ QueryCharacter, // 0x3d =
+ InvalidCharacter, // 0x3e >
+ QueryCharacter, // 0x3f ?
+ QueryCharacter, // 0x40 @
+ QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter, // 0x41 A
+ QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter, // 0x42 B
+ QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter, // 0x43 C
+ QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter, // 0x44 D
+ QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter, // 0x45 E
+ QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter, // 0x46 F
+ QueryCharacter | UserInfoCharacter, // 0x47 G
+ QueryCharacter | UserInfoCharacter, // 0x48 H
+ QueryCharacter | UserInfoCharacter, // 0x49 I
+ QueryCharacter | UserInfoCharacter, // 0x4a J
+ QueryCharacter | UserInfoCharacter, // 0x4b K
+ QueryCharacter | UserInfoCharacter, // 0x4c L
+ QueryCharacter | UserInfoCharacter, // 0x4d M
+ QueryCharacter | UserInfoCharacter, // 0x4e N
+ QueryCharacter | UserInfoCharacter, // 0x4f O
+ QueryCharacter | UserInfoCharacter, // 0x50 P
+ QueryCharacter | UserInfoCharacter, // 0x51 Q
+ QueryCharacter | UserInfoCharacter, // 0x52 R
+ QueryCharacter | UserInfoCharacter, // 0x53 S
+ QueryCharacter | UserInfoCharacter, // 0x54 T
+ QueryCharacter | UserInfoCharacter, // 0x55 U
+ QueryCharacter | UserInfoCharacter, // 0x56 V
+ QueryCharacter | UserInfoCharacter, // 0x57 W
+ QueryCharacter | UserInfoCharacter | IPv4Character, // 0x58 X
+ QueryCharacter | UserInfoCharacter, // 0x59 Y
+ QueryCharacter | UserInfoCharacter, // 0x5a Z
+ QueryCharacter, // 0x5b [
+ QueryCharacter, // 0x5c '\'
+ QueryCharacter, // 0x5d ]
+ QueryCharacter, // 0x5e ^
+ QueryCharacter | UserInfoCharacter, // 0x5f _
+ QueryCharacter, // 0x60 `
+ QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter, // 0x61 a
+ QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter, // 0x62 b
+ QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter, // 0x63 c
+ QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter, // 0x64 d
+ QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter, // 0x65 e
+ QueryCharacter | UserInfoCharacter | IPv4Character | HexCharacter, // 0x66 f
+ QueryCharacter | UserInfoCharacter, // 0x67 g
+ QueryCharacter | UserInfoCharacter, // 0x68 h
+ QueryCharacter | UserInfoCharacter, // 0x69 i
+ QueryCharacter | UserInfoCharacter, // 0x6a j
+ QueryCharacter | UserInfoCharacter, // 0x6b k
+ QueryCharacter | UserInfoCharacter, // 0x6c l
+ QueryCharacter | UserInfoCharacter, // 0x6d m
+ QueryCharacter | UserInfoCharacter, // 0x6e n
+ QueryCharacter | UserInfoCharacter, // 0x6f o
+ QueryCharacter | UserInfoCharacter, // 0x70 p
+ QueryCharacter | UserInfoCharacter, // 0x71 q
+ QueryCharacter | UserInfoCharacter, // 0x72 r
+ QueryCharacter | UserInfoCharacter, // 0x73 s
+ QueryCharacter | UserInfoCharacter, // 0x74 t
+ QueryCharacter | UserInfoCharacter, // 0x75 u
+ QueryCharacter | UserInfoCharacter, // 0x76 v
+ QueryCharacter | UserInfoCharacter, // 0x77 w
+ QueryCharacter | UserInfoCharacter | IPv4Character, // 0x78 x
+ QueryCharacter | UserInfoCharacter, // 0x79 y
+ QueryCharacter | UserInfoCharacter, // 0x7a z
+ QueryCharacter, // 0x7b {
+ QueryCharacter, // 0x7c |
+ QueryCharacter, // 0x7d }
+ QueryCharacter | UserInfoCharacter, // 0x7e ~
+ InvalidCharacter, // 0x7f
+ InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter,
+ InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter,
+ InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter,
+ InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, // 0x80 - 0x8f
+ InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter,
+ InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter,
+ InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter,
+ InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, // 0x90 - 0x9f
+ InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter,
+ InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter,
+ InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter,
+ InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, // 0xa0 - 0xaf
+ InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter,
+ InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter,
+ InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter,
+ InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, // 0xb0 - 0xbf
+ InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter,
+ InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter,
+ InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter,
+ InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, // 0xc0 - 0xcf
+ InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter,
+ InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter,
+ InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter,
+ InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, // 0xd0 - 0xdf
+ InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter,
+ InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter,
+ InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter,
+ InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, // 0xe0 - 0xef
+ InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter,
+ InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter,
+ InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter,
+ InvalidCharacter, InvalidCharacter, InvalidCharacter, InvalidCharacter, // 0xf0 - 0xff
+};
+
+}
--- /dev/null
+// Copyright 2010, Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef URLCharacterTypes_h
+#define URLCharacterTypes_h
+
+namespace WTF {
+
+class URLCharacterTypes {
+public:
+ static inline bool isQueryChar(unsigned char c) { return isCharOfType(c, QueryCharacter); }
+ static inline bool isIPv4Char(unsigned char c) { return isCharOfType(c, IPv4Character); }
+ static inline bool isHexChar(unsigned char c) { return isCharOfType(c, HexCharacter); }
+
+private:
+ enum CharTypes {
+ InvalidCharacter = 0,
+ QueryCharacter = 1 << 0,
+ UserInfoCharacter = 1 << 1,
+ IPv4Character = 1 << 2,
+ HexCharacter = 1 << 3,
+ DecimalCharacter = 1 << 4,
+ OctalCharacter = 1 << 5,
+ };
+
+ static const unsigned char characterTypeTable[0x100];
+
+ static inline bool isCharOfType(unsigned char c, CharTypes type)
+ {
+ return !!(characterTypeTable[c] & type);
+ }
+};
+
+}
+
+#endif
URLComponent() : m_begin(0), m_length(-1) { }
URLComponent(int begin, int length) : m_begin(begin), m_length(length) { }
+ // Helper that returns a component created with the given begin and ending
+ // points. The ending point is non-inclusive.
+ static inline URLComponent fromRange(int begin, int end)
+ {
+ return URLComponent(begin, end - begin);
+ }
+
// Returns true if this component is valid, meaning the length is given. Even
// valid components may be empty to record the fact that they exist.
bool isValid() const { return m_length != -1; }
- // Returns true if the given component is specified on false, the component
- // is either empty or invalid.
- bool isNonempty() const { return m_length > 0; }
+ bool isNonEmpty() const { return m_length > 0; }
+ bool isEmptyOrInvalid() const { return m_length <= 0; }
void reset()
{
--- /dev/null
+// Copyright 2010, Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "config.h"
+#include "URLEscape.h"
+
+namespace WTF {
+
+const char hexCharacterTable[16] = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
+};
+
+}
--- /dev/null
+// Copyright 2010, Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+#ifndef URLEscape_h
+#define URLEscape_h
+
+#include "URLBuffer.h"
+
+namespace WTF {
+
+extern const char hexCharacterTable[16];
+
+template<typename InChar, typename OutChar>
+inline void appendURLEscapedCharacter(InChar ch, URLBuffer<OutChar>& buffer)
+{
+ buffer.append('%');
+ buffer.append(hexCharacterTable[ch >> 4]);
+ buffer.append(hexCharacterTable[ch & 0xf]);
+}
+
+}
+
+#endif
--- /dev/null
+/* Based on nsURLParsers.cc from Mozilla
+ * -------------------------------------
+ * Copyright (C) 1998 Netscape Communications Corporation.
+ *
+ * Other contributors:
+ * Darin Fisher (original author)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Alternatively, the contents of this file may be used under the terms
+ * of either the Mozilla Public License Version 1.1, found at
+ * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public
+ * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html
+ * (the "GPL"), in which case the provisions of the MPL or the GPL are
+ * applicable instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of one of those two
+ * licenses (the MPL or the GPL) and not to allow others to use your
+ * version of this file under the LGPL, indicate your decision by
+ * deletingthe provisions above and replace them with the notice and
+ * other provisions required by the MPL or the GPL, as the case may be.
+ * If you do not delete the provisions above, a recipient may use your
+ * version of this file under any of the LGPL, the MPL or the GPL.
+ */
+
+#ifndef URLParser_h
+#define URLParser_h
+
+#include "URLComponent.h"
+#include "URLSegments.h"
+
+namespace WTF {
+
+template<typename CHAR>
+class URLParser {
+public:
+ enum SpecialPort {
+ UnspecifiedPort = -1,
+ InvalidPort = -2,
+ };
+
+ // This handles everything that may be an authority terminator, including
+ // backslash. For special backslash handling see parseAfterScheme.
+ static bool isPossibleAuthorityTerminator(CHAR ch)
+ {
+ return isURLSlash(ch) || ch == '?' || ch == '#' || ch == ';';
+ }
+
+ // Given an already-identified auth section, breaks it into its constituent
+ // parts. The port number will be parsed and the resulting integer will be
+ // filled into the given *port variable, or -1 if there is no port number
+ // or it is invalid.
+ static void parseAuthority(const CHAR* spec, const URLComponent& auth, URLComponent& username, URLComponent& password, URLComponent& host, URLComponent& port)
+ {
+ // FIXME: add ASSERT(auth.isValid()); // We should always get an authority.
+ if (!auth.length()) {
+ username.reset();
+ password.reset();
+ host.reset();
+ port.reset();
+ return;
+ }
+
+ // Search backwards for @, which is the separator between the user info
+ // and the server info. RFC 3986 forbids @ from occuring in auth, but
+ // someone might include it in a password unescaped.
+ int i = auth.begin() + auth.length() - 1;
+ while (i > auth.begin() && spec[i] != '@')
+ --i;
+
+ if (spec[i] == '@') {
+ // Found user info: <user-info>@<server-info>
+ parseUserInfo(spec, URLComponent(auth.begin(), i - auth.begin()), username, password);
+ parseServerInfo(spec, URLComponent::fromRange(i + 1, auth.begin() + auth.length()), host, port);
+ } else {
+ // No user info, everything is server info.
+ username.reset();
+ password.reset();
+ parseServerInfo(spec, auth, host, port);
+ }
+ }
+
+ static bool extractScheme(const CHAR* spec, int specLength, URLComponent& scheme)
+ {
+ // Skip leading whitespace and control characters.
+ int begin = 0;
+ while (begin < specLength && shouldTrimFromURL(spec[begin]))
+ begin++;
+ if (begin == specLength)
+ return false; // Input is empty or all whitespace.
+
+ // Find the first colon character.
+ for (int i = begin; i < specLength; i++) {
+ if (spec[i] == ':') {
+ scheme = URLComponent::fromRange(begin, i);
+ return true;
+ }
+ }
+ return false; // No colon found: no scheme
+ }
+
+ // Fills in all members of the URLSegments structure (except for the
+ // scheme) for standard URLs.
+ //
+ // |spec| is the full spec being parsed, of length |specLength|.
+ // |afterScheme| is the character immediately following the scheme (after
+ // the colon) where we'll begin parsing.
+ static void parseAfterScheme(const CHAR* spec, int specLength, int afterScheme, URLSegments& parsed)
+ {
+ int numberOfSlashes = consecutiveSlashes(spec, afterScheme, specLength);
+ int afterSlashes = afterScheme + numberOfSlashes;
+
+ // First split into two main parts, the authority (username, password,
+ // host, and port) and the full path (path, query, and reference).
+ URLComponent authority;
+ URLComponent fullPath;
+
+ // Found "//<some data>", looks like an authority section. Treat
+ // everything from there to the next slash (or end of spec) to be the
+ // authority. Note that we ignore the number of slashes and treat it as
+ // the authority.
+ int authEnd = nextAuthorityTerminator(spec, afterSlashes, specLength);
+ authority = URLComponent(afterSlashes, authEnd - afterSlashes);
+
+ if (authEnd == specLength) // No beginning of path found.
+ fullPath = URLComponent();
+ else // Everything starting from the slash to the end is the path.
+ fullPath = URLComponent(authEnd, specLength - authEnd);
+
+ // Now parse those two sub-parts.
+ parseAuthority(spec, authority, parsed.username, parsed.password, parsed.host, parsed.port);
+ parsePath(spec, fullPath, parsed.path, parsed.query, parsed.fragment);
+ }
+
+ // The main parsing function for standard URLs. Standard URLs have a scheme,
+ // host, path, etc.
+ static void parseStandardURL(const CHAR* spec, int specLength, URLSegments& parsed)
+ {
+ // FIXME: add ASSERT(specLength >= 0);
+
+ // Strip leading & trailing spaces and control characters.
+ int begin = 0;
+ trimURL(spec, begin, specLength);
+
+ int afterScheme;
+ if (extractScheme(spec, specLength, parsed.scheme))
+ afterScheme = parsed.scheme.end() + 1; // Skip past the colon.
+ else {
+ // Say there's no scheme when there is a colon. We could also say
+ // that everything is the scheme. Both would produce an invalid
+ // URL, but this way seems less wrong in more cases.
+ parsed.scheme.reset();
+ afterScheme = begin;
+ }
+ parseAfterScheme(spec, specLength, afterScheme, parsed);
+ }
+
+ static void parsePath(const CHAR* spec, const URLComponent& path, URLComponent& filepath, URLComponent& query, URLComponent& fragment)
+ {
+ // path = [/]<segment1>/<segment2>/<...>/<segmentN>;<param>?<query>#<fragment>
+
+ // Special case when there is no path.
+ if (!path.isValid()) {
+ filepath.reset();
+ query.reset();
+ fragment.reset();
+ return;
+ }
+ // FIXME: add ASSERT(path.length() > 0); // We should never have 0 length paths.
+
+ // Search for first occurrence of either ? or #.
+ int pathEnd = path.begin() + path.length();
+
+ int querySeparator = -1; // Index of the '?'
+ int refSeparator = -1; // Index of the '#'
+ for (int i = path.begin(); i < pathEnd; i++) {
+ switch (spec[i]) {
+ case '?':
+ if (querySeparator < 0)
+ querySeparator = i;
+ break;
+ case '#':
+ refSeparator = i;
+ i = pathEnd; // Break out of the loop.
+ break;
+ default:
+ break;
+ }
+ }
+
+ // Markers pointing to the character after each of these corresponding
+ // components. The code below works from the end back to the beginning,
+ // and will update these indices as it finds components that exist.
+ int fileEnd, queryEnd;
+
+ // Fragment: from the # to the end of the path.
+ if (refSeparator >= 0) {
+ fileEnd = refSeparator;
+ queryEnd = refSeparator;
+ fragment = URLComponent::fromRange(refSeparator + 1, pathEnd);
+ } else {
+ fileEnd = pathEnd;
+ queryEnd = pathEnd;
+ fragment.reset();
+ }
+
+ // Query fragment: everything from the ? to the next boundary (either
+ // the end of the path or the fragment fragment).
+ if (querySeparator >= 0) {
+ fileEnd = querySeparator;
+ query = URLComponent::fromRange(querySeparator + 1, queryEnd);
+ } else
+ query.reset();
+
+ // File path: treat an empty file path as no file path.
+ if (fileEnd != path.begin())
+ filepath = URLComponent::fromRange(path.begin(), fileEnd);
+ else
+ filepath.reset();
+ }
+
+ // Initializes a path URL which is merely a scheme followed by a path.
+ // Examples include "about:foo" and "javascript:alert('bar');"
+ static void parsePathURL(const CHAR* spec, int specLength, URLSegments& parsed)
+ {
+ // Get the non-path and non-scheme parts of the URL out of the way, we
+ // never use them.
+ parsed.username.reset();
+ parsed.password.reset();
+ parsed.host.reset();
+ parsed.port.reset();
+ parsed.query.reset();
+ parsed.fragment.reset();
+
+ // Strip leading & trailing spaces and control characters.
+ // FIXME: Perhaps this is unnecessary?
+ int begin = 0;
+ trimURL(spec, begin, specLength);
+
+ // Handle empty specs or ones that contain only whitespace or control
+ // chars.
+ if (begin == specLength) {
+ parsed.scheme.reset();
+ parsed.path.reset();
+ return;
+ }
+
+ // Extract the scheme, with the path being everything following. We also
+ // handle the case where there is no scheme.
+ if (extractScheme(&spec[begin], specLength - begin, parsed.scheme)) {
+ // Offset the results since we gave extractScheme a substring.
+ parsed.scheme.setBegin(parsed.scheme.begin() + begin);
+
+ // For compatibility with the standard URL parser, we treat no path
+ // as -1, rather than having a length of 0 (we normally wouldn't
+ // care so much for these non-standard URLs).
+ if (parsed.scheme.end() == specLength - 1)
+ parsed.path.reset();
+ else
+ parsed.path = URLComponent::fromRange(parsed.scheme.end() + 1, specLength);
+ } else {
+ // No scheme found, just path.
+ parsed.scheme.reset();
+ parsed.path = URLComponent::fromRange(begin, specLength);
+ }
+ }
+
+ static void parseMailtoURL(const CHAR* spec, int specLength, URLSegments& parsed)
+ {
+ // FIXME: add ASSERT(specLength >= 0);
+
+ // Get the non-path and non-scheme parts of the URL out of the way, we
+ // never use them.
+ parsed.username.reset();
+ parsed.password.reset();
+ parsed.host.reset();
+ parsed.port.reset();
+ parsed.fragment.reset();
+ parsed.query.reset(); // May use this; reset for convenience.
+
+ // Strip leading & trailing spaces and control characters.
+ int begin = 0;
+ trimURL(spec, begin, specLength);
+
+ // Handle empty specs or ones that contain only whitespace or control
+ // chars.
+ if (begin == specLength) {
+ parsed.scheme.reset();
+ parsed.path.reset();
+ return;
+ }
+
+ int pathBegin = -1;
+ int pathEnd = -1;
+
+ // Extract the scheme, with the path being everything following. We also
+ // handle the case where there is no scheme.
+ if (extractScheme(&spec[begin], specLength - begin, parsed.scheme)) {
+ // Offset the results since we gave extractScheme a substring.
+ parsed.scheme.setBegin(parsed.scheme.begin() + begin);
+
+ if (parsed.scheme.end() != specLength - 1) {
+ pathBegin = parsed.scheme.end() + 1;
+ pathEnd = specLength;
+ }
+ } else {
+ // No scheme found, just path.
+ parsed.scheme.reset();
+ pathBegin = begin;
+ pathEnd = specLength;
+ }
+
+ // Split [pathBegin, pathEnd) into a path + query.
+ for (int i = pathBegin; i < pathEnd; ++i) {
+ if (spec[i] == '?') {
+ parsed.query = URLComponent::fromRange(i + 1, pathEnd);
+ pathEnd = i;
+ break;
+ }
+ }
+
+ // For compatibility with the standard URL parser, treat no path as
+ // -1, rather than having a length of 0
+ if (pathBegin == pathEnd)
+ parsed.path.reset();
+ else
+ parsed.path = URLComponent::fromRange(pathBegin, pathEnd);
+ }
+
+ static int parsePort(const CHAR* spec, const URLComponent& component)
+ {
+ // Easy success case when there is no port.
+ const int maxDigits = 5;
+ if (component.isEmptyOrInvalid())
+ return UnspecifiedPort;
+
+ URLComponent nonZeroDigits(component.end(), 0);
+ for (int i = 0; i < component.length(); ++i) {
+ if (spec[component.begin() + i] != '0') {
+ nonZeroDigits = URLComponent::fromRange(component.begin() + i, component.end());
+ break;
+ }
+ }
+ if (!nonZeroDigits.length())
+ return 0; // All digits were 0.
+
+ if (nonZeroDigits.length() > maxDigits)
+ return InvalidPort;
+
+ int port = 0;
+ for (int i = 0; i < nonZeroDigits.length(); ++i) {
+ CHAR ch = spec[nonZeroDigits.begin() + i];
+ if (!isPortDigit(ch))
+ return InvalidPort;
+ port *= 10;
+ port += static_cast<char>(ch) - '0';
+ }
+ if (port > 65535)
+ return InvalidPort;
+ return port;
+ }
+
+ static void extractFileName(const CHAR* spec, const URLComponent& path, URLComponent& fileName)
+ {
+ // Handle empty paths: they have no file names.
+ if (path.isEmptyOrInvalid()) {
+ fileName.reset();
+ return;
+ }
+
+ // Search backwards for a parameter, which is a normally unused field
+ // in a URL delimited by a semicolon. We parse the parameter as part of
+ // the path, but here, we don't want to count it. The last semicolon is
+ // the parameter.
+ int fileEnd = path.end();
+ for (int i = path.end() - 1; i > path.begin(); --i) {
+ if (spec[i] == ';') {
+ fileEnd = i;
+ break;
+ }
+ }
+
+ // Now search backwards from the filename end to the previous slash
+ // to find the beginning of the filename.
+ for (int i = fileEnd - 1; i >= path.begin(); --i) {
+ if (isURLSlash(spec[i])) {
+ // File name is everything following this character to the end
+ fileName = URLComponent::fromRange(i + 1, fileEnd);
+ return;
+ }
+ }
+
+ // No slash found, this means the input was degenerate (generally paths
+ // will start with a slash). Let's call everything the file name.
+ fileName = URLComponent::fromRange(path.begin(), fileEnd);
+ }
+
+ static bool extractQueryKeyValue(const CHAR* spec, URLComponent& query, URLComponent& key, URLComponent& value)
+ {
+ if (query.isEmptyOrInvalid())
+ return false;
+
+ int start = query.begin();
+ int current = start;
+ int end = query.end();
+
+ // We assume the beginning of the input is the beginning of the "key"
+ // and we skip to the end of it.
+ key.setBegin(current);
+ while (current < end && spec[current] != '&' && spec[current] != '=')
+ ++current;
+ key.setLength(current - key.begin());
+
+ // Skip the separator after the key (if any).
+ if (current < end && spec[current] == '=')
+ ++current;
+
+ // Find the value part.
+ value.setBegin(current);
+ while (current < end && spec[current] != '&')
+ ++current;
+ value.setLength(current - value.begin());
+
+ // Finally skip the next separator if any
+ if (current < end && spec[current] == '&')
+ ++current;
+
+ // Save the new query
+ query = URLComponent::fromRange(current, end);
+ return true;
+ }
+
+// FIXME: This should be protected or private.
+public:
+ // We treat slashes and backslashes the same for IE compatibility.
+ static inline bool isURLSlash(CHAR ch)
+ {
+ return ch == '/' || ch == '\\';
+ }
+
+ // Returns true if we should trim this character from the URL because it is
+ // a space or a control character.
+ static inline bool shouldTrimFromURL(CHAR ch)
+ {
+ return ch <= ' ';
+ }
+
+ // Given an already-initialized begin index and end index (the index after
+ // the last CHAR in spec), this shrinks the range to eliminate
+ // "should-be-trimmed" characters.
+ static inline void trimURL(const CHAR* spec, int& begin, int& end)
+ {
+ // Strip leading whitespace and control characters.
+ while (begin < end && shouldTrimFromURL(spec[begin]))
+ ++begin;
+
+ // Strip trailing whitespace and control characters. We need the >i
+ // test for when the input string is all blanks; we don't want to back
+ // past the input.
+ while (end > begin && shouldTrimFromURL(spec[end - 1]))
+ --end;
+ }
+
+ // Counts the number of consecutive slashes starting at the given offset
+ // in the given string of the given length.
+ static inline int consecutiveSlashes(const CHAR *string, int beginOffset, int stringLength)
+ {
+ int count = 0;
+ while (beginOffset + count < stringLength && isURLSlash(string[beginOffset + count]))
+ ++count;
+ return count;
+ }
+
+private:
+ // URLParser cannot be constructed.
+ URLParser();
+
+ // Returns true if the given character is a valid digit to use in a port.
+ static inline bool isPortDigit(CHAR ch)
+ {
+ return ch >= '0' && ch <= '9';
+ }
+
+ // Returns the offset of the next authority terminator in the input starting
+ // from startOffset. If no terminator is found, the return value will be equal
+ // to specLength.
+ static int nextAuthorityTerminator(const CHAR* spec, int startOffset, int specLength)
+ {
+ for (int i = startOffset; i < specLength; i++) {
+ if (isPossibleAuthorityTerminator(spec[i]))
+ return i;
+ }
+ return specLength; // Not found.
+ }
+
+ static void parseUserInfo(const CHAR* spec, const URLComponent& user, URLComponent& username, URLComponent& password)
+ {
+ // Find the first colon in the user section, which separates the
+ // username and password.
+ int colonOffset = 0;
+ while (colonOffset < user.length() && spec[user.begin() + colonOffset] != ':')
+ ++colonOffset;
+
+ if (colonOffset < user.length()) {
+ // Found separator: <username>:<password>
+ username = URLComponent(user.begin(), colonOffset);
+ password = URLComponent::fromRange(user.begin() + colonOffset + 1, user.begin() + user.length());
+ } else {
+ // No separator, treat everything as the username
+ username = user;
+ password = URLComponent();
+ }
+ }
+
+ static void parseServerInfo(const CHAR* spec, const URLComponent& serverInfo, URLComponent& host, URLComponent& port)
+ {
+ if (!serverInfo.length()) {
+ // No server info, host name is empty.
+ host.reset();
+ port.reset();
+ return;
+ }
+
+ // If the host starts with a left-bracket, assume the entire host is an
+ // IPv6 literal. Otherwise, assume none of the host is an IPv6 literal.
+ // This assumption will be overridden if we find a right-bracket.
+ //
+ // Our IPv6 address canonicalization code requires both brackets to
+ // exist, but the ability to locate an incomplete address can still be
+ // useful.
+ int ipv6Terminator = spec[serverInfo.begin()] == '[' ? serverInfo.end() : -1;
+ int colon = -1;
+
+ // Find the last right-bracket, and the last colon.
+ for (int i = serverInfo.begin(); i < serverInfo.end(); i++) {
+ switch (spec[i]) {
+ case ']':
+ ipv6Terminator = i;
+ break;
+ case ':':
+ colon = i;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (colon > ipv6Terminator) {
+ // Found a port number: <hostname>:<port>
+ host = URLComponent::fromRange(serverInfo.begin(), colon);
+ if (!host.length())
+ host.reset();
+ port = URLComponent::fromRange(colon + 1, serverInfo.end());
+ } else {
+ // No port: <hostname>
+ host = serverInfo;
+ port.reset();
+ }
+ }
+};
+
+} // namespace WTF
+
+#endif // URLParser_h
--- /dev/null
+// Copyright 2010, Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+#ifndef URLQueryCanonicalizer_h
+#define URLQueryCanonicalizer_h
+
+#include "RawURLBuffer.h"
+#include "URLBuffer.h"
+#include "URLCharacterTypes.h"
+#include "URLComponent.h"
+#include "URLEscape.h"
+
+namespace WTF {
+
+template<typename InChar, typename OutChar, void convertCharset(const InChar*, int length, URLBuffer<char>&)>
+class URLQueryCanonicalizer {
+public:
+ static void canonicalize(const InChar* spec, const URLComponent& query, URLBuffer<OutChar>& buffer, URLComponent& resultQuery)
+ {
+ if (query.length() < 0) {
+ resultQuery = URLComponent();
+ return;
+ }
+
+ buffer->append('?');
+ resultQuery.setBegin(buffer->length());
+ convertToQueryEncoding(spec, query, buffer);
+ resultQuery.setLength(buffer->length() - resultQuery.begin());
+ }
+
+private:
+ static bool isAllASCII(const InChar* spec, const URLComponent& query)
+ {
+ int end = query.end();
+ for (int i = query.begin(); i < end; ++i) {
+ if (static_cast<unsigned>(spec[i]) >= 0x80)
+ return false;
+ }
+ return true;
+ }
+
+#ifndef NDEBUG
+ static bool isRaw8Bit(const InChar* source, int length)
+ {
+ for (int i = source; i < length; ++i) {
+ if (source[i] & 0xFF != source[i])
+ return false;
+ }
+ return true;
+ }
+#endif
+
+ static void appendRaw8BitQueryString(const InChar* source, int length, URLBuffer<OutChar>* buffer)
+ {
+ ASSERT(isRaw8Bit(source, length));
+ for (int i = 0; i < length; ++i) {
+ if (!URLCharacterTypes::isQueryChar(source[i]))
+ appendURLEscapedCharacter(static_cast<unsigned char>(source[i]), buffer);
+ else
+ buffer->append(static_cast<char>(source[i]));
+ }
+ }
+
+ static void convertToQueryEncoding(const InChar* spec, const URLComponent& query, URLBuffer<OutChar>& buffer)
+ {
+ if (isAllASCII(spec, query)) {
+ appendRaw8BitQueryString(&spec[query.begin()], query.length(), buffer);
+ return;
+ }
+
+ RawURLBuffer<char, 1024> convertedQuery;
+ convertCharset(spec, query, convertedQuery);
+ appendRaw8BitQueryString(convertedQuery.data(), convertedQuery.length(), buffer);
+ }
+};
+
+}
+
+#endif
+
+
--- /dev/null
+/*
+ * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2007-2009 Torch Mobile, Inc. All rights reserved
+ *
+ * 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.
+ *
+ */
+
+#ifndef WTF_FastMallocWinCE_h
+#define WTF_FastMallocWinCE_h
+
+#include <new.h>
+
+#ifdef __cplusplus
+#include <new>
+#include "MemoryManager.h"
+extern "C" {
+#endif
+
+void* fastMalloc(size_t n);
+void* fastCalloc(size_t n_elements, size_t element_size);
+void fastFree(void* p);
+void* fastRealloc(void* p, size_t n);
+void* fastZeroedMalloc(size_t n);
+// These functions return 0 if an allocation fails.
+void* tryFastMalloc(size_t n);
+void* tryFastZeroedMalloc(size_t n);
+void* tryFastCalloc(size_t n_elements, size_t element_size);
+void* tryFastRealloc(void* p, size_t n);
+char* fastStrDup(const char*);
+
+#ifndef NDEBUG
+void fastMallocForbid();
+void fastMallocAllow();
+#endif
+
+#if !defined(USE_SYSTEM_MALLOC) || !USE_SYSTEM_MALLOC
+
+#define malloc(n) fastMalloc(n)
+#define calloc(n_elements, element_size) fastCalloc(n_elements, element_size)
+#define realloc(p, n) fastRealloc(p, n)
+#define free(p) fastFree(p)
+#define strdup(p) fastStrDup(p)
+
+#else
+
+#define strdup(p) _strdup(p)
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef __cplusplus
+#if !defined(USE_SYSTEM_MALLOC) || !USE_SYSTEM_MALLOC
+static inline void* __cdecl operator new(size_t s) { return fastMalloc(s); }
+static inline void __cdecl operator delete(void* p) { fastFree(p); }
+static inline void* __cdecl operator new[](size_t s) { return fastMalloc(s); }
+static inline void __cdecl operator delete[](void* p) { fastFree(p); }
+static inline void* operator new(size_t s, const std::nothrow_t&) throw() { return fastMalloc(s); }
+static inline void operator delete(void* p, const std::nothrow_t&) throw() { fastFree(p); }
+static inline void* operator new[](size_t s, const std::nothrow_t&) throw() { return fastMalloc(s); }
+static inline void operator delete[](void* p, const std::nothrow_t&) throw() { fastFree(p); }
+#endif
+
+namespace WTF {
+ // This defines a type which holds an unsigned integer and is the same
+ // size as the minimally aligned memory allocation.
+ typedef unsigned long long AllocAlignmentInteger;
+
+ namespace Internal {
+ enum AllocType { // Start with an unusual number instead of zero, because zero is common.
+ AllocTypeMalloc = 0x375d6750, // Encompasses fastMalloc, fastZeroedMalloc, fastCalloc, fastRealloc.
+ AllocTypeClassNew, // Encompasses class operator new from FastAllocBase.
+ AllocTypeClassNewArray, // Encompasses class operator new[] from FastAllocBase.
+ AllocTypeFastNew, // Encompasses fastNew.
+ AllocTypeFastNewArray, // Encompasses fastNewArray.
+ AllocTypeNew, // Encompasses global operator new.
+ AllocTypeNewArray // Encompasses global operator new[].
+ };
+ }
+
+
+#if ENABLE(FAST_MALLOC_MATCH_VALIDATION)
+
+ // Malloc validation is a scheme whereby a tag is attached to an
+ // allocation which identifies how it was originally allocated.
+ // This allows us to verify that the freeing operation matches the
+ // allocation operation. If memory is allocated with operator new[]
+ // but freed with free or delete, this system would detect that.
+ // In the implementation here, the tag is an integer prepended to
+ // the allocation memory which is assigned one of the AllocType
+ // enumeration values. An alternative implementation of this
+ // scheme could store the tag somewhere else or ignore it.
+ // Users of FastMalloc don't need to know or care how this tagging
+ // is implemented.
+
+ namespace Internal {
+
+ // Return the AllocType tag associated with the allocated block p.
+ inline AllocType fastMallocMatchValidationType(const void* p)
+ {
+ const AllocAlignmentInteger* type = static_cast<const AllocAlignmentInteger*>(p) - 1;
+ return static_cast<AllocType>(*type);
+ }
+
+ // Return the address of the AllocType tag associated with the allocated block p.
+ inline AllocAlignmentInteger* fastMallocMatchValidationValue(void* p)
+ {
+ return reinterpret_cast<AllocAlignmentInteger*>(static_cast<char*>(p) - sizeof(AllocAlignmentInteger));
+ }
+
+ // Set the AllocType tag to be associaged with the allocated block p.
+ inline void setFastMallocMatchValidationType(void* p, AllocType allocType)
+ {
+ AllocAlignmentInteger* type = static_cast<AllocAlignmentInteger*>(p) - 1;
+ *type = static_cast<AllocAlignmentInteger>(allocType);
+ }
+
+ // Handle a detected alloc/free mismatch. By default this calls CRASH().
+ void fastMallocMatchFailed(void* p);
+
+ } // namespace Internal
+
+ // This is a higher level function which is used by FastMalloc-using code.
+ inline void fastMallocMatchValidateMalloc(void* p, Internal::AllocType allocType)
+ {
+ if (!p)
+ return;
+
+ Internal::setFastMallocMatchValidationType(p, allocType);
+ }
+
+ // This is a higher level function which is used by FastMalloc-using code.
+ inline void fastMallocMatchValidateFree(void* p, Internal::AllocType allocType)
+ {
+ if (!p)
+ return;
+
+ if (Internal::fastMallocMatchValidationType(p) != allocType)
+ Internal::fastMallocMatchFailed(p);
+ Internal::setFastMallocMatchValidationType(p, Internal::AllocTypeMalloc); // Set it to this so that fastFree thinks it's OK.
+ }
+
+#else
+
+ inline void fastMallocMatchValidateMalloc(void*, Internal::AllocType)
+ {
+ }
+
+ inline void fastMallocMatchValidateFree(void*, Internal::AllocType)
+ {
+ }
+
+#endif
+
+} // namespace WTF
+
+#endif
+
+#endif // WTF_FastMallocWinCE_h
+++ /dev/null
-/*
- * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
- * Copyright (C) 2007-2009 Torch Mobile, Inc. All rights reserved
- *
- * 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.
- *
- */
-
-#ifndef FastMallocWince_h
-#define FastMallocWince_h
-
-#include <new.h>
-
-#ifdef __cplusplus
-#include <new>
-#include "MemoryManager.h"
-extern "C" {
-#endif
-
-void* fastMalloc(size_t n);
-void* fastCalloc(size_t n_elements, size_t element_size);
-void fastFree(void* p);
-void* fastRealloc(void* p, size_t n);
-void* fastZeroedMalloc(size_t n);
-// These functions return 0 if an allocation fails.
-void* tryFastMalloc(size_t n);
-void* tryFastZeroedMalloc(size_t n);
-void* tryFastCalloc(size_t n_elements, size_t element_size);
-void* tryFastRealloc(void* p, size_t n);
-char* fastStrDup(const char*);
-
-#ifndef NDEBUG
-void fastMallocForbid();
-void fastMallocAllow();
-#endif
-
-#if !defined(USE_SYSTEM_MALLOC) || !USE_SYSTEM_MALLOC
-
-#define malloc(n) fastMalloc(n)
-#define calloc(n_elements, element_size) fastCalloc(n_elements, element_size)
-#define realloc(p, n) fastRealloc(p, n)
-#define free(p) fastFree(p)
-#define strdup(p) fastStrDup(p)
-
-#else
-
-#define strdup(p) _strdup(p)
-
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#ifdef __cplusplus
-#if !defined(USE_SYSTEM_MALLOC) || !USE_SYSTEM_MALLOC
-static inline void* __cdecl operator new(size_t s) { return fastMalloc(s); }
-static inline void __cdecl operator delete(void* p) { fastFree(p); }
-static inline void* __cdecl operator new[](size_t s) { return fastMalloc(s); }
-static inline void __cdecl operator delete[](void* p) { fastFree(p); }
-static inline void* operator new(size_t s, const std::nothrow_t&) throw() { return fastMalloc(s); }
-static inline void operator delete(void* p, const std::nothrow_t&) throw() { fastFree(p); }
-static inline void* operator new[](size_t s, const std::nothrow_t&) throw() { return fastMalloc(s); }
-static inline void operator delete[](void* p, const std::nothrow_t&) throw() { fastFree(p); }
-#endif
-
-namespace WTF {
- // This defines a type which holds an unsigned integer and is the same
- // size as the minimally aligned memory allocation.
- typedef unsigned long long AllocAlignmentInteger;
-
- namespace Internal {
- enum AllocType { // Start with an unusual number instead of zero, because zero is common.
- AllocTypeMalloc = 0x375d6750, // Encompasses fastMalloc, fastZeroedMalloc, fastCalloc, fastRealloc.
- AllocTypeClassNew, // Encompasses class operator new from FastAllocBase.
- AllocTypeClassNewArray, // Encompasses class operator new[] from FastAllocBase.
- AllocTypeFastNew, // Encompasses fastNew.
- AllocTypeFastNewArray, // Encompasses fastNewArray.
- AllocTypeNew, // Encompasses global operator new.
- AllocTypeNewArray // Encompasses global operator new[].
- };
- }
-
-
-#if ENABLE(FAST_MALLOC_MATCH_VALIDATION)
-
- // Malloc validation is a scheme whereby a tag is attached to an
- // allocation which identifies how it was originally allocated.
- // This allows us to verify that the freeing operation matches the
- // allocation operation. If memory is allocated with operator new[]
- // but freed with free or delete, this system would detect that.
- // In the implementation here, the tag is an integer prepended to
- // the allocation memory which is assigned one of the AllocType
- // enumeration values. An alternative implementation of this
- // scheme could store the tag somewhere else or ignore it.
- // Users of FastMalloc don't need to know or care how this tagging
- // is implemented.
-
- namespace Internal {
-
- // Return the AllocType tag associated with the allocated block p.
- inline AllocType fastMallocMatchValidationType(const void* p)
- {
- const AllocAlignmentInteger* type = static_cast<const AllocAlignmentInteger*>(p) - 1;
- return static_cast<AllocType>(*type);
- }
-
- // Return the address of the AllocType tag associated with the allocated block p.
- inline AllocAlignmentInteger* fastMallocMatchValidationValue(void* p)
- {
- return reinterpret_cast<AllocAlignmentInteger*>(static_cast<char*>(p) - sizeof(AllocAlignmentInteger));
- }
-
- // Set the AllocType tag to be associaged with the allocated block p.
- inline void setFastMallocMatchValidationType(void* p, AllocType allocType)
- {
- AllocAlignmentInteger* type = static_cast<AllocAlignmentInteger*>(p) - 1;
- *type = static_cast<AllocAlignmentInteger>(allocType);
- }
-
- // Handle a detected alloc/free mismatch. By default this calls CRASH().
- void fastMallocMatchFailed(void* p);
-
- } // namespace Internal
-
- // This is a higher level function which is used by FastMalloc-using code.
- inline void fastMallocMatchValidateMalloc(void* p, Internal::AllocType allocType)
- {
- if (!p)
- return;
-
- Internal::setFastMallocMatchValidationType(p, allocType);
- }
-
- // This is a higher level function which is used by FastMalloc-using code.
- inline void fastMallocMatchValidateFree(void* p, Internal::AllocType allocType)
- {
- if (!p)
- return;
-
- if (Internal::fastMallocMatchValidationType(p) != allocType)
- Internal::fastMallocMatchFailed(p);
- Internal::setFastMallocMatchValidationType(p, Internal::AllocTypeMalloc); // Set it to this so that fastFree thinks it's OK.
- }
-
-#else
-
- inline void fastMallocMatchValidateMalloc(void*, Internal::AllocType)
- {
- }
-
- inline void fastMallocMatchValidateFree(void*, Internal::AllocType)
- {
- }
-
-#endif
-
-} // namespace WTF
-
-#endif
-
-#endif // FastMallocWince_h
-
+++ /dev/null
-/*
- A C-program for MT19937, with initialization improved 2002/1/26.
- Coded by Takuji Nishimura and Makoto Matsumoto.
-
- Before using, initialize the state by using init_genrand(seed)
- or init_by_array(init_key, key_length).
-
- Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
-
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- 3. The names of its contributors may not be used to endorse or promote
- products derived from this software without specific prior written
- permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
- Any feedback is very welcome.
- http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
- email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
-*/
-
-#include <stdio.h>
-
-/* Period parameters */
-#define N 624
-#define M 397
-#define MATRIX_A 0x9908b0dfUL /* constant vector a */
-#define UPPER_MASK 0x80000000UL /* most significant w-r bits */
-#define LOWER_MASK 0x7fffffffUL /* least significant r bits */
-
-static unsigned long mt[N]; /* the array for the state vector */
-static int mti=N+1; /* mti==N+1 means mt[N] is not initialized */
-
-/* initializes mt[N] with a seed */
-void init_genrand(unsigned long s)
-{
- mt[0]= s & 0xffffffffUL;
- for (mti=1; mti<N; mti++) {
- mt[mti] = (1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti);
- /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
- /* In the previous versions, MSBs of the seed affect */
- /* only MSBs of the array mt[]. */
- /* 2002/01/09 modified by Makoto Matsumoto */
- mt[mti] &= 0xffffffffUL;
- /* for >32 bit machines */
- }
-}
-
-/* initialize by an array with array-length */
-/* init_key is the array for initializing keys */
-/* key_length is its length */
-/* slight change for C++, 2004/2/26 */
-void init_by_array(unsigned long init_key[],int key_length)
-{
- int i, j, k;
- init_genrand(19650218UL);
- i=1; j=0;
- k = (N>key_length ? N : key_length);
- for (; k; k--) {
- mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL))
- + init_key[j] + j; /* non linear */
- mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
- i++; j++;
- if (i>=N) { mt[0] = mt[N-1]; i=1; }
- if (j>=key_length) j=0;
- }
- for (k=N-1; k; k--) {
- mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL))
- - i; /* non linear */
- mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
- i++;
- if (i>=N) { mt[0] = mt[N-1]; i=1; }
- }
-
- mt[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */
-}
-
-/* generates a random number on [0,0xffffffff]-interval */
-unsigned long genrand_int32(void)
-{
- unsigned long y;
- static unsigned long mag01[2]={0x0UL, MATRIX_A};
- /* mag01[x] = x * MATRIX_A for x=0,1 */
-
- if (mti >= N) { /* generate N words at one time */
- int kk;
-
- if (mti == N+1) /* if init_genrand() has not been called, */
- init_genrand(5489UL); /* a default initial seed is used */
-
- for (kk=0;kk<N-M;kk++) {
- y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
- mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1UL];
- }
- for (;kk<N-1;kk++) {
- y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
- mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
- }
- y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK);
- mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL];
-
- mti = 0;
- }
-
- y = mt[mti++];
-
- /* Tempering */
- y ^= (y >> 11);
- y ^= (y << 7) & 0x9d2c5680UL;
- y ^= (y << 15) & 0xefc60000UL;
- y ^= (y >> 18);
-
- return y;
-}
-
-/* generates a random number on [0,0x7fffffff]-interval */
-long genrand_int31(void)
-{
- return (long)(genrand_int32()>>1);
-}
-
-/* generates a random number on [0,1]-real-interval */
-double genrand_real1(void)
-{
- return genrand_int32()*(1.0/4294967295.0);
- /* divided by 2^32-1 */
-}
-
-/* generates a random number on [0,1)-real-interval */
-double genrand_real2(void)
-{
- return genrand_int32()*(1.0/4294967296.0);
- /* divided by 2^32 */
-}
-
-/* generates a random number on (0,1)-real-interval */
-double genrand_real3(void)
-{
- return (((double)genrand_int32()) + 0.5)*(1.0/4294967296.0);
- /* divided by 2^32 */
-}
-
-/* generates a random number on [0,1) with 53-bit resolution*/
-double genrand_res53(void)
-{
- unsigned long a=genrand_int32()>>5, b=genrand_int32()>>6;
- return(a*67108864.0+b)*(1.0/9007199254740992.0);
-}
--- /dev/null
+# wtf - qmake build info
+
+SOURCES += \
+ wtf/Assertions.cpp \
+ wtf/ByteArray.cpp \
+ wtf/CryptographicallyRandomNumber.cpp \
+ wtf/CurrentTime.cpp \
+ wtf/DateMath.cpp \
+ wtf/dtoa.cpp \
+ wtf/DecimalNumber.cpp \
+ wtf/FastMalloc.cpp \
+ wtf/gobject/GOwnPtr.cpp \
+ wtf/gobject/GRefPtr.cpp \
+ wtf/HashTable.cpp \
+ wtf/MD5.cpp \
+ wtf/MainThread.cpp \
+ wtf/NullPtr.cpp \
+ wtf/OSRandomSource.cpp \
+ wtf/qt/MainThreadQt.cpp \
+ wtf/qt/StringQt.cpp \
+ wtf/qt/ThreadingQt.cpp \
+ wtf/PageAllocationAligned.cpp \
+ wtf/PageBlock.cpp \
+ wtf/ParallelJobsGeneric.cpp \
+ wtf/RandomNumber.cpp \
+ wtf/RefCountedLeakCounter.cpp \
+ wtf/SHA1.cpp \
+ wtf/StackBounds.cpp \
+ wtf/TCSystemAlloc.cpp \
+ wtf/ThreadingNone.cpp \
+ wtf/Threading.cpp \
+ wtf/TypeTraits.cpp \
+ wtf/WTFThreadData.cpp \
+ wtf/text/AtomicString.cpp \
+ wtf/text/CString.cpp \
+ wtf/text/StringBuilder.cpp \
+ wtf/text/StringImpl.cpp \
+ wtf/text/StringStatics.cpp \
+ wtf/text/WTFString.cpp \
+ wtf/unicode/CollatorDefault.cpp \
+ wtf/unicode/icu/CollatorICU.cpp \
+ wtf/unicode/UTF8.cpp
+
+contains(DEFINES, USE_GSTREAMER=1) {
+ DEFINES += ENABLE_GLIB_SUPPORT=1
+ PKGCONFIG += glib-2.0 gio-2.0
+ CONFIG += link_pkgconfig
+}
+
+unix:!symbian: SOURCES += wtf/OSAllocatorPosix.cpp
+symbian: SOURCES += wtf/OSAllocatorSymbian.cpp
+win*|wince*: SOURCES += wtf/OSAllocatorWin.cpp
--- /dev/null
+/*
+ * Copyright (C) 2007 Vaclav Slavik, Kevin Ollivier <kevino@theolliviers.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+// The wx headers must come first in this case, because the wtf/text headers
+// import windows.h, and we need to allow the wx headers to set its configuration
+// first.
+#include <wx/defs.h>
+#include <wx/string.h>
+
+#include <wtf/text/CString.h>
+#include <wtf/text/WTFString.h>
+
+namespace WTF {
+
+String::String(const wxString& wxstr)
+{
+#if !wxUSE_UNICODE
+ #error "This code only works in Unicode build of wxWidgets"
+#endif
+
+#if SIZEOF_WCHAR_T == 2
+
+ const UChar* str = wxstr.wc_str();
+ const size_t len = wxstr.length();
+
+#else // SIZEOF_WCHAR_T == 4
+
+ // NB: we can't simply use wxstr.mb_str(wxMBConvUTF16()) here because
+ // the number of characters in UTF-16 encoding of the string may differ
+ // from the number of UTF-32 values and we can't get the length from
+ // returned buffer:
+
+#if defined(wxUSE_UNICODE_UTF8) && wxUSE_UNICODE_UTF8
+ // in wx3's UTF8 mode, wc_str() returns a buffer, not raw pointer
+ wxWCharBuffer wideString(wxstr.wc_str());
+#else
+ const wxChar *wideString = wxstr.wc_str();
+#endif
+ size_t wideLength = wxstr.length();
+
+ wxMBConvUTF16 conv;
+
+ const size_t utf16bufLen = conv.FromWChar(0, 0, wideString, wideLength);
+ wxCharBuffer utf16buf(utf16bufLen);
+
+ const UChar* str = (const UChar*)utf16buf.data();
+ size_t len = conv.FromWChar(utf16buf.data(), utf16bufLen, wideString, wideLength) / 2;
+
+#endif // SIZEOF_WCHAR_T == 2
+
+ m_impl = StringImpl::create(str, len);
+
+}
+
+String::operator wxString() const
+{
+ return wxString(utf8().data(), wxConvUTF8);
+}
+
+} // namespace WTF
+++ /dev/null
-/*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "RegexCompiler.h"
-
-#include "RegexInterpreter.h"
-#include "RegexPattern.h"
-#include <wtf/Vector.h>
-
-#if ENABLE(YARR)
-
-using namespace WTF;
-
-namespace JSC { namespace Yarr {
-
-#include "RegExpJitTables.h"
-
-class CharacterClassConstructor {
-public:
- CharacterClassConstructor(bool isCaseInsensitive = false)
- : m_isCaseInsensitive(isCaseInsensitive)
- {
- }
-
- void reset()
- {
- m_matches.clear();
- m_ranges.clear();
- m_matchesUnicode.clear();
- m_rangesUnicode.clear();
- }
-
- void append(const CharacterClass* other)
- {
- for (size_t i = 0; i < other->m_matches.size(); ++i)
- addSorted(m_matches, other->m_matches[i]);
- for (size_t i = 0; i < other->m_ranges.size(); ++i)
- addSortedRange(m_ranges, other->m_ranges[i].begin, other->m_ranges[i].end);
- for (size_t i = 0; i < other->m_matchesUnicode.size(); ++i)
- addSorted(m_matchesUnicode, other->m_matchesUnicode[i]);
- for (size_t i = 0; i < other->m_rangesUnicode.size(); ++i)
- addSortedRange(m_rangesUnicode, other->m_rangesUnicode[i].begin, other->m_rangesUnicode[i].end);
- }
-
- void putChar(UChar ch)
- {
- if (ch <= 0x7f) {
- if (m_isCaseInsensitive && isASCIIAlpha(ch)) {
- addSorted(m_matches, toASCIIUpper(ch));
- addSorted(m_matches, toASCIILower(ch));
- } else
- addSorted(m_matches, ch);
- } else {
- UChar upper, lower;
- if (m_isCaseInsensitive && ((upper = Unicode::toUpper(ch)) != (lower = Unicode::toLower(ch)))) {
- addSorted(m_matchesUnicode, upper);
- addSorted(m_matchesUnicode, lower);
- } else
- addSorted(m_matchesUnicode, ch);
- }
- }
-
- // returns true if this character has another case, and 'ch' is the upper case form.
- static inline bool isUnicodeUpper(UChar ch)
- {
- return ch != Unicode::toLower(ch);
- }
-
- // returns true if this character has another case, and 'ch' is the lower case form.
- static inline bool isUnicodeLower(UChar ch)
- {
- return ch != Unicode::toUpper(ch);
- }
-
- void putRange(UChar lo, UChar hi)
- {
- if (lo <= 0x7f) {
- char asciiLo = lo;
- char asciiHi = std::min(hi, (UChar)0x7f);
- addSortedRange(m_ranges, lo, asciiHi);
-
- if (m_isCaseInsensitive) {
- if ((asciiLo <= 'Z') && (asciiHi >= 'A'))
- addSortedRange(m_ranges, std::max(asciiLo, 'A')+('a'-'A'), std::min(asciiHi, 'Z')+('a'-'A'));
- if ((asciiLo <= 'z') && (asciiHi >= 'a'))
- addSortedRange(m_ranges, std::max(asciiLo, 'a')+('A'-'a'), std::min(asciiHi, 'z')+('A'-'a'));
- }
- }
- if (hi >= 0x80) {
- uint32_t unicodeCurr = std::max(lo, (UChar)0x80);
- addSortedRange(m_rangesUnicode, unicodeCurr, hi);
-
- if (m_isCaseInsensitive) {
- while (unicodeCurr <= hi) {
- // If the upper bound of the range (hi) is 0xffff, the increments to
- // unicodeCurr in this loop may take it to 0x10000. This is fine
- // (if so we won't re-enter the loop, since the loop condition above
- // will definitely fail) - but this does mean we cannot use a UChar
- // to represent unicodeCurr, we must use a 32-bit value instead.
- ASSERT(unicodeCurr <= 0xffff);
-
- if (isUnicodeUpper(unicodeCurr)) {
- UChar lowerCaseRangeBegin = Unicode::toLower(unicodeCurr);
- UChar lowerCaseRangeEnd = lowerCaseRangeBegin;
- while ((++unicodeCurr <= hi) && isUnicodeUpper(unicodeCurr) && (Unicode::toLower(unicodeCurr) == (lowerCaseRangeEnd + 1)))
- lowerCaseRangeEnd++;
- addSortedRange(m_rangesUnicode, lowerCaseRangeBegin, lowerCaseRangeEnd);
- } else if (isUnicodeLower(unicodeCurr)) {
- UChar upperCaseRangeBegin = Unicode::toUpper(unicodeCurr);
- UChar upperCaseRangeEnd = upperCaseRangeBegin;
- while ((++unicodeCurr <= hi) && isUnicodeLower(unicodeCurr) && (Unicode::toUpper(unicodeCurr) == (upperCaseRangeEnd + 1)))
- upperCaseRangeEnd++;
- addSortedRange(m_rangesUnicode, upperCaseRangeBegin, upperCaseRangeEnd);
- } else
- ++unicodeCurr;
- }
- }
- }
- }
-
- CharacterClass* charClass()
- {
- CharacterClass* characterClass = new CharacterClass(0);
-
- characterClass->m_matches.append(m_matches);
- characterClass->m_ranges.append(m_ranges);
- characterClass->m_matchesUnicode.append(m_matchesUnicode);
- characterClass->m_rangesUnicode.append(m_rangesUnicode);
-
- reset();
-
- return characterClass;
- }
-
-private:
- void addSorted(Vector<UChar>& matches, UChar ch)
- {
- unsigned pos = 0;
- unsigned range = matches.size();
-
- // binary chop, find position to insert char.
- while (range) {
- unsigned index = range >> 1;
-
- int val = matches[pos+index] - ch;
- if (!val)
- return;
- else if (val > 0)
- range = index;
- else {
- pos += (index+1);
- range -= (index+1);
- }
- }
-
- if (pos == matches.size())
- matches.append(ch);
- else
- matches.insert(pos, ch);
- }
-
- void addSortedRange(Vector<CharacterRange>& ranges, UChar lo, UChar hi)
- {
- unsigned end = ranges.size();
-
- // Simple linear scan - I doubt there are that many ranges anyway...
- // feel free to fix this with something faster (eg binary chop).
- for (unsigned i = 0; i < end; ++i) {
- // does the new range fall before the current position in the array
- if (hi < ranges[i].begin) {
- // optional optimization: concatenate appending ranges? - may not be worthwhile.
- if (hi == (ranges[i].begin - 1)) {
- ranges[i].begin = lo;
- return;
- }
- ranges.insert(i, CharacterRange(lo, hi));
- return;
- }
- // Okay, since we didn't hit the last case, the end of the new range is definitely at or after the begining
- // If the new range start at or before the end of the last range, then the overlap (if it starts one after the
- // end of the last range they concatenate, which is just as good.
- if (lo <= (ranges[i].end + 1)) {
- // found an intersect! we'll replace this entry in the array.
- ranges[i].begin = std::min(ranges[i].begin, lo);
- ranges[i].end = std::max(ranges[i].end, hi);
-
- // now check if the new range can subsume any subsequent ranges.
- unsigned next = i+1;
- // each iteration of the loop we will either remove something from the list, or break the loop.
- while (next < ranges.size()) {
- if (ranges[next].begin <= (ranges[i].end + 1)) {
- // the next entry now overlaps / concatenates this one.
- ranges[i].end = std::max(ranges[i].end, ranges[next].end);
- ranges.remove(next);
- } else
- break;
- }
-
- return;
- }
- }
-
- // CharacterRange comes after all existing ranges.
- ranges.append(CharacterRange(lo, hi));
- }
-
- bool m_isCaseInsensitive;
-
- Vector<UChar> m_matches;
- Vector<CharacterRange> m_ranges;
- Vector<UChar> m_matchesUnicode;
- Vector<CharacterRange> m_rangesUnicode;
-};
-
-class RegexPatternConstructor {
-public:
- RegexPatternConstructor(RegexPattern& pattern)
- : m_pattern(pattern)
- , m_characterClassConstructor(pattern.m_ignoreCase)
- {
- }
-
- ~RegexPatternConstructor()
- {
- }
-
- void reset()
- {
- m_pattern.reset();
- m_characterClassConstructor.reset();
- }
-
- void assertionBOL()
- {
- m_alternative->m_terms.append(PatternTerm::BOL());
- }
- void assertionEOL()
- {
- m_alternative->m_terms.append(PatternTerm::EOL());
- }
- void assertionWordBoundary(bool invert)
- {
- m_alternative->m_terms.append(PatternTerm::WordBoundary(invert));
- }
-
- void atomPatternCharacter(UChar ch)
- {
- // We handle case-insensitive checking of unicode characters which do have both
- // cases by handling them as if they were defined using a CharacterClass.
- if (m_pattern.m_ignoreCase && !isASCII(ch) && (Unicode::toUpper(ch) != Unicode::toLower(ch))) {
- atomCharacterClassBegin();
- atomCharacterClassAtom(ch);
- atomCharacterClassEnd();
- } else
- m_alternative->m_terms.append(PatternTerm(ch));
- }
-
- void atomBuiltInCharacterClass(BuiltInCharacterClassID classID, bool invert)
- {
- switch (classID) {
- case DigitClassID:
- m_alternative->m_terms.append(PatternTerm(m_pattern.digitsCharacterClass(), invert));
- break;
- case SpaceClassID:
- m_alternative->m_terms.append(PatternTerm(m_pattern.spacesCharacterClass(), invert));
- break;
- case WordClassID:
- m_alternative->m_terms.append(PatternTerm(m_pattern.wordcharCharacterClass(), invert));
- break;
- case NewlineClassID:
- m_alternative->m_terms.append(PatternTerm(m_pattern.newlineCharacterClass(), invert));
- break;
- }
- }
-
- void atomCharacterClassBegin(bool invert = false)
- {
- m_invertCharacterClass = invert;
- }
-
- void atomCharacterClassAtom(UChar ch)
- {
- m_characterClassConstructor.putChar(ch);
- }
-
- void atomCharacterClassRange(UChar begin, UChar end)
- {
- m_characterClassConstructor.putRange(begin, end);
- }
-
- void atomCharacterClassBuiltIn(BuiltInCharacterClassID classID, bool invert)
- {
- ASSERT(classID != NewlineClassID);
-
- switch (classID) {
- case DigitClassID:
- m_characterClassConstructor.append(invert ? m_pattern.nondigitsCharacterClass() : m_pattern.digitsCharacterClass());
- break;
-
- case SpaceClassID:
- m_characterClassConstructor.append(invert ? m_pattern.nonspacesCharacterClass() : m_pattern.spacesCharacterClass());
- break;
-
- case WordClassID:
- m_characterClassConstructor.append(invert ? m_pattern.nonwordcharCharacterClass() : m_pattern.wordcharCharacterClass());
- break;
-
- default:
- ASSERT_NOT_REACHED();
- }
- }
-
- void atomCharacterClassEnd()
- {
- CharacterClass* newCharacterClass = m_characterClassConstructor.charClass();
- m_pattern.m_userCharacterClasses.append(newCharacterClass);
- m_alternative->m_terms.append(PatternTerm(newCharacterClass, m_invertCharacterClass));
- }
-
- void atomParenthesesSubpatternBegin(bool capture = true)
- {
- unsigned subpatternId = m_pattern.m_numSubpatterns + 1;
- if (capture)
- m_pattern.m_numSubpatterns++;
-
- PatternDisjunction* parenthesesDisjunction = new PatternDisjunction(m_alternative);
- m_pattern.m_disjunctions.append(parenthesesDisjunction);
- m_alternative->m_terms.append(PatternTerm(PatternTerm::TypeParenthesesSubpattern, subpatternId, parenthesesDisjunction, capture));
- m_alternative = parenthesesDisjunction->addNewAlternative();
- }
-
- void atomParentheticalAssertionBegin(bool invert = false)
- {
- PatternDisjunction* parenthesesDisjunction = new PatternDisjunction(m_alternative);
- m_pattern.m_disjunctions.append(parenthesesDisjunction);
- m_alternative->m_terms.append(PatternTerm(PatternTerm::TypeParentheticalAssertion, m_pattern.m_numSubpatterns + 1, parenthesesDisjunction, invert));
- m_alternative = parenthesesDisjunction->addNewAlternative();
- }
-
- void atomParenthesesEnd()
- {
- ASSERT(m_alternative->m_parent);
- ASSERT(m_alternative->m_parent->m_parent);
- m_alternative = m_alternative->m_parent->m_parent;
-
- m_alternative->lastTerm().parentheses.lastSubpatternId = m_pattern.m_numSubpatterns;
- }
-
- void atomBackReference(unsigned subpatternId)
- {
- ASSERT(subpatternId);
- m_pattern.m_shouldFallBack = true;
- m_pattern.m_maxBackReference = std::max(m_pattern.m_maxBackReference, subpatternId);
-
- if (subpatternId > m_pattern.m_numSubpatterns) {
- m_alternative->m_terms.append(PatternTerm::ForwardReference());
- return;
- }
-
- PatternAlternative* currentAlternative = m_alternative;
- ASSERT(currentAlternative);
-
- // Note to self: if we waited until the AST was baked, we could also remove forwards refs
- while ((currentAlternative = currentAlternative->m_parent->m_parent)) {
- PatternTerm& term = currentAlternative->lastTerm();
- ASSERT((term.type == PatternTerm::TypeParenthesesSubpattern) || (term.type == PatternTerm::TypeParentheticalAssertion));
-
- if ((term.type == PatternTerm::TypeParenthesesSubpattern) && term.invertOrCapture && (subpatternId == term.subpatternId)) {
- m_alternative->m_terms.append(PatternTerm::ForwardReference());
- return;
- }
- }
-
- m_alternative->m_terms.append(PatternTerm(subpatternId));
- }
-
- PatternDisjunction* copyDisjunction(PatternDisjunction* disjunction)
- {
- PatternDisjunction* newDisjunction = new PatternDisjunction();
-
- newDisjunction->m_parent = disjunction->m_parent;
- for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) {
- PatternAlternative* alternative = disjunction->m_alternatives[alt];
- PatternAlternative* newAlternative = newDisjunction->addNewAlternative();
- for (unsigned i = 0; i < alternative->m_terms.size(); ++i)
- newAlternative->m_terms.append(copyTerm(alternative->m_terms[i]));
- }
-
- m_pattern.m_disjunctions.append(newDisjunction);
- return newDisjunction;
- }
-
- PatternTerm copyTerm(PatternTerm& term)
- {
- if ((term.type != PatternTerm::TypeParenthesesSubpattern) && (term.type != PatternTerm::TypeParentheticalAssertion))
- return PatternTerm(term);
-
- PatternTerm termCopy = term;
- termCopy.parentheses.disjunction = copyDisjunction(termCopy.parentheses.disjunction);
- return termCopy;
- }
-
- void quantifyAtom(unsigned min, unsigned max, bool greedy)
- {
- ASSERT(min <= max);
- ASSERT(m_alternative->m_terms.size());
-
- if (!max) {
- m_alternative->removeLastTerm();
- return;
- }
-
- PatternTerm& term = m_alternative->lastTerm();
- ASSERT(term.type > PatternTerm::TypeAssertionWordBoundary);
- ASSERT((term.quantityCount == 1) && (term.quantityType == QuantifierFixedCount));
-
- // For any assertion with a zero minimum, not matching is valid and has no effect,
- // remove it. Otherwise, we need to match as least once, but there is no point
- // matching more than once, so remove the quantifier. It is not entirely clear
- // from the spec whether or not this behavior is correct, but I believe this
- // matches Firefox. :-/
- if (term.type == PatternTerm::TypeParentheticalAssertion) {
- if (!min)
- m_alternative->removeLastTerm();
- return;
- }
-
- if (max > 1 && term.type == PatternTerm::TypeParenthesesSubpattern)
- m_pattern.m_shouldFallBack = true;
-
- if (min == 0)
- term.quantify(max, greedy ? QuantifierGreedy : QuantifierNonGreedy);
- else if (min == max)
- term.quantify(min, QuantifierFixedCount);
- else {
- term.quantify(min, QuantifierFixedCount);
- m_alternative->m_terms.append(copyTerm(term));
- // NOTE: this term is interesting from an analysis perspective, in that it can be ignored.....
- m_alternative->lastTerm().quantify((max == UINT_MAX) ? max : max - min, greedy ? QuantifierGreedy : QuantifierNonGreedy);
- if (m_alternative->lastTerm().type == PatternTerm::TypeParenthesesSubpattern)
- m_alternative->lastTerm().parentheses.isCopy = true;
- }
- }
-
- void disjunction()
- {
- m_alternative = m_alternative->m_parent->addNewAlternative();
- }
-
- void regexBegin()
- {
- m_pattern.m_body = new PatternDisjunction();
- m_alternative = m_pattern.m_body->addNewAlternative();
- m_pattern.m_disjunctions.append(m_pattern.m_body);
- }
- void regexEnd()
- {
- }
- void regexError()
- {
- }
-
- unsigned setupAlternativeOffsets(PatternAlternative* alternative, unsigned currentCallFrameSize, unsigned initialInputPosition)
- {
- alternative->m_hasFixedSize = true;
- unsigned currentInputPosition = initialInputPosition;
-
- for (unsigned i = 0; i < alternative->m_terms.size(); ++i) {
- PatternTerm& term = alternative->m_terms[i];
-
- switch (term.type) {
- case PatternTerm::TypeAssertionBOL:
- case PatternTerm::TypeAssertionEOL:
- case PatternTerm::TypeAssertionWordBoundary:
- term.inputPosition = currentInputPosition;
- break;
-
- case PatternTerm::TypeBackReference:
- term.inputPosition = currentInputPosition;
- term.frameLocation = currentCallFrameSize;
- currentCallFrameSize += RegexStackSpaceForBackTrackInfoBackReference;
- alternative->m_hasFixedSize = false;
- break;
-
- case PatternTerm::TypeForwardReference:
- break;
-
- case PatternTerm::TypePatternCharacter:
- term.inputPosition = currentInputPosition;
- if (term.quantityType != QuantifierFixedCount) {
- term.frameLocation = currentCallFrameSize;
- currentCallFrameSize += RegexStackSpaceForBackTrackInfoPatternCharacter;
- alternative->m_hasFixedSize = false;
- } else
- currentInputPosition += term.quantityCount;
- break;
-
- case PatternTerm::TypeCharacterClass:
- term.inputPosition = currentInputPosition;
- if (term.quantityType != QuantifierFixedCount) {
- term.frameLocation = currentCallFrameSize;
- currentCallFrameSize += RegexStackSpaceForBackTrackInfoCharacterClass;
- alternative->m_hasFixedSize = false;
- } else
- currentInputPosition += term.quantityCount;
- break;
-
- case PatternTerm::TypeParenthesesSubpattern:
- // Note: for fixed once parentheses we will ensure at least the minimum is available; others are on their own.
- term.frameLocation = currentCallFrameSize;
- if ((term.quantityCount == 1) && !term.parentheses.isCopy) {
- if (term.quantityType == QuantifierFixedCount) {
- currentCallFrameSize = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize, currentInputPosition);
- currentInputPosition += term.parentheses.disjunction->m_minimumSize;
- } else {
- currentCallFrameSize += RegexStackSpaceForBackTrackInfoParenthesesOnce;
- currentCallFrameSize = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize, currentInputPosition);
- }
- term.inputPosition = currentInputPosition;
- } else {
- term.inputPosition = currentInputPosition;
- setupDisjunctionOffsets(term.parentheses.disjunction, 0, currentInputPosition);
- currentCallFrameSize += RegexStackSpaceForBackTrackInfoParentheses;
- }
- // Fixed count of 1 could be accepted, if they have a fixed size *AND* if all alternatives are of the same length.
- alternative->m_hasFixedSize = false;
- break;
-
- case PatternTerm::TypeParentheticalAssertion:
- term.inputPosition = currentInputPosition;
- term.frameLocation = currentCallFrameSize;
- currentCallFrameSize = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize + RegexStackSpaceForBackTrackInfoParentheticalAssertion, currentInputPosition);
- break;
- }
- }
-
- alternative->m_minimumSize = currentInputPosition - initialInputPosition;
- return currentCallFrameSize;
- }
-
- unsigned setupDisjunctionOffsets(PatternDisjunction* disjunction, unsigned initialCallFrameSize, unsigned initialInputPosition)
- {
- if ((disjunction != m_pattern.m_body) && (disjunction->m_alternatives.size() > 1))
- initialCallFrameSize += RegexStackSpaceForBackTrackInfoAlternative;
-
- unsigned minimumInputSize = UINT_MAX;
- unsigned maximumCallFrameSize = 0;
- bool hasFixedSize = true;
-
- for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) {
- PatternAlternative* alternative = disjunction->m_alternatives[alt];
- unsigned currentAlternativeCallFrameSize = setupAlternativeOffsets(alternative, initialCallFrameSize, initialInputPosition);
- minimumInputSize = min(minimumInputSize, alternative->m_minimumSize);
- maximumCallFrameSize = max(maximumCallFrameSize, currentAlternativeCallFrameSize);
- hasFixedSize &= alternative->m_hasFixedSize;
- }
-
- ASSERT(minimumInputSize != UINT_MAX);
- ASSERT(maximumCallFrameSize >= initialCallFrameSize);
-
- disjunction->m_hasFixedSize = hasFixedSize;
- disjunction->m_minimumSize = minimumInputSize;
- disjunction->m_callFrameSize = maximumCallFrameSize;
- return maximumCallFrameSize;
- }
-
- void setupOffsets()
- {
- setupDisjunctionOffsets(m_pattern.m_body, 0, 0);
- }
-
-private:
- RegexPattern& m_pattern;
- PatternAlternative* m_alternative;
- CharacterClassConstructor m_characterClassConstructor;
- bool m_invertCharacterClass;
-};
-
-
-const char* compileRegex(const UString& patternString, RegexPattern& pattern)
-{
- RegexPatternConstructor constructor(pattern);
-
- if (const char* error = parse(constructor, patternString))
- return error;
-
- // If the pattern contains illegal backreferences reset & reparse.
- // Quoting Netscape's "What's new in JavaScript 1.2",
- // "Note: if the number of left parentheses is less than the number specified
- // in \#, the \# is taken as an octal escape as described in the next row."
- if (pattern.containsIllegalBackReference()) {
- unsigned numSubpatterns = pattern.m_numSubpatterns;
-
- constructor.reset();
-#if !ASSERT_DISABLED
- const char* error =
-#endif
- parse(constructor, patternString, numSubpatterns);
-
- ASSERT(!error);
- ASSERT(numSubpatterns == pattern.m_numSubpatterns);
- }
-
- constructor.setupOffsets();
-
- return false;
-};
-
-
-} }
-
-#endif
+++ /dev/null
-/*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef RegexCompiler_h
-#define RegexCompiler_h
-
-#if ENABLE(YARR)
-
-#include "RegexParser.h"
-#include "RegexPattern.h"
-#include <wtf/unicode/Unicode.h>
-
-namespace JSC { namespace Yarr {
-
-const char* compileRegex(const UString& patternString, RegexPattern& pattern);
-
-} } // namespace JSC::Yarr
-
-#endif
-
-#endif // RegexCompiler_h
+++ /dev/null
-/*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "RegexInterpreter.h"
-
-#include "RegexCompiler.h"
-#include "RegexPattern.h"
-
-#ifndef NDEBUG
-#include <stdio.h>
-#endif
-
-#if ENABLE(YARR)
-
-using namespace WTF;
-
-namespace JSC { namespace Yarr {
-
-class Interpreter {
-public:
- struct ParenthesesDisjunctionContext;
-
- struct BackTrackInfoPatternCharacter {
- uintptr_t matchAmount;
- };
- struct BackTrackInfoCharacterClass {
- uintptr_t matchAmount;
- };
- struct BackTrackInfoBackReference {
- uintptr_t begin; // Not really needed for greedy quantifiers.
- uintptr_t matchAmount; // Not really needed for fixed quantifiers.
- };
- struct BackTrackInfoAlternative {
- uintptr_t offset;
- };
- struct BackTrackInfoParentheticalAssertion {
- uintptr_t begin;
- };
- struct BackTrackInfoParenthesesOnce {
- uintptr_t inParentheses;
- };
- struct BackTrackInfoParentheses {
- uintptr_t matchAmount;
- ParenthesesDisjunctionContext* lastContext;
- uintptr_t prevBegin;
- uintptr_t prevEnd;
- };
-
- static inline void appendParenthesesDisjunctionContext(BackTrackInfoParentheses* backTrack, ParenthesesDisjunctionContext* context)
- {
- context->next = backTrack->lastContext;
- backTrack->lastContext = context;
- ++backTrack->matchAmount;
- }
-
- static inline void popParenthesesDisjunctionContext(BackTrackInfoParentheses* backTrack)
- {
- ASSERT(backTrack->matchAmount);
- ASSERT(backTrack->lastContext);
- backTrack->lastContext = backTrack->lastContext->next;
- --backTrack->matchAmount;
- }
-
- struct DisjunctionContext
- {
- DisjunctionContext()
- : term(0)
- {
- }
-
- void* operator new(size_t, void* where)
- {
- return where;
- }
-
- int term;
- unsigned matchBegin;
- unsigned matchEnd;
- uintptr_t frame[1];
- };
-
- DisjunctionContext* allocDisjunctionContext(ByteDisjunction* disjunction)
- {
- return new(malloc(sizeof(DisjunctionContext) + (disjunction->m_frameSize - 1) * sizeof(uintptr_t))) DisjunctionContext();
- }
-
- void freeDisjunctionContext(DisjunctionContext* context)
- {
- free(context);
- }
-
- struct ParenthesesDisjunctionContext
- {
- ParenthesesDisjunctionContext(int* output, ByteTerm& term)
- : next(0)
- {
- unsigned firstSubpatternId = term.atom.subpatternId;
- unsigned numNestedSubpatterns = term.atom.parenthesesDisjunction->m_numSubpatterns;
-
- for (unsigned i = 0; i < (numNestedSubpatterns << 1); ++i) {
- subpatternBackup[i] = output[(firstSubpatternId << 1) + i];
- output[(firstSubpatternId << 1) + i] = -1;
- }
-
- new(getDisjunctionContext(term)) DisjunctionContext();
- }
-
- void* operator new(size_t, void* where)
- {
- return where;
- }
-
- void restoreOutput(int* output, unsigned firstSubpatternId, unsigned numNestedSubpatterns)
- {
- for (unsigned i = 0; i < (numNestedSubpatterns << 1); ++i)
- output[(firstSubpatternId << 1) + i] = subpatternBackup[i];
- }
-
- DisjunctionContext* getDisjunctionContext(ByteTerm& term)
- {
- return reinterpret_cast<DisjunctionContext*>(&(subpatternBackup[term.atom.parenthesesDisjunction->m_numSubpatterns << 1]));
- }
-
- ParenthesesDisjunctionContext* next;
- int subpatternBackup[1];
- };
-
- ParenthesesDisjunctionContext* allocParenthesesDisjunctionContext(ByteDisjunction* disjunction, int* output, ByteTerm& term)
- {
- return new(malloc(sizeof(ParenthesesDisjunctionContext) + (((term.atom.parenthesesDisjunction->m_numSubpatterns << 1) - 1) * sizeof(int)) + sizeof(DisjunctionContext) + (disjunction->m_frameSize - 1) * sizeof(uintptr_t))) ParenthesesDisjunctionContext(output, term);
- }
-
- void freeParenthesesDisjunctionContext(ParenthesesDisjunctionContext* context)
- {
- free(context);
- }
-
- class InputStream {
- public:
- InputStream(const UChar* input, unsigned start, unsigned length)
- : input(input)
- , pos(start)
- , length(length)
- {
- }
-
- void next()
- {
- ++pos;
- }
-
- void rewind(unsigned amount)
- {
- ASSERT(pos >= amount);
- pos -= amount;
- }
-
- int read()
- {
- ASSERT(pos < length);
- if (pos < length)
- return input[pos];
- return -1;
- }
-
- int readChecked(int position)
- {
- ASSERT(position < 0);
- ASSERT((unsigned)-position <= pos);
- unsigned p = pos + position;
- ASSERT(p < length);
- return input[p];
- }
-
- int reread(unsigned from)
- {
- ASSERT(from < length);
- return input[from];
- }
-
- int prev()
- {
- ASSERT(!(pos > length));
- if (pos && length)
- return input[pos - 1];
- return -1;
- }
-
- unsigned getPos()
- {
- return pos;
- }
-
- void setPos(unsigned p)
- {
- pos = p;
- }
-
- bool atStart()
- {
- return pos == 0;
- }
-
- bool atEnd()
- {
- return pos == length;
- }
-
- bool checkInput(int count)
- {
- if ((pos + count) <= length) {
- pos += count;
- return true;
- } else
- return false;
- }
-
- void uncheckInput(int count)
- {
- pos -= count;
- }
-
- bool atStart(int position)
- {
- return (pos + position) == 0;
- }
-
- bool atEnd(int position)
- {
- return (pos + position) == length;
- }
-
- private:
- const UChar* input;
- unsigned pos;
- unsigned length;
- };
-
- bool testCharacterClass(CharacterClass* characterClass, int ch)
- {
- if (ch & 0xFF80) {
- for (unsigned i = 0; i < characterClass->m_matchesUnicode.size(); ++i)
- if (ch == characterClass->m_matchesUnicode[i])
- return true;
- for (unsigned i = 0; i < characterClass->m_rangesUnicode.size(); ++i)
- if ((ch >= characterClass->m_rangesUnicode[i].begin) && (ch <= characterClass->m_rangesUnicode[i].end))
- return true;
- } else {
- for (unsigned i = 0; i < characterClass->m_matches.size(); ++i)
- if (ch == characterClass->m_matches[i])
- return true;
- for (unsigned i = 0; i < characterClass->m_ranges.size(); ++i)
- if ((ch >= characterClass->m_ranges[i].begin) && (ch <= characterClass->m_ranges[i].end))
- return true;
- }
-
- return false;
- }
-
- bool checkCharacter(int testChar, int inputPosition)
- {
- return testChar == input.readChecked(inputPosition);
- }
-
- bool checkCasedCharacter(int loChar, int hiChar, int inputPosition)
- {
- int ch = input.readChecked(inputPosition);
- return (loChar == ch) || (hiChar == ch);
- }
-
- bool checkCharacterClass(CharacterClass* characterClass, bool invert, int inputPosition)
- {
- bool match = testCharacterClass(characterClass, input.readChecked(inputPosition));
- return invert ? !match : match;
- }
-
- bool tryConsumeBackReference(int matchBegin, int matchEnd, int inputOffset)
- {
- int matchSize = matchEnd - matchBegin;
-
- if (!input.checkInput(matchSize))
- return false;
-
- for (int i = 0; i < matchSize; ++i) {
- if (!checkCharacter(input.reread(matchBegin + i), inputOffset - matchSize + i)) {
- input.uncheckInput(matchSize);
- return false;
- }
- }
-
- return true;
- }
-
- bool matchAssertionBOL(ByteTerm& term)
- {
- return (input.atStart(term.inputPosition)) || (pattern->m_multiline && testCharacterClass(pattern->newlineCharacterClass, input.readChecked(term.inputPosition - 1)));
- }
-
- bool matchAssertionEOL(ByteTerm& term)
- {
- if (term.inputPosition)
- return (input.atEnd(term.inputPosition)) || (pattern->m_multiline && testCharacterClass(pattern->newlineCharacterClass, input.readChecked(term.inputPosition)));
- else
- return (input.atEnd()) || (pattern->m_multiline && testCharacterClass(pattern->newlineCharacterClass, input.read()));
- }
-
- bool matchAssertionWordBoundary(ByteTerm& term)
- {
- bool prevIsWordchar = !input.atStart(term.inputPosition) && testCharacterClass(pattern->wordcharCharacterClass, input.readChecked(term.inputPosition - 1));
- bool readIsWordchar;
- if (term.inputPosition)
- readIsWordchar = !input.atEnd(term.inputPosition) && testCharacterClass(pattern->wordcharCharacterClass, input.readChecked(term.inputPosition));
- else
- readIsWordchar = !input.atEnd() && testCharacterClass(pattern->wordcharCharacterClass, input.read());
-
- bool wordBoundary = prevIsWordchar != readIsWordchar;
- return term.invert() ? !wordBoundary : wordBoundary;
- }
-
- bool backtrackPatternCharacter(ByteTerm& term, DisjunctionContext* context)
- {
- BackTrackInfoPatternCharacter* backTrack = reinterpret_cast<BackTrackInfoPatternCharacter*>(context->frame + term.frameLocation);
-
- switch (term.atom.quantityType) {
- case QuantifierFixedCount:
- break;
-
- case QuantifierGreedy:
- if (backTrack->matchAmount) {
- --backTrack->matchAmount;
- input.uncheckInput(1);
- return true;
- }
- break;
-
- case QuantifierNonGreedy:
- if ((backTrack->matchAmount < term.atom.quantityCount) && input.checkInput(1)) {
- ++backTrack->matchAmount;
- if (checkCharacter(term.atom.patternCharacter, term.inputPosition - 1))
- return true;
- }
- input.uncheckInput(backTrack->matchAmount);
- break;
- }
-
- return false;
- }
-
- bool backtrackPatternCasedCharacter(ByteTerm& term, DisjunctionContext* context)
- {
- BackTrackInfoPatternCharacter* backTrack = reinterpret_cast<BackTrackInfoPatternCharacter*>(context->frame + term.frameLocation);
-
- switch (term.atom.quantityType) {
- case QuantifierFixedCount:
- break;
-
- case QuantifierGreedy:
- if (backTrack->matchAmount) {
- --backTrack->matchAmount;
- input.uncheckInput(1);
- return true;
- }
- break;
-
- case QuantifierNonGreedy:
- if ((backTrack->matchAmount < term.atom.quantityCount) && input.checkInput(1)) {
- ++backTrack->matchAmount;
- if (checkCasedCharacter(term.atom.casedCharacter.lo, term.atom.casedCharacter.hi, term.inputPosition - 1))
- return true;
- }
- input.uncheckInput(backTrack->matchAmount);
- break;
- }
-
- return false;
- }
-
- bool matchCharacterClass(ByteTerm& term, DisjunctionContext* context)
- {
- ASSERT(term.type == ByteTerm::TypeCharacterClass);
- BackTrackInfoPatternCharacter* backTrack = reinterpret_cast<BackTrackInfoPatternCharacter*>(context->frame + term.frameLocation);
-
- switch (term.atom.quantityType) {
- case QuantifierFixedCount: {
- for (unsigned matchAmount = 0; matchAmount < term.atom.quantityCount; ++matchAmount) {
- if (!checkCharacterClass(term.atom.characterClass, term.invert(), term.inputPosition + matchAmount))
- return false;
- }
- return true;
- }
-
- case QuantifierGreedy: {
- unsigned matchAmount = 0;
- while ((matchAmount < term.atom.quantityCount) && input.checkInput(1)) {
- if (!checkCharacterClass(term.atom.characterClass, term.invert(), term.inputPosition - 1)) {
- input.uncheckInput(1);
- break;
- }
- ++matchAmount;
- }
- backTrack->matchAmount = matchAmount;
-
- return true;
- }
-
- case QuantifierNonGreedy:
- backTrack->matchAmount = 0;
- return true;
- }
-
- ASSERT_NOT_REACHED();
- return false;
- }
-
- bool backtrackCharacterClass(ByteTerm& term, DisjunctionContext* context)
- {
- ASSERT(term.type == ByteTerm::TypeCharacterClass);
- BackTrackInfoPatternCharacter* backTrack = reinterpret_cast<BackTrackInfoPatternCharacter*>(context->frame + term.frameLocation);
-
- switch (term.atom.quantityType) {
- case QuantifierFixedCount:
- break;
-
- case QuantifierGreedy:
- if (backTrack->matchAmount) {
- --backTrack->matchAmount;
- input.uncheckInput(1);
- return true;
- }
- break;
-
- case QuantifierNonGreedy:
- if ((backTrack->matchAmount < term.atom.quantityCount) && input.checkInput(1)) {
- ++backTrack->matchAmount;
- if (checkCharacterClass(term.atom.characterClass, term.invert(), term.inputPosition - 1))
- return true;
- }
- input.uncheckInput(backTrack->matchAmount);
- break;
- }
-
- return false;
- }
-
- bool matchBackReference(ByteTerm& term, DisjunctionContext* context)
- {
- ASSERT(term.type == ByteTerm::TypeBackReference);
- BackTrackInfoBackReference* backTrack = reinterpret_cast<BackTrackInfoBackReference*>(context->frame + term.frameLocation);
-
- int matchBegin = output[(term.atom.subpatternId << 1)];
- int matchEnd = output[(term.atom.subpatternId << 1) + 1];
- ASSERT((matchBegin == -1) == (matchEnd == -1));
- ASSERT(matchBegin <= matchEnd);
-
- if (matchBegin == matchEnd)
- return true;
-
- switch (term.atom.quantityType) {
- case QuantifierFixedCount: {
- backTrack->begin = input.getPos();
- for (unsigned matchAmount = 0; matchAmount < term.atom.quantityCount; ++matchAmount) {
- if (!tryConsumeBackReference(matchBegin, matchEnd, term.inputPosition)) {
- input.setPos(backTrack->begin);
- return false;
- }
- }
- return true;
- }
-
- case QuantifierGreedy: {
- unsigned matchAmount = 0;
- while ((matchAmount < term.atom.quantityCount) && tryConsumeBackReference(matchBegin, matchEnd, term.inputPosition))
- ++matchAmount;
- backTrack->matchAmount = matchAmount;
- return true;
- }
-
- case QuantifierNonGreedy:
- backTrack->begin = input.getPos();
- backTrack->matchAmount = 0;
- return true;
- }
-
- ASSERT_NOT_REACHED();
- return false;
- }
-
- bool backtrackBackReference(ByteTerm& term, DisjunctionContext* context)
- {
- ASSERT(term.type == ByteTerm::TypeBackReference);
- BackTrackInfoBackReference* backTrack = reinterpret_cast<BackTrackInfoBackReference*>(context->frame + term.frameLocation);
-
- int matchBegin = output[(term.atom.subpatternId << 1)];
- int matchEnd = output[(term.atom.subpatternId << 1) + 1];
- ASSERT((matchBegin == -1) == (matchEnd == -1));
- ASSERT(matchBegin <= matchEnd);
-
- if (matchBegin == matchEnd)
- return false;
-
- switch (term.atom.quantityType) {
- case QuantifierFixedCount:
- // for quantityCount == 1, could rewind.
- input.setPos(backTrack->begin);
- break;
-
- case QuantifierGreedy:
- if (backTrack->matchAmount) {
- --backTrack->matchAmount;
- input.rewind(matchEnd - matchBegin);
- return true;
- }
- break;
-
- case QuantifierNonGreedy:
- if ((backTrack->matchAmount < term.atom.quantityCount) && tryConsumeBackReference(matchBegin, matchEnd, term.inputPosition)) {
- ++backTrack->matchAmount;
- return true;
- } else
- input.setPos(backTrack->begin);
- break;
- }
-
- return false;
- }
-
- void recordParenthesesMatch(ByteTerm& term, ParenthesesDisjunctionContext* context)
- {
- if (term.capture()) {
- unsigned subpatternId = term.atom.subpatternId;
- output[(subpatternId << 1)] = context->getDisjunctionContext(term)->matchBegin + term.inputPosition;
- output[(subpatternId << 1) + 1] = context->getDisjunctionContext(term)->matchEnd + term.inputPosition;
- }
- }
- void resetMatches(ByteTerm& term, ParenthesesDisjunctionContext* context)
- {
- unsigned firstSubpatternId = term.atom.subpatternId;
- unsigned count = term.atom.parenthesesDisjunction->m_numSubpatterns;
- context->restoreOutput(output, firstSubpatternId, count);
- }
- void resetAssertionMatches(ByteTerm& term)
- {
- unsigned firstSubpatternId = term.atom.subpatternId;
- unsigned count = term.atom.parenthesesDisjunction->m_numSubpatterns;
- for (unsigned i = 0; i < (count << 1); ++i)
- output[(firstSubpatternId << 1) + i] = -1;
- }
- bool parenthesesDoBacktrack(ByteTerm& term, BackTrackInfoParentheses* backTrack)
- {
- while (backTrack->matchAmount) {
- ParenthesesDisjunctionContext* context = backTrack->lastContext;
-
- if (matchDisjunction(term.atom.parenthesesDisjunction, context->getDisjunctionContext(term), true))
- return true;
-
- resetMatches(term, context);
- popParenthesesDisjunctionContext(backTrack);
- freeParenthesesDisjunctionContext(context);
- }
-
- return false;
- }
-
- bool matchParenthesesOnceBegin(ByteTerm& term, DisjunctionContext* context)
- {
- ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceBegin);
- ASSERT(term.atom.quantityCount == 1);
-
- BackTrackInfoParenthesesOnce* backTrack = reinterpret_cast<BackTrackInfoParenthesesOnce*>(context->frame + term.frameLocation);
-
- switch (term.atom.quantityType) {
- case QuantifierGreedy: {
- // set this speculatively; if we get to the parens end this will be true.
- backTrack->inParentheses = 1;
- break;
- }
- case QuantifierNonGreedy: {
- backTrack->inParentheses = 0;
- context->term += term.atom.parenthesesWidth;
- return true;
- }
- case QuantifierFixedCount:
- break;
- }
-
- if (term.capture()) {
- unsigned subpatternId = term.atom.subpatternId;
- output[(subpatternId << 1)] = input.getPos() + term.inputPosition;
- }
-
- return true;
- }
-
- bool matchParenthesesOnceEnd(ByteTerm& term, DisjunctionContext*)
- {
- ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceEnd);
- ASSERT(term.atom.quantityCount == 1);
-
- if (term.capture()) {
- unsigned subpatternId = term.atom.subpatternId;
- output[(subpatternId << 1) + 1] = input.getPos() + term.inputPosition;
- }
- return true;
- }
-
- bool backtrackParenthesesOnceBegin(ByteTerm& term, DisjunctionContext* context)
- {
- ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceBegin);
- ASSERT(term.atom.quantityCount == 1);
-
- BackTrackInfoParenthesesOnce* backTrack = reinterpret_cast<BackTrackInfoParenthesesOnce*>(context->frame + term.frameLocation);
-
- if (term.capture()) {
- unsigned subpatternId = term.atom.subpatternId;
- output[(subpatternId << 1)] = -1;
- output[(subpatternId << 1) + 1] = -1;
- }
-
- switch (term.atom.quantityType) {
- case QuantifierGreedy:
- // if we backtrack to this point, there is another chance - try matching nothing.
- ASSERT(backTrack->inParentheses);
- backTrack->inParentheses = 0;
- context->term += term.atom.parenthesesWidth;
- return true;
- case QuantifierNonGreedy:
- ASSERT(backTrack->inParentheses);
- case QuantifierFixedCount:
- break;
- }
-
- return false;
- }
-
- bool backtrackParenthesesOnceEnd(ByteTerm& term, DisjunctionContext* context)
- {
- ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceEnd);
- ASSERT(term.atom.quantityCount == 1);
-
- BackTrackInfoParenthesesOnce* backTrack = reinterpret_cast<BackTrackInfoParenthesesOnce*>(context->frame + term.frameLocation);
-
- switch (term.atom.quantityType) {
- case QuantifierGreedy:
- if (!backTrack->inParentheses) {
- context->term -= term.atom.parenthesesWidth;
- return false;
- }
- case QuantifierNonGreedy:
- if (!backTrack->inParentheses) {
- // now try to match the parens; set this speculatively.
- backTrack->inParentheses = 1;
- if (term.capture()) {
- unsigned subpatternId = term.atom.subpatternId;
- output[(subpatternId << 1) + 1] = input.getPos() + term.inputPosition;
- }
- context->term -= term.atom.parenthesesWidth;
- return true;
- }
- case QuantifierFixedCount:
- break;
- }
-
- return false;
- }
-
- bool matchParentheticalAssertionBegin(ByteTerm& term, DisjunctionContext* context)
- {
- ASSERT(term.type == ByteTerm::TypeParentheticalAssertionBegin);
- ASSERT(term.atom.quantityCount == 1);
-
- BackTrackInfoParentheticalAssertion* backTrack = reinterpret_cast<BackTrackInfoParentheticalAssertion*>(context->frame + term.frameLocation);
-
- backTrack->begin = input.getPos();
- return true;
- }
-
- bool matchParentheticalAssertionEnd(ByteTerm& term, DisjunctionContext* context)
- {
- ASSERT(term.type == ByteTerm::TypeParentheticalAssertionEnd);
- ASSERT(term.atom.quantityCount == 1);
-
- BackTrackInfoParentheticalAssertion* backTrack = reinterpret_cast<BackTrackInfoParentheticalAssertion*>(context->frame + term.frameLocation);
-
- input.setPos(backTrack->begin);
-
- // We've reached the end of the parens; if they are inverted, this is failure.
- if (term.invert()) {
- context->term -= term.atom.parenthesesWidth;
- return false;
- }
-
- return true;
- }
-
- bool backtrackParentheticalAssertionBegin(ByteTerm& term, DisjunctionContext* context)
- {
- ASSERT(term.type == ByteTerm::TypeParentheticalAssertionBegin);
- ASSERT(term.atom.quantityCount == 1);
-
- // We've failed to match parens; if they are inverted, this is win!
- if (term.invert()) {
- context->term += term.atom.parenthesesWidth;
- return true;
- }
-
- return false;
- }
-
- bool backtrackParentheticalAssertionEnd(ByteTerm& term, DisjunctionContext* context)
- {
- ASSERT(term.type == ByteTerm::TypeParentheticalAssertionEnd);
- ASSERT(term.atom.quantityCount == 1);
-
- BackTrackInfoParentheticalAssertion* backTrack = reinterpret_cast<BackTrackInfoParentheticalAssertion*>(context->frame + term.frameLocation);
-
- input.setPos(backTrack->begin);
-
- context->term -= term.atom.parenthesesWidth;
- return false;
- }
-
- bool matchParentheses(ByteTerm& term, DisjunctionContext* context)
- {
- ASSERT(term.type == ByteTerm::TypeParenthesesSubpattern);
-
- BackTrackInfoParentheses* backTrack = reinterpret_cast<BackTrackInfoParentheses*>(context->frame + term.frameLocation);
-
- unsigned subpatternId = term.atom.subpatternId;
- ByteDisjunction* disjunctionBody = term.atom.parenthesesDisjunction;
-
- backTrack->prevBegin = output[(subpatternId << 1)];
- backTrack->prevEnd = output[(subpatternId << 1) + 1];
-
- backTrack->matchAmount = 0;
- backTrack->lastContext = 0;
-
- switch (term.atom.quantityType) {
- case QuantifierFixedCount: {
- // While we haven't yet reached our fixed limit,
- while (backTrack->matchAmount < term.atom.quantityCount) {
- // Try to do a match, and it it succeeds, add it to the list.
- ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term);
- if (matchDisjunction(disjunctionBody, context->getDisjunctionContext(term)))
- appendParenthesesDisjunctionContext(backTrack, context);
- else {
- // The match failed; try to find an alternate point to carry on from.
- resetMatches(term, context);
- freeParenthesesDisjunctionContext(context);
- if (!parenthesesDoBacktrack(term, backTrack))
- return false;
- }
- }
-
- ASSERT(backTrack->matchAmount == term.atom.quantityCount);
- ParenthesesDisjunctionContext* context = backTrack->lastContext;
- recordParenthesesMatch(term, context);
- return true;
- }
-
- case QuantifierGreedy: {
- while (backTrack->matchAmount < term.atom.quantityCount) {
- ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term);
- if (matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term)))
- appendParenthesesDisjunctionContext(backTrack, context);
- else {
- resetMatches(term, context);
- freeParenthesesDisjunctionContext(context);
- break;
- }
- }
-
- if (backTrack->matchAmount) {
- ParenthesesDisjunctionContext* context = backTrack->lastContext;
- recordParenthesesMatch(term, context);
- }
- return true;
- }
-
- case QuantifierNonGreedy:
- return true;
- }
-
- ASSERT_NOT_REACHED();
- return false;
- }
-
- // Rules for backtracking differ depending on whether this is greedy or non-greedy.
- //
- // Greedy matches never should try just adding more - you should already have done
- // the 'more' cases. Always backtrack, at least a leetle bit. However cases where
- // you backtrack an item off the list needs checking, since we'll never have matched
- // the one less case. Tracking forwards, still add as much as possible.
- //
- // Non-greedy, we've already done the one less case, so don't match on popping.
- // We haven't done the one more case, so always try to add that.
- //
- bool backtrackParentheses(ByteTerm& term, DisjunctionContext* context)
- {
- ASSERT(term.type == ByteTerm::TypeParenthesesSubpattern);
-
- BackTrackInfoParentheses* backTrack = reinterpret_cast<BackTrackInfoParentheses*>(context->frame + term.frameLocation);
-
- if (term.capture()) {
- unsigned subpatternId = term.atom.subpatternId;
- output[(subpatternId << 1)] = backTrack->prevBegin;
- output[(subpatternId << 1) + 1] = backTrack->prevEnd;
- }
-
- ByteDisjunction* disjunctionBody = term.atom.parenthesesDisjunction;
-
- switch (term.atom.quantityType) {
- case QuantifierFixedCount: {
- ASSERT(backTrack->matchAmount == term.atom.quantityCount);
-
- ParenthesesDisjunctionContext* context = 0;
-
- if (!parenthesesDoBacktrack(term, backTrack))
- return false;
-
- // While we haven't yet reached our fixed limit,
- while (backTrack->matchAmount < term.atom.quantityCount) {
- // Try to do a match, and it it succeeds, add it to the list.
- context = allocParenthesesDisjunctionContext(disjunctionBody, output, term);
- if (matchDisjunction(disjunctionBody, context->getDisjunctionContext(term)))
- appendParenthesesDisjunctionContext(backTrack, context);
- else {
- // The match failed; try to find an alternate point to carry on from.
- resetMatches(term, context);
- freeParenthesesDisjunctionContext(context);
- if (!parenthesesDoBacktrack(term, backTrack))
- return false;
- }
- }
-
- ASSERT(backTrack->matchAmount == term.atom.quantityCount);
- context = backTrack->lastContext;
- recordParenthesesMatch(term, context);
- return true;
- }
-
- case QuantifierGreedy: {
- if (!backTrack->matchAmount)
- return false;
-
- ParenthesesDisjunctionContext* context = backTrack->lastContext;
- if (matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term), true)) {
- while (backTrack->matchAmount < term.atom.quantityCount) {
- ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term);
- if (matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term)))
- appendParenthesesDisjunctionContext(backTrack, context);
- else {
- resetMatches(term, context);
- freeParenthesesDisjunctionContext(context);
- break;
- }
- }
- } else {
- resetMatches(term, context);
- popParenthesesDisjunctionContext(backTrack);
- freeParenthesesDisjunctionContext(context);
- }
-
- if (backTrack->matchAmount) {
- ParenthesesDisjunctionContext* context = backTrack->lastContext;
- recordParenthesesMatch(term, context);
- }
- return true;
- }
-
- case QuantifierNonGreedy: {
- // If we've not reached the limit, try to add one more match.
- if (backTrack->matchAmount < term.atom.quantityCount) {
- ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term);
- if (matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term))) {
- appendParenthesesDisjunctionContext(backTrack, context);
- recordParenthesesMatch(term, context);
- return true;
- } else {
- resetMatches(term, context);
- freeParenthesesDisjunctionContext(context);
- }
- }
-
- // Nope - okay backtrack looking for an alternative.
- while (backTrack->matchAmount) {
- ParenthesesDisjunctionContext* context = backTrack->lastContext;
- if (matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term), true)) {
- // successful backtrack! we're back in the game!
- if (backTrack->matchAmount) {
- context = backTrack->lastContext;
- recordParenthesesMatch(term, context);
- }
- return true;
- }
-
- // pop a match off the stack
- resetMatches(term, context);
- popParenthesesDisjunctionContext(backTrack);
- freeParenthesesDisjunctionContext(context);
- }
-
- return false;
- }
- }
-
- ASSERT_NOT_REACHED();
- return false;
- }
-
-#define MATCH_NEXT() { ++context->term; goto matchAgain; }
-#define BACKTRACK() { --context->term; goto backtrack; }
-#define currentTerm() (disjunction->terms[context->term])
- bool matchDisjunction(ByteDisjunction* disjunction, DisjunctionContext* context, bool btrack = false)
- {
- if (btrack)
- BACKTRACK();
-
- context->matchBegin = input.getPos();
- context->term = 0;
-
- matchAgain:
- ASSERT(context->term < static_cast<int>(disjunction->terms.size()));
-
- switch (currentTerm().type) {
- case ByteTerm::TypeSubpatternBegin:
- MATCH_NEXT();
- case ByteTerm::TypeSubpatternEnd:
- context->matchEnd = input.getPos();
- return true;
-
- case ByteTerm::TypeBodyAlternativeBegin:
- MATCH_NEXT();
- case ByteTerm::TypeBodyAlternativeDisjunction:
- case ByteTerm::TypeBodyAlternativeEnd:
- context->matchEnd = input.getPos();
- return true;
-
- case ByteTerm::TypeAlternativeBegin:
- MATCH_NEXT();
- case ByteTerm::TypeAlternativeDisjunction:
- case ByteTerm::TypeAlternativeEnd: {
- int offset = currentTerm().alternative.end;
- BackTrackInfoAlternative* backTrack = reinterpret_cast<BackTrackInfoAlternative*>(context->frame + currentTerm().frameLocation);
- backTrack->offset = offset;
- context->term += offset;
- MATCH_NEXT();
- }
-
- case ByteTerm::TypeAssertionBOL:
- if (matchAssertionBOL(currentTerm()))
- MATCH_NEXT();
- BACKTRACK();
- case ByteTerm::TypeAssertionEOL:
- if (matchAssertionEOL(currentTerm()))
- MATCH_NEXT();
- BACKTRACK();
- case ByteTerm::TypeAssertionWordBoundary:
- if (matchAssertionWordBoundary(currentTerm()))
- MATCH_NEXT();
- BACKTRACK();
-
- case ByteTerm::TypePatternCharacterOnce:
- case ByteTerm::TypePatternCharacterFixed: {
- for (unsigned matchAmount = 0; matchAmount < currentTerm().atom.quantityCount; ++matchAmount) {
- if (!checkCharacter(currentTerm().atom.patternCharacter, currentTerm().inputPosition + matchAmount))
- BACKTRACK();
- }
- MATCH_NEXT();
- }
- case ByteTerm::TypePatternCharacterGreedy: {
- BackTrackInfoPatternCharacter* backTrack = reinterpret_cast<BackTrackInfoPatternCharacter*>(context->frame + currentTerm().frameLocation);
- unsigned matchAmount = 0;
- while ((matchAmount < currentTerm().atom.quantityCount) && input.checkInput(1)) {
- if (!checkCharacter(currentTerm().atom.patternCharacter, currentTerm().inputPosition - 1)) {
- input.uncheckInput(1);
- break;
- }
- ++matchAmount;
- }
- backTrack->matchAmount = matchAmount;
-
- MATCH_NEXT();
- }
- case ByteTerm::TypePatternCharacterNonGreedy: {
- BackTrackInfoPatternCharacter* backTrack = reinterpret_cast<BackTrackInfoPatternCharacter*>(context->frame + currentTerm().frameLocation);
- backTrack->matchAmount = 0;
- MATCH_NEXT();
- }
-
- case ByteTerm::TypePatternCasedCharacterOnce:
- case ByteTerm::TypePatternCasedCharacterFixed: {
- for (unsigned matchAmount = 0; matchAmount < currentTerm().atom.quantityCount; ++matchAmount) {
- if (!checkCasedCharacter(currentTerm().atom.casedCharacter.lo, currentTerm().atom.casedCharacter.hi, currentTerm().inputPosition + matchAmount))
- BACKTRACK();
- }
- MATCH_NEXT();
- }
- case ByteTerm::TypePatternCasedCharacterGreedy: {
- BackTrackInfoPatternCharacter* backTrack = reinterpret_cast<BackTrackInfoPatternCharacter*>(context->frame + currentTerm().frameLocation);
- unsigned matchAmount = 0;
- while ((matchAmount < currentTerm().atom.quantityCount) && input.checkInput(1)) {
- if (!checkCasedCharacter(currentTerm().atom.casedCharacter.lo, currentTerm().atom.casedCharacter.hi, currentTerm().inputPosition - 1)) {
- input.uncheckInput(1);
- break;
- }
- ++matchAmount;
- }
- backTrack->matchAmount = matchAmount;
-
- MATCH_NEXT();
- }
- case ByteTerm::TypePatternCasedCharacterNonGreedy: {
- BackTrackInfoPatternCharacter* backTrack = reinterpret_cast<BackTrackInfoPatternCharacter*>(context->frame + currentTerm().frameLocation);
- backTrack->matchAmount = 0;
- MATCH_NEXT();
- }
-
- case ByteTerm::TypeCharacterClass:
- if (matchCharacterClass(currentTerm(), context))
- MATCH_NEXT();
- BACKTRACK();
- case ByteTerm::TypeBackReference:
- if (matchBackReference(currentTerm(), context))
- MATCH_NEXT();
- BACKTRACK();
- case ByteTerm::TypeParenthesesSubpattern:
- if (matchParentheses(currentTerm(), context))
- MATCH_NEXT();
- BACKTRACK();
- case ByteTerm::TypeParenthesesSubpatternOnceBegin:
- if (matchParenthesesOnceBegin(currentTerm(), context))
- MATCH_NEXT();
- BACKTRACK();
- case ByteTerm::TypeParenthesesSubpatternOnceEnd:
- if (matchParenthesesOnceEnd(currentTerm(), context))
- MATCH_NEXT();
- BACKTRACK();
- case ByteTerm::TypeParentheticalAssertionBegin:
- if (matchParentheticalAssertionBegin(currentTerm(), context))
- MATCH_NEXT();
- BACKTRACK();
- case ByteTerm::TypeParentheticalAssertionEnd:
- if (matchParentheticalAssertionEnd(currentTerm(), context))
- MATCH_NEXT();
- BACKTRACK();
-
- case ByteTerm::TypeCheckInput:
- if (input.checkInput(currentTerm().checkInputCount))
- MATCH_NEXT();
- BACKTRACK();
- }
-
- // We should never fall-through to here.
- ASSERT_NOT_REACHED();
-
- backtrack:
- ASSERT(context->term < static_cast<int>(disjunction->terms.size()));
-
- switch (currentTerm().type) {
- case ByteTerm::TypeSubpatternBegin:
- return false;
- case ByteTerm::TypeSubpatternEnd:
- ASSERT_NOT_REACHED();
-
- case ByteTerm::TypeBodyAlternativeBegin:
- case ByteTerm::TypeBodyAlternativeDisjunction: {
- int offset = currentTerm().alternative.next;
- context->term += offset;
- if (offset > 0)
- MATCH_NEXT();
-
- if (input.atEnd())
- return false;
-
- input.next();
- context->matchBegin = input.getPos();
- MATCH_NEXT();
- }
- case ByteTerm::TypeBodyAlternativeEnd:
- ASSERT_NOT_REACHED();
-
- case ByteTerm::TypeAlternativeBegin:
- case ByteTerm::TypeAlternativeDisjunction: {
- int offset = currentTerm().alternative.next;
- context->term += offset;
- if (offset > 0)
- MATCH_NEXT();
- BACKTRACK();
- }
- case ByteTerm::TypeAlternativeEnd: {
- // We should never backtrack back into an alternative of the main body of the regex.
- BackTrackInfoAlternative* backTrack = reinterpret_cast<BackTrackInfoAlternative*>(context->frame + currentTerm().frameLocation);
- unsigned offset = backTrack->offset;
- context->term -= offset;
- BACKTRACK();
- }
-
- case ByteTerm::TypeAssertionBOL:
- case ByteTerm::TypeAssertionEOL:
- case ByteTerm::TypeAssertionWordBoundary:
- BACKTRACK();
-
- case ByteTerm::TypePatternCharacterOnce:
- case ByteTerm::TypePatternCharacterFixed:
- case ByteTerm::TypePatternCharacterGreedy:
- case ByteTerm::TypePatternCharacterNonGreedy:
- if (backtrackPatternCharacter(currentTerm(), context))
- MATCH_NEXT();
- BACKTRACK();
- case ByteTerm::TypePatternCasedCharacterOnce:
- case ByteTerm::TypePatternCasedCharacterFixed:
- case ByteTerm::TypePatternCasedCharacterGreedy:
- case ByteTerm::TypePatternCasedCharacterNonGreedy:
- if (backtrackPatternCasedCharacter(currentTerm(), context))
- MATCH_NEXT();
- BACKTRACK();
- case ByteTerm::TypeCharacterClass:
- if (backtrackCharacterClass(currentTerm(), context))
- MATCH_NEXT();
- BACKTRACK();
- case ByteTerm::TypeBackReference:
- if (backtrackBackReference(currentTerm(), context))
- MATCH_NEXT();
- BACKTRACK();
- case ByteTerm::TypeParenthesesSubpattern:
- if (backtrackParentheses(currentTerm(), context))
- MATCH_NEXT();
- BACKTRACK();
- case ByteTerm::TypeParenthesesSubpatternOnceBegin:
- if (backtrackParenthesesOnceBegin(currentTerm(), context))
- MATCH_NEXT();
- BACKTRACK();
- case ByteTerm::TypeParenthesesSubpatternOnceEnd:
- if (backtrackParenthesesOnceEnd(currentTerm(), context))
- MATCH_NEXT();
- BACKTRACK();
- case ByteTerm::TypeParentheticalAssertionBegin:
- if (backtrackParentheticalAssertionBegin(currentTerm(), context))
- MATCH_NEXT();
- BACKTRACK();
- case ByteTerm::TypeParentheticalAssertionEnd:
- if (backtrackParentheticalAssertionEnd(currentTerm(), context))
- MATCH_NEXT();
- BACKTRACK();
-
- case ByteTerm::TypeCheckInput:
- input.uncheckInput(currentTerm().checkInputCount);
- BACKTRACK();
- }
-
- ASSERT_NOT_REACHED();
- return false;
- }
-
- bool matchNonZeroDisjunction(ByteDisjunction* disjunction, DisjunctionContext* context, bool btrack = false)
- {
- if (matchDisjunction(disjunction, context, btrack)) {
- while (context->matchBegin == context->matchEnd) {
- if (!matchDisjunction(disjunction, context, true))
- return false;
- }
- return true;
- }
-
- return false;
- }
-
- int interpret()
- {
- for (unsigned i = 0; i < ((pattern->m_body->m_numSubpatterns + 1) << 1); ++i)
- output[i] = -1;
-
- DisjunctionContext* context = allocDisjunctionContext(pattern->m_body.get());
-
- if (matchDisjunction(pattern->m_body.get(), context)) {
- output[0] = context->matchBegin;
- output[1] = context->matchEnd;
- }
-
- freeDisjunctionContext(context);
-
- return output[0];
- }
-
- Interpreter(BytecodePattern* pattern, int* output, const UChar* inputChar, unsigned start, unsigned length)
- : pattern(pattern)
- , output(output)
- , input(inputChar, start, length)
- {
- }
-
-private:
- BytecodePattern *pattern;
- int* output;
- InputStream input;
-};
-
-
-
-class ByteCompiler {
- struct ParenthesesStackEntry {
- unsigned beginTerm;
- unsigned savedAlternativeIndex;
- ParenthesesStackEntry(unsigned beginTerm, unsigned savedAlternativeIndex/*, unsigned subpatternId, bool capture = false*/)
- : beginTerm(beginTerm)
- , savedAlternativeIndex(savedAlternativeIndex)
- {
- }
- };
-
-public:
- ByteCompiler(RegexPattern& pattern)
- : m_pattern(pattern)
- {
- m_bodyDisjunction = 0;
- m_currentAlternativeIndex = 0;
- }
-
- BytecodePattern* compile()
- {
- regexBegin(m_pattern.m_numSubpatterns, m_pattern.m_body->m_callFrameSize);
- emitDisjunction(m_pattern.m_body);
- regexEnd();
-
- return new BytecodePattern(m_bodyDisjunction, m_allParenthesesInfo, m_pattern);
- }
-
- void checkInput(unsigned count)
- {
- m_bodyDisjunction->terms.append(ByteTerm::CheckInput(count));
- }
-
- void assertionBOL(int inputPosition)
- {
- m_bodyDisjunction->terms.append(ByteTerm::BOL(inputPosition));
- }
-
- void assertionEOL(int inputPosition)
- {
- m_bodyDisjunction->terms.append(ByteTerm::EOL(inputPosition));
- }
-
- void assertionWordBoundary(bool invert, int inputPosition)
- {
- m_bodyDisjunction->terms.append(ByteTerm::WordBoundary(invert, inputPosition));
- }
-
- void atomPatternCharacter(UChar ch, int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
- {
- if (m_pattern.m_ignoreCase) {
- UChar lo = Unicode::toLower(ch);
- UChar hi = Unicode::toUpper(ch);
-
- if (lo != hi) {
- m_bodyDisjunction->terms.append(ByteTerm(lo, hi, inputPosition, frameLocation, quantityCount, quantityType));
- return;
- }
- }
-
- m_bodyDisjunction->terms.append(ByteTerm(ch, inputPosition, frameLocation, quantityCount, quantityType));
- }
-
- void atomCharacterClass(CharacterClass* characterClass, bool invert, int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
- {
- m_bodyDisjunction->terms.append(ByteTerm(characterClass, invert, inputPosition));
-
- m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityCount = quantityCount;
- m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityType = quantityType;
- m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
- }
-
- void atomBackReference(unsigned subpatternId, int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
- {
- ASSERT(subpatternId);
-
- m_bodyDisjunction->terms.append(ByteTerm::BackReference(subpatternId, inputPosition));
-
- m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityCount = quantityCount;
- m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityType = quantityType;
- m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
- }
-
- void atomParenthesesSubpatternBegin(unsigned subpatternId, bool capture, int inputPosition, unsigned frameLocation, unsigned alternativeFrameLocation)
- {
- int beginTerm = m_bodyDisjunction->terms.size();
-
- m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternOnceBegin, subpatternId, capture, inputPosition));
- m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
- m_bodyDisjunction->terms.append(ByteTerm::AlternativeBegin());
- m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = alternativeFrameLocation;
-
- m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, m_currentAlternativeIndex));
- m_currentAlternativeIndex = beginTerm + 1;
- }
-
- void atomParentheticalAssertionBegin(unsigned subpatternId, bool invert, unsigned frameLocation, unsigned alternativeFrameLocation)
- {
- int beginTerm = m_bodyDisjunction->terms.size();
-
- m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParentheticalAssertionBegin, subpatternId, invert, 0));
- m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
- m_bodyDisjunction->terms.append(ByteTerm::AlternativeBegin());
- m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = alternativeFrameLocation;
-
- m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, m_currentAlternativeIndex));
- m_currentAlternativeIndex = beginTerm + 1;
- }
-
- unsigned popParenthesesStack()
- {
- ASSERT(m_parenthesesStack.size());
- int stackEnd = m_parenthesesStack.size() - 1;
- unsigned beginTerm = m_parenthesesStack[stackEnd].beginTerm;
- m_currentAlternativeIndex = m_parenthesesStack[stackEnd].savedAlternativeIndex;
- m_parenthesesStack.shrink(stackEnd);
-
- ASSERT(beginTerm < m_bodyDisjunction->terms.size());
- ASSERT(m_currentAlternativeIndex < m_bodyDisjunction->terms.size());
-
- return beginTerm;
- }
-
-#ifndef NDEBUG
- void dumpDisjunction(ByteDisjunction* disjunction)
- {
- printf("ByteDisjunction(%p):\n\t", disjunction);
- for (unsigned i = 0; i < disjunction->terms.size(); ++i)
- printf("{ %d } ", disjunction->terms[i].type);
- printf("\n");
- }
-#endif
-
- void closeAlternative(int beginTerm)
- {
- int origBeginTerm = beginTerm;
- ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeAlternativeBegin);
- int endIndex = m_bodyDisjunction->terms.size();
-
- unsigned frameLocation = m_bodyDisjunction->terms[beginTerm].frameLocation;
-
- if (!m_bodyDisjunction->terms[beginTerm].alternative.next)
- m_bodyDisjunction->terms.remove(beginTerm);
- else {
- while (m_bodyDisjunction->terms[beginTerm].alternative.next) {
- beginTerm += m_bodyDisjunction->terms[beginTerm].alternative.next;
- ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeAlternativeDisjunction);
- m_bodyDisjunction->terms[beginTerm].alternative.end = endIndex - beginTerm;
- m_bodyDisjunction->terms[beginTerm].frameLocation = frameLocation;
- }
-
- m_bodyDisjunction->terms[beginTerm].alternative.next = origBeginTerm - beginTerm;
-
- m_bodyDisjunction->terms.append(ByteTerm::AlternativeEnd());
- m_bodyDisjunction->terms[endIndex].frameLocation = frameLocation;
- }
- }
-
- void closeBodyAlternative()
- {
- int beginTerm = 0;
- int origBeginTerm = 0;
- ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeBodyAlternativeBegin);
- int endIndex = m_bodyDisjunction->terms.size();
-
- unsigned frameLocation = m_bodyDisjunction->terms[beginTerm].frameLocation;
-
- while (m_bodyDisjunction->terms[beginTerm].alternative.next) {
- beginTerm += m_bodyDisjunction->terms[beginTerm].alternative.next;
- ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeBodyAlternativeDisjunction);
- m_bodyDisjunction->terms[beginTerm].alternative.end = endIndex - beginTerm;
- m_bodyDisjunction->terms[beginTerm].frameLocation = frameLocation;
- }
-
- m_bodyDisjunction->terms[beginTerm].alternative.next = origBeginTerm - beginTerm;
-
- m_bodyDisjunction->terms.append(ByteTerm::BodyAlternativeEnd());
- m_bodyDisjunction->terms[endIndex].frameLocation = frameLocation;
- }
-
- void atomParenthesesEnd(bool doInline, unsigned lastSubpatternId, int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType, unsigned callFrameSize = 0)
- {
- unsigned beginTerm = popParenthesesStack();
- closeAlternative(beginTerm + 1);
- unsigned endTerm = m_bodyDisjunction->terms.size();
-
- bool isAssertion = m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeParentheticalAssertionBegin;
- bool invertOrCapture = m_bodyDisjunction->terms[beginTerm].invertOrCapture;
- unsigned subpatternId = m_bodyDisjunction->terms[beginTerm].atom.subpatternId;
-
- m_bodyDisjunction->terms.append(ByteTerm(isAssertion ? ByteTerm::TypeParentheticalAssertionEnd : ByteTerm::TypeParenthesesSubpatternOnceEnd, subpatternId, invertOrCapture, inputPosition));
- m_bodyDisjunction->terms[beginTerm].atom.parenthesesWidth = endTerm - beginTerm;
- m_bodyDisjunction->terms[endTerm].atom.parenthesesWidth = endTerm - beginTerm;
- m_bodyDisjunction->terms[endTerm].frameLocation = frameLocation;
-
- if (doInline) {
- m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount;
- m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType;
- m_bodyDisjunction->terms[endTerm].atom.quantityCount = quantityCount;
- m_bodyDisjunction->terms[endTerm].atom.quantityType = quantityType;
- } else {
- ByteTerm& parenthesesBegin = m_bodyDisjunction->terms[beginTerm];
- ASSERT(parenthesesBegin.type == ByteTerm::TypeParenthesesSubpatternOnceBegin);
-
- bool invertOrCapture = parenthesesBegin.invertOrCapture;
- unsigned subpatternId = parenthesesBegin.atom.subpatternId;
-
- unsigned numSubpatterns = lastSubpatternId - subpatternId + 1;
- ByteDisjunction* parenthesesDisjunction = new ByteDisjunction(numSubpatterns, callFrameSize);
-
- parenthesesDisjunction->terms.append(ByteTerm::SubpatternBegin());
- for (unsigned termInParentheses = beginTerm + 1; termInParentheses < endTerm; ++termInParentheses)
- parenthesesDisjunction->terms.append(m_bodyDisjunction->terms[termInParentheses]);
- parenthesesDisjunction->terms.append(ByteTerm::SubpatternEnd());
-
- m_bodyDisjunction->terms.shrink(beginTerm);
-
- m_allParenthesesInfo.append(parenthesesDisjunction);
- m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpattern, subpatternId, parenthesesDisjunction, invertOrCapture, inputPosition));
-
- m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount;
- m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType;
- m_bodyDisjunction->terms[beginTerm].frameLocation = frameLocation;
- }
- }
-
- void regexBegin(unsigned numSubpatterns, unsigned callFrameSize)
- {
- m_bodyDisjunction = new ByteDisjunction(numSubpatterns, callFrameSize);
- m_bodyDisjunction->terms.append(ByteTerm::BodyAlternativeBegin());
- m_bodyDisjunction->terms[0].frameLocation = 0;
- m_currentAlternativeIndex = 0;
- }
-
- void regexEnd()
- {
- closeBodyAlternative();
- }
-
- void alternativeBodyDisjunction()
- {
- int newAlternativeIndex = m_bodyDisjunction->terms.size();
- m_bodyDisjunction->terms[m_currentAlternativeIndex].alternative.next = newAlternativeIndex - m_currentAlternativeIndex;
- m_bodyDisjunction->terms.append(ByteTerm::BodyAlternativeDisjunction());
-
- m_currentAlternativeIndex = newAlternativeIndex;
- }
-
- void alternativeDisjunction()
- {
- int newAlternativeIndex = m_bodyDisjunction->terms.size();
- m_bodyDisjunction->terms[m_currentAlternativeIndex].alternative.next = newAlternativeIndex - m_currentAlternativeIndex;
- m_bodyDisjunction->terms.append(ByteTerm::AlternativeDisjunction());
-
- m_currentAlternativeIndex = newAlternativeIndex;
- }
-
- void emitDisjunction(PatternDisjunction* disjunction, unsigned inputCountAlreadyChecked = 0, unsigned parenthesesInputCountAlreadyChecked = 0)
- {
- for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) {
- unsigned currentCountAlreadyChecked = inputCountAlreadyChecked;
-
- if (alt) {
- if (disjunction == m_pattern.m_body)
- alternativeBodyDisjunction();
- else
- alternativeDisjunction();
- }
-
- PatternAlternative* alternative = disjunction->m_alternatives[alt];
- unsigned minimumSize = alternative->m_minimumSize;
-
- ASSERT(minimumSize >= parenthesesInputCountAlreadyChecked);
- unsigned countToCheck = minimumSize - parenthesesInputCountAlreadyChecked;
- if (countToCheck)
- checkInput(countToCheck);
- currentCountAlreadyChecked += countToCheck;
-
- for (unsigned i = 0; i < alternative->m_terms.size(); ++i) {
- PatternTerm& term = alternative->m_terms[i];
-
- switch (term.type) {
- case PatternTerm::TypeAssertionBOL:
- assertionBOL(term.inputPosition - currentCountAlreadyChecked);
- break;
-
- case PatternTerm::TypeAssertionEOL:
- assertionEOL(term.inputPosition - currentCountAlreadyChecked);
- break;
-
- case PatternTerm::TypeAssertionWordBoundary:
- assertionWordBoundary(term.invertOrCapture, term.inputPosition - currentCountAlreadyChecked);
- break;
-
- case PatternTerm::TypePatternCharacter:
- atomPatternCharacter(term.patternCharacter, term.inputPosition - currentCountAlreadyChecked, term.frameLocation, term.quantityCount, term.quantityType);
- break;
-
- case PatternTerm::TypeCharacterClass:
- atomCharacterClass(term.characterClass, term.invertOrCapture, term.inputPosition - currentCountAlreadyChecked, term.frameLocation, term.quantityCount, term.quantityType);
- break;
-
- case PatternTerm::TypeBackReference:
- atomBackReference(term.subpatternId, term.inputPosition - currentCountAlreadyChecked, term.frameLocation, term.quantityCount, term.quantityType);
- break;
-
- case PatternTerm::TypeForwardReference:
- break;
-
- case PatternTerm::TypeParenthesesSubpattern: {
- unsigned disjunctionAlreadyCheckedCount = 0;
- if ((term.quantityCount == 1) && !term.parentheses.isCopy) {
- if (term.quantityType == QuantifierFixedCount) {
- disjunctionAlreadyCheckedCount = term.parentheses.disjunction->m_minimumSize;
- unsigned delegateEndInputOffset = term.inputPosition - currentCountAlreadyChecked;
- atomParenthesesSubpatternBegin(term.parentheses.subpatternId, term.invertOrCapture, delegateEndInputOffset - disjunctionAlreadyCheckedCount, term.frameLocation, term.frameLocation);
- emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, term.parentheses.disjunction->m_minimumSize);
- atomParenthesesEnd(true, term.parentheses.lastSubpatternId, delegateEndInputOffset, term.frameLocation, term.quantityCount, term.quantityType, term.parentheses.disjunction->m_callFrameSize);
- } else {
- unsigned delegateEndInputOffset = term.inputPosition - currentCountAlreadyChecked;
- atomParenthesesSubpatternBegin(term.parentheses.subpatternId, term.invertOrCapture, delegateEndInputOffset - disjunctionAlreadyCheckedCount, term.frameLocation, term.frameLocation + RegexStackSpaceForBackTrackInfoParenthesesOnce);
- emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, 0);
- atomParenthesesEnd(true, term.parentheses.lastSubpatternId, delegateEndInputOffset, term.frameLocation, term.quantityCount, term.quantityType, term.parentheses.disjunction->m_callFrameSize);
- }
- } else {
- unsigned delegateEndInputOffset = term.inputPosition - currentCountAlreadyChecked;
- atomParenthesesSubpatternBegin(term.parentheses.subpatternId, term.invertOrCapture, delegateEndInputOffset - disjunctionAlreadyCheckedCount, term.frameLocation, 0);
- emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, 0);
- atomParenthesesEnd(false, term.parentheses.lastSubpatternId, delegateEndInputOffset, term.frameLocation, term.quantityCount, term.quantityType, term.parentheses.disjunction->m_callFrameSize);
- }
- break;
- }
-
- case PatternTerm::TypeParentheticalAssertion: {
- unsigned alternativeFrameLocation = term.frameLocation + RegexStackSpaceForBackTrackInfoParentheticalAssertion;
-
- atomParentheticalAssertionBegin(term.parentheses.subpatternId, term.invertOrCapture, term.frameLocation, alternativeFrameLocation);
- emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, 0);
- atomParenthesesEnd(true, term.parentheses.lastSubpatternId, 0, term.frameLocation, term.quantityCount, term.quantityType);
- break;
- }
- }
- }
- }
- }
-
-private:
- RegexPattern& m_pattern;
- ByteDisjunction* m_bodyDisjunction;
- unsigned m_currentAlternativeIndex;
- Vector<ParenthesesStackEntry> m_parenthesesStack;
- Vector<ByteDisjunction*> m_allParenthesesInfo;
-};
-
-
-BytecodePattern* byteCompileRegex(const UString& patternString, unsigned& numSubpatterns, const char*& error, bool ignoreCase, bool multiline)
-{
- RegexPattern pattern(ignoreCase, multiline);
-
- if ((error = compileRegex(patternString, pattern)))
- return 0;
-
- numSubpatterns = pattern.m_numSubpatterns;
-
- return ByteCompiler(pattern).compile();
-}
-
-int interpretRegex(BytecodePattern* regex, const UChar* input, unsigned start, unsigned length, int* output)
-{
- return Interpreter(regex, output, input, start, length).interpret();
-}
-
-
-COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoPatternCharacter) == (RegexStackSpaceForBackTrackInfoPatternCharacter * sizeof(uintptr_t)), CheckRegexStackSpaceForBackTrackInfoPatternCharacter);
-COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoCharacterClass) == (RegexStackSpaceForBackTrackInfoCharacterClass * sizeof(uintptr_t)), CheckRegexStackSpaceForBackTrackInfoCharacterClass);
-COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoBackReference) == (RegexStackSpaceForBackTrackInfoBackReference * sizeof(uintptr_t)), CheckRegexStackSpaceForBackTrackInfoBackReference);
-COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoAlternative) == (RegexStackSpaceForBackTrackInfoAlternative * sizeof(uintptr_t)), CheckRegexStackSpaceForBackTrackInfoAlternative);
-COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoParentheticalAssertion) == (RegexStackSpaceForBackTrackInfoParentheticalAssertion * sizeof(uintptr_t)), CheckRegexStackSpaceForBackTrackInfoParentheticalAssertion);
-COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoParenthesesOnce) == (RegexStackSpaceForBackTrackInfoParenthesesOnce * sizeof(uintptr_t)), CheckRegexStackSpaceForBackTrackInfoParenthesesOnce);
-COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoParentheses) == (RegexStackSpaceForBackTrackInfoParentheses * sizeof(uintptr_t)), CheckRegexStackSpaceForBackTrackInfoParentheses);
-
-
-} }
-
-#endif
+++ /dev/null
-/*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef RegexInterpreter_h
-#define RegexInterpreter_h
-
-#if ENABLE(YARR)
-
-#include "RegexParser.h"
-#include "RegexPattern.h"
-#include <wtf/unicode/Unicode.h>
-
-namespace JSC { namespace Yarr {
-
-class ByteDisjunction;
-
-struct ByteTerm {
- enum Type {
- TypeBodyAlternativeBegin,
- TypeBodyAlternativeDisjunction,
- TypeBodyAlternativeEnd,
- TypeAlternativeBegin,
- TypeAlternativeDisjunction,
- TypeAlternativeEnd,
- TypeSubpatternBegin,
- TypeSubpatternEnd,
- TypeAssertionBOL,
- TypeAssertionEOL,
- TypeAssertionWordBoundary,
- TypePatternCharacterOnce,
- TypePatternCharacterFixed,
- TypePatternCharacterGreedy,
- TypePatternCharacterNonGreedy,
- TypePatternCasedCharacterOnce,
- TypePatternCasedCharacterFixed,
- TypePatternCasedCharacterGreedy,
- TypePatternCasedCharacterNonGreedy,
- TypeCharacterClass,
- TypeBackReference,
- TypeParenthesesSubpattern,
- TypeParenthesesSubpatternOnceBegin,
- TypeParenthesesSubpatternOnceEnd,
- TypeParentheticalAssertionBegin,
- TypeParentheticalAssertionEnd,
- TypeCheckInput,
- } type;
- bool invertOrCapture;
- union {
- struct {
- union {
- UChar patternCharacter;
- struct {
- UChar lo;
- UChar hi;
- } casedCharacter;
- CharacterClass* characterClass;
- unsigned subpatternId;
- };
- union {
- ByteDisjunction* parenthesesDisjunction;
- unsigned parenthesesWidth;
- };
- QuantifierType quantityType;
- unsigned quantityCount;
- } atom;
- struct {
- int next;
- int end;
- } alternative;
- unsigned checkInputCount;
- };
- unsigned frameLocation;
- int inputPosition;
-
- ByteTerm(UChar ch, int inputPos, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
- : frameLocation(frameLocation)
- {
- switch (quantityType) {
- case QuantifierFixedCount:
- type = (quantityCount == 1) ? ByteTerm::TypePatternCharacterOnce : ByteTerm::TypePatternCharacterFixed;
- break;
- case QuantifierGreedy:
- type = ByteTerm::TypePatternCharacterGreedy;
- break;
- case QuantifierNonGreedy:
- type = ByteTerm::TypePatternCharacterNonGreedy;
- break;
- }
-
- atom.patternCharacter = ch;
- atom.quantityType = quantityType;
- atom.quantityCount = quantityCount;
- inputPosition = inputPos;
- }
-
- ByteTerm(UChar lo, UChar hi, int inputPos, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
- : frameLocation(frameLocation)
- {
- switch (quantityType) {
- case QuantifierFixedCount:
- type = (quantityCount == 1) ? ByteTerm::TypePatternCasedCharacterOnce : ByteTerm::TypePatternCasedCharacterFixed;
- break;
- case QuantifierGreedy:
- type = ByteTerm::TypePatternCasedCharacterGreedy;
- break;
- case QuantifierNonGreedy:
- type = ByteTerm::TypePatternCasedCharacterNonGreedy;
- break;
- }
-
- atom.casedCharacter.lo = lo;
- atom.casedCharacter.hi = hi;
- atom.quantityType = quantityType;
- atom.quantityCount = quantityCount;
- inputPosition = inputPos;
- }
-
- ByteTerm(CharacterClass* characterClass, bool invert, int inputPos)
- : type(ByteTerm::TypeCharacterClass)
- , invertOrCapture(invert)
- {
- atom.characterClass = characterClass;
- atom.quantityType = QuantifierFixedCount;
- atom.quantityCount = 1;
- inputPosition = inputPos;
- }
-
- ByteTerm(Type type, unsigned subpatternId, ByteDisjunction* parenthesesInfo, bool invertOrCapture, int inputPos)
- : type(type)
- , invertOrCapture(invertOrCapture)
- {
- atom.subpatternId = subpatternId;
- atom.parenthesesDisjunction = parenthesesInfo;
- atom.quantityType = QuantifierFixedCount;
- atom.quantityCount = 1;
- inputPosition = inputPos;
- }
-
- ByteTerm(Type type, bool invert = false)
- : type(type)
- , invertOrCapture(invert)
- {
- atom.quantityType = QuantifierFixedCount;
- atom.quantityCount = 1;
- }
-
- ByteTerm(Type type, unsigned subpatternId, bool invertOrCapture, int inputPos)
- : type(type)
- , invertOrCapture(invertOrCapture)
- {
- atom.subpatternId = subpatternId;
- atom.quantityType = QuantifierFixedCount;
- atom.quantityCount = 1;
- inputPosition = inputPos;
- }
-
- static ByteTerm BOL(int inputPos)
- {
- ByteTerm term(TypeAssertionBOL);
- term.inputPosition = inputPos;
- return term;
- }
-
- static ByteTerm CheckInput(unsigned count)
- {
- ByteTerm term(TypeCheckInput);
- term.checkInputCount = count;
- return term;
- }
-
- static ByteTerm EOL(int inputPos)
- {
- ByteTerm term(TypeAssertionEOL);
- term.inputPosition = inputPos;
- return term;
- }
-
- static ByteTerm WordBoundary(bool invert, int inputPos)
- {
- ByteTerm term(TypeAssertionWordBoundary, invert);
- term.inputPosition = inputPos;
- return term;
- }
-
- static ByteTerm BackReference(unsigned subpatternId, int inputPos)
- {
- return ByteTerm(TypeBackReference, subpatternId, false, inputPos);
- }
-
- static ByteTerm BodyAlternativeBegin()
- {
- ByteTerm term(TypeBodyAlternativeBegin);
- term.alternative.next = 0;
- term.alternative.end = 0;
- return term;
- }
-
- static ByteTerm BodyAlternativeDisjunction()
- {
- ByteTerm term(TypeBodyAlternativeDisjunction);
- term.alternative.next = 0;
- term.alternative.end = 0;
- return term;
- }
-
- static ByteTerm BodyAlternativeEnd()
- {
- ByteTerm term(TypeBodyAlternativeEnd);
- term.alternative.next = 0;
- term.alternative.end = 0;
- return term;
- }
-
- static ByteTerm AlternativeBegin()
- {
- ByteTerm term(TypeAlternativeBegin);
- term.alternative.next = 0;
- term.alternative.end = 0;
- return term;
- }
-
- static ByteTerm AlternativeDisjunction()
- {
- ByteTerm term(TypeAlternativeDisjunction);
- term.alternative.next = 0;
- term.alternative.end = 0;
- return term;
- }
-
- static ByteTerm AlternativeEnd()
- {
- ByteTerm term(TypeAlternativeEnd);
- term.alternative.next = 0;
- term.alternative.end = 0;
- return term;
- }
-
- static ByteTerm SubpatternBegin()
- {
- return ByteTerm(TypeSubpatternBegin);
- }
-
- static ByteTerm SubpatternEnd()
- {
- return ByteTerm(TypeSubpatternEnd);
- }
-
- bool invert()
- {
- return invertOrCapture;
- }
-
- bool capture()
- {
- return invertOrCapture;
- }
-};
-
-class ByteDisjunction : public FastAllocBase {
-public:
- ByteDisjunction(unsigned numSubpatterns, unsigned frameSize)
- : m_numSubpatterns(numSubpatterns)
- , m_frameSize(frameSize)
- {
- }
-
- Vector<ByteTerm> terms;
- unsigned m_numSubpatterns;
- unsigned m_frameSize;
-};
-
-struct BytecodePattern : FastAllocBase {
- BytecodePattern(ByteDisjunction* body, Vector<ByteDisjunction*> allParenthesesInfo, RegexPattern& pattern)
- : m_body(body)
- , m_ignoreCase(pattern.m_ignoreCase)
- , m_multiline(pattern.m_multiline)
- {
- newlineCharacterClass = pattern.newlineCharacterClass();
- wordcharCharacterClass = pattern.wordcharCharacterClass();
-
- m_allParenthesesInfo.append(allParenthesesInfo);
- m_userCharacterClasses.append(pattern.m_userCharacterClasses);
- // 'Steal' the RegexPattern's CharacterClasses! We clear its
- // array, so that it won't delete them on destruction. We'll
- // take responsibility for that.
- pattern.m_userCharacterClasses.clear();
- }
-
- ~BytecodePattern()
- {
- deleteAllValues(m_allParenthesesInfo);
- deleteAllValues(m_userCharacterClasses);
- }
-
- OwnPtr<ByteDisjunction> m_body;
- bool m_ignoreCase;
- bool m_multiline;
-
- CharacterClass* newlineCharacterClass;
- CharacterClass* wordcharCharacterClass;
-private:
- Vector<ByteDisjunction*> m_allParenthesesInfo;
- Vector<CharacterClass*> m_userCharacterClasses;
-};
-
-BytecodePattern* byteCompileRegex(const UString& pattern, unsigned& numSubpatterns, const char*& error, bool ignoreCase = false, bool multiline = false);
-int interpretRegex(BytecodePattern* v_regex, const UChar* input, unsigned start, unsigned length, int* output);
-
-} } // namespace JSC::Yarr
-
-#endif
-
-#endif // RegexInterpreter_h
+++ /dev/null
-/*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "RegexJIT.h"
-
-#include "ASCIICType.h"
-#include "JSGlobalData.h"
-#include "LinkBuffer.h"
-#include "MacroAssembler.h"
-#include "RegExpCache.h"
-#include "RegexCompiler.h"
-
-#include "pcre.h" // temporary, remove when fallback is removed.
-
-#if ENABLE(YARR_JIT)
-
-using namespace WTF;
-
-namespace JSC { namespace Yarr {
-
-class RegexGenerator : private MacroAssembler {
- friend void jitCompileRegex(JSGlobalData* globalData, RegexCodeBlock& jitObject, const UString& pattern, unsigned& numSubpatterns, const char*& error, bool ignoreCase, bool multiline);
-
-#if CPU(ARM)
- static const RegisterID input = ARMRegisters::r0;
- static const RegisterID index = ARMRegisters::r1;
- static const RegisterID length = ARMRegisters::r2;
- static const RegisterID output = ARMRegisters::r4;
-
- static const RegisterID regT0 = ARMRegisters::r5;
- static const RegisterID regT1 = ARMRegisters::r6;
-
- static const RegisterID returnRegister = ARMRegisters::r0;
-#elif CPU(MIPS)
- static const RegisterID input = MIPSRegisters::a0;
- static const RegisterID index = MIPSRegisters::a1;
- static const RegisterID length = MIPSRegisters::a2;
- static const RegisterID output = MIPSRegisters::a3;
-
- static const RegisterID regT0 = MIPSRegisters::t4;
- static const RegisterID regT1 = MIPSRegisters::t5;
-
- static const RegisterID returnRegister = MIPSRegisters::v0;
-#elif CPU(X86)
- static const RegisterID input = X86Registers::eax;
- static const RegisterID index = X86Registers::edx;
- static const RegisterID length = X86Registers::ecx;
- static const RegisterID output = X86Registers::edi;
-
- static const RegisterID regT0 = X86Registers::ebx;
- static const RegisterID regT1 = X86Registers::esi;
-
- static const RegisterID returnRegister = X86Registers::eax;
-#elif CPU(X86_64)
- static const RegisterID input = X86Registers::edi;
- static const RegisterID index = X86Registers::esi;
- static const RegisterID length = X86Registers::edx;
- static const RegisterID output = X86Registers::ecx;
-
- static const RegisterID regT0 = X86Registers::eax;
- static const RegisterID regT1 = X86Registers::ebx;
-
- static const RegisterID returnRegister = X86Registers::eax;
-#endif
-
- void optimizeAlternative(PatternAlternative* alternative)
- {
- if (!alternative->m_terms.size())
- return;
-
- for (unsigned i = 0; i < alternative->m_terms.size() - 1; ++i) {
- PatternTerm& term = alternative->m_terms[i];
- PatternTerm& nextTerm = alternative->m_terms[i + 1];
-
- if ((term.type == PatternTerm::TypeCharacterClass)
- && (term.quantityType == QuantifierFixedCount)
- && (nextTerm.type == PatternTerm::TypePatternCharacter)
- && (nextTerm.quantityType == QuantifierFixedCount)) {
- PatternTerm termCopy = term;
- alternative->m_terms[i] = nextTerm;
- alternative->m_terms[i + 1] = termCopy;
- }
- }
- }
-
- void matchCharacterClassRange(RegisterID character, JumpList& failures, JumpList& matchDest, const CharacterRange* ranges, unsigned count, unsigned* matchIndex, const UChar* matches, unsigned matchCount)
- {
- do {
- // pick which range we're going to generate
- int which = count >> 1;
- char lo = ranges[which].begin;
- char hi = ranges[which].end;
-
- // check if there are any ranges or matches below lo. If not, just jl to failure -
- // if there is anything else to check, check that first, if it falls through jmp to failure.
- if ((*matchIndex < matchCount) && (matches[*matchIndex] < lo)) {
- Jump loOrAbove = branch32(GreaterThanOrEqual, character, Imm32((unsigned short)lo));
-
- // generate code for all ranges before this one
- if (which)
- matchCharacterClassRange(character, failures, matchDest, ranges, which, matchIndex, matches, matchCount);
-
- while ((*matchIndex < matchCount) && (matches[*matchIndex] < lo)) {
- matchDest.append(branch32(Equal, character, Imm32((unsigned short)matches[*matchIndex])));
- ++*matchIndex;
- }
- failures.append(jump());
-
- loOrAbove.link(this);
- } else if (which) {
- Jump loOrAbove = branch32(GreaterThanOrEqual, character, Imm32((unsigned short)lo));
-
- matchCharacterClassRange(character, failures, matchDest, ranges, which, matchIndex, matches, matchCount);
- failures.append(jump());
-
- loOrAbove.link(this);
- } else
- failures.append(branch32(LessThan, character, Imm32((unsigned short)lo)));
-
- while ((*matchIndex < matchCount) && (matches[*matchIndex] <= hi))
- ++*matchIndex;
-
- matchDest.append(branch32(LessThanOrEqual, character, Imm32((unsigned short)hi)));
- // fall through to here, the value is above hi.
-
- // shuffle along & loop around if there are any more matches to handle.
- unsigned next = which + 1;
- ranges += next;
- count -= next;
- } while (count);
- }
-
- void matchCharacterClass(RegisterID character, JumpList& matchDest, const CharacterClass* charClass)
- {
- if (charClass->m_table) {
- ExtendedAddress tableEntry(character, reinterpret_cast<intptr_t>(charClass->m_table->m_table));
- matchDest.append(branchTest8(charClass->m_table->m_inverted ? Zero : NonZero, tableEntry));
- return;
- }
- Jump unicodeFail;
- if (charClass->m_matchesUnicode.size() || charClass->m_rangesUnicode.size()) {
- Jump isAscii = branch32(LessThanOrEqual, character, Imm32(0x7f));
-
- if (charClass->m_matchesUnicode.size()) {
- for (unsigned i = 0; i < charClass->m_matchesUnicode.size(); ++i) {
- UChar ch = charClass->m_matchesUnicode[i];
- matchDest.append(branch32(Equal, character, Imm32(ch)));
- }
- }
-
- if (charClass->m_rangesUnicode.size()) {
- for (unsigned i = 0; i < charClass->m_rangesUnicode.size(); ++i) {
- UChar lo = charClass->m_rangesUnicode[i].begin;
- UChar hi = charClass->m_rangesUnicode[i].end;
-
- Jump below = branch32(LessThan, character, Imm32(lo));
- matchDest.append(branch32(LessThanOrEqual, character, Imm32(hi)));
- below.link(this);
- }
- }
-
- unicodeFail = jump();
- isAscii.link(this);
- }
-
- if (charClass->m_ranges.size()) {
- unsigned matchIndex = 0;
- JumpList failures;
- matchCharacterClassRange(character, failures, matchDest, charClass->m_ranges.begin(), charClass->m_ranges.size(), &matchIndex, charClass->m_matches.begin(), charClass->m_matches.size());
- while (matchIndex < charClass->m_matches.size())
- matchDest.append(branch32(Equal, character, Imm32((unsigned short)charClass->m_matches[matchIndex++])));
-
- failures.link(this);
- } else if (charClass->m_matches.size()) {
- // optimization: gather 'a','A' etc back together, can mask & test once.
- Vector<char> matchesAZaz;
-
- for (unsigned i = 0; i < charClass->m_matches.size(); ++i) {
- char ch = charClass->m_matches[i];
- if (m_pattern.m_ignoreCase) {
- if (isASCIILower(ch)) {
- matchesAZaz.append(ch);
- continue;
- }
- if (isASCIIUpper(ch))
- continue;
- }
- matchDest.append(branch32(Equal, character, Imm32((unsigned short)ch)));
- }
-
- if (unsigned countAZaz = matchesAZaz.size()) {
- or32(Imm32(32), character);
- for (unsigned i = 0; i < countAZaz; ++i)
- matchDest.append(branch32(Equal, character, Imm32(matchesAZaz[i])));
- }
- }
-
- if (charClass->m_matchesUnicode.size() || charClass->m_rangesUnicode.size())
- unicodeFail.link(this);
- }
-
- // Jumps if input not available; will have (incorrectly) incremented already!
- Jump jumpIfNoAvailableInput(unsigned countToCheck)
- {
- add32(Imm32(countToCheck), index);
- return branch32(Above, index, length);
- }
-
- Jump jumpIfAvailableInput(unsigned countToCheck)
- {
- add32(Imm32(countToCheck), index);
- return branch32(BelowOrEqual, index, length);
- }
-
- Jump checkInput()
- {
- return branch32(BelowOrEqual, index, length);
- }
-
- Jump atEndOfInput()
- {
- return branch32(Equal, index, length);
- }
-
- Jump notAtEndOfInput()
- {
- return branch32(NotEqual, index, length);
- }
-
- Jump jumpIfCharEquals(UChar ch, int inputPosition)
- {
- return branch16(Equal, BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), Imm32(ch));
- }
-
- Jump jumpIfCharNotEquals(UChar ch, int inputPosition)
- {
- return branch16(NotEqual, BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), Imm32(ch));
- }
-
- void readCharacter(int inputPosition, RegisterID reg)
- {
- load16(BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), reg);
- }
-
- void storeToFrame(RegisterID reg, unsigned frameLocation)
- {
- poke(reg, frameLocation);
- }
-
- void storeToFrame(Imm32 imm, unsigned frameLocation)
- {
- poke(imm, frameLocation);
- }
-
- DataLabelPtr storeToFrameWithPatch(unsigned frameLocation)
- {
- return storePtrWithPatch(ImmPtr(0), Address(stackPointerRegister, frameLocation * sizeof(void*)));
- }
-
- void loadFromFrame(unsigned frameLocation, RegisterID reg)
- {
- peek(reg, frameLocation);
- }
-
- void loadFromFrameAndJump(unsigned frameLocation)
- {
- jump(Address(stackPointerRegister, frameLocation * sizeof(void*)));
- }
-
- struct AlternativeBacktrackRecord {
- DataLabelPtr dataLabel;
- Label backtrackLocation;
-
- AlternativeBacktrackRecord(DataLabelPtr dataLabel, Label backtrackLocation)
- : dataLabel(dataLabel)
- , backtrackLocation(backtrackLocation)
- {
- }
- };
-
- struct TermGenerationState {
- TermGenerationState(PatternDisjunction* disjunction, unsigned checkedTotal)
- : disjunction(disjunction)
- , checkedTotal(checkedTotal)
- {
- }
-
- void resetAlternative()
- {
- isBackTrackGenerated = false;
- alt = 0;
- }
- bool alternativeValid()
- {
- return alt < disjunction->m_alternatives.size();
- }
- void nextAlternative()
- {
- ++alt;
- }
- PatternAlternative* alternative()
- {
- return disjunction->m_alternatives[alt];
- }
-
- void resetTerm()
- {
- ASSERT(alternativeValid());
- t = 0;
- }
- bool termValid()
- {
- ASSERT(alternativeValid());
- return t < alternative()->m_terms.size();
- }
- void nextTerm()
- {
- ASSERT(alternativeValid());
- ++t;
- }
- PatternTerm& term()
- {
- ASSERT(alternativeValid());
- return alternative()->m_terms[t];
- }
-
- PatternTerm& lookaheadTerm()
- {
- ASSERT(alternativeValid());
- ASSERT((t + 1) < alternative()->m_terms.size());
- return alternative()->m_terms[t + 1];
- }
- bool isSinglePatternCharacterLookaheadTerm()
- {
- ASSERT(alternativeValid());
- return ((t + 1) < alternative()->m_terms.size())
- && (lookaheadTerm().type == PatternTerm::TypePatternCharacter)
- && (lookaheadTerm().quantityType == QuantifierFixedCount)
- && (lookaheadTerm().quantityCount == 1);
- }
-
- int inputOffset()
- {
- return term().inputPosition - checkedTotal;
- }
-
- void jumpToBacktrack(Jump jump, MacroAssembler* masm)
- {
- if (isBackTrackGenerated)
- jump.linkTo(backtrackLabel, masm);
- else
- backTrackJumps.append(jump);
- }
- void jumpToBacktrack(JumpList& jumps, MacroAssembler* masm)
- {
- if (isBackTrackGenerated)
- jumps.linkTo(backtrackLabel, masm);
- else
- backTrackJumps.append(jumps);
- }
- bool plantJumpToBacktrackIfExists(MacroAssembler* masm)
- {
- if (isBackTrackGenerated) {
- masm->jump(backtrackLabel);
- return true;
- }
- return false;
- }
- void addBacktrackJump(Jump jump)
- {
- backTrackJumps.append(jump);
- }
- void setBacktrackGenerated(Label label)
- {
- isBackTrackGenerated = true;
- backtrackLabel = label;
- }
- void linkAlternativeBacktracks(MacroAssembler* masm)
- {
- isBackTrackGenerated = false;
- backTrackJumps.link(masm);
- }
- void linkAlternativeBacktracksTo(Label label, MacroAssembler* masm)
- {
- isBackTrackGenerated = false;
- backTrackJumps.linkTo(label, masm);
- }
- void propagateBacktrackingFrom(TermGenerationState& nestedParenthesesState, MacroAssembler* masm)
- {
- jumpToBacktrack(nestedParenthesesState.backTrackJumps, masm);
- if (nestedParenthesesState.isBackTrackGenerated)
- setBacktrackGenerated(nestedParenthesesState.backtrackLabel);
- }
-
- PatternDisjunction* disjunction;
- int checkedTotal;
- private:
- unsigned alt;
- unsigned t;
- JumpList backTrackJumps;
- Label backtrackLabel;
- bool isBackTrackGenerated;
- };
-
- void generateAssertionBOL(TermGenerationState& state)
- {
- PatternTerm& term = state.term();
-
- if (m_pattern.m_multiline) {
- const RegisterID character = regT0;
-
- JumpList matchDest;
- if (!term.inputPosition)
- matchDest.append(branch32(Equal, index, Imm32(state.checkedTotal)));
-
- readCharacter(state.inputOffset() - 1, character);
- matchCharacterClass(character, matchDest, m_pattern.newlineCharacterClass());
- state.jumpToBacktrack(jump(), this);
-
- matchDest.link(this);
- } else {
- // Erk, really should poison out these alternatives early. :-/
- if (term.inputPosition)
- state.jumpToBacktrack(jump(), this);
- else
- state.jumpToBacktrack(branch32(NotEqual, index, Imm32(state.checkedTotal)), this);
- }
- }
-
- void generateAssertionEOL(TermGenerationState& state)
- {
- PatternTerm& term = state.term();
-
- if (m_pattern.m_multiline) {
- const RegisterID character = regT0;
-
- JumpList matchDest;
- if (term.inputPosition == state.checkedTotal)
- matchDest.append(atEndOfInput());
-
- readCharacter(state.inputOffset(), character);
- matchCharacterClass(character, matchDest, m_pattern.newlineCharacterClass());
- state.jumpToBacktrack(jump(), this);
-
- matchDest.link(this);
- } else {
- if (term.inputPosition == state.checkedTotal)
- state.jumpToBacktrack(notAtEndOfInput(), this);
- // Erk, really should poison out these alternatives early. :-/
- else
- state.jumpToBacktrack(jump(), this);
- }
- }
-
- // Also falls though on nextIsNotWordChar.
- void matchAssertionWordchar(TermGenerationState& state, JumpList& nextIsWordChar, JumpList& nextIsNotWordChar)
- {
- const RegisterID character = regT0;
- PatternTerm& term = state.term();
-
- if (term.inputPosition == state.checkedTotal)
- nextIsNotWordChar.append(atEndOfInput());
-
- readCharacter(state.inputOffset(), character);
- matchCharacterClass(character, nextIsWordChar, m_pattern.wordcharCharacterClass());
- }
-
- void generateAssertionWordBoundary(TermGenerationState& state)
- {
- const RegisterID character = regT0;
- PatternTerm& term = state.term();
-
- Jump atBegin;
- JumpList matchDest;
- if (!term.inputPosition)
- atBegin = branch32(Equal, index, Imm32(state.checkedTotal));
- readCharacter(state.inputOffset() - 1, character);
- matchCharacterClass(character, matchDest, m_pattern.wordcharCharacterClass());
- if (!term.inputPosition)
- atBegin.link(this);
-
- // We fall through to here if the last character was not a wordchar.
- JumpList nonWordCharThenWordChar;
- JumpList nonWordCharThenNonWordChar;
- if (term.invertOrCapture) {
- matchAssertionWordchar(state, nonWordCharThenNonWordChar, nonWordCharThenWordChar);
- nonWordCharThenWordChar.append(jump());
- } else {
- matchAssertionWordchar(state, nonWordCharThenWordChar, nonWordCharThenNonWordChar);
- nonWordCharThenNonWordChar.append(jump());
- }
- state.jumpToBacktrack(nonWordCharThenNonWordChar, this);
-
- // We jump here if the last character was a wordchar.
- matchDest.link(this);
- JumpList wordCharThenWordChar;
- JumpList wordCharThenNonWordChar;
- if (term.invertOrCapture) {
- matchAssertionWordchar(state, wordCharThenNonWordChar, wordCharThenWordChar);
- wordCharThenWordChar.append(jump());
- } else {
- matchAssertionWordchar(state, wordCharThenWordChar, wordCharThenNonWordChar);
- // This can fall-though!
- }
-
- state.jumpToBacktrack(wordCharThenWordChar, this);
-
- nonWordCharThenWordChar.link(this);
- wordCharThenNonWordChar.link(this);
- }
-
- void generatePatternCharacterSingle(TermGenerationState& state)
- {
- const RegisterID character = regT0;
- UChar ch = state.term().patternCharacter;
-
- if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) {
- readCharacter(state.inputOffset(), character);
- or32(Imm32(32), character);
- state.jumpToBacktrack(branch32(NotEqual, character, Imm32(Unicode::toLower(ch))), this);
- } else {
- ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch)));
- state.jumpToBacktrack(jumpIfCharNotEquals(ch, state.inputOffset()), this);
- }
- }
-
- void generatePatternCharacterPair(TermGenerationState& state)
- {
- const RegisterID character = regT0;
- UChar ch1 = state.term().patternCharacter;
- UChar ch2 = state.lookaheadTerm().patternCharacter;
-
- int mask = 0;
- int chPair = ch1 | (ch2 << 16);
-
- if (m_pattern.m_ignoreCase) {
- if (isASCIIAlpha(ch1))
- mask |= 32;
- if (isASCIIAlpha(ch2))
- mask |= 32 << 16;
- }
-
- if (mask) {
- load32WithUnalignedHalfWords(BaseIndex(input, index, TimesTwo, state.inputOffset() * sizeof(UChar)), character);
- or32(Imm32(mask), character);
- state.jumpToBacktrack(branch32(NotEqual, character, Imm32(chPair | mask)), this);
- } else
- state.jumpToBacktrack(branch32WithUnalignedHalfWords(NotEqual, BaseIndex(input, index, TimesTwo, state.inputOffset() * sizeof(UChar)), Imm32(chPair)), this);
- }
-
- void generatePatternCharacterFixed(TermGenerationState& state)
- {
- const RegisterID character = regT0;
- const RegisterID countRegister = regT1;
- PatternTerm& term = state.term();
- UChar ch = term.patternCharacter;
-
- move(index, countRegister);
- sub32(Imm32(term.quantityCount), countRegister);
-
- Label loop(this);
- if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) {
- load16(BaseIndex(input, countRegister, TimesTwo, (state.inputOffset() + term.quantityCount) * sizeof(UChar)), character);
- or32(Imm32(32), character);
- state.jumpToBacktrack(branch32(NotEqual, character, Imm32(Unicode::toLower(ch))), this);
- } else {
- ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch)));
- state.jumpToBacktrack(branch16(NotEqual, BaseIndex(input, countRegister, TimesTwo, (state.inputOffset() + term.quantityCount) * sizeof(UChar)), Imm32(ch)), this);
- }
- add32(Imm32(1), countRegister);
- branch32(NotEqual, countRegister, index).linkTo(loop, this);
- }
-
- void generatePatternCharacterGreedy(TermGenerationState& state)
- {
- const RegisterID character = regT0;
- const RegisterID countRegister = regT1;
- PatternTerm& term = state.term();
- UChar ch = term.patternCharacter;
-
- move(Imm32(0), countRegister);
-
- JumpList failures;
- Label loop(this);
- failures.append(atEndOfInput());
- if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) {
- readCharacter(state.inputOffset(), character);
- or32(Imm32(32), character);
- failures.append(branch32(NotEqual, character, Imm32(Unicode::toLower(ch))));
- } else {
- ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch)));
- failures.append(jumpIfCharNotEquals(ch, state.inputOffset()));
- }
-
- add32(Imm32(1), countRegister);
- add32(Imm32(1), index);
- if (term.quantityCount != 0xffffffff)
- branch32(NotEqual, countRegister, Imm32(term.quantityCount)).linkTo(loop, this);
- else
- jump(loop);
-
- failures.append(jump());
-
- Label backtrackBegin(this);
- loadFromFrame(term.frameLocation, countRegister);
- state.jumpToBacktrack(branchTest32(Zero, countRegister), this);
- sub32(Imm32(1), countRegister);
- sub32(Imm32(1), index);
-
- failures.link(this);
-
- storeToFrame(countRegister, term.frameLocation);
-
- state.setBacktrackGenerated(backtrackBegin);
- }
-
- void generatePatternCharacterNonGreedy(TermGenerationState& state)
- {
- const RegisterID character = regT0;
- const RegisterID countRegister = regT1;
- PatternTerm& term = state.term();
- UChar ch = term.patternCharacter;
-
- move(Imm32(0), countRegister);
-
- Jump firstTimeDoNothing = jump();
-
- Label hardFail(this);
- sub32(countRegister, index);
- state.jumpToBacktrack(jump(), this);
-
- Label backtrackBegin(this);
- loadFromFrame(term.frameLocation, countRegister);
-
- atEndOfInput().linkTo(hardFail, this);
- if (term.quantityCount != 0xffffffff)
- branch32(Equal, countRegister, Imm32(term.quantityCount), hardFail);
- if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) {
- readCharacter(state.inputOffset(), character);
- or32(Imm32(32), character);
- branch32(NotEqual, character, Imm32(Unicode::toLower(ch))).linkTo(hardFail, this);
- } else {
- ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch)));
- jumpIfCharNotEquals(ch, state.inputOffset()).linkTo(hardFail, this);
- }
-
- add32(Imm32(1), countRegister);
- add32(Imm32(1), index);
-
- firstTimeDoNothing.link(this);
- storeToFrame(countRegister, term.frameLocation);
-
- state.setBacktrackGenerated(backtrackBegin);
- }
-
- void generateCharacterClassSingle(TermGenerationState& state)
- {
- const RegisterID character = regT0;
- PatternTerm& term = state.term();
-
- JumpList matchDest;
- readCharacter(state.inputOffset(), character);
- matchCharacterClass(character, matchDest, term.characterClass);
-
- if (term.invertOrCapture)
- state.jumpToBacktrack(matchDest, this);
- else {
- state.jumpToBacktrack(jump(), this);
- matchDest.link(this);
- }
- }
-
- void generateCharacterClassFixed(TermGenerationState& state)
- {
- const RegisterID character = regT0;
- const RegisterID countRegister = regT1;
- PatternTerm& term = state.term();
-
- move(index, countRegister);
- sub32(Imm32(term.quantityCount), countRegister);
-
- Label loop(this);
- JumpList matchDest;
- load16(BaseIndex(input, countRegister, TimesTwo, (state.inputOffset() + term.quantityCount) * sizeof(UChar)), character);
- matchCharacterClass(character, matchDest, term.characterClass);
-
- if (term.invertOrCapture)
- state.jumpToBacktrack(matchDest, this);
- else {
- state.jumpToBacktrack(jump(), this);
- matchDest.link(this);
- }
-
- add32(Imm32(1), countRegister);
- branch32(NotEqual, countRegister, index).linkTo(loop, this);
- }
-
- void generateCharacterClassGreedy(TermGenerationState& state)
- {
- const RegisterID character = regT0;
- const RegisterID countRegister = regT1;
- PatternTerm& term = state.term();
-
- move(Imm32(0), countRegister);
-
- JumpList failures;
- Label loop(this);
- failures.append(atEndOfInput());
-
- if (term.invertOrCapture) {
- readCharacter(state.inputOffset(), character);
- matchCharacterClass(character, failures, term.characterClass);
- } else {
- JumpList matchDest;
- readCharacter(state.inputOffset(), character);
- matchCharacterClass(character, matchDest, term.characterClass);
- failures.append(jump());
- matchDest.link(this);
- }
-
- add32(Imm32(1), countRegister);
- add32(Imm32(1), index);
- if (term.quantityCount != 0xffffffff)
- branch32(NotEqual, countRegister, Imm32(term.quantityCount)).linkTo(loop, this);
- else
- jump(loop);
-
- failures.append(jump());
-
- Label backtrackBegin(this);
- loadFromFrame(term.frameLocation, countRegister);
- state.jumpToBacktrack(branchTest32(Zero, countRegister), this);
- sub32(Imm32(1), countRegister);
- sub32(Imm32(1), index);
-
- failures.link(this);
-
- storeToFrame(countRegister, term.frameLocation);
-
- state.setBacktrackGenerated(backtrackBegin);
- }
-
- void generateCharacterClassNonGreedy(TermGenerationState& state)
- {
- const RegisterID character = regT0;
- const RegisterID countRegister = regT1;
- PatternTerm& term = state.term();
-
- move(Imm32(0), countRegister);
-
- Jump firstTimeDoNothing = jump();
-
- Label hardFail(this);
- sub32(countRegister, index);
- state.jumpToBacktrack(jump(), this);
-
- Label backtrackBegin(this);
- loadFromFrame(term.frameLocation, countRegister);
-
- atEndOfInput().linkTo(hardFail, this);
- branch32(Equal, countRegister, Imm32(term.quantityCount), hardFail);
-
- JumpList matchDest;
- readCharacter(state.inputOffset(), character);
- matchCharacterClass(character, matchDest, term.characterClass);
-
- if (term.invertOrCapture)
- matchDest.linkTo(hardFail, this);
- else {
- jump(hardFail);
- matchDest.link(this);
- }
-
- add32(Imm32(1), countRegister);
- add32(Imm32(1), index);
-
- firstTimeDoNothing.link(this);
- storeToFrame(countRegister, term.frameLocation);
-
- state.setBacktrackGenerated(backtrackBegin);
- }
-
- void generateParenthesesDisjunction(PatternTerm& parenthesesTerm, TermGenerationState& state, unsigned alternativeFrameLocation)
- {
- ASSERT((parenthesesTerm.type == PatternTerm::TypeParenthesesSubpattern) || (parenthesesTerm.type == PatternTerm::TypeParentheticalAssertion));
- ASSERT(parenthesesTerm.quantityCount == 1);
-
- PatternDisjunction* disjunction = parenthesesTerm.parentheses.disjunction;
- unsigned preCheckedCount = ((parenthesesTerm.quantityType == QuantifierFixedCount) && (parenthesesTerm.type != PatternTerm::TypeParentheticalAssertion)) ? disjunction->m_minimumSize : 0;
-
- if (disjunction->m_alternatives.size() == 1) {
- state.resetAlternative();
- ASSERT(state.alternativeValid());
- PatternAlternative* alternative = state.alternative();
- optimizeAlternative(alternative);
-
- int countToCheck = alternative->m_minimumSize - preCheckedCount;
- if (countToCheck) {
- ASSERT((parenthesesTerm.type == PatternTerm::TypeParentheticalAssertion) || (parenthesesTerm.quantityType != QuantifierFixedCount));
-
- // FIXME: This is quite horrible. The call to 'plantJumpToBacktrackIfExists'
- // will be forced to always trampoline into here, just to decrement the index.
- // Ick.
- Jump skip = jump();
-
- Label backtrackBegin(this);
- sub32(Imm32(countToCheck), index);
- state.addBacktrackJump(jump());
-
- skip.link(this);
-
- state.setBacktrackGenerated(backtrackBegin);
-
- state.jumpToBacktrack(jumpIfNoAvailableInput(countToCheck), this);
- state.checkedTotal += countToCheck;
- }
-
- for (state.resetTerm(); state.termValid(); state.nextTerm())
- generateTerm(state);
-
- state.checkedTotal -= countToCheck;
- } else {
- JumpList successes;
-
- for (state.resetAlternative(); state.alternativeValid(); state.nextAlternative()) {
-
- PatternAlternative* alternative = state.alternative();
- optimizeAlternative(alternative);
-
- ASSERT(alternative->m_minimumSize >= preCheckedCount);
- int countToCheck = alternative->m_minimumSize - preCheckedCount;
- if (countToCheck) {
- state.addBacktrackJump(jumpIfNoAvailableInput(countToCheck));
- state.checkedTotal += countToCheck;
- }
-
- for (state.resetTerm(); state.termValid(); state.nextTerm())
- generateTerm(state);
-
- // Matched an alternative.
- DataLabelPtr dataLabel = storeToFrameWithPatch(alternativeFrameLocation);
- successes.append(jump());
-
- // Alternative did not match.
- Label backtrackLocation(this);
-
- // Can we backtrack the alternative? - if so, do so. If not, just fall through to the next one.
- state.plantJumpToBacktrackIfExists(this);
-
- state.linkAlternativeBacktracks(this);
-
- if (countToCheck) {
- sub32(Imm32(countToCheck), index);
- state.checkedTotal -= countToCheck;
- }
-
- m_backtrackRecords.append(AlternativeBacktrackRecord(dataLabel, backtrackLocation));
- }
- // We fall through to here when the last alternative fails.
- // Add a backtrack out of here for the parenthese handling code to link up.
- state.addBacktrackJump(jump());
-
- // Generate a trampoline for the parens code to backtrack to, to retry the
- // next alternative.
- state.setBacktrackGenerated(label());
- loadFromFrameAndJump(alternativeFrameLocation);
-
- // FIXME: both of the above hooks are a little inefficient, in that you
- // may end up trampolining here, just to trampoline back out to the
- // parentheses code, or vice versa. We can probably eliminate a jump
- // by restructuring, but coding this way for now for simplicity during
- // development.
-
- successes.link(this);
- }
- }
-
- void generateParenthesesSingle(TermGenerationState& state)
- {
- const RegisterID indexTemporary = regT0;
- PatternTerm& term = state.term();
- PatternDisjunction* disjunction = term.parentheses.disjunction;
- ASSERT(term.quantityCount == 1);
-
- unsigned preCheckedCount = ((term.quantityCount == 1) && (term.quantityType == QuantifierFixedCount)) ? disjunction->m_minimumSize : 0;
-
- unsigned parenthesesFrameLocation = term.frameLocation;
- unsigned alternativeFrameLocation = parenthesesFrameLocation;
- if (term.quantityType != QuantifierFixedCount)
- alternativeFrameLocation += RegexStackSpaceForBackTrackInfoParenthesesOnce;
-
- // optimized case - no capture & no quantifier can be handled in a light-weight manner.
- if (!term.invertOrCapture && (term.quantityType == QuantifierFixedCount)) {
- TermGenerationState parenthesesState(disjunction, state.checkedTotal);
- generateParenthesesDisjunction(state.term(), parenthesesState, alternativeFrameLocation);
- // this expects that any backtracks back out of the parentheses will be in the
- // parenthesesState's backTrackJumps vector, and that if they need backtracking
- // they will have set an entry point on the parenthesesState's backtrackLabel.
- state.propagateBacktrackingFrom(parenthesesState, this);
- } else {
- Jump nonGreedySkipParentheses;
- Label nonGreedyTryParentheses;
- if (term.quantityType == QuantifierGreedy)
- storeToFrame(Imm32(1), parenthesesFrameLocation);
- else if (term.quantityType == QuantifierNonGreedy) {
- storeToFrame(Imm32(0), parenthesesFrameLocation);
- nonGreedySkipParentheses = jump();
- nonGreedyTryParentheses = label();
- storeToFrame(Imm32(1), parenthesesFrameLocation);
- }
-
- // store the match start index
- if (term.invertOrCapture) {
- int inputOffset = state.inputOffset() - preCheckedCount;
- if (inputOffset) {
- move(index, indexTemporary);
- add32(Imm32(inputOffset), indexTemporary);
- store32(indexTemporary, Address(output, (term.parentheses.subpatternId << 1) * sizeof(int)));
- } else
- store32(index, Address(output, (term.parentheses.subpatternId << 1) * sizeof(int)));
- }
-
- // generate the body of the parentheses
- TermGenerationState parenthesesState(disjunction, state.checkedTotal);
- generateParenthesesDisjunction(state.term(), parenthesesState, alternativeFrameLocation);
-
- // store the match end index
- if (term.invertOrCapture) {
- int inputOffset = state.inputOffset();
- if (inputOffset) {
- move(index, indexTemporary);
- add32(Imm32(state.inputOffset()), indexTemporary);
- store32(indexTemporary, Address(output, ((term.parentheses.subpatternId << 1) + 1) * sizeof(int)));
- } else
- store32(index, Address(output, ((term.parentheses.subpatternId << 1) + 1) * sizeof(int)));
- }
- Jump success = jump();
-
- // A failure AFTER the parens jumps here
- Label backtrackFromAfterParens(this);
-
- if (term.quantityType == QuantifierGreedy) {
- // If this is zero we have now tested with both with and without the parens.
- loadFromFrame(parenthesesFrameLocation, indexTemporary);
- state.jumpToBacktrack(branchTest32(Zero, indexTemporary), this);
- } else if (term.quantityType == QuantifierNonGreedy) {
- // If this is zero we have now tested with both with and without the parens.
- loadFromFrame(parenthesesFrameLocation, indexTemporary);
- branchTest32(Zero, indexTemporary).linkTo(nonGreedyTryParentheses, this);
- }
-
- parenthesesState.plantJumpToBacktrackIfExists(this);
- // A failure WITHIN the parens jumps here
- parenthesesState.linkAlternativeBacktracks(this);
- if (term.invertOrCapture) {
- store32(Imm32(-1), Address(output, (term.parentheses.subpatternId << 1) * sizeof(int)));
- store32(Imm32(-1), Address(output, ((term.parentheses.subpatternId << 1) + 1) * sizeof(int)));
- }
-
- if (term.quantityType == QuantifierGreedy)
- storeToFrame(Imm32(0), parenthesesFrameLocation);
- else
- state.jumpToBacktrack(jump(), this);
-
- state.setBacktrackGenerated(backtrackFromAfterParens);
- if (term.quantityType == QuantifierNonGreedy)
- nonGreedySkipParentheses.link(this);
- success.link(this);
- }
- }
-
- void generateParentheticalAssertion(TermGenerationState& state)
- {
- PatternTerm& term = state.term();
- PatternDisjunction* disjunction = term.parentheses.disjunction;
- ASSERT(term.quantityCount == 1);
- ASSERT(term.quantityType == QuantifierFixedCount);
-
- unsigned parenthesesFrameLocation = term.frameLocation;
- unsigned alternativeFrameLocation = parenthesesFrameLocation + RegexStackSpaceForBackTrackInfoParentheticalAssertion;
-
- int countCheckedAfterAssertion = state.checkedTotal - term.inputPosition;
-
- if (term.invertOrCapture) {
- // Inverted case
- storeToFrame(index, parenthesesFrameLocation);
-
- state.checkedTotal -= countCheckedAfterAssertion;
- if (countCheckedAfterAssertion)
- sub32(Imm32(countCheckedAfterAssertion), index);
-
- TermGenerationState parenthesesState(disjunction, state.checkedTotal);
- generateParenthesesDisjunction(state.term(), parenthesesState, alternativeFrameLocation);
- // Success! - which means - Fail!
- loadFromFrame(parenthesesFrameLocation, index);
- state.jumpToBacktrack(jump(), this);
-
- // And fail means success.
- parenthesesState.linkAlternativeBacktracks(this);
- loadFromFrame(parenthesesFrameLocation, index);
-
- state.checkedTotal += countCheckedAfterAssertion;
- } else {
- // Normal case
- storeToFrame(index, parenthesesFrameLocation);
-
- state.checkedTotal -= countCheckedAfterAssertion;
- if (countCheckedAfterAssertion)
- sub32(Imm32(countCheckedAfterAssertion), index);
-
- TermGenerationState parenthesesState(disjunction, state.checkedTotal);
- generateParenthesesDisjunction(state.term(), parenthesesState, alternativeFrameLocation);
- // Success! - which means - Success!
- loadFromFrame(parenthesesFrameLocation, index);
- Jump success = jump();
-
- parenthesesState.linkAlternativeBacktracks(this);
- loadFromFrame(parenthesesFrameLocation, index);
- state.jumpToBacktrack(jump(), this);
-
- success.link(this);
-
- state.checkedTotal += countCheckedAfterAssertion;
- }
- }
-
- void generateTerm(TermGenerationState& state)
- {
- PatternTerm& term = state.term();
-
- switch (term.type) {
- case PatternTerm::TypeAssertionBOL:
- generateAssertionBOL(state);
- break;
-
- case PatternTerm::TypeAssertionEOL:
- generateAssertionEOL(state);
- break;
-
- case PatternTerm::TypeAssertionWordBoundary:
- generateAssertionWordBoundary(state);
- break;
-
- case PatternTerm::TypePatternCharacter:
- switch (term.quantityType) {
- case QuantifierFixedCount:
- if (term.quantityCount == 1) {
- if (state.isSinglePatternCharacterLookaheadTerm() && (state.lookaheadTerm().inputPosition == (term.inputPosition + 1))) {
- generatePatternCharacterPair(state);
- state.nextTerm();
- } else
- generatePatternCharacterSingle(state);
- } else
- generatePatternCharacterFixed(state);
- break;
- case QuantifierGreedy:
- generatePatternCharacterGreedy(state);
- break;
- case QuantifierNonGreedy:
- generatePatternCharacterNonGreedy(state);
- break;
- }
- break;
-
- case PatternTerm::TypeCharacterClass:
- switch (term.quantityType) {
- case QuantifierFixedCount:
- if (term.quantityCount == 1)
- generateCharacterClassSingle(state);
- else
- generateCharacterClassFixed(state);
- break;
- case QuantifierGreedy:
- generateCharacterClassGreedy(state);
- break;
- case QuantifierNonGreedy:
- generateCharacterClassNonGreedy(state);
- break;
- }
- break;
-
- case PatternTerm::TypeBackReference:
- ASSERT_NOT_REACHED();
- break;
-
- case PatternTerm::TypeForwardReference:
- break;
-
- case PatternTerm::TypeParenthesesSubpattern:
- ASSERT((term.quantityCount == 1) && !term.parentheses.isCopy); // must fallback to pcre before this point
- generateParenthesesSingle(state);
- break;
-
- case PatternTerm::TypeParentheticalAssertion:
- generateParentheticalAssertion(state);
- break;
- }
- }
-
- void generateDisjunction(PatternDisjunction* disjunction)
- {
- TermGenerationState state(disjunction, 0);
- state.resetAlternative();
-
- // Plant a check to see if there is sufficient input available to run the first alternative.
- // Jumping back to the label 'firstAlternative' will get to this check, jumping to
- // 'firstAlternativeInputChecked' will jump directly to matching the alternative having
- // skipped this check.
-
- Label firstAlternative(this);
-
- // check availability for the next alternative
- int countCheckedForCurrentAlternative = 0;
- int countToCheckForFirstAlternative = 0;
- bool hasShorterAlternatives = false;
- JumpList notEnoughInputForPreviousAlternative;
-
- if (state.alternativeValid()) {
- PatternAlternative* alternative = state.alternative();
- countToCheckForFirstAlternative = alternative->m_minimumSize;
- state.checkedTotal += countToCheckForFirstAlternative;
- if (countToCheckForFirstAlternative)
- notEnoughInputForPreviousAlternative.append(jumpIfNoAvailableInput(countToCheckForFirstAlternative));
- countCheckedForCurrentAlternative = countToCheckForFirstAlternative;
- }
-
- Label firstAlternativeInputChecked(this);
-
- while (state.alternativeValid()) {
- // Track whether any alternatives are shorter than the first one.
- hasShorterAlternatives = hasShorterAlternatives || (countCheckedForCurrentAlternative < countToCheckForFirstAlternative);
-
- PatternAlternative* alternative = state.alternative();
- optimizeAlternative(alternative);
-
- for (state.resetTerm(); state.termValid(); state.nextTerm())
- generateTerm(state);
-
- // If we get here, the alternative matched.
- if (m_pattern.m_body->m_callFrameSize)
- addPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister);
-
- ASSERT(index != returnRegister);
- if (m_pattern.m_body->m_hasFixedSize) {
- move(index, returnRegister);
- if (alternative->m_minimumSize)
- sub32(Imm32(alternative->m_minimumSize), returnRegister);
- } else
- pop(returnRegister);
- store32(index, Address(output, 4));
- store32(returnRegister, output);
-
- generateReturn();
-
- state.nextAlternative();
-
- // if there are any more alternatives, plant the check for input before looping.
- if (state.alternativeValid()) {
- PatternAlternative* nextAlternative = state.alternative();
- int countToCheckForNextAlternative = nextAlternative->m_minimumSize;
-
- if (countCheckedForCurrentAlternative > countToCheckForNextAlternative) { // CASE 1: current alternative was longer than the next one.
- // If we get here, there the last input checked failed.
- notEnoughInputForPreviousAlternative.link(this);
-
- // Check if sufficent input available to run the next alternative
- notEnoughInputForPreviousAlternative.append(jumpIfNoAvailableInput(countToCheckForNextAlternative - countCheckedForCurrentAlternative));
- // We are now in the correct state to enter the next alternative; this add is only required
- // to mirror and revert operation of the sub32, just below.
- add32(Imm32(countCheckedForCurrentAlternative - countToCheckForNextAlternative), index);
-
- // If we get here, there the last input checked passed.
- state.linkAlternativeBacktracks(this);
- // No need to check if we can run the next alternative, since it is shorter -
- // just update index.
- sub32(Imm32(countCheckedForCurrentAlternative - countToCheckForNextAlternative), index);
- } else if (countCheckedForCurrentAlternative < countToCheckForNextAlternative) { // CASE 2: next alternative is longer than the current one.
- // If we get here, there the last input checked failed.
- // If there is insufficient input to run the current alternative, and the next alternative is longer,
- // then there is definitely not enough input to run it - don't even check. Just adjust index, as if
- // we had checked.
- notEnoughInputForPreviousAlternative.link(this);
- add32(Imm32(countToCheckForNextAlternative - countCheckedForCurrentAlternative), index);
- notEnoughInputForPreviousAlternative.append(jump());
-
- // The next alternative is longer than the current one; check the difference.
- state.linkAlternativeBacktracks(this);
- notEnoughInputForPreviousAlternative.append(jumpIfNoAvailableInput(countToCheckForNextAlternative - countCheckedForCurrentAlternative));
- } else { // CASE 3: Both alternatives are the same length.
- ASSERT(countCheckedForCurrentAlternative == countToCheckForNextAlternative);
-
- // If the next alterative is the same length as this one, then no need to check the input -
- // if there was sufficent input to run the current alternative then there is sufficient
- // input to run the next one; if not, there isn't.
- state.linkAlternativeBacktracks(this);
- }
-
- state.checkedTotal -= countCheckedForCurrentAlternative;
- countCheckedForCurrentAlternative = countToCheckForNextAlternative;
- state.checkedTotal += countCheckedForCurrentAlternative;
- }
- }
-
- // If we get here, all Alternatives failed...
-
- state.checkedTotal -= countCheckedForCurrentAlternative;
-
- // How much more input need there be to be able to retry from the first alternative?
- // examples:
- // /yarr_jit/ or /wrec|pcre/
- // In these examples we need check for one more input before looping.
- // /yarr_jit|pcre/
- // In this case we need check for 5 more input to loop (+4 to allow for the first alterative
- // being four longer than the last alternative checked, and another +1 to effectively move
- // the start position along by one).
- // /yarr|rules/ or /wrec|notsomuch/
- // In these examples, provided that there was sufficient input to have just been matching for
- // the second alternative we can loop without checking for available input (since the second
- // alternative is longer than the first). In the latter example we need to decrement index
- // (by 4) so the start position is only progressed by 1 from the last iteration.
- int incrementForNextIter = (countToCheckForFirstAlternative - countCheckedForCurrentAlternative) + 1;
-
- // First, deal with the cases where there was sufficient input to try the last alternative.
- if (incrementForNextIter > 0) // We need to check for more input anyway, fall through to the checking below.
- state.linkAlternativeBacktracks(this);
- else if (m_pattern.m_body->m_hasFixedSize && !incrementForNextIter) // No need to update anything, link these backtracks straight to the to pof the loop!
- state.linkAlternativeBacktracksTo(firstAlternativeInputChecked, this);
- else { // no need to check the input, but we do have some bookkeeping to do first.
- state.linkAlternativeBacktracks(this);
-
- // Where necessary update our preserved start position.
- if (!m_pattern.m_body->m_hasFixedSize) {
- move(index, regT0);
- sub32(Imm32(countCheckedForCurrentAlternative - 1), regT0);
- poke(regT0, m_pattern.m_body->m_callFrameSize);
- }
-
- // Update index if necessary, and loop (without checking).
- if (incrementForNextIter)
- add32(Imm32(incrementForNextIter), index);
- jump().linkTo(firstAlternativeInputChecked, this);
- }
-
- notEnoughInputForPreviousAlternative.link(this);
- // Update our idea of the start position, if we're tracking this.
- if (!m_pattern.m_body->m_hasFixedSize) {
- if (countCheckedForCurrentAlternative - 1) {
- move(index, regT0);
- sub32(Imm32(countCheckedForCurrentAlternative - 1), regT0);
- poke(regT0, m_pattern.m_body->m_callFrameSize);
- } else
- poke(index, m_pattern.m_body->m_callFrameSize);
- }
- // Check if there is sufficent input to run the first alternative again.
- jumpIfAvailableInput(incrementForNextIter).linkTo(firstAlternativeInputChecked, this);
- // No - insufficent input to run the first alteranative, are there any other alternatives we
- // might need to check? If so, the last check will have left the index incremented by
- // (countToCheckForFirstAlternative + 1), so we need test whether countToCheckForFirstAlternative
- // LESS input is available, to have the effect of just progressing the start position by 1
- // from the last iteration. If this check passes we can just jump up to the check associated
- // with the first alternative in the loop. This is a bit sad, since we'll end up trying the
- // first alternative again, and this check will fail (otherwise the check planted just above
- // here would have passed). This is a bit sad, however it saves trying to do something more
- // complex here in compilation, and in the common case we should end up coallescing the checks.
- //
- // FIXME: a nice improvement here may be to stop trying to match sooner, based on the least
- // of the minimum-alternative-lengths. E.g. if I have two alternatives of length 200 and 150,
- // and a string of length 100, we'll end up looping index from 0 to 100, checking whether there
- // is sufficient input to run either alternative (constantly failing). If there had been only
- // one alternative, or if the shorter alternative had come first, we would have terminated
- // immediately. :-/
- if (hasShorterAlternatives)
- jumpIfAvailableInput(-countToCheckForFirstAlternative).linkTo(firstAlternative, this);
- // index will now be a bit garbled (depending on whether 'hasShorterAlternatives' is true,
- // it has either been incremented by 1 or by (countToCheckForFirstAlternative + 1) ...
- // but since we're about to return a failure this doesn't really matter!)
-
- unsigned frameSize = m_pattern.m_body->m_callFrameSize;
- if (!m_pattern.m_body->m_hasFixedSize)
- ++frameSize;
- if (frameSize)
- addPtr(Imm32(frameSize * sizeof(void*)), stackPointerRegister);
-
- move(Imm32(-1), returnRegister);
-
- generateReturn();
- }
-
- void generateEnter()
- {
-#if CPU(X86_64)
- push(X86Registers::ebp);
- move(stackPointerRegister, X86Registers::ebp);
- push(X86Registers::ebx);
-#elif CPU(X86)
- push(X86Registers::ebp);
- move(stackPointerRegister, X86Registers::ebp);
- // TODO: do we need spill registers to fill the output pointer if there are no sub captures?
- push(X86Registers::ebx);
- push(X86Registers::edi);
- push(X86Registers::esi);
- // load output into edi (2 = saved ebp + return address).
- #if COMPILER(MSVC)
- loadPtr(Address(X86Registers::ebp, 2 * sizeof(void*)), input);
- loadPtr(Address(X86Registers::ebp, 3 * sizeof(void*)), index);
- loadPtr(Address(X86Registers::ebp, 4 * sizeof(void*)), length);
- loadPtr(Address(X86Registers::ebp, 5 * sizeof(void*)), output);
- #else
- loadPtr(Address(X86Registers::ebp, 2 * sizeof(void*)), output);
- #endif
-#elif CPU(ARM)
- push(ARMRegisters::r4);
- push(ARMRegisters::r5);
- push(ARMRegisters::r6);
- move(ARMRegisters::r3, output);
-#elif CPU(MIPS)
- // Do nothing.
-#endif
- }
-
- void generateReturn()
- {
-#if CPU(X86_64)
- pop(X86Registers::ebx);
- pop(X86Registers::ebp);
-#elif CPU(X86)
- pop(X86Registers::esi);
- pop(X86Registers::edi);
- pop(X86Registers::ebx);
- pop(X86Registers::ebp);
-#elif CPU(ARM)
- pop(ARMRegisters::r6);
- pop(ARMRegisters::r5);
- pop(ARMRegisters::r4);
-#elif CPU(MIPS)
- // Do nothing
-#endif
- ret();
- }
-
-public:
- RegexGenerator(RegexPattern& pattern)
- : m_pattern(pattern)
- {
- }
-
- void generate()
- {
- generateEnter();
-
- // TODO: do I really want this on the stack?
- if (!m_pattern.m_body->m_hasFixedSize)
- push(index);
-
- if (m_pattern.m_body->m_callFrameSize)
- subPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister);
-
- generateDisjunction(m_pattern.m_body);
- }
-
- void compile(JSGlobalData* globalData, RegexCodeBlock& jitObject)
- {
- generate();
-
- LinkBuffer patchBuffer(this, globalData->regexAllocator.poolForSize(size()), 0);
-
- for (unsigned i = 0; i < m_backtrackRecords.size(); ++i)
- patchBuffer.patch(m_backtrackRecords[i].dataLabel, patchBuffer.locationOf(m_backtrackRecords[i].backtrackLocation));
-
- jitObject.set(patchBuffer.finalizeCode());
- }
-
-private:
- RegexPattern& m_pattern;
- Vector<AlternativeBacktrackRecord> m_backtrackRecords;
-};
-
-void jitCompileRegex(JSGlobalData* globalData, RegexCodeBlock& jitObject, const UString& patternString, unsigned& numSubpatterns, const char*& error, bool ignoreCase, bool multiline)
-{
- RegexPattern pattern(ignoreCase, multiline);
- if ((error = compileRegex(patternString, pattern)))
- return;
- numSubpatterns = pattern.m_numSubpatterns;
-
- if (!pattern.m_shouldFallBack && globalData->canUseJIT() && RegExpCache::isCacheable(patternString)) {
- RegexGenerator generator(pattern);
- generator.compile(globalData, jitObject);
- return;
- }
-
- JSRegExpIgnoreCaseOption ignoreCaseOption = ignoreCase ? JSRegExpIgnoreCase : JSRegExpDoNotIgnoreCase;
- JSRegExpMultilineOption multilineOption = multiline ? JSRegExpMultiline : JSRegExpSingleLine;
- jitObject.setFallback(jsRegExpCompile(reinterpret_cast<const UChar*>(patternString.data()), patternString.size(), ignoreCaseOption, multilineOption, &numSubpatterns, &error));
-}
-
-}}
-
-#endif
-
-
-
-
-
+++ /dev/null
-/*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef RegexJIT_h
-#define RegexJIT_h
-
-#if ENABLE(YARR_JIT)
-
-#include "MacroAssembler.h"
-#include "RegexPattern.h"
-#include <UString.h>
-
-#include <pcre.h>
-struct JSRegExp; // temporary, remove when fallback is removed.
-
-#if CPU(X86) && !COMPILER(MSVC)
-#define YARR_CALL __attribute__ ((regparm (3)))
-#else
-#define YARR_CALL
-#endif
-
-namespace JSC {
-
-class JSGlobalData;
-class ExecutablePool;
-
-namespace Yarr {
-
-class RegexCodeBlock {
- typedef int (*RegexJITCode)(const UChar* input, unsigned start, unsigned length, int* output) YARR_CALL;
-
-public:
- RegexCodeBlock()
- : m_fallback(0)
- {
- }
-
- ~RegexCodeBlock()
- {
- if (m_fallback)
- jsRegExpFree(m_fallback);
- }
-
- JSRegExp* getFallback() { return m_fallback; }
- void setFallback(JSRegExp* fallback) { m_fallback = fallback; }
-
- bool operator!() { return (!m_ref.m_code.executableAddress() && !m_fallback); }
- void set(MacroAssembler::CodeRef ref) { m_ref = ref; }
-
- int execute(const UChar* input, unsigned start, unsigned length, int* output)
- {
- return reinterpret_cast<RegexJITCode>(m_ref.m_code.executableAddress())(input, start, length, output);
- }
-
-private:
- MacroAssembler::CodeRef m_ref;
- JSRegExp* m_fallback;
-};
-
-void jitCompileRegex(JSGlobalData* globalData, RegexCodeBlock& jitObject, const UString& pattern, unsigned& numSubpatterns, const char*& error, bool ignoreCase = false, bool multiline = false);
-
-inline int executeRegex(RegexCodeBlock& jitObject, const UChar* input, unsigned start, unsigned length, int* output, int outputArraySize)
-{
- if (JSRegExp* fallback = jitObject.getFallback())
- return (jsRegExpExecute(fallback, input, length, start, output, outputArraySize) < 0) ? -1 : output[0];
-
- return jitObject.execute(input, start, length, output);
-}
-
-} } // namespace JSC::Yarr
-
-#endif
-
-#endif // RegexJIT_h
+++ /dev/null
-/*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef RegexParser_h
-#define RegexParser_h
-
-#if ENABLE(YARR)
-
-#include <UString.h>
-#include <limits.h>
-#include <wtf/ASCIICType.h>
-#include <wtf/unicode/Unicode.h>
-
-namespace JSC { namespace Yarr {
-
-enum BuiltInCharacterClassID {
- DigitClassID,
- SpaceClassID,
- WordClassID,
- NewlineClassID,
-};
-
-// The Parser class should not be used directly - only via the Yarr::parse() method.
-template<class Delegate>
-class Parser {
-private:
- template<class FriendDelegate>
- friend const char* parse(FriendDelegate& delegate, const UString& pattern, unsigned backReferenceLimit);
-
- enum ErrorCode {
- NoError,
- PatternTooLarge,
- QuantifierOutOfOrder,
- QuantifierWithoutAtom,
- MissingParentheses,
- ParenthesesUnmatched,
- ParenthesesTypeInvalid,
- CharacterClassUnmatched,
- CharacterClassOutOfOrder,
- EscapeUnterminated,
- NumberOfErrorCodes
- };
-
- /*
- * CharacterClassParserDelegate:
- *
- * The class CharacterClassParserDelegate is used in the parsing of character
- * classes. This class handles detection of character ranges. This class
- * implements enough of the delegate interface such that it can be passed to
- * parseEscape() as an EscapeDelegate. This allows parseEscape() to be reused
- * to perform the parsing of escape characters in character sets.
- */
- class CharacterClassParserDelegate {
- public:
- CharacterClassParserDelegate(Delegate& delegate, ErrorCode& err)
- : m_delegate(delegate)
- , m_err(err)
- , m_state(empty)
- {
- }
-
- /*
- * begin():
- *
- * Called at beginning of construction.
- */
- void begin(bool invert)
- {
- m_delegate.atomCharacterClassBegin(invert);
- }
-
- /*
- * atomPatternCharacterUnescaped():
- *
- * This method is called directly from parseCharacterClass(), to report a new
- * pattern character token. This method differs from atomPatternCharacter(),
- * which will be called from parseEscape(), since a hypen provided via this
- * method may be indicating a character range, but a hyphen parsed by
- * parseEscape() cannot be interpreted as doing so.
- */
- void atomPatternCharacterUnescaped(UChar ch)
- {
- switch (m_state) {
- case empty:
- m_character = ch;
- m_state = cachedCharacter;
- break;
-
- case cachedCharacter:
- if (ch == '-')
- m_state = cachedCharacterHyphen;
- else {
- m_delegate.atomCharacterClassAtom(m_character);
- m_character = ch;
- }
- break;
-
- case cachedCharacterHyphen:
- if (ch >= m_character)
- m_delegate.atomCharacterClassRange(m_character, ch);
- else
- m_err = CharacterClassOutOfOrder;
- m_state = empty;
- }
- }
-
- /*
- * atomPatternCharacter():
- *
- * Adds a pattern character, called by parseEscape(), as such will not
- * interpret a hyphen as indicating a character range.
- */
- void atomPatternCharacter(UChar ch)
- {
- // Flush if a character is already pending to prevent the
- // hyphen from begin interpreted as indicating a range.
- if((ch == '-') && (m_state == cachedCharacter))
- flush();
-
- atomPatternCharacterUnescaped(ch);
- }
-
- /*
- * atomBuiltInCharacterClass():
- *
- * Adds a built-in character class, called by parseEscape().
- */
- void atomBuiltInCharacterClass(BuiltInCharacterClassID classID, bool invert)
- {
- flush();
- m_delegate.atomCharacterClassBuiltIn(classID, invert);
- }
-
- /*
- * end():
- *
- * Called at end of construction.
- */
- void end()
- {
- flush();
- m_delegate.atomCharacterClassEnd();
- }
-
- // parseEscape() should never call these delegate methods when
- // invoked with inCharacterClass set.
- void assertionWordBoundary(bool) { ASSERT_NOT_REACHED(); }
- void atomBackReference(unsigned) { ASSERT_NOT_REACHED(); }
-
- private:
- void flush()
- {
- if (m_state != empty) // either cachedCharacter or cachedCharacterHyphen
- m_delegate.atomCharacterClassAtom(m_character);
- if (m_state == cachedCharacterHyphen)
- m_delegate.atomCharacterClassAtom('-');
- m_state = empty;
- }
-
- Delegate& m_delegate;
- ErrorCode& m_err;
- enum CharacterClassConstructionState {
- empty,
- cachedCharacter,
- cachedCharacterHyphen,
- } m_state;
- UChar m_character;
- };
-
- Parser(Delegate& delegate, const UString& pattern, unsigned backReferenceLimit)
- : m_delegate(delegate)
- , m_backReferenceLimit(backReferenceLimit)
- , m_err(NoError)
- , m_data(pattern.data())
- , m_size(pattern.size())
- , m_index(0)
- , m_parenthesesNestingDepth(0)
- {
- }
-
- /*
- * parseEscape():
- *
- * Helper for parseTokens() AND parseCharacterClass().
- * Unlike the other parser methods, this function does not report tokens
- * directly to the member delegate (m_delegate), instead tokens are
- * emitted to the delegate provided as an argument. In the case of atom
- * escapes, parseTokens() will call parseEscape() passing m_delegate as
- * an argument, and as such the escape will be reported to the delegate.
- *
- * However this method may also be used by parseCharacterClass(), in which
- * case a CharacterClassParserDelegate will be passed as the delegate that
- * tokens should be added to. A boolean flag is also provided to indicate
- * whether that an escape in a CharacterClass is being parsed (some parsing
- * rules change in this context).
- *
- * The boolean value returned by this method indicates whether the token
- * parsed was an atom (outside of a characted class \b and \B will be
- * interpreted as assertions).
- */
- template<bool inCharacterClass, class EscapeDelegate>
- bool parseEscape(EscapeDelegate& delegate)
- {
- ASSERT(!m_err);
- ASSERT(peek() == '\\');
- consume();
-
- if (atEndOfPattern()) {
- m_err = EscapeUnterminated;
- return false;
- }
-
- switch (peek()) {
- // Assertions
- case 'b':
- consume();
- if (inCharacterClass)
- delegate.atomPatternCharacter('\b');
- else {
- delegate.assertionWordBoundary(false);
- return false;
- }
- break;
- case 'B':
- consume();
- if (inCharacterClass)
- delegate.atomPatternCharacter('B');
- else {
- delegate.assertionWordBoundary(true);
- return false;
- }
- break;
-
- // CharacterClassEscape
- case 'd':
- consume();
- delegate.atomBuiltInCharacterClass(DigitClassID, false);
- break;
- case 's':
- consume();
- delegate.atomBuiltInCharacterClass(SpaceClassID, false);
- break;
- case 'w':
- consume();
- delegate.atomBuiltInCharacterClass(WordClassID, false);
- break;
- case 'D':
- consume();
- delegate.atomBuiltInCharacterClass(DigitClassID, true);
- break;
- case 'S':
- consume();
- delegate.atomBuiltInCharacterClass(SpaceClassID, true);
- break;
- case 'W':
- consume();
- delegate.atomBuiltInCharacterClass(WordClassID, true);
- break;
-
- // DecimalEscape
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9': {
- // To match Firefox, we parse an invalid backreference in the range [1-7] as an octal escape.
- // First, try to parse this as backreference.
- if (!inCharacterClass) {
- ParseState state = saveState();
-
- unsigned backReference = consumeNumber();
- if (backReference <= m_backReferenceLimit) {
- delegate.atomBackReference(backReference);
- break;
- }
-
- restoreState(state);
- }
-
- // Not a backreference, and not octal.
- if (peek() >= '8') {
- delegate.atomPatternCharacter('\\');
- break;
- }
-
- // Fall-through to handle this as an octal escape.
- }
-
- // Octal escape
- case '0':
- delegate.atomPatternCharacter(consumeOctal());
- break;
-
- // ControlEscape
- case 'f':
- consume();
- delegate.atomPatternCharacter('\f');
- break;
- case 'n':
- consume();
- delegate.atomPatternCharacter('\n');
- break;
- case 'r':
- consume();
- delegate.atomPatternCharacter('\r');
- break;
- case 't':
- consume();
- delegate.atomPatternCharacter('\t');
- break;
- case 'v':
- consume();
- delegate.atomPatternCharacter('\v');
- break;
-
- // ControlLetter
- case 'c': {
- ParseState state = saveState();
- consume();
- if (!atEndOfPattern()) {
- int control = consume();
-
- // To match Firefox, inside a character class, we also accept numbers and '_' as control characters.
- if (inCharacterClass ? WTF::isASCIIAlphanumeric(control) || (control == '_') : WTF::isASCIIAlpha(control)) {
- delegate.atomPatternCharacter(control & 0x1f);
- break;
- }
- }
- restoreState(state);
- delegate.atomPatternCharacter('\\');
- break;
- }
-
- // HexEscape
- case 'x': {
- consume();
- int x = tryConsumeHex(2);
- if (x == -1)
- delegate.atomPatternCharacter('x');
- else
- delegate.atomPatternCharacter(x);
- break;
- }
-
- // UnicodeEscape
- case 'u': {
- consume();
- int u = tryConsumeHex(4);
- if (u == -1)
- delegate.atomPatternCharacter('u');
- else
- delegate.atomPatternCharacter(u);
- break;
- }
-
- // IdentityEscape
- default:
- delegate.atomPatternCharacter(consume());
- }
-
- return true;
- }
-
- /*
- * parseAtomEscape(), parseCharacterClassEscape():
- *
- * These methods alias to parseEscape().
- */
- bool parseAtomEscape()
- {
- return parseEscape<false>(m_delegate);
- }
- void parseCharacterClassEscape(CharacterClassParserDelegate& delegate)
- {
- parseEscape<true>(delegate);
- }
-
- /*
- * parseCharacterClass():
- *
- * Helper for parseTokens(); calls dirctly and indirectly (via parseCharacterClassEscape)
- * to an instance of CharacterClassParserDelegate, to describe the character class to the
- * delegate.
- */
- void parseCharacterClass()
- {
- ASSERT(!m_err);
- ASSERT(peek() == '[');
- consume();
-
- CharacterClassParserDelegate characterClassConstructor(m_delegate, m_err);
-
- characterClassConstructor.begin(tryConsume('^'));
-
- while (!atEndOfPattern()) {
- switch (peek()) {
- case ']':
- consume();
- characterClassConstructor.end();
- return;
-
- case '\\':
- parseCharacterClassEscape(characterClassConstructor);
- break;
-
- default:
- characterClassConstructor.atomPatternCharacterUnescaped(consume());
- }
-
- if (m_err)
- return;
- }
-
- m_err = CharacterClassUnmatched;
- }
-
- /*
- * parseParenthesesBegin():
- *
- * Helper for parseTokens(); checks for parentheses types other than regular capturing subpatterns.
- */
- void parseParenthesesBegin()
- {
- ASSERT(!m_err);
- ASSERT(peek() == '(');
- consume();
-
- if (tryConsume('?')) {
- if (atEndOfPattern()) {
- m_err = ParenthesesTypeInvalid;
- return;
- }
-
- switch (consume()) {
- case ':':
- m_delegate.atomParenthesesSubpatternBegin(false);
- break;
-
- case '=':
- m_delegate.atomParentheticalAssertionBegin();
- break;
-
- case '!':
- m_delegate.atomParentheticalAssertionBegin(true);
- break;
-
- default:
- m_err = ParenthesesTypeInvalid;
- }
- } else
- m_delegate.atomParenthesesSubpatternBegin();
-
- ++m_parenthesesNestingDepth;
- }
-
- /*
- * parseParenthesesEnd():
- *
- * Helper for parseTokens(); checks for parse errors (due to unmatched parentheses).
- */
- void parseParenthesesEnd()
- {
- ASSERT(!m_err);
- ASSERT(peek() == ')');
- consume();
-
- if (m_parenthesesNestingDepth > 0)
- m_delegate.atomParenthesesEnd();
- else
- m_err = ParenthesesUnmatched;
-
- --m_parenthesesNestingDepth;
- }
-
- /*
- * parseQuantifier():
- *
- * Helper for parseTokens(); checks for parse errors and non-greedy quantifiers.
- */
- void parseQuantifier(bool lastTokenWasAnAtom, unsigned min, unsigned max)
- {
- ASSERT(!m_err);
- ASSERT(min <= max);
-
- if (lastTokenWasAnAtom)
- m_delegate.quantifyAtom(min, max, !tryConsume('?'));
- else
- m_err = QuantifierWithoutAtom;
- }
-
- /*
- * parseTokens():
- *
- * This method loops over the input pattern reporting tokens to the delegate.
- * The method returns when a parse error is detected, or the end of the pattern
- * is reached. One piece of state is tracked around the loop, which is whether
- * the last token passed to the delegate was an atom (this is necessary to detect
- * a parse error when a quantifier provided without an atom to quantify).
- */
- void parseTokens()
- {
- bool lastTokenWasAnAtom = false;
-
- while (!atEndOfPattern()) {
- switch (peek()) {
- case '|':
- consume();
- m_delegate.disjunction();
- lastTokenWasAnAtom = false;
- break;
-
- case '(':
- parseParenthesesBegin();
- lastTokenWasAnAtom = false;
- break;
-
- case ')':
- parseParenthesesEnd();
- lastTokenWasAnAtom = true;
- break;
-
- case '^':
- consume();
- m_delegate.assertionBOL();
- lastTokenWasAnAtom = false;
- break;
-
- case '$':
- consume();
- m_delegate.assertionEOL();
- lastTokenWasAnAtom = false;
- break;
-
- case '.':
- consume();
- m_delegate.atomBuiltInCharacterClass(NewlineClassID, true);
- lastTokenWasAnAtom = true;
- break;
-
- case '[':
- parseCharacterClass();
- lastTokenWasAnAtom = true;
- break;
-
- case '\\':
- lastTokenWasAnAtom = parseAtomEscape();
- break;
-
- case '*':
- consume();
- parseQuantifier(lastTokenWasAnAtom, 0, UINT_MAX);
- lastTokenWasAnAtom = false;
- break;
-
- case '+':
- consume();
- parseQuantifier(lastTokenWasAnAtom, 1, UINT_MAX);
- lastTokenWasAnAtom = false;
- break;
-
- case '?':
- consume();
- parseQuantifier(lastTokenWasAnAtom, 0, 1);
- lastTokenWasAnAtom = false;
- break;
-
- case '{': {
- ParseState state = saveState();
-
- consume();
- if (peekIsDigit()) {
- unsigned min = consumeNumber();
- unsigned max = min;
-
- if (tryConsume(','))
- max = peekIsDigit() ? consumeNumber() : UINT_MAX;
-
- if (tryConsume('}')) {
- if (min <= max)
- parseQuantifier(lastTokenWasAnAtom, min, max);
- else
- m_err = QuantifierOutOfOrder;
- lastTokenWasAnAtom = false;
- break;
- }
- }
-
- restoreState(state);
- } // if we did not find a complete quantifer, fall through to the default case.
-
- default:
- m_delegate.atomPatternCharacter(consume());
- lastTokenWasAnAtom = true;
- }
-
- if (m_err)
- return;
- }
-
- if (m_parenthesesNestingDepth > 0)
- m_err = MissingParentheses;
- }
-
- /*
- * parse():
- *
- * This method calls regexBegin(), calls parseTokens() to parse over the input
- * patterns, calls regexEnd() or regexError() as appropriate, and converts any
- * error code to a const char* for a result.
- */
- const char* parse()
- {
- m_delegate.regexBegin();
-
- if (m_size > MAX_PATTERN_SIZE)
- m_err = PatternTooLarge;
- else
- parseTokens();
- ASSERT(atEndOfPattern() || m_err);
-
- if (m_err)
- m_delegate.regexError();
- else
- m_delegate.regexEnd();
-
- // The order of this array must match the ErrorCode enum.
- static const char* errorMessages[NumberOfErrorCodes] = {
- 0, // NoError
- "regular expression too large",
- "numbers out of order in {} quantifier",
- "nothing to repeat",
- "missing )",
- "unmatched parentheses",
- "unrecognized character after (?",
- "missing terminating ] for character class",
- "range out of order in character class",
- "\\ at end of pattern"
- };
-
- return errorMessages[m_err];
- }
-
-
- // Misc helper functions:
-
- typedef unsigned ParseState;
-
- ParseState saveState()
- {
- return m_index;
- }
-
- void restoreState(ParseState state)
- {
- m_index = state;
- }
-
- bool atEndOfPattern()
- {
- ASSERT(m_index <= m_size);
- return m_index == m_size;
- }
-
- int peek()
- {
- ASSERT(m_index < m_size);
- return m_data[m_index];
- }
-
- bool peekIsDigit()
- {
- return !atEndOfPattern() && WTF::isASCIIDigit(peek());
- }
-
- unsigned peekDigit()
- {
- ASSERT(peekIsDigit());
- return peek() - '0';
- }
-
- int consume()
- {
- ASSERT(m_index < m_size);
- return m_data[m_index++];
- }
-
- unsigned consumeDigit()
- {
- ASSERT(peekIsDigit());
- return consume() - '0';
- }
-
- unsigned consumeNumber()
- {
- unsigned n = consumeDigit();
- // check for overflow.
- for (unsigned newValue; peekIsDigit() && ((newValue = n * 10 + peekDigit()) >= n); ) {
- n = newValue;
- consume();
- }
- return n;
- }
-
- unsigned consumeOctal()
- {
- ASSERT(WTF::isASCIIOctalDigit(peek()));
-
- unsigned n = consumeDigit();
- while (n < 32 && !atEndOfPattern() && WTF::isASCIIOctalDigit(peek()))
- n = n * 8 + consumeDigit();
- return n;
- }
-
- bool tryConsume(UChar ch)
- {
- if (atEndOfPattern() || (m_data[m_index] != ch))
- return false;
- ++m_index;
- return true;
- }
-
- int tryConsumeHex(int count)
- {
- ParseState state = saveState();
-
- int n = 0;
- while (count--) {
- if (atEndOfPattern() || !WTF::isASCIIHexDigit(peek())) {
- restoreState(state);
- return -1;
- }
- n = (n << 4) | WTF::toASCIIHexValue(consume());
- }
- return n;
- }
-
- Delegate& m_delegate;
- unsigned m_backReferenceLimit;
- ErrorCode m_err;
- const UChar* m_data;
- unsigned m_size;
- unsigned m_index;
- unsigned m_parenthesesNestingDepth;
-
- // Derived by empirical testing of compile time in PCRE and WREC.
- static const unsigned MAX_PATTERN_SIZE = 1024 * 1024;
-};
-
-/*
- * Yarr::parse():
- *
- * The parse method is passed a pattern to be parsed and a delegate upon which
- * callbacks will be made to record the parsed tokens forming the regex.
- * Yarr::parse() returns null on success, or a const C string providing an error
- * message where a parse error occurs.
- *
- * The Delegate must implement the following interface:
- *
- * void assertionBOL();
- * void assertionEOL();
- * void assertionWordBoundary(bool invert);
- *
- * void atomPatternCharacter(UChar ch);
- * void atomBuiltInCharacterClass(BuiltInCharacterClassID classID, bool invert);
- * void atomCharacterClassBegin(bool invert)
- * void atomCharacterClassAtom(UChar ch)
- * void atomCharacterClassRange(UChar begin, UChar end)
- * void atomCharacterClassBuiltIn(BuiltInCharacterClassID classID, bool invert)
- * void atomCharacterClassEnd()
- * void atomParenthesesSubpatternBegin(bool capture = true);
- * void atomParentheticalAssertionBegin(bool invert = false);
- * void atomParenthesesEnd();
- * void atomBackReference(unsigned subpatternId);
- *
- * void quantifyAtom(unsigned min, unsigned max, bool greedy);
- *
- * void disjunction();
- *
- * void regexBegin();
- * void regexEnd();
- * void regexError();
- *
- * Before any call recording tokens are made, regexBegin() will be called on the
- * delegate once. Once parsing is complete either regexEnd() or regexError() will
- * be called, as appropriate.
- *
- * The regular expression is described by a sequence of assertion*() and atom*()
- * callbacks to the delegate, describing the terms in the regular expression.
- * Following an atom a quantifyAtom() call may occur to indicate that the previous
- * atom should be quantified. In the case of atoms described across multiple
- * calls (parentheses and character classes) the call to quantifyAtom() will come
- * after the call to the atom*End() method, never after atom*Begin().
- *
- * Character classes may either be described by a single call to
- * atomBuiltInCharacterClass(), or by a sequence of atomCharacterClass*() calls.
- * In the latter case, ...Begin() will be called, followed by a sequence of
- * calls to ...Atom(), ...Range(), and ...BuiltIn(), followed by a call to ...End().
- *
- * Sequences of atoms and assertions are broken into alternatives via calls to
- * disjunction(). Assertions, atoms, and disjunctions emitted between calls to
- * atomParenthesesBegin() and atomParenthesesEnd() form the body of a subpattern.
- * atomParenthesesBegin() is passed a subpatternId. In the case of a regular
- * capturing subpattern, this will be the subpatternId associated with these
- * parentheses, and will also by definition be the lowest subpatternId of these
- * parentheses and of any nested paretheses. The atomParenthesesEnd() method
- * is passed the subpatternId of the last capturing subexpression nested within
- * these paretheses. In the case of a capturing subpattern with no nested
- * capturing subpatterns, the same subpatternId will be passed to the begin and
- * end functions. In the case of non-capturing subpatterns the subpatternId
- * passed to the begin method is also the first possible subpatternId that might
- * be nested within these paretheses. If a set of non-capturing parentheses does
- * not contain any capturing subpatterns, then the subpatternId passed to begin
- * will be greater than the subpatternId passed to end.
- */
-
-template<class Delegate>
-const char* parse(Delegate& delegate, const UString& pattern, unsigned backReferenceLimit = UINT_MAX)
-{
- return Parser<Delegate>(delegate, pattern, backReferenceLimit).parse();
-}
-
-} } // namespace JSC::Yarr
-
-#endif
-
-#endif // RegexParser_h
+++ /dev/null
-/*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef RegexPattern_h
-#define RegexPattern_h
-
-
-#if ENABLE(YARR)
-
-#include <wtf/Vector.h>
-#include <wtf/unicode/Unicode.h>
-
-
-namespace JSC { namespace Yarr {
-
-#define RegexStackSpaceForBackTrackInfoPatternCharacter 1 // Only for !fixed quantifiers.
-#define RegexStackSpaceForBackTrackInfoCharacterClass 1 // Only for !fixed quantifiers.
-#define RegexStackSpaceForBackTrackInfoBackReference 2
-#define RegexStackSpaceForBackTrackInfoAlternative 1 // One per alternative.
-#define RegexStackSpaceForBackTrackInfoParentheticalAssertion 1
-#define RegexStackSpaceForBackTrackInfoParenthesesOnce 1 // Only for !fixed quantifiers.
-#define RegexStackSpaceForBackTrackInfoParentheses 4
-
-struct PatternDisjunction;
-
-struct CharacterRange {
- UChar begin;
- UChar end;
-
- CharacterRange(UChar begin, UChar end)
- : begin(begin)
- , end(end)
- {
- }
-};
-
-struct CharacterClassTable : RefCounted<CharacterClassTable> {
- const char* m_table;
- bool m_inverted;
- static PassRefPtr<CharacterClassTable> create(const char* table, bool inverted)
- {
- return adoptRef(new CharacterClassTable(table, inverted));
- }
-
-private:
- CharacterClassTable(const char* table, bool inverted)
- : m_table(table)
- , m_inverted(inverted)
- {
- }
-};
-
-struct CharacterClass : FastAllocBase {
- // All CharacterClass instances have to have the full set of matches and ranges,
- // they may have an optional table for faster lookups (which must match the
- // specified matches and ranges)
- CharacterClass(PassRefPtr<CharacterClassTable> table)
- : m_table(table)
- {
- }
- Vector<UChar> m_matches;
- Vector<CharacterRange> m_ranges;
- Vector<UChar> m_matchesUnicode;
- Vector<CharacterRange> m_rangesUnicode;
- RefPtr<CharacterClassTable> m_table;
-};
-
-enum QuantifierType {
- QuantifierFixedCount,
- QuantifierGreedy,
- QuantifierNonGreedy,
-};
-
-struct PatternTerm {
- enum Type {
- TypeAssertionBOL,
- TypeAssertionEOL,
- TypeAssertionWordBoundary,
- TypePatternCharacter,
- TypeCharacterClass,
- TypeBackReference,
- TypeForwardReference,
- TypeParenthesesSubpattern,
- TypeParentheticalAssertion,
- } type;
- bool invertOrCapture;
- union {
- UChar patternCharacter;
- CharacterClass* characterClass;
- unsigned subpatternId;
- struct {
- PatternDisjunction* disjunction;
- unsigned subpatternId;
- unsigned lastSubpatternId;
- bool isCopy;
- } parentheses;
- };
- QuantifierType quantityType;
- unsigned quantityCount;
- int inputPosition;
- unsigned frameLocation;
-
- PatternTerm(UChar ch)
- : type(PatternTerm::TypePatternCharacter)
- {
- patternCharacter = ch;
- quantityType = QuantifierFixedCount;
- quantityCount = 1;
- }
-
- PatternTerm(CharacterClass* charClass, bool invert)
- : type(PatternTerm::TypeCharacterClass)
- , invertOrCapture(invert)
- {
- characterClass = charClass;
- quantityType = QuantifierFixedCount;
- quantityCount = 1;
- }
-
- PatternTerm(Type type, unsigned subpatternId, PatternDisjunction* disjunction, bool invertOrCapture)
- : type(type)
- , invertOrCapture(invertOrCapture)
- {
- parentheses.disjunction = disjunction;
- parentheses.subpatternId = subpatternId;
- parentheses.isCopy = false;
- quantityType = QuantifierFixedCount;
- quantityCount = 1;
- }
-
- PatternTerm(Type type, bool invert = false)
- : type(type)
- , invertOrCapture(invert)
- {
- quantityType = QuantifierFixedCount;
- quantityCount = 1;
- }
-
- PatternTerm(unsigned spatternId)
- : type(TypeBackReference)
- , invertOrCapture(false)
- {
- subpatternId = spatternId;
- quantityType = QuantifierFixedCount;
- quantityCount = 1;
- }
-
- static PatternTerm ForwardReference()
- {
- return PatternTerm(TypeForwardReference);
- }
-
- static PatternTerm BOL()
- {
- return PatternTerm(TypeAssertionBOL);
- }
-
- static PatternTerm EOL()
- {
- return PatternTerm(TypeAssertionEOL);
- }
-
- static PatternTerm WordBoundary(bool invert)
- {
- return PatternTerm(TypeAssertionWordBoundary, invert);
- }
-
- bool invert()
- {
- return invertOrCapture;
- }
-
- bool capture()
- {
- return invertOrCapture;
- }
-
- void quantify(unsigned count, QuantifierType type)
- {
- quantityCount = count;
- quantityType = type;
- }
-};
-
-struct PatternAlternative : FastAllocBase {
- PatternAlternative(PatternDisjunction* disjunction)
- : m_parent(disjunction)
- {
- }
-
- PatternTerm& lastTerm()
- {
- ASSERT(m_terms.size());
- return m_terms[m_terms.size() - 1];
- }
-
- void removeLastTerm()
- {
- ASSERT(m_terms.size());
- m_terms.shrink(m_terms.size() - 1);
- }
-
- Vector<PatternTerm> m_terms;
- PatternDisjunction* m_parent;
- unsigned m_minimumSize;
- bool m_hasFixedSize;
-};
-
-struct PatternDisjunction : FastAllocBase {
- PatternDisjunction(PatternAlternative* parent = 0)
- : m_parent(parent)
- {
- }
-
- ~PatternDisjunction()
- {
- deleteAllValues(m_alternatives);
- }
-
- PatternAlternative* addNewAlternative()
- {
- PatternAlternative* alternative = new PatternAlternative(this);
- m_alternatives.append(alternative);
- return alternative;
- }
-
- Vector<PatternAlternative*> m_alternatives;
- PatternAlternative* m_parent;
- unsigned m_minimumSize;
- unsigned m_callFrameSize;
- bool m_hasFixedSize;
-};
-
-// You probably don't want to be calling these functions directly
-// (please to be calling newlineCharacterClass() et al on your
-// friendly neighborhood RegexPattern instance to get nicely
-// cached copies).
-CharacterClass* newlineCreate();
-CharacterClass* digitsCreate();
-CharacterClass* spacesCreate();
-CharacterClass* wordcharCreate();
-CharacterClass* nondigitsCreate();
-CharacterClass* nonspacesCreate();
-CharacterClass* nonwordcharCreate();
-
-struct RegexPattern {
- RegexPattern(bool ignoreCase, bool multiline)
- : m_ignoreCase(ignoreCase)
- , m_multiline(multiline)
- , m_numSubpatterns(0)
- , m_maxBackReference(0)
- , m_shouldFallBack(false)
- , newlineCached(0)
- , digitsCached(0)
- , spacesCached(0)
- , wordcharCached(0)
- , nondigitsCached(0)
- , nonspacesCached(0)
- , nonwordcharCached(0)
- {
- }
-
- ~RegexPattern()
- {
- deleteAllValues(m_disjunctions);
- deleteAllValues(m_userCharacterClasses);
- }
-
- void reset()
- {
- m_numSubpatterns = 0;
- m_maxBackReference = 0;
-
- m_shouldFallBack = false;
-
- newlineCached = 0;
- digitsCached = 0;
- spacesCached = 0;
- wordcharCached = 0;
- nondigitsCached = 0;
- nonspacesCached = 0;
- nonwordcharCached = 0;
-
- deleteAllValues(m_disjunctions);
- m_disjunctions.clear();
- deleteAllValues(m_userCharacterClasses);
- m_userCharacterClasses.clear();
- }
-
- bool containsIllegalBackReference()
- {
- return m_maxBackReference > m_numSubpatterns;
- }
-
- CharacterClass* newlineCharacterClass()
- {
- if (!newlineCached)
- m_userCharacterClasses.append(newlineCached = newlineCreate());
- return newlineCached;
- }
- CharacterClass* digitsCharacterClass()
- {
- if (!digitsCached)
- m_userCharacterClasses.append(digitsCached = digitsCreate());
- return digitsCached;
- }
- CharacterClass* spacesCharacterClass()
- {
- if (!spacesCached)
- m_userCharacterClasses.append(spacesCached = spacesCreate());
- return spacesCached;
- }
- CharacterClass* wordcharCharacterClass()
- {
- if (!wordcharCached)
- m_userCharacterClasses.append(wordcharCached = wordcharCreate());
- return wordcharCached;
- }
- CharacterClass* nondigitsCharacterClass()
- {
- if (!nondigitsCached)
- m_userCharacterClasses.append(nondigitsCached = nondigitsCreate());
- return nondigitsCached;
- }
- CharacterClass* nonspacesCharacterClass()
- {
- if (!nonspacesCached)
- m_userCharacterClasses.append(nonspacesCached = nonspacesCreate());
- return nonspacesCached;
- }
- CharacterClass* nonwordcharCharacterClass()
- {
- if (!nonwordcharCached)
- m_userCharacterClasses.append(nonwordcharCached = nonwordcharCreate());
- return nonwordcharCached;
- }
-
- bool m_ignoreCase;
- bool m_multiline;
- unsigned m_numSubpatterns;
- unsigned m_maxBackReference;
- bool m_shouldFallBack;
- PatternDisjunction* m_body;
- Vector<PatternDisjunction*, 4> m_disjunctions;
- Vector<CharacterClass*> m_userCharacterClasses;
-
-private:
- CharacterClass* newlineCached;
- CharacterClass* digitsCached;
- CharacterClass* spacesCached;
- CharacterClass* wordcharCached;
- CharacterClass* nondigitsCached;
- CharacterClass* nonspacesCached;
- CharacterClass* nonwordcharCached;
-};
-
-} } // namespace JSC::Yarr
-
-#endif
-
-#endif // RegexPattern_h
--- /dev/null
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Peter Varga (pvarga@inf.u-szeged.hu), University of Szeged
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef Yarr_h
+#define Yarr_h
+
+#include "YarrInterpreter.h"
+#include "YarrPattern.h"
+
+namespace JSC { namespace Yarr {
+
+#define YarrStackSpaceForBackTrackInfoPatternCharacter 1 // Only for !fixed quantifiers.
+#define YarrStackSpaceForBackTrackInfoCharacterClass 1 // Only for !fixed quantifiers.
+#define YarrStackSpaceForBackTrackInfoBackReference 2
+#define YarrStackSpaceForBackTrackInfoAlternative 1 // One per alternative.
+#define YarrStackSpaceForBackTrackInfoParentheticalAssertion 1
+#define YarrStackSpaceForBackTrackInfoParenthesesOnce 1 // Only for !fixed quantifiers.
+#define YarrStackSpaceForBackTrackInfoParenthesesTerminal 1
+#define YarrStackSpaceForBackTrackInfoParentheses 2
+
+static const unsigned quantifyInfinite = UINT_MAX;
+
+// The below limit restricts the number of "recursive" match calls in order to
+// avoid spending exponential time on complex regular expressions.
+static const unsigned matchLimit = 1000000;
+
+enum JSRegExpResult {
+ JSRegExpMatch = 1,
+ JSRegExpNoMatch = 0,
+ JSRegExpErrorNoMatch = -1,
+ JSRegExpErrorHitLimit = -2,
+ JSRegExpErrorNoMemory = -3,
+ JSRegExpErrorInternal = -4
+};
+
+PassOwnPtr<BytecodePattern> byteCompile(YarrPattern&, BumpPointerAllocator*);
+int interpret(BytecodePattern*, const UChar* input, unsigned start, unsigned length, int* output);
+
+} } // namespace JSC::Yarr
+
+#endif // Yarr_h
+
--- /dev/null
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Peter Varga (pvarga@inf.u-szeged.hu), University of Szeged
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "YarrInterpreter.h"
+
+#include "Yarr.h"
+#include <wtf/BumpPointerAllocator.h>
+
+#ifndef NDEBUG
+#include <stdio.h>
+#endif
+
+using namespace WTF;
+
+namespace JSC { namespace Yarr {
+
+class Interpreter {
+public:
+ struct ParenthesesDisjunctionContext;
+
+ struct BackTrackInfoPatternCharacter {
+ uintptr_t matchAmount;
+ };
+ struct BackTrackInfoCharacterClass {
+ uintptr_t matchAmount;
+ };
+ struct BackTrackInfoBackReference {
+ uintptr_t begin; // Not really needed for greedy quantifiers.
+ uintptr_t matchAmount; // Not really needed for fixed quantifiers.
+ };
+ struct BackTrackInfoAlternative {
+ uintptr_t offset;
+ };
+ struct BackTrackInfoParentheticalAssertion {
+ uintptr_t begin;
+ };
+ struct BackTrackInfoParenthesesOnce {
+ uintptr_t begin;
+ };
+ struct BackTrackInfoParenthesesTerminal {
+ uintptr_t begin;
+ };
+ struct BackTrackInfoParentheses {
+ uintptr_t matchAmount;
+ ParenthesesDisjunctionContext* lastContext;
+ };
+
+ static inline void appendParenthesesDisjunctionContext(BackTrackInfoParentheses* backTrack, ParenthesesDisjunctionContext* context)
+ {
+ context->next = backTrack->lastContext;
+ backTrack->lastContext = context;
+ ++backTrack->matchAmount;
+ }
+
+ static inline void popParenthesesDisjunctionContext(BackTrackInfoParentheses* backTrack)
+ {
+ ASSERT(backTrack->matchAmount);
+ ASSERT(backTrack->lastContext);
+ backTrack->lastContext = backTrack->lastContext->next;
+ --backTrack->matchAmount;
+ }
+
+ struct DisjunctionContext
+ {
+ DisjunctionContext()
+ : term(0)
+ {
+ }
+
+ void* operator new(size_t, void* where)
+ {
+ return where;
+ }
+
+ int term;
+ unsigned matchBegin;
+ unsigned matchEnd;
+ uintptr_t frame[1];
+ };
+
+ DisjunctionContext* allocDisjunctionContext(ByteDisjunction* disjunction)
+ {
+ size_t size = sizeof(DisjunctionContext) - sizeof(uintptr_t) + disjunction->m_frameSize * sizeof(uintptr_t);
+ allocatorPool = allocatorPool->ensureCapacity(size);
+ if (!allocatorPool)
+ CRASH();
+ return new(allocatorPool->alloc(size)) DisjunctionContext();
+ }
+
+ void freeDisjunctionContext(DisjunctionContext* context)
+ {
+ allocatorPool = allocatorPool->dealloc(context);
+ }
+
+ struct ParenthesesDisjunctionContext
+ {
+ ParenthesesDisjunctionContext(int* output, ByteTerm& term)
+ : next(0)
+ {
+ unsigned firstSubpatternId = term.atom.subpatternId;
+ unsigned numNestedSubpatterns = term.atom.parenthesesDisjunction->m_numSubpatterns;
+
+ for (unsigned i = 0; i < (numNestedSubpatterns << 1); ++i) {
+ subpatternBackup[i] = output[(firstSubpatternId << 1) + i];
+ output[(firstSubpatternId << 1) + i] = -1;
+ }
+
+ new(getDisjunctionContext(term)) DisjunctionContext();
+ }
+
+ void* operator new(size_t, void* where)
+ {
+ return where;
+ }
+
+ void restoreOutput(int* output, unsigned firstSubpatternId, unsigned numNestedSubpatterns)
+ {
+ for (unsigned i = 0; i < (numNestedSubpatterns << 1); ++i)
+ output[(firstSubpatternId << 1) + i] = subpatternBackup[i];
+ }
+
+ DisjunctionContext* getDisjunctionContext(ByteTerm& term)
+ {
+ return reinterpret_cast<DisjunctionContext*>(&(subpatternBackup[term.atom.parenthesesDisjunction->m_numSubpatterns << 1]));
+ }
+
+ ParenthesesDisjunctionContext* next;
+ int subpatternBackup[1];
+ };
+
+ ParenthesesDisjunctionContext* allocParenthesesDisjunctionContext(ByteDisjunction* disjunction, int* output, ByteTerm& term)
+ {
+ size_t size = sizeof(ParenthesesDisjunctionContext) - sizeof(int) + (term.atom.parenthesesDisjunction->m_numSubpatterns << 1) * sizeof(int) + sizeof(DisjunctionContext) - sizeof(uintptr_t) + disjunction->m_frameSize * sizeof(uintptr_t);
+ allocatorPool = allocatorPool->ensureCapacity(size);
+ if (!allocatorPool)
+ CRASH();
+ return new(allocatorPool->alloc(size)) ParenthesesDisjunctionContext(output, term);
+ }
+
+ void freeParenthesesDisjunctionContext(ParenthesesDisjunctionContext* context)
+ {
+ allocatorPool = allocatorPool->dealloc(context);
+ }
+
+ class InputStream {
+ public:
+ InputStream(const UChar* input, unsigned start, unsigned length)
+ : input(input)
+ , pos(start)
+ , length(length)
+ {
+ }
+
+ void next()
+ {
+ ++pos;
+ }
+
+ void rewind(unsigned amount)
+ {
+ ASSERT(pos >= amount);
+ pos -= amount;
+ }
+
+ int read()
+ {
+ ASSERT(pos < length);
+ if (pos < length)
+ return input[pos];
+ return -1;
+ }
+
+ int readPair()
+ {
+ ASSERT(pos + 1 < length);
+ return input[pos] | input[pos + 1] << 16;
+ }
+
+ int readChecked(int position)
+ {
+ ASSERT(position < 0);
+ ASSERT(static_cast<unsigned>(-position) <= pos);
+ unsigned p = pos + position;
+ ASSERT(p < length);
+ return input[p];
+ }
+
+ int reread(unsigned from)
+ {
+ ASSERT(from < length);
+ return input[from];
+ }
+
+ int prev()
+ {
+ ASSERT(!(pos > length));
+ if (pos && length)
+ return input[pos - 1];
+ return -1;
+ }
+
+ unsigned getPos()
+ {
+ return pos;
+ }
+
+ void setPos(unsigned p)
+ {
+ pos = p;
+ }
+
+ bool atStart()
+ {
+ return pos == 0;
+ }
+
+ bool atEnd()
+ {
+ return pos == length;
+ }
+
+ unsigned end()
+ {
+ return length;
+ }
+
+ bool checkInput(int count)
+ {
+ if ((pos + count) <= length) {
+ pos += count;
+ return true;
+ }
+ return false;
+ }
+
+ void uncheckInput(int count)
+ {
+ pos -= count;
+ }
+
+ bool atStart(int position)
+ {
+ return (pos + position) == 0;
+ }
+
+ bool atEnd(int position)
+ {
+ return (pos + position) == length;
+ }
+
+ bool isNotAvailableInput(int position)
+ {
+ return (pos + position) > length;
+ }
+
+ private:
+ const UChar* input;
+ unsigned pos;
+ unsigned length;
+ };
+
+ bool testCharacterClass(CharacterClass* characterClass, int ch)
+ {
+ if (ch & 0xFF80) {
+ for (unsigned i = 0; i < characterClass->m_matchesUnicode.size(); ++i)
+ if (ch == characterClass->m_matchesUnicode[i])
+ return true;
+ for (unsigned i = 0; i < characterClass->m_rangesUnicode.size(); ++i)
+ if ((ch >= characterClass->m_rangesUnicode[i].begin) && (ch <= characterClass->m_rangesUnicode[i].end))
+ return true;
+ } else {
+ for (unsigned i = 0; i < characterClass->m_matches.size(); ++i)
+ if (ch == characterClass->m_matches[i])
+ return true;
+ for (unsigned i = 0; i < characterClass->m_ranges.size(); ++i)
+ if ((ch >= characterClass->m_ranges[i].begin) && (ch <= characterClass->m_ranges[i].end))
+ return true;
+ }
+
+ return false;
+ }
+
+ bool checkCharacter(int testChar, int inputPosition)
+ {
+ return testChar == input.readChecked(inputPosition);
+ }
+
+ bool checkCasedCharacter(int loChar, int hiChar, int inputPosition)
+ {
+ int ch = input.readChecked(inputPosition);
+ return (loChar == ch) || (hiChar == ch);
+ }
+
+ bool checkCharacterClass(CharacterClass* characterClass, bool invert, int inputPosition)
+ {
+ bool match = testCharacterClass(characterClass, input.readChecked(inputPosition));
+ return invert ? !match : match;
+ }
+
+ bool tryConsumeBackReference(int matchBegin, int matchEnd, int inputOffset)
+ {
+ int matchSize = matchEnd - matchBegin;
+
+ if (!input.checkInput(matchSize))
+ return false;
+
+ if (pattern->m_ignoreCase) {
+ for (int i = 0; i < matchSize; ++i) {
+ int ch = input.reread(matchBegin + i);
+
+ int lo = Unicode::toLower(ch);
+ int hi = Unicode::toUpper(ch);
+
+ if ((lo != hi) ? (!checkCasedCharacter(lo, hi, inputOffset - matchSize + i)) : (!checkCharacter(ch, inputOffset - matchSize + i))) {
+ input.uncheckInput(matchSize);
+ return false;
+ }
+ }
+ } else {
+ for (int i = 0; i < matchSize; ++i) {
+ if (!checkCharacter(input.reread(matchBegin + i), inputOffset - matchSize + i)) {
+ input.uncheckInput(matchSize);
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ bool matchAssertionBOL(ByteTerm& term)
+ {
+ return (input.atStart(term.inputPosition)) || (pattern->m_multiline && testCharacterClass(pattern->newlineCharacterClass, input.readChecked(term.inputPosition - 1)));
+ }
+
+ bool matchAssertionEOL(ByteTerm& term)
+ {
+ if (term.inputPosition)
+ return (input.atEnd(term.inputPosition)) || (pattern->m_multiline && testCharacterClass(pattern->newlineCharacterClass, input.readChecked(term.inputPosition)));
+
+ return (input.atEnd()) || (pattern->m_multiline && testCharacterClass(pattern->newlineCharacterClass, input.read()));
+ }
+
+ bool matchAssertionWordBoundary(ByteTerm& term)
+ {
+ bool prevIsWordchar = !input.atStart(term.inputPosition) && testCharacterClass(pattern->wordcharCharacterClass, input.readChecked(term.inputPosition - 1));
+ bool readIsWordchar;
+ if (term.inputPosition)
+ readIsWordchar = !input.atEnd(term.inputPosition) && testCharacterClass(pattern->wordcharCharacterClass, input.readChecked(term.inputPosition));
+ else
+ readIsWordchar = !input.atEnd() && testCharacterClass(pattern->wordcharCharacterClass, input.read());
+
+ bool wordBoundary = prevIsWordchar != readIsWordchar;
+ return term.invert() ? !wordBoundary : wordBoundary;
+ }
+
+ bool backtrackPatternCharacter(ByteTerm& term, DisjunctionContext* context)
+ {
+ BackTrackInfoPatternCharacter* backTrack = reinterpret_cast<BackTrackInfoPatternCharacter*>(context->frame + term.frameLocation);
+
+ switch (term.atom.quantityType) {
+ case QuantifierFixedCount:
+ break;
+
+ case QuantifierGreedy:
+ if (backTrack->matchAmount) {
+ --backTrack->matchAmount;
+ input.uncheckInput(1);
+ return true;
+ }
+ break;
+
+ case QuantifierNonGreedy:
+ if ((backTrack->matchAmount < term.atom.quantityCount) && input.checkInput(1)) {
+ ++backTrack->matchAmount;
+ if (checkCharacter(term.atom.patternCharacter, term.inputPosition - 1))
+ return true;
+ }
+ input.uncheckInput(backTrack->matchAmount);
+ break;
+ }
+
+ return false;
+ }
+
+ bool backtrackPatternCasedCharacter(ByteTerm& term, DisjunctionContext* context)
+ {
+ BackTrackInfoPatternCharacter* backTrack = reinterpret_cast<BackTrackInfoPatternCharacter*>(context->frame + term.frameLocation);
+
+ switch (term.atom.quantityType) {
+ case QuantifierFixedCount:
+ break;
+
+ case QuantifierGreedy:
+ if (backTrack->matchAmount) {
+ --backTrack->matchAmount;
+ input.uncheckInput(1);
+ return true;
+ }
+ break;
+
+ case QuantifierNonGreedy:
+ if ((backTrack->matchAmount < term.atom.quantityCount) && input.checkInput(1)) {
+ ++backTrack->matchAmount;
+ if (checkCasedCharacter(term.atom.casedCharacter.lo, term.atom.casedCharacter.hi, term.inputPosition - 1))
+ return true;
+ }
+ input.uncheckInput(backTrack->matchAmount);
+ break;
+ }
+
+ return false;
+ }
+
+ bool matchCharacterClass(ByteTerm& term, DisjunctionContext* context)
+ {
+ ASSERT(term.type == ByteTerm::TypeCharacterClass);
+ BackTrackInfoPatternCharacter* backTrack = reinterpret_cast<BackTrackInfoPatternCharacter*>(context->frame + term.frameLocation);
+
+ switch (term.atom.quantityType) {
+ case QuantifierFixedCount: {
+ for (unsigned matchAmount = 0; matchAmount < term.atom.quantityCount; ++matchAmount) {
+ if (!checkCharacterClass(term.atom.characterClass, term.invert(), term.inputPosition + matchAmount))
+ return false;
+ }
+ return true;
+ }
+
+ case QuantifierGreedy: {
+ unsigned matchAmount = 0;
+ while ((matchAmount < term.atom.quantityCount) && input.checkInput(1)) {
+ if (!checkCharacterClass(term.atom.characterClass, term.invert(), term.inputPosition - 1)) {
+ input.uncheckInput(1);
+ break;
+ }
+ ++matchAmount;
+ }
+ backTrack->matchAmount = matchAmount;
+
+ return true;
+ }
+
+ case QuantifierNonGreedy:
+ backTrack->matchAmount = 0;
+ return true;
+ }
+
+ ASSERT_NOT_REACHED();
+ return false;
+ }
+
+ bool backtrackCharacterClass(ByteTerm& term, DisjunctionContext* context)
+ {
+ ASSERT(term.type == ByteTerm::TypeCharacterClass);
+ BackTrackInfoPatternCharacter* backTrack = reinterpret_cast<BackTrackInfoPatternCharacter*>(context->frame + term.frameLocation);
+
+ switch (term.atom.quantityType) {
+ case QuantifierFixedCount:
+ break;
+
+ case QuantifierGreedy:
+ if (backTrack->matchAmount) {
+ --backTrack->matchAmount;
+ input.uncheckInput(1);
+ return true;
+ }
+ break;
+
+ case QuantifierNonGreedy:
+ if ((backTrack->matchAmount < term.atom.quantityCount) && input.checkInput(1)) {
+ ++backTrack->matchAmount;
+ if (checkCharacterClass(term.atom.characterClass, term.invert(), term.inputPosition - 1))
+ return true;
+ }
+ input.uncheckInput(backTrack->matchAmount);
+ break;
+ }
+
+ return false;
+ }
+
+ bool matchBackReference(ByteTerm& term, DisjunctionContext* context)
+ {
+ ASSERT(term.type == ByteTerm::TypeBackReference);
+ BackTrackInfoBackReference* backTrack = reinterpret_cast<BackTrackInfoBackReference*>(context->frame + term.frameLocation);
+
+ int matchBegin = output[(term.atom.subpatternId << 1)];
+ int matchEnd = output[(term.atom.subpatternId << 1) + 1];
+
+ // If the end position of the referenced match hasn't set yet then the backreference in the same parentheses where it references to that.
+ // In this case the result of match is empty string like when it references to a parentheses with zero-width match.
+ // Eg.: /(a\1)/
+ if (matchEnd == -1)
+ return true;
+
+ ASSERT((matchBegin == -1) || (matchBegin <= matchEnd));
+
+ if (matchBegin == matchEnd)
+ return true;
+
+ switch (term.atom.quantityType) {
+ case QuantifierFixedCount: {
+ backTrack->begin = input.getPos();
+ for (unsigned matchAmount = 0; matchAmount < term.atom.quantityCount; ++matchAmount) {
+ if (!tryConsumeBackReference(matchBegin, matchEnd, term.inputPosition)) {
+ input.setPos(backTrack->begin);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ case QuantifierGreedy: {
+ unsigned matchAmount = 0;
+ while ((matchAmount < term.atom.quantityCount) && tryConsumeBackReference(matchBegin, matchEnd, term.inputPosition))
+ ++matchAmount;
+ backTrack->matchAmount = matchAmount;
+ return true;
+ }
+
+ case QuantifierNonGreedy:
+ backTrack->begin = input.getPos();
+ backTrack->matchAmount = 0;
+ return true;
+ }
+
+ ASSERT_NOT_REACHED();
+ return false;
+ }
+
+ bool backtrackBackReference(ByteTerm& term, DisjunctionContext* context)
+ {
+ ASSERT(term.type == ByteTerm::TypeBackReference);
+ BackTrackInfoBackReference* backTrack = reinterpret_cast<BackTrackInfoBackReference*>(context->frame + term.frameLocation);
+
+ int matchBegin = output[(term.atom.subpatternId << 1)];
+ int matchEnd = output[(term.atom.subpatternId << 1) + 1];
+ ASSERT((matchBegin == -1) || (matchBegin <= matchEnd));
+
+ if (matchBegin == matchEnd)
+ return false;
+
+ switch (term.atom.quantityType) {
+ case QuantifierFixedCount:
+ // for quantityCount == 1, could rewind.
+ input.setPos(backTrack->begin);
+ break;
+
+ case QuantifierGreedy:
+ if (backTrack->matchAmount) {
+ --backTrack->matchAmount;
+ input.rewind(matchEnd - matchBegin);
+ return true;
+ }
+ break;
+
+ case QuantifierNonGreedy:
+ if ((backTrack->matchAmount < term.atom.quantityCount) && tryConsumeBackReference(matchBegin, matchEnd, term.inputPosition)) {
+ ++backTrack->matchAmount;
+ return true;
+ }
+ input.setPos(backTrack->begin);
+ break;
+ }
+
+ return false;
+ }
+
+ void recordParenthesesMatch(ByteTerm& term, ParenthesesDisjunctionContext* context)
+ {
+ if (term.capture()) {
+ unsigned subpatternId = term.atom.subpatternId;
+ output[(subpatternId << 1)] = context->getDisjunctionContext(term)->matchBegin + term.inputPosition;
+ output[(subpatternId << 1) + 1] = context->getDisjunctionContext(term)->matchEnd + term.inputPosition;
+ }
+ }
+ void resetMatches(ByteTerm& term, ParenthesesDisjunctionContext* context)
+ {
+ unsigned firstSubpatternId = term.atom.subpatternId;
+ unsigned count = term.atom.parenthesesDisjunction->m_numSubpatterns;
+ context->restoreOutput(output, firstSubpatternId, count);
+ }
+ JSRegExpResult parenthesesDoBacktrack(ByteTerm& term, BackTrackInfoParentheses* backTrack)
+ {
+ while (backTrack->matchAmount) {
+ ParenthesesDisjunctionContext* context = backTrack->lastContext;
+
+ JSRegExpResult result = matchDisjunction(term.atom.parenthesesDisjunction, context->getDisjunctionContext(term), true);
+ if (result == JSRegExpMatch)
+ return JSRegExpMatch;
+
+ resetMatches(term, context);
+ popParenthesesDisjunctionContext(backTrack);
+ freeParenthesesDisjunctionContext(context);
+
+ if (result != JSRegExpNoMatch)
+ return result;
+ }
+
+ return JSRegExpNoMatch;
+ }
+
+ bool matchParenthesesOnceBegin(ByteTerm& term, DisjunctionContext* context)
+ {
+ ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceBegin);
+ ASSERT(term.atom.quantityCount == 1);
+
+ BackTrackInfoParenthesesOnce* backTrack = reinterpret_cast<BackTrackInfoParenthesesOnce*>(context->frame + term.frameLocation);
+
+ switch (term.atom.quantityType) {
+ case QuantifierGreedy: {
+ // set this speculatively; if we get to the parens end this will be true.
+ backTrack->begin = input.getPos();
+ break;
+ }
+ case QuantifierNonGreedy: {
+ backTrack->begin = notFound;
+ context->term += term.atom.parenthesesWidth;
+ return true;
+ }
+ case QuantifierFixedCount:
+ break;
+ }
+
+ if (term.capture()) {
+ unsigned subpatternId = term.atom.subpatternId;
+ output[(subpatternId << 1)] = input.getPos() + term.inputPosition;
+ }
+
+ return true;
+ }
+
+ bool matchParenthesesOnceEnd(ByteTerm& term, DisjunctionContext* context)
+ {
+ ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceEnd);
+ ASSERT(term.atom.quantityCount == 1);
+
+ if (term.capture()) {
+ unsigned subpatternId = term.atom.subpatternId;
+ output[(subpatternId << 1) + 1] = input.getPos() + term.inputPosition;
+ }
+
+ if (term.atom.quantityType == QuantifierFixedCount)
+ return true;
+
+ BackTrackInfoParenthesesOnce* backTrack = reinterpret_cast<BackTrackInfoParenthesesOnce*>(context->frame + term.frameLocation);
+ return backTrack->begin != input.getPos();
+ }
+
+ bool backtrackParenthesesOnceBegin(ByteTerm& term, DisjunctionContext* context)
+ {
+ ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceBegin);
+ ASSERT(term.atom.quantityCount == 1);
+
+ BackTrackInfoParenthesesOnce* backTrack = reinterpret_cast<BackTrackInfoParenthesesOnce*>(context->frame + term.frameLocation);
+
+ if (term.capture()) {
+ unsigned subpatternId = term.atom.subpatternId;
+ output[(subpatternId << 1)] = -1;
+ output[(subpatternId << 1) + 1] = -1;
+ }
+
+ switch (term.atom.quantityType) {
+ case QuantifierGreedy:
+ // if we backtrack to this point, there is another chance - try matching nothing.
+ ASSERT(backTrack->begin != notFound);
+ backTrack->begin = notFound;
+ context->term += term.atom.parenthesesWidth;
+ return true;
+ case QuantifierNonGreedy:
+ ASSERT(backTrack->begin != notFound);
+ case QuantifierFixedCount:
+ break;
+ }
+
+ return false;
+ }
+
+ bool backtrackParenthesesOnceEnd(ByteTerm& term, DisjunctionContext* context)
+ {
+ ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceEnd);
+ ASSERT(term.atom.quantityCount == 1);
+
+ BackTrackInfoParenthesesOnce* backTrack = reinterpret_cast<BackTrackInfoParenthesesOnce*>(context->frame + term.frameLocation);
+
+ switch (term.atom.quantityType) {
+ case QuantifierGreedy:
+ if (backTrack->begin == notFound) {
+ context->term -= term.atom.parenthesesWidth;
+ return false;
+ }
+ case QuantifierNonGreedy:
+ if (backTrack->begin == notFound) {
+ backTrack->begin = input.getPos();
+ if (term.capture()) {
+ // Technically this access to inputPosition should be accessing the begin term's
+ // inputPosition, but for repeats other than fixed these values should be
+ // the same anyway! (We don't pre-check for greedy or non-greedy matches.)
+ ASSERT((&term - term.atom.parenthesesWidth)->type == ByteTerm::TypeParenthesesSubpatternOnceBegin);
+ ASSERT((&term - term.atom.parenthesesWidth)->inputPosition == term.inputPosition);
+ unsigned subpatternId = term.atom.subpatternId;
+ output[subpatternId << 1] = input.getPos() + term.inputPosition;
+ }
+ context->term -= term.atom.parenthesesWidth;
+ return true;
+ }
+ case QuantifierFixedCount:
+ break;
+ }
+
+ return false;
+ }
+
+ bool matchParenthesesTerminalBegin(ByteTerm& term, DisjunctionContext* context)
+ {
+ ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternTerminalBegin);
+ ASSERT(term.atom.quantityType == QuantifierGreedy);
+ ASSERT(term.atom.quantityCount == quantifyInfinite);
+ ASSERT(!term.capture());
+
+ BackTrackInfoParenthesesTerminal* backTrack = reinterpret_cast<BackTrackInfoParenthesesTerminal*>(context->frame + term.frameLocation);
+ backTrack->begin = input.getPos();
+ return true;
+ }
+
+ bool matchParenthesesTerminalEnd(ByteTerm& term, DisjunctionContext* context)
+ {
+ ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternTerminalEnd);
+
+ BackTrackInfoParenthesesTerminal* backTrack = reinterpret_cast<BackTrackInfoParenthesesTerminal*>(context->frame + term.frameLocation);
+ // Empty match is a failed match.
+ if (backTrack->begin == input.getPos())
+ return false;
+
+ // Successful match! Okay, what's next? - loop around and try to match moar!
+ context->term -= (term.atom.parenthesesWidth + 1);
+ return true;
+ }
+
+ bool backtrackParenthesesTerminalBegin(ByteTerm& term, DisjunctionContext* context)
+ {
+ ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternTerminalBegin);
+ ASSERT(term.atom.quantityType == QuantifierGreedy);
+ ASSERT(term.atom.quantityCount == quantifyInfinite);
+ ASSERT(!term.capture());
+
+ // If we backtrack to this point, we have failed to match this iteration of the parens.
+ // Since this is greedy / zero minimum a failed is also accepted as a match!
+ context->term += term.atom.parenthesesWidth;
+ return true;
+ }
+
+ bool backtrackParenthesesTerminalEnd(ByteTerm&, DisjunctionContext*)
+ {
+ // 'Terminal' parentheses are at the end of the regex, and as such a match past end
+ // should always be returned as a successful match - we should never backtrack to here.
+ ASSERT_NOT_REACHED();
+ return false;
+ }
+
+ bool matchParentheticalAssertionBegin(ByteTerm& term, DisjunctionContext* context)
+ {
+ ASSERT(term.type == ByteTerm::TypeParentheticalAssertionBegin);
+ ASSERT(term.atom.quantityCount == 1);
+
+ BackTrackInfoParentheticalAssertion* backTrack = reinterpret_cast<BackTrackInfoParentheticalAssertion*>(context->frame + term.frameLocation);
+
+ backTrack->begin = input.getPos();
+ return true;
+ }
+
+ bool matchParentheticalAssertionEnd(ByteTerm& term, DisjunctionContext* context)
+ {
+ ASSERT(term.type == ByteTerm::TypeParentheticalAssertionEnd);
+ ASSERT(term.atom.quantityCount == 1);
+
+ BackTrackInfoParentheticalAssertion* backTrack = reinterpret_cast<BackTrackInfoParentheticalAssertion*>(context->frame + term.frameLocation);
+
+ input.setPos(backTrack->begin);
+
+ // We've reached the end of the parens; if they are inverted, this is failure.
+ if (term.invert()) {
+ context->term -= term.atom.parenthesesWidth;
+ return false;
+ }
+
+ return true;
+ }
+
+ bool backtrackParentheticalAssertionBegin(ByteTerm& term, DisjunctionContext* context)
+ {
+ ASSERT(term.type == ByteTerm::TypeParentheticalAssertionBegin);
+ ASSERT(term.atom.quantityCount == 1);
+
+ // We've failed to match parens; if they are inverted, this is win!
+ if (term.invert()) {
+ context->term += term.atom.parenthesesWidth;
+ return true;
+ }
+
+ return false;
+ }
+
+ bool backtrackParentheticalAssertionEnd(ByteTerm& term, DisjunctionContext* context)
+ {
+ ASSERT(term.type == ByteTerm::TypeParentheticalAssertionEnd);
+ ASSERT(term.atom.quantityCount == 1);
+
+ BackTrackInfoParentheticalAssertion* backTrack = reinterpret_cast<BackTrackInfoParentheticalAssertion*>(context->frame + term.frameLocation);
+
+ input.setPos(backTrack->begin);
+
+ context->term -= term.atom.parenthesesWidth;
+ return false;
+ }
+
+ JSRegExpResult matchParentheses(ByteTerm& term, DisjunctionContext* context)
+ {
+ ASSERT(term.type == ByteTerm::TypeParenthesesSubpattern);
+
+ BackTrackInfoParentheses* backTrack = reinterpret_cast<BackTrackInfoParentheses*>(context->frame + term.frameLocation);
+ ByteDisjunction* disjunctionBody = term.atom.parenthesesDisjunction;
+
+ backTrack->matchAmount = 0;
+ backTrack->lastContext = 0;
+
+ switch (term.atom.quantityType) {
+ case QuantifierFixedCount: {
+ // While we haven't yet reached our fixed limit,
+ while (backTrack->matchAmount < term.atom.quantityCount) {
+ // Try to do a match, and it it succeeds, add it to the list.
+ ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term);
+ JSRegExpResult result = matchDisjunction(disjunctionBody, context->getDisjunctionContext(term));
+ if (result == JSRegExpMatch)
+ appendParenthesesDisjunctionContext(backTrack, context);
+ else {
+ // The match failed; try to find an alternate point to carry on from.
+ resetMatches(term, context);
+ freeParenthesesDisjunctionContext(context);
+
+ if (result == JSRegExpNoMatch) {
+ JSRegExpResult backtrackResult = parenthesesDoBacktrack(term, backTrack);
+ if (backtrackResult != JSRegExpMatch)
+ return backtrackResult;
+ } else
+ return result;
+ }
+ }
+
+ ASSERT(backTrack->matchAmount == term.atom.quantityCount);
+ ParenthesesDisjunctionContext* context = backTrack->lastContext;
+ recordParenthesesMatch(term, context);
+ return JSRegExpMatch;
+ }
+
+ case QuantifierGreedy: {
+ while (backTrack->matchAmount < term.atom.quantityCount) {
+ ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term);
+ JSRegExpResult result = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term));
+ if (result == JSRegExpMatch)
+ appendParenthesesDisjunctionContext(backTrack, context);
+ else {
+ resetMatches(term, context);
+ freeParenthesesDisjunctionContext(context);
+
+ if (result != JSRegExpNoMatch)
+ return result;
+
+ break;
+ }
+ }
+
+ if (backTrack->matchAmount) {
+ ParenthesesDisjunctionContext* context = backTrack->lastContext;
+ recordParenthesesMatch(term, context);
+ }
+ return JSRegExpMatch;
+ }
+
+ case QuantifierNonGreedy:
+ return JSRegExpMatch;
+ }
+
+ ASSERT_NOT_REACHED();
+ return JSRegExpErrorNoMatch;
+ }
+
+ // Rules for backtracking differ depending on whether this is greedy or non-greedy.
+ //
+ // Greedy matches never should try just adding more - you should already have done
+ // the 'more' cases. Always backtrack, at least a leetle bit. However cases where
+ // you backtrack an item off the list needs checking, since we'll never have matched
+ // the one less case. Tracking forwards, still add as much as possible.
+ //
+ // Non-greedy, we've already done the one less case, so don't match on popping.
+ // We haven't done the one more case, so always try to add that.
+ //
+ JSRegExpResult backtrackParentheses(ByteTerm& term, DisjunctionContext* context)
+ {
+ ASSERT(term.type == ByteTerm::TypeParenthesesSubpattern);
+
+ BackTrackInfoParentheses* backTrack = reinterpret_cast<BackTrackInfoParentheses*>(context->frame + term.frameLocation);
+ ByteDisjunction* disjunctionBody = term.atom.parenthesesDisjunction;
+
+ switch (term.atom.quantityType) {
+ case QuantifierFixedCount: {
+ ASSERT(backTrack->matchAmount == term.atom.quantityCount);
+
+ ParenthesesDisjunctionContext* context = 0;
+ JSRegExpResult result = parenthesesDoBacktrack(term, backTrack);
+
+ if (result != JSRegExpMatch)
+ return result;
+
+ // While we haven't yet reached our fixed limit,
+ while (backTrack->matchAmount < term.atom.quantityCount) {
+ // Try to do a match, and it it succeeds, add it to the list.
+ context = allocParenthesesDisjunctionContext(disjunctionBody, output, term);
+ result = matchDisjunction(disjunctionBody, context->getDisjunctionContext(term));
+
+ if (result == JSRegExpMatch)
+ appendParenthesesDisjunctionContext(backTrack, context);
+ else {
+ // The match failed; try to find an alternate point to carry on from.
+ resetMatches(term, context);
+ freeParenthesesDisjunctionContext(context);
+
+ if (result == JSRegExpNoMatch) {
+ JSRegExpResult backtrackResult = parenthesesDoBacktrack(term, backTrack);
+ if (backtrackResult != JSRegExpMatch)
+ return backtrackResult;
+ } else
+ return result;
+ }
+ }
+
+ ASSERT(backTrack->matchAmount == term.atom.quantityCount);
+ context = backTrack->lastContext;
+ recordParenthesesMatch(term, context);
+ return JSRegExpMatch;
+ }
+
+ case QuantifierGreedy: {
+ if (!backTrack->matchAmount)
+ return JSRegExpNoMatch;
+
+ ParenthesesDisjunctionContext* context = backTrack->lastContext;
+ JSRegExpResult result = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term), true);
+ if (result == JSRegExpMatch) {
+ while (backTrack->matchAmount < term.atom.quantityCount) {
+ ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term);
+ JSRegExpResult parenthesesResult = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term));
+ if (parenthesesResult == JSRegExpMatch)
+ appendParenthesesDisjunctionContext(backTrack, context);
+ else {
+ resetMatches(term, context);
+ freeParenthesesDisjunctionContext(context);
+
+ if (parenthesesResult != JSRegExpNoMatch)
+ return parenthesesResult;
+
+ break;
+ }
+ }
+ } else {
+ resetMatches(term, context);
+ popParenthesesDisjunctionContext(backTrack);
+ freeParenthesesDisjunctionContext(context);
+
+ if (result != JSRegExpNoMatch)
+ return result;
+ }
+
+ if (backTrack->matchAmount) {
+ ParenthesesDisjunctionContext* context = backTrack->lastContext;
+ recordParenthesesMatch(term, context);
+ }
+ return JSRegExpMatch;
+ }
+
+ case QuantifierNonGreedy: {
+ // If we've not reached the limit, try to add one more match.
+ if (backTrack->matchAmount < term.atom.quantityCount) {
+ ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term);
+ JSRegExpResult result = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term));
+ if (result == JSRegExpMatch) {
+ appendParenthesesDisjunctionContext(backTrack, context);
+ recordParenthesesMatch(term, context);
+ return JSRegExpMatch;
+ }
+
+ resetMatches(term, context);
+ freeParenthesesDisjunctionContext(context);
+
+ if (result != JSRegExpNoMatch)
+ return result;
+ }
+
+ // Nope - okay backtrack looking for an alternative.
+ while (backTrack->matchAmount) {
+ ParenthesesDisjunctionContext* context = backTrack->lastContext;
+ JSRegExpResult result = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term), true);
+ if (result == JSRegExpMatch) {
+ // successful backtrack! we're back in the game!
+ if (backTrack->matchAmount) {
+ context = backTrack->lastContext;
+ recordParenthesesMatch(term, context);
+ }
+ return JSRegExpMatch;
+ }
+
+ // pop a match off the stack
+ resetMatches(term, context);
+ popParenthesesDisjunctionContext(backTrack);
+ freeParenthesesDisjunctionContext(context);
+
+ return result;
+ }
+
+ return JSRegExpNoMatch;
+ }
+ }
+
+ ASSERT_NOT_REACHED();
+ return JSRegExpErrorNoMatch;
+ }
+
+ bool matchDotStarEnclosure(ByteTerm& term, DisjunctionContext* context)
+ {
+ UNUSED_PARAM(term);
+ unsigned matchBegin = context->matchBegin;
+
+ if (matchBegin) {
+ for (matchBegin--; true; matchBegin--) {
+ if (testCharacterClass(pattern->newlineCharacterClass, input.reread(matchBegin))) {
+ ++matchBegin;
+ break;
+ }
+
+ if (!matchBegin)
+ break;
+ }
+ }
+
+ unsigned matchEnd = input.getPos();
+
+ for (; (matchEnd != input.end())
+ && (!testCharacterClass(pattern->newlineCharacterClass, input.reread(matchEnd))); matchEnd++) { }
+
+ if (((matchBegin && term.anchors.m_bol)
+ || ((matchEnd != input.end()) && term.anchors.m_eol))
+ && !pattern->m_multiline)
+ return false;
+
+ context->matchBegin = matchBegin;
+ context->matchEnd = matchEnd;
+ return true;
+ }
+
+#define MATCH_NEXT() { ++context->term; goto matchAgain; }
+#define BACKTRACK() { --context->term; goto backtrack; }
+#define currentTerm() (disjunction->terms[context->term])
+ JSRegExpResult matchDisjunction(ByteDisjunction* disjunction, DisjunctionContext* context, bool btrack = false)
+ {
+ if (!--remainingMatchCount)
+ return JSRegExpErrorHitLimit;
+
+ if (btrack)
+ BACKTRACK();
+
+ context->matchBegin = input.getPos();
+ context->term = 0;
+
+ matchAgain:
+ ASSERT(context->term < static_cast<int>(disjunction->terms.size()));
+
+ switch (currentTerm().type) {
+ case ByteTerm::TypeSubpatternBegin:
+ MATCH_NEXT();
+ case ByteTerm::TypeSubpatternEnd:
+ context->matchEnd = input.getPos();
+ return JSRegExpMatch;
+
+ case ByteTerm::TypeBodyAlternativeBegin:
+ MATCH_NEXT();
+ case ByteTerm::TypeBodyAlternativeDisjunction:
+ case ByteTerm::TypeBodyAlternativeEnd:
+ context->matchEnd = input.getPos();
+ return JSRegExpMatch;
+
+ case ByteTerm::TypeAlternativeBegin:
+ MATCH_NEXT();
+ case ByteTerm::TypeAlternativeDisjunction:
+ case ByteTerm::TypeAlternativeEnd: {
+ int offset = currentTerm().alternative.end;
+ BackTrackInfoAlternative* backTrack = reinterpret_cast<BackTrackInfoAlternative*>(context->frame + currentTerm().frameLocation);
+ backTrack->offset = offset;
+ context->term += offset;
+ MATCH_NEXT();
+ }
+
+ case ByteTerm::TypeAssertionBOL:
+ if (matchAssertionBOL(currentTerm()))
+ MATCH_NEXT();
+ BACKTRACK();
+ case ByteTerm::TypeAssertionEOL:
+ if (matchAssertionEOL(currentTerm()))
+ MATCH_NEXT();
+ BACKTRACK();
+ case ByteTerm::TypeAssertionWordBoundary:
+ if (matchAssertionWordBoundary(currentTerm()))
+ MATCH_NEXT();
+ BACKTRACK();
+
+ case ByteTerm::TypePatternCharacterOnce:
+ case ByteTerm::TypePatternCharacterFixed: {
+ for (unsigned matchAmount = 0; matchAmount < currentTerm().atom.quantityCount; ++matchAmount) {
+ if (!checkCharacter(currentTerm().atom.patternCharacter, currentTerm().inputPosition + matchAmount))
+ BACKTRACK();
+ }
+ MATCH_NEXT();
+ }
+ case ByteTerm::TypePatternCharacterGreedy: {
+ BackTrackInfoPatternCharacter* backTrack = reinterpret_cast<BackTrackInfoPatternCharacter*>(context->frame + currentTerm().frameLocation);
+ unsigned matchAmount = 0;
+ while ((matchAmount < currentTerm().atom.quantityCount) && input.checkInput(1)) {
+ if (!checkCharacter(currentTerm().atom.patternCharacter, currentTerm().inputPosition - 1)) {
+ input.uncheckInput(1);
+ break;
+ }
+ ++matchAmount;
+ }
+ backTrack->matchAmount = matchAmount;
+
+ MATCH_NEXT();
+ }
+ case ByteTerm::TypePatternCharacterNonGreedy: {
+ BackTrackInfoPatternCharacter* backTrack = reinterpret_cast<BackTrackInfoPatternCharacter*>(context->frame + currentTerm().frameLocation);
+ backTrack->matchAmount = 0;
+ MATCH_NEXT();
+ }
+
+ case ByteTerm::TypePatternCasedCharacterOnce:
+ case ByteTerm::TypePatternCasedCharacterFixed: {
+ for (unsigned matchAmount = 0; matchAmount < currentTerm().atom.quantityCount; ++matchAmount) {
+ if (!checkCasedCharacter(currentTerm().atom.casedCharacter.lo, currentTerm().atom.casedCharacter.hi, currentTerm().inputPosition + matchAmount))
+ BACKTRACK();
+ }
+ MATCH_NEXT();
+ }
+ case ByteTerm::TypePatternCasedCharacterGreedy: {
+ BackTrackInfoPatternCharacter* backTrack = reinterpret_cast<BackTrackInfoPatternCharacter*>(context->frame + currentTerm().frameLocation);
+ unsigned matchAmount = 0;
+ while ((matchAmount < currentTerm().atom.quantityCount) && input.checkInput(1)) {
+ if (!checkCasedCharacter(currentTerm().atom.casedCharacter.lo, currentTerm().atom.casedCharacter.hi, currentTerm().inputPosition - 1)) {
+ input.uncheckInput(1);
+ break;
+ }
+ ++matchAmount;
+ }
+ backTrack->matchAmount = matchAmount;
+
+ MATCH_NEXT();
+ }
+ case ByteTerm::TypePatternCasedCharacterNonGreedy: {
+ BackTrackInfoPatternCharacter* backTrack = reinterpret_cast<BackTrackInfoPatternCharacter*>(context->frame + currentTerm().frameLocation);
+ backTrack->matchAmount = 0;
+ MATCH_NEXT();
+ }
+
+ case ByteTerm::TypeCharacterClass:
+ if (matchCharacterClass(currentTerm(), context))
+ MATCH_NEXT();
+ BACKTRACK();
+ case ByteTerm::TypeBackReference:
+ if (matchBackReference(currentTerm(), context))
+ MATCH_NEXT();
+ BACKTRACK();
+ case ByteTerm::TypeParenthesesSubpattern: {
+ JSRegExpResult result = matchParentheses(currentTerm(), context);
+
+ if (result == JSRegExpMatch) {
+ MATCH_NEXT();
+ } else if (result != JSRegExpNoMatch)
+ return result;
+
+ BACKTRACK();
+ }
+ case ByteTerm::TypeParenthesesSubpatternOnceBegin:
+ if (matchParenthesesOnceBegin(currentTerm(), context))
+ MATCH_NEXT();
+ BACKTRACK();
+ case ByteTerm::TypeParenthesesSubpatternOnceEnd:
+ if (matchParenthesesOnceEnd(currentTerm(), context))
+ MATCH_NEXT();
+ BACKTRACK();
+ case ByteTerm::TypeParenthesesSubpatternTerminalBegin:
+ if (matchParenthesesTerminalBegin(currentTerm(), context))
+ MATCH_NEXT();
+ BACKTRACK();
+ case ByteTerm::TypeParenthesesSubpatternTerminalEnd:
+ if (matchParenthesesTerminalEnd(currentTerm(), context))
+ MATCH_NEXT();
+ BACKTRACK();
+ case ByteTerm::TypeParentheticalAssertionBegin:
+ if (matchParentheticalAssertionBegin(currentTerm(), context))
+ MATCH_NEXT();
+ BACKTRACK();
+ case ByteTerm::TypeParentheticalAssertionEnd:
+ if (matchParentheticalAssertionEnd(currentTerm(), context))
+ MATCH_NEXT();
+ BACKTRACK();
+
+ case ByteTerm::TypeCheckInput:
+ if (input.checkInput(currentTerm().checkInputCount))
+ MATCH_NEXT();
+ BACKTRACK();
+
+ case ByteTerm::TypeUncheckInput:
+ input.uncheckInput(currentTerm().checkInputCount);
+ MATCH_NEXT();
+
+ case ByteTerm::TypeDotStarEnclosure:
+ if (matchDotStarEnclosure(currentTerm(), context))
+ return JSRegExpMatch;
+ BACKTRACK();
+ }
+
+ // We should never fall-through to here.
+ ASSERT_NOT_REACHED();
+
+ backtrack:
+ ASSERT(context->term < static_cast<int>(disjunction->terms.size()));
+
+ switch (currentTerm().type) {
+ case ByteTerm::TypeSubpatternBegin:
+ return JSRegExpNoMatch;
+ case ByteTerm::TypeSubpatternEnd:
+ ASSERT_NOT_REACHED();
+
+ case ByteTerm::TypeBodyAlternativeBegin:
+ case ByteTerm::TypeBodyAlternativeDisjunction: {
+ int offset = currentTerm().alternative.next;
+ context->term += offset;
+ if (offset > 0)
+ MATCH_NEXT();
+
+ if (input.atEnd())
+ return JSRegExpNoMatch;
+
+ input.next();
+
+ context->matchBegin = input.getPos();
+
+ if (currentTerm().alternative.onceThrough)
+ context->term += currentTerm().alternative.next;
+
+ MATCH_NEXT();
+ }
+ case ByteTerm::TypeBodyAlternativeEnd:
+ ASSERT_NOT_REACHED();
+
+ case ByteTerm::TypeAlternativeBegin:
+ case ByteTerm::TypeAlternativeDisjunction: {
+ int offset = currentTerm().alternative.next;
+ context->term += offset;
+ if (offset > 0)
+ MATCH_NEXT();
+ BACKTRACK();
+ }
+ case ByteTerm::TypeAlternativeEnd: {
+ // We should never backtrack back into an alternative of the main body of the regex.
+ BackTrackInfoAlternative* backTrack = reinterpret_cast<BackTrackInfoAlternative*>(context->frame + currentTerm().frameLocation);
+ unsigned offset = backTrack->offset;
+ context->term -= offset;
+ BACKTRACK();
+ }
+
+ case ByteTerm::TypeAssertionBOL:
+ case ByteTerm::TypeAssertionEOL:
+ case ByteTerm::TypeAssertionWordBoundary:
+ BACKTRACK();
+
+ case ByteTerm::TypePatternCharacterOnce:
+ case ByteTerm::TypePatternCharacterFixed:
+ case ByteTerm::TypePatternCharacterGreedy:
+ case ByteTerm::TypePatternCharacterNonGreedy:
+ if (backtrackPatternCharacter(currentTerm(), context))
+ MATCH_NEXT();
+ BACKTRACK();
+ case ByteTerm::TypePatternCasedCharacterOnce:
+ case ByteTerm::TypePatternCasedCharacterFixed:
+ case ByteTerm::TypePatternCasedCharacterGreedy:
+ case ByteTerm::TypePatternCasedCharacterNonGreedy:
+ if (backtrackPatternCasedCharacter(currentTerm(), context))
+ MATCH_NEXT();
+ BACKTRACK();
+ case ByteTerm::TypeCharacterClass:
+ if (backtrackCharacterClass(currentTerm(), context))
+ MATCH_NEXT();
+ BACKTRACK();
+ case ByteTerm::TypeBackReference:
+ if (backtrackBackReference(currentTerm(), context))
+ MATCH_NEXT();
+ BACKTRACK();
+ case ByteTerm::TypeParenthesesSubpattern: {
+ JSRegExpResult result = backtrackParentheses(currentTerm(), context);
+
+ if (result == JSRegExpMatch) {
+ MATCH_NEXT();
+ } else if (result != JSRegExpNoMatch)
+ return result;
+
+ BACKTRACK();
+ }
+ case ByteTerm::TypeParenthesesSubpatternOnceBegin:
+ if (backtrackParenthesesOnceBegin(currentTerm(), context))
+ MATCH_NEXT();
+ BACKTRACK();
+ case ByteTerm::TypeParenthesesSubpatternOnceEnd:
+ if (backtrackParenthesesOnceEnd(currentTerm(), context))
+ MATCH_NEXT();
+ BACKTRACK();
+ case ByteTerm::TypeParenthesesSubpatternTerminalBegin:
+ if (backtrackParenthesesTerminalBegin(currentTerm(), context))
+ MATCH_NEXT();
+ BACKTRACK();
+ case ByteTerm::TypeParenthesesSubpatternTerminalEnd:
+ if (backtrackParenthesesTerminalEnd(currentTerm(), context))
+ MATCH_NEXT();
+ BACKTRACK();
+ case ByteTerm::TypeParentheticalAssertionBegin:
+ if (backtrackParentheticalAssertionBegin(currentTerm(), context))
+ MATCH_NEXT();
+ BACKTRACK();
+ case ByteTerm::TypeParentheticalAssertionEnd:
+ if (backtrackParentheticalAssertionEnd(currentTerm(), context))
+ MATCH_NEXT();
+ BACKTRACK();
+
+ case ByteTerm::TypeCheckInput:
+ input.uncheckInput(currentTerm().checkInputCount);
+ BACKTRACK();
+
+ case ByteTerm::TypeUncheckInput:
+ input.checkInput(currentTerm().checkInputCount);
+ BACKTRACK();
+
+ case ByteTerm::TypeDotStarEnclosure:
+ ASSERT_NOT_REACHED();
+ }
+
+ ASSERT_NOT_REACHED();
+ return JSRegExpErrorNoMatch;
+ }
+
+ JSRegExpResult matchNonZeroDisjunction(ByteDisjunction* disjunction, DisjunctionContext* context, bool btrack = false)
+ {
+ JSRegExpResult result = matchDisjunction(disjunction, context, btrack);
+
+ if (result == JSRegExpMatch) {
+ while (context->matchBegin == context->matchEnd) {
+ result = matchDisjunction(disjunction, context, true);
+ if (result != JSRegExpMatch)
+ return result;
+ }
+ return JSRegExpMatch;
+ }
+
+ return result;
+ }
+
+ int interpret()
+ {
+ allocatorPool = pattern->m_allocator->startAllocator();
+ if (!allocatorPool)
+ CRASH();
+
+ for (unsigned i = 0; i < ((pattern->m_body->m_numSubpatterns + 1) << 1); ++i)
+ output[i] = -1;
+
+ DisjunctionContext* context = allocDisjunctionContext(pattern->m_body.get());
+
+ JSRegExpResult result = matchDisjunction(pattern->m_body.get(), context, false);
+ if (result == JSRegExpMatch) {
+ output[0] = context->matchBegin;
+ output[1] = context->matchEnd;
+ }
+
+ freeDisjunctionContext(context);
+
+ pattern->m_allocator->stopAllocator();
+
+ // RegExp.cpp currently expects all error to be converted to -1.
+ ASSERT((result == JSRegExpMatch) == (output[0] != -1));
+ return output[0];
+ }
+
+ Interpreter(BytecodePattern* pattern, int* output, const UChar* inputChar, unsigned start, unsigned length)
+ : pattern(pattern)
+ , output(output)
+ , input(inputChar, start, length)
+ , allocatorPool(0)
+ , remainingMatchCount(matchLimit)
+ {
+ }
+
+private:
+ BytecodePattern* pattern;
+ int* output;
+ InputStream input;
+ BumpPointerPool* allocatorPool;
+ unsigned remainingMatchCount;
+};
+
+
+
+class ByteCompiler {
+ struct ParenthesesStackEntry {
+ unsigned beginTerm;
+ unsigned savedAlternativeIndex;
+ ParenthesesStackEntry(unsigned beginTerm, unsigned savedAlternativeIndex/*, unsigned subpatternId, bool capture = false*/)
+ : beginTerm(beginTerm)
+ , savedAlternativeIndex(savedAlternativeIndex)
+ {
+ }
+ };
+
+public:
+ ByteCompiler(YarrPattern& pattern)
+ : m_pattern(pattern)
+ {
+ m_currentAlternativeIndex = 0;
+ }
+
+ PassOwnPtr<BytecodePattern> compile(BumpPointerAllocator* allocator)
+ {
+ regexBegin(m_pattern.m_numSubpatterns, m_pattern.m_body->m_callFrameSize, m_pattern.m_body->m_alternatives[0]->onceThrough());
+ emitDisjunction(m_pattern.m_body);
+ regexEnd();
+
+ return adoptPtr(new BytecodePattern(m_bodyDisjunction.release(), m_allParenthesesInfo, m_pattern, allocator));
+ }
+
+ void checkInput(unsigned count)
+ {
+ m_bodyDisjunction->terms.append(ByteTerm::CheckInput(count));
+ }
+
+ void uncheckInput(unsigned count)
+ {
+ m_bodyDisjunction->terms.append(ByteTerm::UncheckInput(count));
+ }
+
+ void assertionBOL(int inputPosition)
+ {
+ m_bodyDisjunction->terms.append(ByteTerm::BOL(inputPosition));
+ }
+
+ void assertionEOL(int inputPosition)
+ {
+ m_bodyDisjunction->terms.append(ByteTerm::EOL(inputPosition));
+ }
+
+ void assertionWordBoundary(bool invert, int inputPosition)
+ {
+ m_bodyDisjunction->terms.append(ByteTerm::WordBoundary(invert, inputPosition));
+ }
+
+ void atomPatternCharacter(UChar ch, int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
+ {
+ if (m_pattern.m_ignoreCase) {
+ UChar lo = Unicode::toLower(ch);
+ UChar hi = Unicode::toUpper(ch);
+
+ if (lo != hi) {
+ m_bodyDisjunction->terms.append(ByteTerm(lo, hi, inputPosition, frameLocation, quantityCount, quantityType));
+ return;
+ }
+ }
+
+ m_bodyDisjunction->terms.append(ByteTerm(ch, inputPosition, frameLocation, quantityCount, quantityType));
+ }
+
+ void atomCharacterClass(CharacterClass* characterClass, bool invert, int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
+ {
+ m_bodyDisjunction->terms.append(ByteTerm(characterClass, invert, inputPosition));
+
+ m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityCount = quantityCount;
+ m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityType = quantityType;
+ m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
+ }
+
+ void atomBackReference(unsigned subpatternId, int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
+ {
+ ASSERT(subpatternId);
+
+ m_bodyDisjunction->terms.append(ByteTerm::BackReference(subpatternId, inputPosition));
+
+ m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityCount = quantityCount;
+ m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityType = quantityType;
+ m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
+ }
+
+ void atomParenthesesOnceBegin(unsigned subpatternId, bool capture, int inputPosition, unsigned frameLocation, unsigned alternativeFrameLocation)
+ {
+ int beginTerm = m_bodyDisjunction->terms.size();
+
+ m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternOnceBegin, subpatternId, capture, false, inputPosition));
+ m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
+ m_bodyDisjunction->terms.append(ByteTerm::AlternativeBegin());
+ m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = alternativeFrameLocation;
+
+ m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, m_currentAlternativeIndex));
+ m_currentAlternativeIndex = beginTerm + 1;
+ }
+
+ void atomParenthesesTerminalBegin(unsigned subpatternId, bool capture, int inputPosition, unsigned frameLocation, unsigned alternativeFrameLocation)
+ {
+ int beginTerm = m_bodyDisjunction->terms.size();
+
+ m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternTerminalBegin, subpatternId, capture, false, inputPosition));
+ m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
+ m_bodyDisjunction->terms.append(ByteTerm::AlternativeBegin());
+ m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = alternativeFrameLocation;
+
+ m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, m_currentAlternativeIndex));
+ m_currentAlternativeIndex = beginTerm + 1;
+ }
+
+ void atomParenthesesSubpatternBegin(unsigned subpatternId, bool capture, int inputPosition, unsigned frameLocation, unsigned alternativeFrameLocation)
+ {
+ // Errrk! - this is a little crazy, we initially generate as a TypeParenthesesSubpatternOnceBegin,
+ // then fix this up at the end! - simplifying this should make it much clearer.
+ // https://bugs.webkit.org/show_bug.cgi?id=50136
+
+ int beginTerm = m_bodyDisjunction->terms.size();
+
+ m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternOnceBegin, subpatternId, capture, false, inputPosition));
+ m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
+ m_bodyDisjunction->terms.append(ByteTerm::AlternativeBegin());
+ m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = alternativeFrameLocation;
+
+ m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, m_currentAlternativeIndex));
+ m_currentAlternativeIndex = beginTerm + 1;
+ }
+
+ void atomParentheticalAssertionBegin(unsigned subpatternId, bool invert, unsigned frameLocation, unsigned alternativeFrameLocation)
+ {
+ int beginTerm = m_bodyDisjunction->terms.size();
+
+ m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParentheticalAssertionBegin, subpatternId, false, invert, 0));
+ m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
+ m_bodyDisjunction->terms.append(ByteTerm::AlternativeBegin());
+ m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = alternativeFrameLocation;
+
+ m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, m_currentAlternativeIndex));
+ m_currentAlternativeIndex = beginTerm + 1;
+ }
+
+ void atomParentheticalAssertionEnd(int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
+ {
+ unsigned beginTerm = popParenthesesStack();
+ closeAlternative(beginTerm + 1);
+ unsigned endTerm = m_bodyDisjunction->terms.size();
+
+ ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeParentheticalAssertionBegin);
+
+ bool invert = m_bodyDisjunction->terms[beginTerm].invert();
+ unsigned subpatternId = m_bodyDisjunction->terms[beginTerm].atom.subpatternId;
+
+ m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParentheticalAssertionEnd, subpatternId, false, invert, inputPosition));
+ m_bodyDisjunction->terms[beginTerm].atom.parenthesesWidth = endTerm - beginTerm;
+ m_bodyDisjunction->terms[endTerm].atom.parenthesesWidth = endTerm - beginTerm;
+ m_bodyDisjunction->terms[endTerm].frameLocation = frameLocation;
+
+ m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount;
+ m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType;
+ m_bodyDisjunction->terms[endTerm].atom.quantityCount = quantityCount;
+ m_bodyDisjunction->terms[endTerm].atom.quantityType = quantityType;
+ }
+
+ void assertionDotStarEnclosure(bool bolAnchored, bool eolAnchored)
+ {
+ m_bodyDisjunction->terms.append(ByteTerm::DotStarEnclosure(bolAnchored, eolAnchored));
+ }
+
+ unsigned popParenthesesStack()
+ {
+ ASSERT(m_parenthesesStack.size());
+ int stackEnd = m_parenthesesStack.size() - 1;
+ unsigned beginTerm = m_parenthesesStack[stackEnd].beginTerm;
+ m_currentAlternativeIndex = m_parenthesesStack[stackEnd].savedAlternativeIndex;
+ m_parenthesesStack.shrink(stackEnd);
+
+ ASSERT(beginTerm < m_bodyDisjunction->terms.size());
+ ASSERT(m_currentAlternativeIndex < m_bodyDisjunction->terms.size());
+
+ return beginTerm;
+ }
+
+#ifndef NDEBUG
+ void dumpDisjunction(ByteDisjunction* disjunction)
+ {
+ printf("ByteDisjunction(%p):\n\t", disjunction);
+ for (unsigned i = 0; i < disjunction->terms.size(); ++i)
+ printf("{ %d } ", disjunction->terms[i].type);
+ printf("\n");
+ }
+#endif
+
+ void closeAlternative(int beginTerm)
+ {
+ int origBeginTerm = beginTerm;
+ ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeAlternativeBegin);
+ int endIndex = m_bodyDisjunction->terms.size();
+
+ unsigned frameLocation = m_bodyDisjunction->terms[beginTerm].frameLocation;
+
+ if (!m_bodyDisjunction->terms[beginTerm].alternative.next)
+ m_bodyDisjunction->terms.remove(beginTerm);
+ else {
+ while (m_bodyDisjunction->terms[beginTerm].alternative.next) {
+ beginTerm += m_bodyDisjunction->terms[beginTerm].alternative.next;
+ ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeAlternativeDisjunction);
+ m_bodyDisjunction->terms[beginTerm].alternative.end = endIndex - beginTerm;
+ m_bodyDisjunction->terms[beginTerm].frameLocation = frameLocation;
+ }
+
+ m_bodyDisjunction->terms[beginTerm].alternative.next = origBeginTerm - beginTerm;
+
+ m_bodyDisjunction->terms.append(ByteTerm::AlternativeEnd());
+ m_bodyDisjunction->terms[endIndex].frameLocation = frameLocation;
+ }
+ }
+
+ void closeBodyAlternative()
+ {
+ int beginTerm = 0;
+ int origBeginTerm = 0;
+ ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeBodyAlternativeBegin);
+ int endIndex = m_bodyDisjunction->terms.size();
+
+ unsigned frameLocation = m_bodyDisjunction->terms[beginTerm].frameLocation;
+
+ while (m_bodyDisjunction->terms[beginTerm].alternative.next) {
+ beginTerm += m_bodyDisjunction->terms[beginTerm].alternative.next;
+ ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeBodyAlternativeDisjunction);
+ m_bodyDisjunction->terms[beginTerm].alternative.end = endIndex - beginTerm;
+ m_bodyDisjunction->terms[beginTerm].frameLocation = frameLocation;
+ }
+
+ m_bodyDisjunction->terms[beginTerm].alternative.next = origBeginTerm - beginTerm;
+
+ m_bodyDisjunction->terms.append(ByteTerm::BodyAlternativeEnd());
+ m_bodyDisjunction->terms[endIndex].frameLocation = frameLocation;
+ }
+
+ void atomParenthesesSubpatternEnd(unsigned lastSubpatternId, int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType, unsigned callFrameSize = 0)
+ {
+ unsigned beginTerm = popParenthesesStack();
+ closeAlternative(beginTerm + 1);
+ unsigned endTerm = m_bodyDisjunction->terms.size();
+
+ ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeParenthesesSubpatternOnceBegin);
+
+ ByteTerm& parenthesesBegin = m_bodyDisjunction->terms[beginTerm];
+
+ bool capture = parenthesesBegin.capture();
+ unsigned subpatternId = parenthesesBegin.atom.subpatternId;
+
+ unsigned numSubpatterns = lastSubpatternId - subpatternId + 1;
+ ByteDisjunction* parenthesesDisjunction = new ByteDisjunction(numSubpatterns, callFrameSize);
+
+ parenthesesDisjunction->terms.append(ByteTerm::SubpatternBegin());
+ for (unsigned termInParentheses = beginTerm + 1; termInParentheses < endTerm; ++termInParentheses)
+ parenthesesDisjunction->terms.append(m_bodyDisjunction->terms[termInParentheses]);
+ parenthesesDisjunction->terms.append(ByteTerm::SubpatternEnd());
+
+ m_bodyDisjunction->terms.shrink(beginTerm);
+
+ m_allParenthesesInfo.append(parenthesesDisjunction);
+ m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpattern, subpatternId, parenthesesDisjunction, capture, inputPosition));
+
+ m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount;
+ m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType;
+ m_bodyDisjunction->terms[beginTerm].frameLocation = frameLocation;
+ }
+
+ void atomParenthesesOnceEnd(int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
+ {
+ unsigned beginTerm = popParenthesesStack();
+ closeAlternative(beginTerm + 1);
+ unsigned endTerm = m_bodyDisjunction->terms.size();
+
+ ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeParenthesesSubpatternOnceBegin);
+
+ bool capture = m_bodyDisjunction->terms[beginTerm].capture();
+ unsigned subpatternId = m_bodyDisjunction->terms[beginTerm].atom.subpatternId;
+
+ m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternOnceEnd, subpatternId, capture, false, inputPosition));
+ m_bodyDisjunction->terms[beginTerm].atom.parenthesesWidth = endTerm - beginTerm;
+ m_bodyDisjunction->terms[endTerm].atom.parenthesesWidth = endTerm - beginTerm;
+ m_bodyDisjunction->terms[endTerm].frameLocation = frameLocation;
+
+ m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount;
+ m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType;
+ m_bodyDisjunction->terms[endTerm].atom.quantityCount = quantityCount;
+ m_bodyDisjunction->terms[endTerm].atom.quantityType = quantityType;
+ }
+
+ void atomParenthesesTerminalEnd(int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
+ {
+ unsigned beginTerm = popParenthesesStack();
+ closeAlternative(beginTerm + 1);
+ unsigned endTerm = m_bodyDisjunction->terms.size();
+
+ ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeParenthesesSubpatternTerminalBegin);
+
+ bool capture = m_bodyDisjunction->terms[beginTerm].capture();
+ unsigned subpatternId = m_bodyDisjunction->terms[beginTerm].atom.subpatternId;
+
+ m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternTerminalEnd, subpatternId, capture, false, inputPosition));
+ m_bodyDisjunction->terms[beginTerm].atom.parenthesesWidth = endTerm - beginTerm;
+ m_bodyDisjunction->terms[endTerm].atom.parenthesesWidth = endTerm - beginTerm;
+ m_bodyDisjunction->terms[endTerm].frameLocation = frameLocation;
+
+ m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount;
+ m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType;
+ m_bodyDisjunction->terms[endTerm].atom.quantityCount = quantityCount;
+ m_bodyDisjunction->terms[endTerm].atom.quantityType = quantityType;
+ }
+
+ void regexBegin(unsigned numSubpatterns, unsigned callFrameSize, bool onceThrough)
+ {
+ m_bodyDisjunction = adoptPtr(new ByteDisjunction(numSubpatterns, callFrameSize));
+ m_bodyDisjunction->terms.append(ByteTerm::BodyAlternativeBegin(onceThrough));
+ m_bodyDisjunction->terms[0].frameLocation = 0;
+ m_currentAlternativeIndex = 0;
+ }
+
+ void regexEnd()
+ {
+ closeBodyAlternative();
+ }
+
+ void alternativeBodyDisjunction(bool onceThrough)
+ {
+ int newAlternativeIndex = m_bodyDisjunction->terms.size();
+ m_bodyDisjunction->terms[m_currentAlternativeIndex].alternative.next = newAlternativeIndex - m_currentAlternativeIndex;
+ m_bodyDisjunction->terms.append(ByteTerm::BodyAlternativeDisjunction(onceThrough));
+
+ m_currentAlternativeIndex = newAlternativeIndex;
+ }
+
+ void alternativeDisjunction()
+ {
+ int newAlternativeIndex = m_bodyDisjunction->terms.size();
+ m_bodyDisjunction->terms[m_currentAlternativeIndex].alternative.next = newAlternativeIndex - m_currentAlternativeIndex;
+ m_bodyDisjunction->terms.append(ByteTerm::AlternativeDisjunction());
+
+ m_currentAlternativeIndex = newAlternativeIndex;
+ }
+
+ void emitDisjunction(PatternDisjunction* disjunction, unsigned inputCountAlreadyChecked = 0, unsigned parenthesesInputCountAlreadyChecked = 0)
+ {
+ for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) {
+ unsigned currentCountAlreadyChecked = inputCountAlreadyChecked;
+
+ PatternAlternative* alternative = disjunction->m_alternatives[alt];
+
+ if (alt) {
+ if (disjunction == m_pattern.m_body)
+ alternativeBodyDisjunction(alternative->onceThrough());
+ else
+ alternativeDisjunction();
+ }
+
+ unsigned minimumSize = alternative->m_minimumSize;
+ ASSERT(minimumSize >= parenthesesInputCountAlreadyChecked);
+ unsigned countToCheck = minimumSize - parenthesesInputCountAlreadyChecked;
+
+ if (countToCheck) {
+ checkInput(countToCheck);
+ currentCountAlreadyChecked += countToCheck;
+ }
+
+ for (unsigned i = 0; i < alternative->m_terms.size(); ++i) {
+ PatternTerm& term = alternative->m_terms[i];
+
+ switch (term.type) {
+ case PatternTerm::TypeAssertionBOL:
+ assertionBOL(term.inputPosition - currentCountAlreadyChecked);
+ break;
+
+ case PatternTerm::TypeAssertionEOL:
+ assertionEOL(term.inputPosition - currentCountAlreadyChecked);
+ break;
+
+ case PatternTerm::TypeAssertionWordBoundary:
+ assertionWordBoundary(term.invert(), term.inputPosition - currentCountAlreadyChecked);
+ break;
+
+ case PatternTerm::TypePatternCharacter:
+ atomPatternCharacter(term.patternCharacter, term.inputPosition - currentCountAlreadyChecked, term.frameLocation, term.quantityCount, term.quantityType);
+ break;
+
+ case PatternTerm::TypeCharacterClass:
+ atomCharacterClass(term.characterClass, term.invert(), term.inputPosition - currentCountAlreadyChecked, term.frameLocation, term.quantityCount, term.quantityType);
+ break;
+
+ case PatternTerm::TypeBackReference:
+ atomBackReference(term.backReferenceSubpatternId, term.inputPosition - currentCountAlreadyChecked, term.frameLocation, term.quantityCount, term.quantityType);
+ break;
+
+ case PatternTerm::TypeForwardReference:
+ break;
+
+ case PatternTerm::TypeParenthesesSubpattern: {
+ unsigned disjunctionAlreadyCheckedCount = 0;
+ if (term.quantityCount == 1 && !term.parentheses.isCopy) {
+ unsigned alternativeFrameLocation = term.frameLocation;
+ // For QuantifierFixedCount we pre-check the minimum size; for greedy/non-greedy we reserve a slot in the frame.
+ if (term.quantityType == QuantifierFixedCount)
+ disjunctionAlreadyCheckedCount = term.parentheses.disjunction->m_minimumSize;
+ else
+ alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesOnce;
+ unsigned delegateEndInputOffset = term.inputPosition - currentCountAlreadyChecked;
+ atomParenthesesOnceBegin(term.parentheses.subpatternId, term.capture(), delegateEndInputOffset - disjunctionAlreadyCheckedCount, term.frameLocation, alternativeFrameLocation);
+ emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, disjunctionAlreadyCheckedCount);
+ atomParenthesesOnceEnd(delegateEndInputOffset, term.frameLocation, term.quantityCount, term.quantityType);
+ } else if (term.parentheses.isTerminal) {
+ unsigned delegateEndInputOffset = term.inputPosition - currentCountAlreadyChecked;
+ atomParenthesesTerminalBegin(term.parentheses.subpatternId, term.capture(), delegateEndInputOffset - disjunctionAlreadyCheckedCount, term.frameLocation, term.frameLocation + YarrStackSpaceForBackTrackInfoParenthesesOnce);
+ emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, disjunctionAlreadyCheckedCount);
+ atomParenthesesTerminalEnd(delegateEndInputOffset, term.frameLocation, term.quantityCount, term.quantityType);
+ } else {
+ unsigned delegateEndInputOffset = term.inputPosition - currentCountAlreadyChecked;
+ atomParenthesesSubpatternBegin(term.parentheses.subpatternId, term.capture(), delegateEndInputOffset - disjunctionAlreadyCheckedCount, term.frameLocation, 0);
+ emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, 0);
+ atomParenthesesSubpatternEnd(term.parentheses.lastSubpatternId, delegateEndInputOffset, term.frameLocation, term.quantityCount, term.quantityType, term.parentheses.disjunction->m_callFrameSize);
+ }
+ break;
+ }
+
+ case PatternTerm::TypeParentheticalAssertion: {
+ unsigned alternativeFrameLocation = term.frameLocation + YarrStackSpaceForBackTrackInfoParentheticalAssertion;
+
+ ASSERT(currentCountAlreadyChecked >= static_cast<unsigned>(term.inputPosition));
+ unsigned positiveInputOffset = currentCountAlreadyChecked - static_cast<unsigned>(term.inputPosition);
+ unsigned uncheckAmount = 0;
+ if (positiveInputOffset > term.parentheses.disjunction->m_minimumSize) {
+ uncheckAmount = positiveInputOffset - term.parentheses.disjunction->m_minimumSize;
+ uncheckInput(uncheckAmount);
+ currentCountAlreadyChecked -= uncheckAmount;
+ }
+
+ atomParentheticalAssertionBegin(term.parentheses.subpatternId, term.invert(), term.frameLocation, alternativeFrameLocation);
+ emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, positiveInputOffset - uncheckAmount);
+ atomParentheticalAssertionEnd(0, term.frameLocation, term.quantityCount, term.quantityType);
+ if (uncheckAmount) {
+ checkInput(uncheckAmount);
+ currentCountAlreadyChecked += uncheckAmount;
+ }
+ break;
+ }
+
+ case PatternTerm::TypeDotStarEnclosure:
+ assertionDotStarEnclosure(term.anchors.bolAnchor, term.anchors.eolAnchor);
+ break;
+ }
+ }
+ }
+ }
+
+private:
+ YarrPattern& m_pattern;
+ OwnPtr<ByteDisjunction> m_bodyDisjunction;
+ unsigned m_currentAlternativeIndex;
+ Vector<ParenthesesStackEntry> m_parenthesesStack;
+ Vector<ByteDisjunction*> m_allParenthesesInfo;
+};
+
+PassOwnPtr<BytecodePattern> byteCompile(YarrPattern& pattern, BumpPointerAllocator* allocator)
+{
+ return ByteCompiler(pattern).compile(allocator);
+}
+
+int interpret(BytecodePattern* bytecode, const UChar* input, unsigned start, unsigned length, int* output)
+{
+ return Interpreter(bytecode, output, input, start, length).interpret();
+}
+
+COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoPatternCharacter) == (YarrStackSpaceForBackTrackInfoPatternCharacter * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoPatternCharacter);
+COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoCharacterClass) == (YarrStackSpaceForBackTrackInfoCharacterClass * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoCharacterClass);
+COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoBackReference) == (YarrStackSpaceForBackTrackInfoBackReference * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoBackReference);
+COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoAlternative) == (YarrStackSpaceForBackTrackInfoAlternative * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoAlternative);
+COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoParentheticalAssertion) == (YarrStackSpaceForBackTrackInfoParentheticalAssertion * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoParentheticalAssertion);
+COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoParenthesesOnce) == (YarrStackSpaceForBackTrackInfoParenthesesOnce * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoParenthesesOnce);
+COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoParentheses) == (YarrStackSpaceForBackTrackInfoParentheses * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoParentheses);
+
+
+} }
--- /dev/null
+/*
+ * Copyright (C) 2009, 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef YarrInterpreter_h
+#define YarrInterpreter_h
+
+#include "YarrPattern.h"
+#include <wtf/PassOwnPtr.h>
+#include <wtf/unicode/Unicode.h>
+
+namespace WTF {
+class BumpPointerAllocator;
+}
+using WTF::BumpPointerAllocator;
+
+namespace JSC { namespace Yarr {
+
+class ByteDisjunction;
+
+struct ByteTerm {
+ enum Type {
+ TypeBodyAlternativeBegin,
+ TypeBodyAlternativeDisjunction,
+ TypeBodyAlternativeEnd,
+ TypeAlternativeBegin,
+ TypeAlternativeDisjunction,
+ TypeAlternativeEnd,
+ TypeSubpatternBegin,
+ TypeSubpatternEnd,
+ TypeAssertionBOL,
+ TypeAssertionEOL,
+ TypeAssertionWordBoundary,
+ TypePatternCharacterOnce,
+ TypePatternCharacterFixed,
+ TypePatternCharacterGreedy,
+ TypePatternCharacterNonGreedy,
+ TypePatternCasedCharacterOnce,
+ TypePatternCasedCharacterFixed,
+ TypePatternCasedCharacterGreedy,
+ TypePatternCasedCharacterNonGreedy,
+ TypeCharacterClass,
+ TypeBackReference,
+ TypeParenthesesSubpattern,
+ TypeParenthesesSubpatternOnceBegin,
+ TypeParenthesesSubpatternOnceEnd,
+ TypeParenthesesSubpatternTerminalBegin,
+ TypeParenthesesSubpatternTerminalEnd,
+ TypeParentheticalAssertionBegin,
+ TypeParentheticalAssertionEnd,
+ TypeCheckInput,
+ TypeUncheckInput,
+ TypeDotStarEnclosure,
+ } type;
+ union {
+ struct {
+ union {
+ UChar patternCharacter;
+ struct {
+ UChar lo;
+ UChar hi;
+ } casedCharacter;
+ CharacterClass* characterClass;
+ unsigned subpatternId;
+ };
+ union {
+ ByteDisjunction* parenthesesDisjunction;
+ unsigned parenthesesWidth;
+ };
+ QuantifierType quantityType;
+ unsigned quantityCount;
+ } atom;
+ struct {
+ int next;
+ int end;
+ bool onceThrough;
+ } alternative;
+ struct {
+ bool m_bol : 1;
+ bool m_eol : 1;
+ } anchors;
+ unsigned checkInputCount;
+ };
+ unsigned frameLocation;
+ bool m_capture : 1;
+ bool m_invert : 1;
+ int inputPosition;
+
+ ByteTerm(UChar ch, int inputPos, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
+ : frameLocation(frameLocation)
+ , m_capture(false)
+ , m_invert(false)
+ {
+ switch (quantityType) {
+ case QuantifierFixedCount:
+ type = (quantityCount == 1) ? ByteTerm::TypePatternCharacterOnce : ByteTerm::TypePatternCharacterFixed;
+ break;
+ case QuantifierGreedy:
+ type = ByteTerm::TypePatternCharacterGreedy;
+ break;
+ case QuantifierNonGreedy:
+ type = ByteTerm::TypePatternCharacterNonGreedy;
+ break;
+ }
+
+ atom.patternCharacter = ch;
+ atom.quantityType = quantityType;
+ atom.quantityCount = quantityCount;
+ inputPosition = inputPos;
+ }
+
+ ByteTerm(UChar lo, UChar hi, int inputPos, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
+ : frameLocation(frameLocation)
+ , m_capture(false)
+ , m_invert(false)
+ {
+ switch (quantityType) {
+ case QuantifierFixedCount:
+ type = (quantityCount == 1) ? ByteTerm::TypePatternCasedCharacterOnce : ByteTerm::TypePatternCasedCharacterFixed;
+ break;
+ case QuantifierGreedy:
+ type = ByteTerm::TypePatternCasedCharacterGreedy;
+ break;
+ case QuantifierNonGreedy:
+ type = ByteTerm::TypePatternCasedCharacterNonGreedy;
+ break;
+ }
+
+ atom.casedCharacter.lo = lo;
+ atom.casedCharacter.hi = hi;
+ atom.quantityType = quantityType;
+ atom.quantityCount = quantityCount;
+ inputPosition = inputPos;
+ }
+
+ ByteTerm(CharacterClass* characterClass, bool invert, int inputPos)
+ : type(ByteTerm::TypeCharacterClass)
+ , m_capture(false)
+ , m_invert(invert)
+ {
+ atom.characterClass = characterClass;
+ atom.quantityType = QuantifierFixedCount;
+ atom.quantityCount = 1;
+ inputPosition = inputPos;
+ }
+
+ ByteTerm(Type type, unsigned subpatternId, ByteDisjunction* parenthesesInfo, bool capture, int inputPos)
+ : type(type)
+ , m_capture(capture)
+ , m_invert(false)
+ {
+ atom.subpatternId = subpatternId;
+ atom.parenthesesDisjunction = parenthesesInfo;
+ atom.quantityType = QuantifierFixedCount;
+ atom.quantityCount = 1;
+ inputPosition = inputPos;
+ }
+
+ ByteTerm(Type type, bool invert = false)
+ : type(type)
+ , m_capture(false)
+ , m_invert(invert)
+ {
+ atom.quantityType = QuantifierFixedCount;
+ atom.quantityCount = 1;
+ }
+
+ ByteTerm(Type type, unsigned subpatternId, bool capture, bool invert, int inputPos)
+ : type(type)
+ , m_capture(capture)
+ , m_invert(invert)
+ {
+ atom.subpatternId = subpatternId;
+ atom.quantityType = QuantifierFixedCount;
+ atom.quantityCount = 1;
+ inputPosition = inputPos;
+ }
+
+ static ByteTerm BOL(int inputPos)
+ {
+ ByteTerm term(TypeAssertionBOL);
+ term.inputPosition = inputPos;
+ return term;
+ }
+
+ static ByteTerm CheckInput(unsigned count)
+ {
+ ByteTerm term(TypeCheckInput);
+ term.checkInputCount = count;
+ return term;
+ }
+
+ static ByteTerm UncheckInput(unsigned count)
+ {
+ ByteTerm term(TypeUncheckInput);
+ term.checkInputCount = count;
+ return term;
+ }
+
+ static ByteTerm EOL(int inputPos)
+ {
+ ByteTerm term(TypeAssertionEOL);
+ term.inputPosition = inputPos;
+ return term;
+ }
+
+ static ByteTerm WordBoundary(bool invert, int inputPos)
+ {
+ ByteTerm term(TypeAssertionWordBoundary, invert);
+ term.inputPosition = inputPos;
+ return term;
+ }
+
+ static ByteTerm BackReference(unsigned subpatternId, int inputPos)
+ {
+ return ByteTerm(TypeBackReference, subpatternId, false, false, inputPos);
+ }
+
+ static ByteTerm BodyAlternativeBegin(bool onceThrough)
+ {
+ ByteTerm term(TypeBodyAlternativeBegin);
+ term.alternative.next = 0;
+ term.alternative.end = 0;
+ term.alternative.onceThrough = onceThrough;
+ return term;
+ }
+
+ static ByteTerm BodyAlternativeDisjunction(bool onceThrough)
+ {
+ ByteTerm term(TypeBodyAlternativeDisjunction);
+ term.alternative.next = 0;
+ term.alternative.end = 0;
+ term.alternative.onceThrough = onceThrough;
+ return term;
+ }
+
+ static ByteTerm BodyAlternativeEnd()
+ {
+ ByteTerm term(TypeBodyAlternativeEnd);
+ term.alternative.next = 0;
+ term.alternative.end = 0;
+ term.alternative.onceThrough = false;
+ return term;
+ }
+
+ static ByteTerm AlternativeBegin()
+ {
+ ByteTerm term(TypeAlternativeBegin);
+ term.alternative.next = 0;
+ term.alternative.end = 0;
+ term.alternative.onceThrough = false;
+ return term;
+ }
+
+ static ByteTerm AlternativeDisjunction()
+ {
+ ByteTerm term(TypeAlternativeDisjunction);
+ term.alternative.next = 0;
+ term.alternative.end = 0;
+ term.alternative.onceThrough = false;
+ return term;
+ }
+
+ static ByteTerm AlternativeEnd()
+ {
+ ByteTerm term(TypeAlternativeEnd);
+ term.alternative.next = 0;
+ term.alternative.end = 0;
+ term.alternative.onceThrough = false;
+ return term;
+ }
+
+ static ByteTerm SubpatternBegin()
+ {
+ return ByteTerm(TypeSubpatternBegin);
+ }
+
+ static ByteTerm SubpatternEnd()
+ {
+ return ByteTerm(TypeSubpatternEnd);
+ }
+
+ static ByteTerm DotStarEnclosure(bool bolAnchor, bool eolAnchor)
+ {
+ ByteTerm term(TypeDotStarEnclosure);
+ term.anchors.m_bol = bolAnchor;
+ term.anchors.m_eol = eolAnchor;
+ return term;
+ }
+
+ bool invert()
+ {
+ return m_invert;
+ }
+
+ bool capture()
+ {
+ return m_capture;
+ }
+};
+
+class ByteDisjunction {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ ByteDisjunction(unsigned numSubpatterns, unsigned frameSize)
+ : m_numSubpatterns(numSubpatterns)
+ , m_frameSize(frameSize)
+ {
+ }
+
+ Vector<ByteTerm> terms;
+ unsigned m_numSubpatterns;
+ unsigned m_frameSize;
+};
+
+struct BytecodePattern {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ BytecodePattern(PassOwnPtr<ByteDisjunction> body, Vector<ByteDisjunction*> allParenthesesInfo, YarrPattern& pattern, BumpPointerAllocator* allocator)
+ : m_body(body)
+ , m_ignoreCase(pattern.m_ignoreCase)
+ , m_multiline(pattern.m_multiline)
+ , m_allocator(allocator)
+ {
+ newlineCharacterClass = pattern.newlineCharacterClass();
+ wordcharCharacterClass = pattern.wordcharCharacterClass();
+
+ m_allParenthesesInfo.append(allParenthesesInfo);
+ m_userCharacterClasses.append(pattern.m_userCharacterClasses);
+ // 'Steal' the YarrPattern's CharacterClasses! We clear its
+ // array, so that it won't delete them on destruction. We'll
+ // take responsibility for that.
+ pattern.m_userCharacterClasses.clear();
+ }
+
+ ~BytecodePattern()
+ {
+ deleteAllValues(m_allParenthesesInfo);
+ deleteAllValues(m_userCharacterClasses);
+ }
+
+ OwnPtr<ByteDisjunction> m_body;
+ bool m_ignoreCase;
+ bool m_multiline;
+ // Each BytecodePattern is associated with a RegExp, each RegExp is associated
+ // with a JSGlobalData. Cache a pointer to out JSGlobalData's m_regExpAllocator.
+ BumpPointerAllocator* m_allocator;
+
+ CharacterClass* newlineCharacterClass;
+ CharacterClass* wordcharCharacterClass;
+
+private:
+ Vector<ByteDisjunction*> m_allParenthesesInfo;
+ Vector<CharacterClass*> m_userCharacterClasses;
+};
+
+} } // namespace JSC::Yarr
+
+#endif // YarrInterpreter_h
--- /dev/null
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "YarrJIT.h"
+
+#include "ASCIICType.h"
+#include "LinkBuffer.h"
+#include "Yarr.h"
+
+#if ENABLE(YARR_JIT)
+
+using namespace WTF;
+
+namespace JSC { namespace Yarr {
+
+class YarrGenerator : private MacroAssembler {
+ friend void jitCompile(JSGlobalData*, YarrCodeBlock& jitObject, const UString& pattern, unsigned& numSubpatterns, const char*& error, bool ignoreCase, bool multiline);
+
+#if CPU(ARM)
+ static const RegisterID input = ARMRegisters::r0;
+ static const RegisterID index = ARMRegisters::r1;
+ static const RegisterID length = ARMRegisters::r2;
+ static const RegisterID output = ARMRegisters::r4;
+
+ static const RegisterID regT0 = ARMRegisters::r5;
+ static const RegisterID regT1 = ARMRegisters::r6;
+
+ static const RegisterID returnRegister = ARMRegisters::r0;
+#elif CPU(MIPS)
+ static const RegisterID input = MIPSRegisters::a0;
+ static const RegisterID index = MIPSRegisters::a1;
+ static const RegisterID length = MIPSRegisters::a2;
+ static const RegisterID output = MIPSRegisters::a3;
+
+ static const RegisterID regT0 = MIPSRegisters::t4;
+ static const RegisterID regT1 = MIPSRegisters::t5;
+
+ static const RegisterID returnRegister = MIPSRegisters::v0;
+#elif CPU(SH4)
+ static const RegisterID input = SH4Registers::r4;
+ static const RegisterID index = SH4Registers::r5;
+ static const RegisterID length = SH4Registers::r6;
+ static const RegisterID output = SH4Registers::r7;
+
+ static const RegisterID regT0 = SH4Registers::r0;
+ static const RegisterID regT1 = SH4Registers::r1;
+
+ static const RegisterID returnRegister = SH4Registers::r0;
+#elif CPU(X86)
+ static const RegisterID input = X86Registers::eax;
+ static const RegisterID index = X86Registers::edx;
+ static const RegisterID length = X86Registers::ecx;
+ static const RegisterID output = X86Registers::edi;
+
+ static const RegisterID regT0 = X86Registers::ebx;
+ static const RegisterID regT1 = X86Registers::esi;
+
+ static const RegisterID returnRegister = X86Registers::eax;
+#elif CPU(X86_64)
+ static const RegisterID input = X86Registers::edi;
+ static const RegisterID index = X86Registers::esi;
+ static const RegisterID length = X86Registers::edx;
+ static const RegisterID output = X86Registers::ecx;
+
+ static const RegisterID regT0 = X86Registers::eax;
+ static const RegisterID regT1 = X86Registers::ebx;
+
+ static const RegisterID returnRegister = X86Registers::eax;
+#endif
+
+ void optimizeAlternative(PatternAlternative* alternative)
+ {
+ if (!alternative->m_terms.size())
+ return;
+
+ for (unsigned i = 0; i < alternative->m_terms.size() - 1; ++i) {
+ PatternTerm& term = alternative->m_terms[i];
+ PatternTerm& nextTerm = alternative->m_terms[i + 1];
+
+ if ((term.type == PatternTerm::TypeCharacterClass)
+ && (term.quantityType == QuantifierFixedCount)
+ && (nextTerm.type == PatternTerm::TypePatternCharacter)
+ && (nextTerm.quantityType == QuantifierFixedCount)) {
+ PatternTerm termCopy = term;
+ alternative->m_terms[i] = nextTerm;
+ alternative->m_terms[i + 1] = termCopy;
+ }
+ }
+ }
+
+ void matchCharacterClassRange(RegisterID character, JumpList& failures, JumpList& matchDest, const CharacterRange* ranges, unsigned count, unsigned* matchIndex, const UChar* matches, unsigned matchCount)
+ {
+ do {
+ // pick which range we're going to generate
+ int which = count >> 1;
+ char lo = ranges[which].begin;
+ char hi = ranges[which].end;
+
+ // check if there are any ranges or matches below lo. If not, just jl to failure -
+ // if there is anything else to check, check that first, if it falls through jmp to failure.
+ if ((*matchIndex < matchCount) && (matches[*matchIndex] < lo)) {
+ Jump loOrAbove = branch32(GreaterThanOrEqual, character, Imm32((unsigned short)lo));
+
+ // generate code for all ranges before this one
+ if (which)
+ matchCharacterClassRange(character, failures, matchDest, ranges, which, matchIndex, matches, matchCount);
+
+ while ((*matchIndex < matchCount) && (matches[*matchIndex] < lo)) {
+ matchDest.append(branch32(Equal, character, Imm32((unsigned short)matches[*matchIndex])));
+ ++*matchIndex;
+ }
+ failures.append(jump());
+
+ loOrAbove.link(this);
+ } else if (which) {
+ Jump loOrAbove = branch32(GreaterThanOrEqual, character, Imm32((unsigned short)lo));
+
+ matchCharacterClassRange(character, failures, matchDest, ranges, which, matchIndex, matches, matchCount);
+ failures.append(jump());
+
+ loOrAbove.link(this);
+ } else
+ failures.append(branch32(LessThan, character, Imm32((unsigned short)lo)));
+
+ while ((*matchIndex < matchCount) && (matches[*matchIndex] <= hi))
+ ++*matchIndex;
+
+ matchDest.append(branch32(LessThanOrEqual, character, Imm32((unsigned short)hi)));
+ // fall through to here, the value is above hi.
+
+ // shuffle along & loop around if there are any more matches to handle.
+ unsigned next = which + 1;
+ ranges += next;
+ count -= next;
+ } while (count);
+ }
+
+ void matchCharacterClass(RegisterID character, JumpList& matchDest, const CharacterClass* charClass)
+ {
+ if (charClass->m_table) {
+ ExtendedAddress tableEntry(character, reinterpret_cast<intptr_t>(charClass->m_table->m_table));
+ matchDest.append(branchTest8(charClass->m_table->m_inverted ? Zero : NonZero, tableEntry));
+ return;
+ }
+ Jump unicodeFail;
+ if (charClass->m_matchesUnicode.size() || charClass->m_rangesUnicode.size()) {
+ Jump isAscii = branch32(LessThanOrEqual, character, TrustedImm32(0x7f));
+
+ if (charClass->m_matchesUnicode.size()) {
+ for (unsigned i = 0; i < charClass->m_matchesUnicode.size(); ++i) {
+ UChar ch = charClass->m_matchesUnicode[i];
+ matchDest.append(branch32(Equal, character, Imm32(ch)));
+ }
+ }
+
+ if (charClass->m_rangesUnicode.size()) {
+ for (unsigned i = 0; i < charClass->m_rangesUnicode.size(); ++i) {
+ UChar lo = charClass->m_rangesUnicode[i].begin;
+ UChar hi = charClass->m_rangesUnicode[i].end;
+
+ Jump below = branch32(LessThan, character, Imm32(lo));
+ matchDest.append(branch32(LessThanOrEqual, character, Imm32(hi)));
+ below.link(this);
+ }
+ }
+
+ unicodeFail = jump();
+ isAscii.link(this);
+ }
+
+ if (charClass->m_ranges.size()) {
+ unsigned matchIndex = 0;
+ JumpList failures;
+ matchCharacterClassRange(character, failures, matchDest, charClass->m_ranges.begin(), charClass->m_ranges.size(), &matchIndex, charClass->m_matches.begin(), charClass->m_matches.size());
+ while (matchIndex < charClass->m_matches.size())
+ matchDest.append(branch32(Equal, character, Imm32((unsigned short)charClass->m_matches[matchIndex++])));
+
+ failures.link(this);
+ } else if (charClass->m_matches.size()) {
+ // optimization: gather 'a','A' etc back together, can mask & test once.
+ Vector<char> matchesAZaz;
+
+ for (unsigned i = 0; i < charClass->m_matches.size(); ++i) {
+ char ch = charClass->m_matches[i];
+ if (m_pattern.m_ignoreCase) {
+ if (isASCIILower(ch)) {
+ matchesAZaz.append(ch);
+ continue;
+ }
+ if (isASCIIUpper(ch))
+ continue;
+ }
+ matchDest.append(branch32(Equal, character, Imm32((unsigned short)ch)));
+ }
+
+ if (unsigned countAZaz = matchesAZaz.size()) {
+ or32(TrustedImm32(32), character);
+ for (unsigned i = 0; i < countAZaz; ++i)
+ matchDest.append(branch32(Equal, character, TrustedImm32(matchesAZaz[i])));
+ }
+ }
+
+ if (charClass->m_matchesUnicode.size() || charClass->m_rangesUnicode.size())
+ unicodeFail.link(this);
+ }
+
+ // Jumps if input not available; will have (incorrectly) incremented already!
+ Jump jumpIfNoAvailableInput(unsigned countToCheck = 0)
+ {
+ if (countToCheck)
+ add32(Imm32(countToCheck), index);
+ return branch32(Above, index, length);
+ }
+
+ Jump jumpIfAvailableInput(unsigned countToCheck)
+ {
+ add32(Imm32(countToCheck), index);
+ return branch32(BelowOrEqual, index, length);
+ }
+
+ Jump checkInput()
+ {
+ return branch32(BelowOrEqual, index, length);
+ }
+
+ Jump atEndOfInput()
+ {
+ return branch32(Equal, index, length);
+ }
+
+ Jump notAtEndOfInput()
+ {
+ return branch32(NotEqual, index, length);
+ }
+
+ Jump jumpIfCharEquals(UChar ch, int inputPosition)
+ {
+ return branch16(Equal, BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), Imm32(ch));
+ }
+
+ Jump jumpIfCharNotEquals(UChar ch, int inputPosition)
+ {
+ return branch16(NotEqual, BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), Imm32(ch));
+ }
+
+ void readCharacter(int inputPosition, RegisterID reg)
+ {
+ load16(BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), reg);
+ }
+
+ void storeToFrame(RegisterID reg, unsigned frameLocation)
+ {
+ poke(reg, frameLocation);
+ }
+
+ void storeToFrame(TrustedImm32 imm, unsigned frameLocation)
+ {
+ poke(imm, frameLocation);
+ }
+
+ DataLabelPtr storeToFrameWithPatch(unsigned frameLocation)
+ {
+ return storePtrWithPatch(TrustedImmPtr(0), Address(stackPointerRegister, frameLocation * sizeof(void*)));
+ }
+
+ void loadFromFrame(unsigned frameLocation, RegisterID reg)
+ {
+ peek(reg, frameLocation);
+ }
+
+ void loadFromFrameAndJump(unsigned frameLocation)
+ {
+ jump(Address(stackPointerRegister, frameLocation * sizeof(void*)));
+ }
+
+ enum YarrOpCode {
+ // These nodes wrap body alternatives - those in the main disjunction,
+ // rather than subpatterns or assertions. These are chained together in
+ // a doubly linked list, with a 'begin' node for the first alternative,
+ // a 'next' node for each subsequent alternative, and an 'end' node at
+ // the end. In the case of repeating alternatives, the 'end' node also
+ // has a reference back to 'begin'.
+ OpBodyAlternativeBegin,
+ OpBodyAlternativeNext,
+ OpBodyAlternativeEnd,
+ // Similar to the body alternatives, but used for subpatterns with two
+ // or more alternatives.
+ OpNestedAlternativeBegin,
+ OpNestedAlternativeNext,
+ OpNestedAlternativeEnd,
+ // Used for alternatives in subpatterns where there is only a single
+ // alternative (backtrackingis easier in these cases), or for alternatives
+ // which never need to be backtracked (those in parenthetical assertions,
+ // terminal subpatterns).
+ OpSimpleNestedAlternativeBegin,
+ OpSimpleNestedAlternativeNext,
+ OpSimpleNestedAlternativeEnd,
+ // Used to wrap 'Once' subpattern matches (quantityCount == 1).
+ OpParenthesesSubpatternOnceBegin,
+ OpParenthesesSubpatternOnceEnd,
+ // Used to wrap 'Terminal' subpattern matches (at the end of the regexp).
+ OpParenthesesSubpatternTerminalBegin,
+ OpParenthesesSubpatternTerminalEnd,
+ // Used to wrap parenthetical assertions.
+ OpParentheticalAssertionBegin,
+ OpParentheticalAssertionEnd,
+ // Wraps all simple terms (pattern characters, character classes).
+ OpTerm,
+ // Where an expression contains only 'once through' body alternatives
+ // and no repeating ones, this op is used to return match failure.
+ OpMatchFailed
+ };
+
+ // This structure is used to hold the compiled opcode information,
+ // including reference back to the original PatternTerm/PatternAlternatives,
+ // and JIT compilation data structures.
+ struct YarrOp {
+ explicit YarrOp(PatternTerm* term)
+ : m_op(OpTerm)
+ , m_term(term)
+ , m_isDeadCode(false)
+ {
+ }
+
+ explicit YarrOp(YarrOpCode op)
+ : m_op(op)
+ , m_isDeadCode(false)
+ {
+ }
+
+ // The operation, as a YarrOpCode, and also a reference to the PatternTerm.
+ YarrOpCode m_op;
+ PatternTerm* m_term;
+
+ // For alternatives, this holds the PatternAlternative and doubly linked
+ // references to this alternative's siblings. In the case of the
+ // OpBodyAlternativeEnd node at the end of a section of repeating nodes,
+ // m_nextOp will reference the OpBodyAlternativeBegin node of the first
+ // repeating alternative.
+ PatternAlternative* m_alternative;
+ size_t m_previousOp;
+ size_t m_nextOp;
+
+ // Used to record a set of Jumps out of the generated code, typically
+ // used for jumps out to backtracking code, and a single reentry back
+ // into the code for a node (likely where a backtrack will trigger
+ // rematching).
+ Label m_reentry;
+ JumpList m_jumps;
+
+ // This flag is used to null out the second pattern character, when
+ // two are fused to match a pair together.
+ bool m_isDeadCode;
+
+ // Currently used in the case of some of the more complex management of
+ // 'm_checked', to cache the offset used in this alternative, to avoid
+ // recalculating it.
+ int m_checkAdjust;
+
+ // Used by OpNestedAlternativeNext/End to hold the pointer to the
+ // value that will be pushed into the pattern's frame to return to,
+ // upon backtracking back into the disjunction.
+ DataLabelPtr m_returnAddress;
+ };
+
+ // BacktrackingState
+ // This class encapsulates information about the state of code generation
+ // whilst generating the code for backtracking, when a term fails to match.
+ // Upon entry to code generation of the backtracking code for a given node,
+ // the Backtracking state will hold references to all control flow sources
+ // that are outputs in need of further backtracking from the prior node
+ // generated (which is the subsequent operation in the regular expression,
+ // and in the m_ops Vector, since we generated backtracking backwards).
+ // These references to control flow take the form of:
+ // - A jump list of jumps, to be linked to code that will backtrack them
+ // further.
+ // - A set of DataLabelPtr values, to be populated with values to be
+ // treated effectively as return addresses backtracking into complex
+ // subpatterns.
+ // - A flag indicating that the current sequence of generated code up to
+ // this point requires backtracking.
+ class BacktrackingState {
+ public:
+ BacktrackingState()
+ : m_pendingFallthrough(false)
+ {
+ }
+
+ // Add a jump or jumps, a return address, or set the flag indicating
+ // that the current 'fallthrough' control flow requires backtracking.
+ void append(const Jump& jump)
+ {
+ m_laterFailures.append(jump);
+ }
+ void append(JumpList& jumpList)
+ {
+ m_laterFailures.append(jumpList);
+ }
+ void append(const DataLabelPtr& returnAddress)
+ {
+ m_pendingReturns.append(returnAddress);
+ }
+ void fallthrough()
+ {
+ ASSERT(!m_pendingFallthrough);
+ m_pendingFallthrough = true;
+ }
+
+ // These methods clear the backtracking state, either linking to the
+ // current location, a provided label, or copying the backtracking out
+ // to a JumpList. All actions may require code generation to take place,
+ // and as such are passed a pointer to the assembler.
+ void link(MacroAssembler* assembler)
+ {
+ if (m_pendingReturns.size()) {
+ Label here(assembler);
+ for (unsigned i = 0; i < m_pendingReturns.size(); ++i)
+ m_backtrackRecords.append(ReturnAddressRecord(m_pendingReturns[i], here));
+ m_pendingReturns.clear();
+ }
+ m_laterFailures.link(assembler);
+ m_laterFailures.clear();
+ m_pendingFallthrough = false;
+ }
+ void linkTo(Label label, MacroAssembler* assembler)
+ {
+ if (m_pendingReturns.size()) {
+ for (unsigned i = 0; i < m_pendingReturns.size(); ++i)
+ m_backtrackRecords.append(ReturnAddressRecord(m_pendingReturns[i], label));
+ m_pendingReturns.clear();
+ }
+ if (m_pendingFallthrough)
+ assembler->jump(label);
+ m_laterFailures.linkTo(label, assembler);
+ m_laterFailures.clear();
+ m_pendingFallthrough = false;
+ }
+ void takeBacktracksToJumpList(JumpList& jumpList, MacroAssembler* assembler)
+ {
+ if (m_pendingReturns.size()) {
+ Label here(assembler);
+ for (unsigned i = 0; i < m_pendingReturns.size(); ++i)
+ m_backtrackRecords.append(ReturnAddressRecord(m_pendingReturns[i], here));
+ m_pendingReturns.clear();
+ m_pendingFallthrough = true;
+ }
+ if (m_pendingFallthrough)
+ jumpList.append(assembler->jump());
+ jumpList.append(m_laterFailures);
+ m_laterFailures.clear();
+ m_pendingFallthrough = false;
+ }
+
+ bool isEmpty()
+ {
+ return m_laterFailures.empty() && m_pendingReturns.isEmpty() && !m_pendingFallthrough;
+ }
+
+ // Called at the end of code generation to link all return addresses.
+ void linkDataLabels(LinkBuffer& linkBuffer)
+ {
+ ASSERT(isEmpty());
+ for (unsigned i = 0; i < m_backtrackRecords.size(); ++i)
+ linkBuffer.patch(m_backtrackRecords[i].m_dataLabel, linkBuffer.locationOf(m_backtrackRecords[i].m_backtrackLocation));
+ }
+
+ private:
+ struct ReturnAddressRecord {
+ ReturnAddressRecord(DataLabelPtr dataLabel, Label backtrackLocation)
+ : m_dataLabel(dataLabel)
+ , m_backtrackLocation(backtrackLocation)
+ {
+ }
+
+ DataLabelPtr m_dataLabel;
+ Label m_backtrackLocation;
+ };
+
+ JumpList m_laterFailures;
+ bool m_pendingFallthrough;
+ Vector<DataLabelPtr, 4> m_pendingReturns;
+ Vector<ReturnAddressRecord, 4> m_backtrackRecords;
+ };
+
+ // Generation methods:
+ // ===================
+
+ // This method provides a default implementation of backtracking common
+ // to many terms; terms commonly jump out of the forwards matching path
+ // on any failed conditions, and add these jumps to the m_jumps list. If
+ // no special handling is required we can often just backtrack to m_jumps.
+ void backtrackTermDefault(size_t opIndex)
+ {
+ YarrOp& op = m_ops[opIndex];
+ m_backtrackingState.append(op.m_jumps);
+ }
+
+ void generateAssertionBOL(size_t opIndex)
+ {
+ YarrOp& op = m_ops[opIndex];
+ PatternTerm* term = op.m_term;
+
+ if (m_pattern.m_multiline) {
+ const RegisterID character = regT0;
+
+ JumpList matchDest;
+ if (!term->inputPosition)
+ matchDest.append(branch32(Equal, index, Imm32(m_checked)));
+
+ readCharacter((term->inputPosition - m_checked) - 1, character);
+ matchCharacterClass(character, matchDest, m_pattern.newlineCharacterClass());
+ op.m_jumps.append(jump());
+
+ matchDest.link(this);
+ } else {
+ // Erk, really should poison out these alternatives early. :-/
+ if (term->inputPosition)
+ op.m_jumps.append(jump());
+ else
+ op.m_jumps.append(branch32(NotEqual, index, Imm32(m_checked)));
+ }
+ }
+ void backtrackAssertionBOL(size_t opIndex)
+ {
+ backtrackTermDefault(opIndex);
+ }
+
+ void generateAssertionEOL(size_t opIndex)
+ {
+ YarrOp& op = m_ops[opIndex];
+ PatternTerm* term = op.m_term;
+
+ if (m_pattern.m_multiline) {
+ const RegisterID character = regT0;
+
+ JumpList matchDest;
+ if (term->inputPosition == m_checked)
+ matchDest.append(atEndOfInput());
+
+ readCharacter((term->inputPosition - m_checked), character);
+ matchCharacterClass(character, matchDest, m_pattern.newlineCharacterClass());
+ op.m_jumps.append(jump());
+
+ matchDest.link(this);
+ } else {
+ if (term->inputPosition == m_checked)
+ op.m_jumps.append(notAtEndOfInput());
+ // Erk, really should poison out these alternatives early. :-/
+ else
+ op.m_jumps.append(jump());
+ }
+ }
+ void backtrackAssertionEOL(size_t opIndex)
+ {
+ backtrackTermDefault(opIndex);
+ }
+
+ // Also falls though on nextIsNotWordChar.
+ void matchAssertionWordchar(size_t opIndex, JumpList& nextIsWordChar, JumpList& nextIsNotWordChar)
+ {
+ YarrOp& op = m_ops[opIndex];
+ PatternTerm* term = op.m_term;
+
+ const RegisterID character = regT0;
+
+ if (term->inputPosition == m_checked)
+ nextIsNotWordChar.append(atEndOfInput());
+
+ readCharacter((term->inputPosition - m_checked), character);
+ matchCharacterClass(character, nextIsWordChar, m_pattern.wordcharCharacterClass());
+ }
+
+ void generateAssertionWordBoundary(size_t opIndex)
+ {
+ YarrOp& op = m_ops[opIndex];
+ PatternTerm* term = op.m_term;
+
+ const RegisterID character = regT0;
+
+ Jump atBegin;
+ JumpList matchDest;
+ if (!term->inputPosition)
+ atBegin = branch32(Equal, index, Imm32(m_checked));
+ readCharacter((term->inputPosition - m_checked) - 1, character);
+ matchCharacterClass(character, matchDest, m_pattern.wordcharCharacterClass());
+ if (!term->inputPosition)
+ atBegin.link(this);
+
+ // We fall through to here if the last character was not a wordchar.
+ JumpList nonWordCharThenWordChar;
+ JumpList nonWordCharThenNonWordChar;
+ if (term->invert()) {
+ matchAssertionWordchar(opIndex, nonWordCharThenNonWordChar, nonWordCharThenWordChar);
+ nonWordCharThenWordChar.append(jump());
+ } else {
+ matchAssertionWordchar(opIndex, nonWordCharThenWordChar, nonWordCharThenNonWordChar);
+ nonWordCharThenNonWordChar.append(jump());
+ }
+ op.m_jumps.append(nonWordCharThenNonWordChar);
+
+ // We jump here if the last character was a wordchar.
+ matchDest.link(this);
+ JumpList wordCharThenWordChar;
+ JumpList wordCharThenNonWordChar;
+ if (term->invert()) {
+ matchAssertionWordchar(opIndex, wordCharThenNonWordChar, wordCharThenWordChar);
+ wordCharThenWordChar.append(jump());
+ } else {
+ matchAssertionWordchar(opIndex, wordCharThenWordChar, wordCharThenNonWordChar);
+ // This can fall-though!
+ }
+
+ op.m_jumps.append(wordCharThenWordChar);
+
+ nonWordCharThenWordChar.link(this);
+ wordCharThenNonWordChar.link(this);
+ }
+ void backtrackAssertionWordBoundary(size_t opIndex)
+ {
+ backtrackTermDefault(opIndex);
+ }
+
+ void generatePatternCharacterOnce(size_t opIndex)
+ {
+ YarrOp& op = m_ops[opIndex];
+
+ // m_ops always ends with a OpBodyAlternativeEnd or OpMatchFailed
+ // node, so there must always be at least one more node.
+ ASSERT(opIndex + 1 < m_ops.size());
+ YarrOp& nextOp = m_ops[opIndex + 1];
+
+ if (op.m_isDeadCode)
+ return;
+
+ PatternTerm* term = op.m_term;
+ UChar ch = term->patternCharacter;
+
+ const RegisterID character = regT0;
+
+ if (nextOp.m_op == OpTerm) {
+ PatternTerm* nextTerm = nextOp.m_term;
+ if (nextTerm->type == PatternTerm::TypePatternCharacter
+ && nextTerm->quantityType == QuantifierFixedCount
+ && nextTerm->quantityCount == 1
+ && nextTerm->inputPosition == (term->inputPosition + 1)) {
+
+ UChar ch2 = nextTerm->patternCharacter;
+
+ int mask = 0;
+ int chPair = ch | (ch2 << 16);
+
+ if (m_pattern.m_ignoreCase) {
+ if (isASCIIAlpha(ch))
+ mask |= 32;
+ if (isASCIIAlpha(ch2))
+ mask |= 32 << 16;
+ }
+
+ BaseIndex address(input, index, TimesTwo, (term->inputPosition - m_checked) * sizeof(UChar));
+ if (mask) {
+ load32WithUnalignedHalfWords(address, character);
+ or32(Imm32(mask), character);
+ op.m_jumps.append(branch32(NotEqual, character, Imm32(chPair | mask)));
+ } else
+ op.m_jumps.append(branch32WithUnalignedHalfWords(NotEqual, address, Imm32(chPair)));
+
+ nextOp.m_isDeadCode = true;
+ return;
+ }
+ }
+
+ if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) {
+ readCharacter(term->inputPosition - m_checked, character);
+ or32(TrustedImm32(32), character);
+ op.m_jumps.append(branch32(NotEqual, character, Imm32(Unicode::toLower(ch))));
+ } else {
+ ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch)));
+ op.m_jumps.append(jumpIfCharNotEquals(ch, term->inputPosition - m_checked));
+ }
+ }
+ void backtrackPatternCharacterOnce(size_t opIndex)
+ {
+ backtrackTermDefault(opIndex);
+ }
+
+ void generatePatternCharacterFixed(size_t opIndex)
+ {
+ YarrOp& op = m_ops[opIndex];
+ PatternTerm* term = op.m_term;
+ UChar ch = term->patternCharacter;
+
+ const RegisterID character = regT0;
+ const RegisterID countRegister = regT1;
+
+ move(index, countRegister);
+ sub32(Imm32(term->quantityCount), countRegister);
+
+ Label loop(this);
+ BaseIndex address(input, countRegister, TimesTwo, (term->inputPosition - m_checked + term->quantityCount) * sizeof(UChar));
+
+ if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) {
+ load16(address, character);
+ or32(TrustedImm32(32), character);
+ op.m_jumps.append(branch32(NotEqual, character, Imm32(Unicode::toLower(ch))));
+ } else {
+ ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch)));
+ op.m_jumps.append(branch16(NotEqual, address, Imm32(ch)));
+ }
+ add32(TrustedImm32(1), countRegister);
+ branch32(NotEqual, countRegister, index).linkTo(loop, this);
+ }
+ void backtrackPatternCharacterFixed(size_t opIndex)
+ {
+ backtrackTermDefault(opIndex);
+ }
+
+ void generatePatternCharacterGreedy(size_t opIndex)
+ {
+ YarrOp& op = m_ops[opIndex];
+ PatternTerm* term = op.m_term;
+ UChar ch = term->patternCharacter;
+
+ const RegisterID character = regT0;
+ const RegisterID countRegister = regT1;
+
+ move(TrustedImm32(0), countRegister);
+
+ JumpList failures;
+ Label loop(this);
+ failures.append(atEndOfInput());
+ if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) {
+ readCharacter(term->inputPosition - m_checked, character);
+ or32(TrustedImm32(32), character);
+ failures.append(branch32(NotEqual, character, Imm32(Unicode::toLower(ch))));
+ } else {
+ ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch)));
+ failures.append(jumpIfCharNotEquals(ch, term->inputPosition - m_checked));
+ }
+
+ add32(TrustedImm32(1), countRegister);
+ add32(TrustedImm32(1), index);
+ if (term->quantityCount == quantifyInfinite)
+ jump(loop);
+ else
+ branch32(NotEqual, countRegister, Imm32(term->quantityCount)).linkTo(loop, this);
+
+ failures.link(this);
+ op.m_reentry = label();
+
+ storeToFrame(countRegister, term->frameLocation);
+
+ }
+ void backtrackPatternCharacterGreedy(size_t opIndex)
+ {
+ YarrOp& op = m_ops[opIndex];
+ PatternTerm* term = op.m_term;
+
+ const RegisterID countRegister = regT1;
+
+ m_backtrackingState.link(this);
+
+ loadFromFrame(term->frameLocation, countRegister);
+ m_backtrackingState.append(branchTest32(Zero, countRegister));
+ sub32(TrustedImm32(1), countRegister);
+ sub32(TrustedImm32(1), index);
+ jump(op.m_reentry);
+ }
+
+ void generatePatternCharacterNonGreedy(size_t opIndex)
+ {
+ YarrOp& op = m_ops[opIndex];
+ PatternTerm* term = op.m_term;
+
+ const RegisterID countRegister = regT1;
+
+ move(TrustedImm32(0), countRegister);
+ op.m_reentry = label();
+ storeToFrame(countRegister, term->frameLocation);
+ }
+ void backtrackPatternCharacterNonGreedy(size_t opIndex)
+ {
+ YarrOp& op = m_ops[opIndex];
+ PatternTerm* term = op.m_term;
+ UChar ch = term->patternCharacter;
+
+ const RegisterID character = regT0;
+ const RegisterID countRegister = regT1;
+
+ JumpList nonGreedyFailures;
+
+ m_backtrackingState.link(this);
+
+ loadFromFrame(term->frameLocation, countRegister);
+
+ nonGreedyFailures.append(atEndOfInput());
+ if (term->quantityCount != quantifyInfinite)
+ nonGreedyFailures.append(branch32(Equal, countRegister, Imm32(term->quantityCount)));
+ if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) {
+ readCharacter(term->inputPosition - m_checked, character);
+ or32(TrustedImm32(32), character);
+ nonGreedyFailures.append(branch32(NotEqual, character, Imm32(Unicode::toLower(ch))));
+ } else {
+ ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch)));
+ nonGreedyFailures.append(jumpIfCharNotEquals(ch, term->inputPosition - m_checked));
+ }
+
+ add32(TrustedImm32(1), countRegister);
+ add32(TrustedImm32(1), index);
+
+ jump(op.m_reentry);
+
+ nonGreedyFailures.link(this);
+ sub32(countRegister, index);
+ m_backtrackingState.fallthrough();
+ }
+
+ void generateCharacterClassOnce(size_t opIndex)
+ {
+ YarrOp& op = m_ops[opIndex];
+ PatternTerm* term = op.m_term;
+
+ const RegisterID character = regT0;
+
+ JumpList matchDest;
+ readCharacter((term->inputPosition - m_checked), character);
+ matchCharacterClass(character, matchDest, term->characterClass);
+
+ if (term->invert())
+ op.m_jumps.append(matchDest);
+ else {
+ op.m_jumps.append(jump());
+ matchDest.link(this);
+ }
+ }
+ void backtrackCharacterClassOnce(size_t opIndex)
+ {
+ backtrackTermDefault(opIndex);
+ }
+
+ void generateCharacterClassFixed(size_t opIndex)
+ {
+ YarrOp& op = m_ops[opIndex];
+ PatternTerm* term = op.m_term;
+
+ const RegisterID character = regT0;
+ const RegisterID countRegister = regT1;
+
+ move(index, countRegister);
+ sub32(Imm32(term->quantityCount), countRegister);
+
+ Label loop(this);
+ JumpList matchDest;
+ load16(BaseIndex(input, countRegister, TimesTwo, (term->inputPosition - m_checked + term->quantityCount) * sizeof(UChar)), character);
+ matchCharacterClass(character, matchDest, term->characterClass);
+
+ if (term->invert())
+ op.m_jumps.append(matchDest);
+ else {
+ op.m_jumps.append(jump());
+ matchDest.link(this);
+ }
+
+ add32(TrustedImm32(1), countRegister);
+ branch32(NotEqual, countRegister, index).linkTo(loop, this);
+ }
+ void backtrackCharacterClassFixed(size_t opIndex)
+ {
+ backtrackTermDefault(opIndex);
+ }
+
+ void generateCharacterClassGreedy(size_t opIndex)
+ {
+ YarrOp& op = m_ops[opIndex];
+ PatternTerm* term = op.m_term;
+
+ const RegisterID character = regT0;
+ const RegisterID countRegister = regT1;
+
+ move(TrustedImm32(0), countRegister);
+
+ JumpList failures;
+ Label loop(this);
+ failures.append(atEndOfInput());
+
+ if (term->invert()) {
+ readCharacter(term->inputPosition - m_checked, character);
+ matchCharacterClass(character, failures, term->characterClass);
+ } else {
+ JumpList matchDest;
+ readCharacter(term->inputPosition - m_checked, character);
+ matchCharacterClass(character, matchDest, term->characterClass);
+ failures.append(jump());
+ matchDest.link(this);
+ }
+
+ add32(TrustedImm32(1), countRegister);
+ add32(TrustedImm32(1), index);
+ if (term->quantityCount != quantifyInfinite) {
+ branch32(NotEqual, countRegister, Imm32(term->quantityCount)).linkTo(loop, this);
+ failures.append(jump());
+ } else
+ jump(loop);
+
+ failures.link(this);
+ op.m_reentry = label();
+
+ storeToFrame(countRegister, term->frameLocation);
+ }
+ void backtrackCharacterClassGreedy(size_t opIndex)
+ {
+ YarrOp& op = m_ops[opIndex];
+ PatternTerm* term = op.m_term;
+
+ const RegisterID countRegister = regT1;
+
+ m_backtrackingState.link(this);
+
+ loadFromFrame(term->frameLocation, countRegister);
+ m_backtrackingState.append(branchTest32(Zero, countRegister));
+ sub32(TrustedImm32(1), countRegister);
+ sub32(TrustedImm32(1), index);
+ jump(op.m_reentry);
+ }
+
+ void generateCharacterClassNonGreedy(size_t opIndex)
+ {
+ YarrOp& op = m_ops[opIndex];
+ PatternTerm* term = op.m_term;
+
+ const RegisterID countRegister = regT1;
+
+ move(TrustedImm32(0), countRegister);
+ op.m_reentry = label();
+ storeToFrame(countRegister, term->frameLocation);
+ }
+ void backtrackCharacterClassNonGreedy(size_t opIndex)
+ {
+ YarrOp& op = m_ops[opIndex];
+ PatternTerm* term = op.m_term;
+
+ const RegisterID character = regT0;
+ const RegisterID countRegister = regT1;
+
+ JumpList nonGreedyFailures;
+
+ m_backtrackingState.link(this);
+
+ Label backtrackBegin(this);
+ loadFromFrame(term->frameLocation, countRegister);
+
+ nonGreedyFailures.append(atEndOfInput());
+ nonGreedyFailures.append(branch32(Equal, countRegister, Imm32(term->quantityCount)));
+
+ JumpList matchDest;
+ readCharacter(term->inputPosition - m_checked, character);
+ matchCharacterClass(character, matchDest, term->characterClass);
+
+ if (term->invert())
+ nonGreedyFailures.append(matchDest);
+ else {
+ nonGreedyFailures.append(jump());
+ matchDest.link(this);
+ }
+
+ add32(TrustedImm32(1), countRegister);
+ add32(TrustedImm32(1), index);
+
+ jump(op.m_reentry);
+
+ nonGreedyFailures.link(this);
+ sub32(countRegister, index);
+ m_backtrackingState.fallthrough();
+ }
+
+ void generateDotStarEnclosure(size_t opIndex)
+ {
+ YarrOp& op = m_ops[opIndex];
+ PatternTerm* term = op.m_term;
+
+ const RegisterID character = regT0;
+ const RegisterID matchPos = regT1;
+
+ JumpList foundBeginningNewLine;
+ JumpList saveStartIndex;
+ JumpList foundEndingNewLine;
+
+ if (m_pattern.m_body->m_hasFixedSize) {
+ move(index, matchPos);
+ sub32(Imm32(m_checked), matchPos);
+ } else
+ load32(Address(output), matchPos);
+
+ saveStartIndex.append(branchTest32(Zero, matchPos));
+ Label findBOLLoop(this);
+ sub32(TrustedImm32(1), matchPos);
+ load16(BaseIndex(input, matchPos, TimesTwo, 0), character);
+ matchCharacterClass(character, foundBeginningNewLine, m_pattern.newlineCharacterClass());
+ branchTest32(NonZero, matchPos).linkTo(findBOLLoop, this);
+ saveStartIndex.append(jump());
+
+ foundBeginningNewLine.link(this);
+ add32(TrustedImm32(1), matchPos); // Advance past newline
+ saveStartIndex.link(this);
+
+ if (!m_pattern.m_multiline && term->anchors.bolAnchor)
+ op.m_jumps.append(branchTest32(NonZero, matchPos));
+
+ store32(matchPos, Address(output));
+
+ move(index, matchPos);
+
+ Label findEOLLoop(this);
+ foundEndingNewLine.append(branch32(Equal, matchPos, length));
+ load16(BaseIndex(input, matchPos, TimesTwo, 0), character);
+ matchCharacterClass(character, foundEndingNewLine, m_pattern.newlineCharacterClass());
+ add32(TrustedImm32(1), matchPos);
+ jump(findEOLLoop);
+
+ foundEndingNewLine.link(this);
+
+ if (!m_pattern.m_multiline && term->anchors.eolAnchor)
+ op.m_jumps.append(branch32(NotEqual, matchPos, length));
+
+ move(matchPos, index);
+ }
+
+ void backtrackDotStarEnclosure(size_t opIndex)
+ {
+ backtrackTermDefault(opIndex);
+ }
+
+ // Code generation/backtracking for simple terms
+ // (pattern characters, character classes, and assertions).
+ // These methods farm out work to the set of functions above.
+ void generateTerm(size_t opIndex)
+ {
+ YarrOp& op = m_ops[opIndex];
+ PatternTerm* term = op.m_term;
+
+ switch (term->type) {
+ case PatternTerm::TypePatternCharacter:
+ switch (term->quantityType) {
+ case QuantifierFixedCount:
+ if (term->quantityCount == 1)
+ generatePatternCharacterOnce(opIndex);
+ else
+ generatePatternCharacterFixed(opIndex);
+ break;
+ case QuantifierGreedy:
+ generatePatternCharacterGreedy(opIndex);
+ break;
+ case QuantifierNonGreedy:
+ generatePatternCharacterNonGreedy(opIndex);
+ break;
+ }
+ break;
+
+ case PatternTerm::TypeCharacterClass:
+ switch (term->quantityType) {
+ case QuantifierFixedCount:
+ if (term->quantityCount == 1)
+ generateCharacterClassOnce(opIndex);
+ else
+ generateCharacterClassFixed(opIndex);
+ break;
+ case QuantifierGreedy:
+ generateCharacterClassGreedy(opIndex);
+ break;
+ case QuantifierNonGreedy:
+ generateCharacterClassNonGreedy(opIndex);
+ break;
+ }
+ break;
+
+ case PatternTerm::TypeAssertionBOL:
+ generateAssertionBOL(opIndex);
+ break;
+
+ case PatternTerm::TypeAssertionEOL:
+ generateAssertionEOL(opIndex);
+ break;
+
+ case PatternTerm::TypeAssertionWordBoundary:
+ generateAssertionWordBoundary(opIndex);
+ break;
+
+ case PatternTerm::TypeForwardReference:
+ break;
+
+ case PatternTerm::TypeParenthesesSubpattern:
+ case PatternTerm::TypeParentheticalAssertion:
+ ASSERT_NOT_REACHED();
+ case PatternTerm::TypeBackReference:
+ m_shouldFallBack = true;
+ break;
+ case PatternTerm::TypeDotStarEnclosure:
+ generateDotStarEnclosure(opIndex);
+ break;
+ }
+ }
+ void backtrackTerm(size_t opIndex)
+ {
+ YarrOp& op = m_ops[opIndex];
+ PatternTerm* term = op.m_term;
+
+ switch (term->type) {
+ case PatternTerm::TypePatternCharacter:
+ switch (term->quantityType) {
+ case QuantifierFixedCount:
+ if (term->quantityCount == 1)
+ backtrackPatternCharacterOnce(opIndex);
+ else
+ backtrackPatternCharacterFixed(opIndex);
+ break;
+ case QuantifierGreedy:
+ backtrackPatternCharacterGreedy(opIndex);
+ break;
+ case QuantifierNonGreedy:
+ backtrackPatternCharacterNonGreedy(opIndex);
+ break;
+ }
+ break;
+
+ case PatternTerm::TypeCharacterClass:
+ switch (term->quantityType) {
+ case QuantifierFixedCount:
+ if (term->quantityCount == 1)
+ backtrackCharacterClassOnce(opIndex);
+ else
+ backtrackCharacterClassFixed(opIndex);
+ break;
+ case QuantifierGreedy:
+ backtrackCharacterClassGreedy(opIndex);
+ break;
+ case QuantifierNonGreedy:
+ backtrackCharacterClassNonGreedy(opIndex);
+ break;
+ }
+ break;
+
+ case PatternTerm::TypeAssertionBOL:
+ backtrackAssertionBOL(opIndex);
+ break;
+
+ case PatternTerm::TypeAssertionEOL:
+ backtrackAssertionEOL(opIndex);
+ break;
+
+ case PatternTerm::TypeAssertionWordBoundary:
+ backtrackAssertionWordBoundary(opIndex);
+ break;
+
+ case PatternTerm::TypeForwardReference:
+ break;
+
+ case PatternTerm::TypeParenthesesSubpattern:
+ case PatternTerm::TypeParentheticalAssertion:
+ ASSERT_NOT_REACHED();
+
+ case PatternTerm::TypeDotStarEnclosure:
+ backtrackDotStarEnclosure(opIndex);
+ break;
+
+ case PatternTerm::TypeBackReference:
+ m_shouldFallBack = true;
+ break;
+ }
+ }
+
+ void generate()
+ {
+ // Forwards generate the matching code.
+ ASSERT(m_ops.size());
+ size_t opIndex = 0;
+
+ do {
+ YarrOp& op = m_ops[opIndex];
+ switch (op.m_op) {
+
+ case OpTerm:
+ generateTerm(opIndex);
+ break;
+
+ // OpBodyAlternativeBegin/Next/End
+ //
+ // These nodes wrap the set of alternatives in the body of the regular expression.
+ // There may be either one or two chains of OpBodyAlternative nodes, one representing
+ // the 'once through' sequence of alternatives (if any exist), and one representing
+ // the repeating alternatives (again, if any exist).
+ //
+ // Upon normal entry to the Begin alternative, we will check that input is available.
+ // Reentry to the Begin alternative will take place after the check has taken place,
+ // and will assume that the input position has already been progressed as appropriate.
+ //
+ // Entry to subsequent Next/End alternatives occurs when the prior alternative has
+ // successfully completed a match - return a success state from JIT code.
+ //
+ // Next alternatives allow for reentry optimized to suit backtracking from its
+ // preceding alternative. It expects the input position to still be set to a position
+ // appropriate to its predecessor, and it will only perform an input check if the
+ // predecessor had a minimum size less than its own.
+ //
+ // In the case 'once through' expressions, the End node will also have a reentry
+ // point to jump to when the last alternative fails. Again, this expects the input
+ // position to still reflect that expected by the prior alternative.
+ case OpBodyAlternativeBegin: {
+ PatternAlternative* alternative = op.m_alternative;
+
+ // Upon entry at the head of the set of alternatives, check if input is available
+ // to run the first alternative. (This progresses the input position).
+ op.m_jumps.append(jumpIfNoAvailableInput(alternative->m_minimumSize));
+ // We will reenter after the check, and assume the input position to have been
+ // set as appropriate to this alternative.
+ op.m_reentry = label();
+
+ m_checked += alternative->m_minimumSize;
+ break;
+ }
+ case OpBodyAlternativeNext:
+ case OpBodyAlternativeEnd: {
+ PatternAlternative* priorAlternative = m_ops[op.m_previousOp].m_alternative;
+ PatternAlternative* alternative = op.m_alternative;
+
+ // If we get here, the prior alternative matched - return success.
+
+ // Adjust the stack pointer to remove the pattern's frame.
+ if (m_pattern.m_body->m_callFrameSize)
+ addPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister);
+
+ // Load appropriate values into the return register and the first output
+ // slot, and return. In the case of pattern with a fixed size, we will
+ // not have yet set the value in the first
+ ASSERT(index != returnRegister);
+ if (m_pattern.m_body->m_hasFixedSize) {
+ move(index, returnRegister);
+ if (priorAlternative->m_minimumSize)
+ sub32(Imm32(priorAlternative->m_minimumSize), returnRegister);
+ store32(returnRegister, output);
+ } else
+ load32(Address(output), returnRegister);
+ store32(index, Address(output, 4));
+ generateReturn();
+
+ // This is the divide between the tail of the prior alternative, above, and
+ // the head of the subsequent alternative, below.
+
+ if (op.m_op == OpBodyAlternativeNext) {
+ // This is the reentry point for the Next alternative. We expect any code
+ // that jumps here to do so with the input position matching that of the
+ // PRIOR alteranative, and we will only check input availability if we
+ // need to progress it forwards.
+ op.m_reentry = label();
+ if (alternative->m_minimumSize > priorAlternative->m_minimumSize) {
+ add32(Imm32(alternative->m_minimumSize - priorAlternative->m_minimumSize), index);
+ op.m_jumps.append(jumpIfNoAvailableInput());
+ } else if (priorAlternative->m_minimumSize > alternative->m_minimumSize)
+ sub32(Imm32(priorAlternative->m_minimumSize - alternative->m_minimumSize), index);
+ } else if (op.m_nextOp == notFound) {
+ // This is the reentry point for the End of 'once through' alternatives,
+ // jumped to when the las alternative fails to match.
+ op.m_reentry = label();
+ sub32(Imm32(priorAlternative->m_minimumSize), index);
+ }
+
+ if (op.m_op == OpBodyAlternativeNext)
+ m_checked += alternative->m_minimumSize;
+ m_checked -= priorAlternative->m_minimumSize;
+ break;
+ }
+
+ // OpSimpleNestedAlternativeBegin/Next/End
+ // OpNestedAlternativeBegin/Next/End
+ //
+ // These nodes are used to handle sets of alternatives that are nested within
+ // subpatterns and parenthetical assertions. The 'simple' forms are used where
+ // we do not need to be able to backtrack back into any alternative other than
+ // the last, the normal forms allow backtracking into any alternative.
+ //
+ // Each Begin/Next node is responsible for planting an input check to ensure
+ // sufficient input is available on entry. Next nodes additionally need to
+ // jump to the end - Next nodes use the End node's m_jumps list to hold this
+ // set of jumps.
+ //
+ // In the non-simple forms, successful alternative matches must store a
+ // 'return address' using a DataLabelPtr, used to store the address to jump
+ // to when backtracking, to get to the code for the appropriate alternative.
+ case OpSimpleNestedAlternativeBegin:
+ case OpNestedAlternativeBegin: {
+ PatternTerm* term = op.m_term;
+ PatternAlternative* alternative = op.m_alternative;
+ PatternDisjunction* disjunction = term->parentheses.disjunction;
+
+ // Calculate how much input we need to check for, and if non-zero check.
+ op.m_checkAdjust = alternative->m_minimumSize;
+ if ((term->quantityType == QuantifierFixedCount) && (term->type != PatternTerm::TypeParentheticalAssertion))
+ op.m_checkAdjust -= disjunction->m_minimumSize;
+ if (op.m_checkAdjust)
+ op.m_jumps.append(jumpIfNoAvailableInput(op.m_checkAdjust));
+
+ m_checked += op.m_checkAdjust;
+ break;
+ }
+ case OpSimpleNestedAlternativeNext:
+ case OpNestedAlternativeNext: {
+ PatternTerm* term = op.m_term;
+ PatternAlternative* alternative = op.m_alternative;
+ PatternDisjunction* disjunction = term->parentheses.disjunction;
+
+ // In the non-simple case, store a 'return address' so we can backtrack correctly.
+ if (op.m_op == OpNestedAlternativeNext) {
+ unsigned parenthesesFrameLocation = term->frameLocation;
+ unsigned alternativeFrameLocation = parenthesesFrameLocation;
+ if (term->quantityType != QuantifierFixedCount)
+ alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesOnce;
+ op.m_returnAddress = storeToFrameWithPatch(alternativeFrameLocation);
+ }
+
+ // If we reach here then the last alternative has matched - jump to the
+ // End node, to skip over any further alternatives.
+ //
+ // FIXME: this is logically O(N^2) (though N can be expected to be very
+ // small). We could avoid this either by adding an extra jump to the JIT
+ // data structures, or by making backtracking code that jumps to Next
+ // alternatives are responsible for checking that input is available (if
+ // we didn't need to plant the input checks, then m_jumps would be free).
+ YarrOp* endOp = &m_ops[op.m_nextOp];
+ while (endOp->m_nextOp != notFound) {
+ ASSERT(endOp->m_op == OpSimpleNestedAlternativeNext || endOp->m_op == OpNestedAlternativeNext);
+ endOp = &m_ops[endOp->m_nextOp];
+ }
+ ASSERT(endOp->m_op == OpSimpleNestedAlternativeEnd || endOp->m_op == OpNestedAlternativeEnd);
+ endOp->m_jumps.append(jump());
+
+ // This is the entry point for the next alternative.
+ op.m_reentry = label();
+
+ // Calculate how much input we need to check for, and if non-zero check.
+ op.m_checkAdjust = alternative->m_minimumSize;
+ if ((term->quantityType == QuantifierFixedCount) && (term->type != PatternTerm::TypeParentheticalAssertion))
+ op.m_checkAdjust -= disjunction->m_minimumSize;
+ if (op.m_checkAdjust)
+ op.m_jumps.append(jumpIfNoAvailableInput(op.m_checkAdjust));
+
+ YarrOp& lastOp = m_ops[op.m_previousOp];
+ m_checked -= lastOp.m_checkAdjust;
+ m_checked += op.m_checkAdjust;
+ break;
+ }
+ case OpSimpleNestedAlternativeEnd:
+ case OpNestedAlternativeEnd: {
+ PatternTerm* term = op.m_term;
+
+ // In the non-simple case, store a 'return address' so we can backtrack correctly.
+ if (op.m_op == OpNestedAlternativeEnd) {
+ unsigned parenthesesFrameLocation = term->frameLocation;
+ unsigned alternativeFrameLocation = parenthesesFrameLocation;
+ if (term->quantityType != QuantifierFixedCount)
+ alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesOnce;
+ op.m_returnAddress = storeToFrameWithPatch(alternativeFrameLocation);
+ }
+
+ // If this set of alternatives contains more than one alternative,
+ // then the Next nodes will have planted jumps to the End, and added
+ // them to this node's m_jumps list.
+ op.m_jumps.link(this);
+ op.m_jumps.clear();
+
+ YarrOp& lastOp = m_ops[op.m_previousOp];
+ m_checked -= lastOp.m_checkAdjust;
+ break;
+ }
+
+ // OpParenthesesSubpatternOnceBegin/End
+ //
+ // These nodes support (optionally) capturing subpatterns, that have a
+ // quantity count of 1 (this covers fixed once, and ?/?? quantifiers).
+ case OpParenthesesSubpatternOnceBegin: {
+ PatternTerm* term = op.m_term;
+ unsigned parenthesesFrameLocation = term->frameLocation;
+ const RegisterID indexTemporary = regT0;
+ ASSERT(term->quantityCount == 1);
+
+ // Upon entry to a Greedy quantified set of parenthese store the index.
+ // We'll use this for two purposes:
+ // - To indicate which iteration we are on of mathing the remainder of
+ // the expression after the parentheses - the first, including the
+ // match within the parentheses, or the second having skipped over them.
+ // - To check for empty matches, which must be rejected.
+ //
+ // At the head of a NonGreedy set of parentheses we'll immediately set the
+ // value on the stack to -1 (indicating a match skipping the subpattern),
+ // and plant a jump to the end. We'll also plant a label to backtrack to
+ // to reenter the subpattern later, with a store to set up index on the
+ // second iteration.
+ //
+ // FIXME: for capturing parens, could use the index in the capture array?
+ if (term->quantityType == QuantifierGreedy)
+ storeToFrame(index, parenthesesFrameLocation);
+ else if (term->quantityType == QuantifierNonGreedy) {
+ storeToFrame(TrustedImm32(-1), parenthesesFrameLocation);
+ op.m_jumps.append(jump());
+ op.m_reentry = label();
+ storeToFrame(index, parenthesesFrameLocation);
+ }
+
+ // If the parenthese are capturing, store the starting index value to the
+ // captures array, offsetting as necessary.
+ //
+ // FIXME: could avoid offsetting this value in JIT code, apply
+ // offsets only afterwards, at the point the results array is
+ // being accessed.
+ if (term->capture()) {
+ int offsetId = term->parentheses.subpatternId << 1;
+ int inputOffset = term->inputPosition - m_checked;
+ if (term->quantityType == QuantifierFixedCount)
+ inputOffset -= term->parentheses.disjunction->m_minimumSize;
+ if (inputOffset) {
+ move(index, indexTemporary);
+ add32(Imm32(inputOffset), indexTemporary);
+ store32(indexTemporary, Address(output, offsetId * sizeof(int)));
+ } else
+ store32(index, Address(output, offsetId * sizeof(int)));
+ }
+ break;
+ }
+ case OpParenthesesSubpatternOnceEnd: {
+ PatternTerm* term = op.m_term;
+ unsigned parenthesesFrameLocation = term->frameLocation;
+ const RegisterID indexTemporary = regT0;
+ ASSERT(term->quantityCount == 1);
+
+ // For Greedy/NonGreedy quantified parentheses, we must reject zero length
+ // matches. If the minimum size is know to be non-zero we need not check.
+ if (term->quantityType != QuantifierFixedCount && !term->parentheses.disjunction->m_minimumSize)
+ op.m_jumps.append(branch32(Equal, index, Address(stackPointerRegister, parenthesesFrameLocation * sizeof(void*))));
+
+ // If the parenthese are capturing, store the ending index value to the
+ // captures array, offsetting as necessary.
+ //
+ // FIXME: could avoid offsetting this value in JIT code, apply
+ // offsets only afterwards, at the point the results array is
+ // being accessed.
+ if (term->capture()) {
+ int offsetId = (term->parentheses.subpatternId << 1) + 1;
+ int inputOffset = term->inputPosition - m_checked;
+ if (inputOffset) {
+ move(index, indexTemporary);
+ add32(Imm32(inputOffset), indexTemporary);
+ store32(indexTemporary, Address(output, offsetId * sizeof(int)));
+ } else
+ store32(index, Address(output, offsetId * sizeof(int)));
+ }
+
+ // If the parentheses are quantified Greedy then add a label to jump back
+ // to if get a failed match from after the parentheses. For NonGreedy
+ // parentheses, link the jump from before the subpattern to here.
+ if (term->quantityType == QuantifierGreedy)
+ op.m_reentry = label();
+ else if (term->quantityType == QuantifierNonGreedy) {
+ YarrOp& beginOp = m_ops[op.m_previousOp];
+ beginOp.m_jumps.link(this);
+ }
+ break;
+ }
+
+ // OpParenthesesSubpatternTerminalBegin/End
+ case OpParenthesesSubpatternTerminalBegin: {
+ PatternTerm* term = op.m_term;
+ ASSERT(term->quantityType == QuantifierGreedy);
+ ASSERT(term->quantityCount == quantifyInfinite);
+ ASSERT(!term->capture());
+
+ // Upon entry set a label to loop back to.
+ op.m_reentry = label();
+
+ // Store the start index of the current match; we need to reject zero
+ // length matches.
+ storeToFrame(index, term->frameLocation);
+ break;
+ }
+ case OpParenthesesSubpatternTerminalEnd: {
+ PatternTerm* term = op.m_term;
+
+ // Check for zero length matches - if the match is non-zero, then we
+ // can accept it & loop back up to the head of the subpattern.
+ YarrOp& beginOp = m_ops[op.m_previousOp];
+ branch32(NotEqual, index, Address(stackPointerRegister, term->frameLocation * sizeof(void*)), beginOp.m_reentry);
+
+ // Reject the match - backtrack back into the subpattern.
+ op.m_jumps.append(jump());
+
+ // This is the entry point to jump to when we stop matching - we will
+ // do so once the subpattern cannot match any more.
+ op.m_reentry = label();
+ break;
+ }
+
+ // OpParentheticalAssertionBegin/End
+ case OpParentheticalAssertionBegin: {
+ PatternTerm* term = op.m_term;
+
+ // Store the current index - assertions should not update index, so
+ // we will need to restore it upon a successful match.
+ unsigned parenthesesFrameLocation = term->frameLocation;
+ storeToFrame(index, parenthesesFrameLocation);
+
+ // Check
+ op.m_checkAdjust = m_checked - term->inputPosition;
+ if (op.m_checkAdjust)
+ sub32(Imm32(op.m_checkAdjust), index);
+
+ m_checked -= op.m_checkAdjust;
+ break;
+ }
+ case OpParentheticalAssertionEnd: {
+ PatternTerm* term = op.m_term;
+
+ // Restore the input index value.
+ unsigned parenthesesFrameLocation = term->frameLocation;
+ loadFromFrame(parenthesesFrameLocation, index);
+
+ // If inverted, a successful match of the assertion must be treated
+ // as a failure, so jump to backtracking.
+ if (term->invert()) {
+ op.m_jumps.append(jump());
+ op.m_reentry = label();
+ }
+
+ YarrOp& lastOp = m_ops[op.m_previousOp];
+ m_checked += lastOp.m_checkAdjust;
+ break;
+ }
+
+ case OpMatchFailed:
+ if (m_pattern.m_body->m_callFrameSize)
+ addPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister);
+ move(TrustedImm32(-1), returnRegister);
+ generateReturn();
+ break;
+ }
+
+ ++opIndex;
+ } while (opIndex < m_ops.size());
+ }
+
+ void backtrack()
+ {
+ // Backwards generate the backtracking code.
+ size_t opIndex = m_ops.size();
+ ASSERT(opIndex);
+
+ do {
+ --opIndex;
+ YarrOp& op = m_ops[opIndex];
+ switch (op.m_op) {
+
+ case OpTerm:
+ backtrackTerm(opIndex);
+ break;
+
+ // OpBodyAlternativeBegin/Next/End
+ //
+ // For each Begin/Next node representing an alternative, we need to decide what to do
+ // in two circumstances:
+ // - If we backtrack back into this node, from within the alternative.
+ // - If the input check at the head of the alternative fails (if this exists).
+ //
+ // We treat these two cases differently since in the former case we have slightly
+ // more information - since we are backtracking out of a prior alternative we know
+ // that at least enough input was available to run it. For example, given the regular
+ // expression /a|b/, if we backtrack out of the first alternative (a failed pattern
+ // character match of 'a'), then we need not perform an additional input availability
+ // check before running the second alternative.
+ //
+ // Backtracking required differs for the last alternative, which in the case of the
+ // repeating set of alternatives must loop. The code generated for the last alternative
+ // will also be used to handle all input check failures from any prior alternatives -
+ // these require similar functionality, in seeking the next available alternative for
+ // which there is sufficient input.
+ //
+ // Since backtracking of all other alternatives simply requires us to link backtracks
+ // to the reentry point for the subsequent alternative, we will only be generating any
+ // code when backtracking the last alternative.
+ case OpBodyAlternativeBegin:
+ case OpBodyAlternativeNext: {
+ PatternAlternative* alternative = op.m_alternative;
+
+ if (op.m_op == OpBodyAlternativeNext) {
+ PatternAlternative* priorAlternative = m_ops[op.m_previousOp].m_alternative;
+ m_checked += priorAlternative->m_minimumSize;
+ }
+ m_checked -= alternative->m_minimumSize;
+
+ // Is this the last alternative? If not, then if we backtrack to this point we just
+ // need to jump to try to match the next alternative.
+ if (m_ops[op.m_nextOp].m_op != OpBodyAlternativeEnd) {
+ m_backtrackingState.linkTo(m_ops[op.m_nextOp].m_reentry, this);
+ break;
+ }
+ YarrOp& endOp = m_ops[op.m_nextOp];
+
+ YarrOp* beginOp = &op;
+ while (beginOp->m_op != OpBodyAlternativeBegin) {
+ ASSERT(beginOp->m_op == OpBodyAlternativeNext);
+ beginOp = &m_ops[beginOp->m_previousOp];
+ }
+
+ bool onceThrough = endOp.m_nextOp == notFound;
+
+ // First, generate code to handle cases where we backtrack out of an attempted match
+ // of the last alternative. If this is a 'once through' set of alternatives then we
+ // have nothing to do - link this straight through to the End.
+ if (onceThrough)
+ m_backtrackingState.linkTo(endOp.m_reentry, this);
+ else {
+ // If we don't need to move the input poistion, and the pattern has a fixed size
+ // (in which case we omit the store of the start index until the pattern has matched)
+ // then we can just link the backtrack out of the last alternative straight to the
+ // head of the first alternative.
+ if (m_pattern.m_body->m_hasFixedSize
+ && (alternative->m_minimumSize > beginOp->m_alternative->m_minimumSize)
+ && (alternative->m_minimumSize - beginOp->m_alternative->m_minimumSize == 1))
+ m_backtrackingState.linkTo(beginOp->m_reentry, this);
+ else {
+ // We need to generate a trampoline of code to execute before looping back
+ // around to the first alternative.
+ m_backtrackingState.link(this);
+
+ // If the pattern size is not fixed, then store the start index, for use if we match.
+ if (!m_pattern.m_body->m_hasFixedSize) {
+ if (alternative->m_minimumSize == 1)
+ store32(index, Address(output));
+ else {
+ move(index, regT0);
+ if (alternative->m_minimumSize)
+ sub32(Imm32(alternative->m_minimumSize - 1), regT0);
+ else
+ add32(Imm32(1), regT0);
+ store32(regT0, Address(output));
+ }
+ }
+
+ // Generate code to loop. Check whether the last alternative is longer than the
+ // first (e.g. /a|xy/ or /a|xyz/).
+ if (alternative->m_minimumSize > beginOp->m_alternative->m_minimumSize) {
+ // We want to loop, and increment input position. If the delta is 1, it is
+ // already correctly incremented, if more than one then decrement as appropriate.
+ unsigned delta = alternative->m_minimumSize - beginOp->m_alternative->m_minimumSize;
+ ASSERT(delta);
+ if (delta != 1)
+ sub32(Imm32(delta - 1), index);
+ jump(beginOp->m_reentry);
+ } else {
+ // If the first alternative has minimum size 0xFFFFFFFFu, then there cannot
+ // be sufficent input available to handle this, so just fall through.
+ unsigned delta = beginOp->m_alternative->m_minimumSize - alternative->m_minimumSize;
+ if (delta != 0xFFFFFFFFu) {
+ // We need to check input because we are incrementing the input.
+ add32(Imm32(delta + 1), index);
+ checkInput().linkTo(beginOp->m_reentry, this);
+ }
+ }
+ }
+ }
+
+ // We can reach this point in the code in two ways:
+ // - Fallthrough from the code above (a repeating alternative backtracked out of its
+ // last alternative, and did not have sufficent input to run the first).
+ // - We will loop back up to the following label when a releating alternative loops,
+ // following a failed input check.
+ //
+ // Either way, we have just failed the input check for the first alternative.
+ Label firstInputCheckFailed(this);
+
+ // Generate code to handle input check failures from alternatives except the last.
+ // prevOp is the alternative we're handling a bail out from (initially Begin), and
+ // nextOp is the alternative we will be attempting to reenter into.
+ //
+ // We will link input check failures from the forwards matching path back to the code
+ // that can handle them.
+ YarrOp* prevOp = beginOp;
+ YarrOp* nextOp = &m_ops[beginOp->m_nextOp];
+ while (nextOp->m_op != OpBodyAlternativeEnd) {
+ prevOp->m_jumps.link(this);
+
+ // We only get here if an input check fails, it is only worth checking again
+ // if the next alternative has a minimum size less than the last.
+ if (prevOp->m_alternative->m_minimumSize > nextOp->m_alternative->m_minimumSize) {
+ // FIXME: if we added an extra label to YarrOp, we could avoid needing to
+ // subtract delta back out, and reduce this code. Should performance test
+ // the benefit of this.
+ unsigned delta = prevOp->m_alternative->m_minimumSize - nextOp->m_alternative->m_minimumSize;
+ sub32(Imm32(delta), index);
+ Jump fail = jumpIfNoAvailableInput();
+ add32(Imm32(delta), index);
+ jump(nextOp->m_reentry);
+ fail.link(this);
+ } else if (prevOp->m_alternative->m_minimumSize < nextOp->m_alternative->m_minimumSize)
+ add32(Imm32(nextOp->m_alternative->m_minimumSize - prevOp->m_alternative->m_minimumSize), index);
+ prevOp = nextOp;
+ nextOp = &m_ops[nextOp->m_nextOp];
+ }
+
+ // We fall through to here if there is insufficient input to run the last alternative.
+
+ // If there is insufficient input to run the last alternative, then for 'once through'
+ // alternatives we are done - just jump back up into the forwards matching path at the End.
+ if (onceThrough) {
+ op.m_jumps.linkTo(endOp.m_reentry, this);
+ jump(endOp.m_reentry);
+ break;
+ }
+
+ // For repeating alternatives, link any input check failure from the last alternative to
+ // this point.
+ op.m_jumps.link(this);
+
+ bool needsToUpdateMatchStart = !m_pattern.m_body->m_hasFixedSize;
+
+ // Check for cases where input position is already incremented by 1 for the last
+ // alternative (this is particularly useful where the minimum size of the body
+ // disjunction is 0, e.g. /a*|b/).
+ if (needsToUpdateMatchStart && alternative->m_minimumSize == 1) {
+ // index is already incremented by 1, so just store it now!
+ store32(index, Address(output));
+ needsToUpdateMatchStart = false;
+ }
+
+ // Check whether there is sufficient input to loop. Increment the input position by
+ // one, and check. Also add in the minimum disjunction size before checking - there
+ // is no point in looping if we're just going to fail all the input checks around
+ // the next iteration.
+ ASSERT(alternative->m_minimumSize >= m_pattern.m_body->m_minimumSize);
+ if (alternative->m_minimumSize == m_pattern.m_body->m_minimumSize) {
+ // If the last alternative had the same minimum size as the disjunction,
+ // just simply increment input pos by 1, no adjustment based on minimum size.
+ add32(Imm32(1), index);
+ } else {
+ // If the minumum for the last alternative was one greater than than that
+ // for the disjunction, we're already progressed by 1, nothing to do!
+ unsigned delta = (alternative->m_minimumSize - m_pattern.m_body->m_minimumSize) - 1;
+ if (delta)
+ sub32(Imm32(delta), index);
+ }
+ Jump matchFailed = jumpIfNoAvailableInput();
+
+ if (needsToUpdateMatchStart) {
+ if (!m_pattern.m_body->m_minimumSize)
+ store32(index, Address(output));
+ else {
+ move(index, regT0);
+ sub32(Imm32(m_pattern.m_body->m_minimumSize), regT0);
+ store32(regT0, Address(output));
+ }
+ }
+
+ // Calculate how much more input the first alternative requires than the minimum
+ // for the body as a whole. If no more is needed then we dont need an additional
+ // input check here - jump straight back up to the start of the first alternative.
+ if (beginOp->m_alternative->m_minimumSize == m_pattern.m_body->m_minimumSize)
+ jump(beginOp->m_reentry);
+ else {
+ if (beginOp->m_alternative->m_minimumSize > m_pattern.m_body->m_minimumSize)
+ add32(Imm32(beginOp->m_alternative->m_minimumSize - m_pattern.m_body->m_minimumSize), index);
+ else
+ sub32(Imm32(m_pattern.m_body->m_minimumSize - beginOp->m_alternative->m_minimumSize), index);
+ checkInput().linkTo(beginOp->m_reentry, this);
+ jump(firstInputCheckFailed);
+ }
+
+ // We jump to here if we iterate to the point that there is insufficient input to
+ // run any matches, and need to return a failure state from JIT code.
+ matchFailed.link(this);
+
+ if (m_pattern.m_body->m_callFrameSize)
+ addPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister);
+ move(TrustedImm32(-1), returnRegister);
+ generateReturn();
+ break;
+ }
+ case OpBodyAlternativeEnd: {
+ // We should never backtrack back into a body disjunction.
+ ASSERT(m_backtrackingState.isEmpty());
+
+ PatternAlternative* priorAlternative = m_ops[op.m_previousOp].m_alternative;
+ m_checked += priorAlternative->m_minimumSize;
+ break;
+ }
+
+ // OpSimpleNestedAlternativeBegin/Next/End
+ // OpNestedAlternativeBegin/Next/End
+ //
+ // Generate code for when we backtrack back out of an alternative into
+ // a Begin or Next node, or when the entry input count check fails. If
+ // there are more alternatives we need to jump to the next alternative,
+ // if not we backtrack back out of the current set of parentheses.
+ //
+ // In the case of non-simple nested assertions we need to also link the
+ // 'return address' appropriately to backtrack back out into the correct
+ // alternative.
+ case OpSimpleNestedAlternativeBegin:
+ case OpSimpleNestedAlternativeNext:
+ case OpNestedAlternativeBegin:
+ case OpNestedAlternativeNext: {
+ YarrOp& nextOp = m_ops[op.m_nextOp];
+ bool isBegin = op.m_previousOp == notFound;
+ bool isLastAlternative = nextOp.m_nextOp == notFound;
+ ASSERT(isBegin == (op.m_op == OpSimpleNestedAlternativeBegin || op.m_op == OpNestedAlternativeBegin));
+ ASSERT(isLastAlternative == (nextOp.m_op == OpSimpleNestedAlternativeEnd || nextOp.m_op == OpNestedAlternativeEnd));
+
+ // Treat an input check failure the same as a failed match.
+ m_backtrackingState.append(op.m_jumps);
+
+ // Set the backtracks to jump to the appropriate place. We may need
+ // to link the backtracks in one of three different way depending on
+ // the type of alternative we are dealing with:
+ // - A single alternative, with no simplings.
+ // - The last alternative of a set of two or more.
+ // - An alternative other than the last of a set of two or more.
+ //
+ // In the case of a single alternative on its own, we don't need to
+ // jump anywhere - if the alternative fails to match we can just
+ // continue to backtrack out of the parentheses without jumping.
+ //
+ // In the case of the last alternative in a set of more than one, we
+ // need to jump to return back out to the beginning. We'll do so by
+ // adding a jump to the End node's m_jumps list, and linking this
+ // when we come to generate the Begin node. For alternatives other
+ // than the last, we need to jump to the next alternative.
+ //
+ // If the alternative had adjusted the input position we must link
+ // backtracking to here, correct, and then jump on. If not we can
+ // link the backtracks directly to their destination.
+ if (op.m_checkAdjust) {
+ // Handle the cases where we need to link the backtracks here.
+ m_backtrackingState.link(this);
+ sub32(Imm32(op.m_checkAdjust), index);
+ if (!isLastAlternative) {
+ // An alternative that is not the last should jump to its successor.
+ jump(nextOp.m_reentry);
+ } else if (!isBegin) {
+ // The last of more than one alternatives must jump back to the begnning.
+ nextOp.m_jumps.append(jump());
+ } else {
+ // A single alternative on its own can fall through.
+ m_backtrackingState.fallthrough();
+ }
+ } else {
+ // Handle the cases where we can link the backtracks directly to their destinations.
+ if (!isLastAlternative) {
+ // An alternative that is not the last should jump to its successor.
+ m_backtrackingState.linkTo(nextOp.m_reentry, this);
+ } else if (!isBegin) {
+ // The last of more than one alternatives must jump back to the begnning.
+ m_backtrackingState.takeBacktracksToJumpList(nextOp.m_jumps, this);
+ }
+ // In the case of a single alternative on its own do nothing - it can fall through.
+ }
+
+ // At this point we've handled the backtracking back into this node.
+ // Now link any backtracks that need to jump to here.
+
+ // For non-simple alternatives, link the alternative's 'return address'
+ // so that we backtrack back out into the previous alternative.
+ if (op.m_op == OpNestedAlternativeNext)
+ m_backtrackingState.append(op.m_returnAddress);
+
+ // If there is more than one alternative, then the last alternative will
+ // have planted a jump to be linked to the end. This jump was added to the
+ // End node's m_jumps list. If we are back at the beginning, link it here.
+ if (isBegin) {
+ YarrOp* endOp = &m_ops[op.m_nextOp];
+ while (endOp->m_nextOp != notFound) {
+ ASSERT(endOp->m_op == OpSimpleNestedAlternativeNext || endOp->m_op == OpNestedAlternativeNext);
+ endOp = &m_ops[endOp->m_nextOp];
+ }
+ ASSERT(endOp->m_op == OpSimpleNestedAlternativeEnd || endOp->m_op == OpNestedAlternativeEnd);
+ m_backtrackingState.append(endOp->m_jumps);
+ }
+
+ if (!isBegin) {
+ YarrOp& lastOp = m_ops[op.m_previousOp];
+ m_checked += lastOp.m_checkAdjust;
+ }
+ m_checked -= op.m_checkAdjust;
+ break;
+ }
+ case OpSimpleNestedAlternativeEnd:
+ case OpNestedAlternativeEnd: {
+ PatternTerm* term = op.m_term;
+
+ // If we backtrack into the end of a simple subpattern do nothing;
+ // just continue through into the last alternative. If we backtrack
+ // into the end of a non-simple set of alterntives we need to jump
+ // to the backtracking return address set up during generation.
+ if (op.m_op == OpNestedAlternativeEnd) {
+ m_backtrackingState.link(this);
+
+ // Plant a jump to the return address.
+ unsigned parenthesesFrameLocation = term->frameLocation;
+ unsigned alternativeFrameLocation = parenthesesFrameLocation;
+ if (term->quantityType != QuantifierFixedCount)
+ alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesOnce;
+ loadFromFrameAndJump(alternativeFrameLocation);
+
+ // Link the DataLabelPtr associated with the end of the last
+ // alternative to this point.
+ m_backtrackingState.append(op.m_returnAddress);
+ }
+
+ YarrOp& lastOp = m_ops[op.m_previousOp];
+ m_checked += lastOp.m_checkAdjust;
+ break;
+ }
+
+ // OpParenthesesSubpatternOnceBegin/End
+ //
+ // When we are backtracking back out of a capturing subpattern we need
+ // to clear the start index in the matches output array, to record that
+ // this subpattern has not been captured.
+ //
+ // When backtracking back out of a Greedy quantified subpattern we need
+ // to catch this, and try running the remainder of the alternative after
+ // the subpattern again, skipping the parentheses.
+ //
+ // Upon backtracking back into a quantified set of parentheses we need to
+ // check whether we were currently skipping the subpattern. If not, we
+ // can backtrack into them, if we were we need to either backtrack back
+ // out of the start of the parentheses, or jump back to the forwards
+ // matching start, depending of whether the match is Greedy or NonGreedy.
+ case OpParenthesesSubpatternOnceBegin: {
+ PatternTerm* term = op.m_term;
+ ASSERT(term->quantityCount == 1);
+
+ // We only need to backtrack to thispoint if capturing or greedy.
+ if (term->capture() || term->quantityType == QuantifierGreedy) {
+ m_backtrackingState.link(this);
+
+ // If capturing, clear the capture (we only need to reset start).
+ if (term->capture())
+ store32(TrustedImm32(-1), Address(output, (term->parentheses.subpatternId << 1) * sizeof(int)));
+
+ // If Greedy, jump to the end.
+ if (term->quantityType == QuantifierGreedy) {
+ // Clear the flag in the stackframe indicating we ran through the subpattern.
+ unsigned parenthesesFrameLocation = term->frameLocation;
+ storeToFrame(TrustedImm32(-1), parenthesesFrameLocation);
+ // Jump to after the parentheses, skipping the subpattern.
+ jump(m_ops[op.m_nextOp].m_reentry);
+ // A backtrack from after the parentheses, when skipping the subpattern,
+ // will jump back to here.
+ op.m_jumps.link(this);
+ }
+
+ m_backtrackingState.fallthrough();
+ }
+ break;
+ }
+ case OpParenthesesSubpatternOnceEnd: {
+ PatternTerm* term = op.m_term;
+
+ if (term->quantityType != QuantifierFixedCount) {
+ m_backtrackingState.link(this);
+
+ // Check whether we should backtrack back into the parentheses, or if we
+ // are currently in a state where we had skipped over the subpattern
+ // (in which case the flag value on the stack will be -1).
+ unsigned parenthesesFrameLocation = term->frameLocation;
+ Jump hadSkipped = branch32(Equal, Address(stackPointerRegister, parenthesesFrameLocation * sizeof(void*)), TrustedImm32(-1));
+
+ if (term->quantityType == QuantifierGreedy) {
+ // For Greedy parentheses, we skip after having already tried going
+ // through the subpattern, so if we get here we're done.
+ YarrOp& beginOp = m_ops[op.m_previousOp];
+ beginOp.m_jumps.append(hadSkipped);
+ } else {
+ // For NonGreedy parentheses, we try skipping the subpattern first,
+ // so if we get here we need to try running through the subpattern
+ // next. Jump back to the start of the parentheses in the forwards
+ // matching path.
+ ASSERT(term->quantityType == QuantifierNonGreedy);
+ YarrOp& beginOp = m_ops[op.m_previousOp];
+ hadSkipped.linkTo(beginOp.m_reentry, this);
+ }
+
+ m_backtrackingState.fallthrough();
+ }
+
+ m_backtrackingState.append(op.m_jumps);
+ break;
+ }
+
+ // OpParenthesesSubpatternTerminalBegin/End
+ //
+ // Terminal subpatterns will always match - there is nothing after them to
+ // force a backtrack, and they have a minimum count of 0, and as such will
+ // always produce an acceptable result.
+ case OpParenthesesSubpatternTerminalBegin: {
+ // We will backtrack to this point once the subpattern cannot match any
+ // more. Since no match is accepted as a successful match (we are Greedy
+ // quantified with a minimum of zero) jump back to the forwards matching
+ // path at the end.
+ YarrOp& endOp = m_ops[op.m_nextOp];
+ m_backtrackingState.linkTo(endOp.m_reentry, this);
+ break;
+ }
+ case OpParenthesesSubpatternTerminalEnd:
+ // We should never be backtracking to here (hence the 'terminal' in the name).
+ ASSERT(m_backtrackingState.isEmpty());
+ m_backtrackingState.append(op.m_jumps);
+ break;
+
+ // OpParentheticalAssertionBegin/End
+ case OpParentheticalAssertionBegin: {
+ PatternTerm* term = op.m_term;
+ YarrOp& endOp = m_ops[op.m_nextOp];
+
+ // We need to handle the backtracks upon backtracking back out
+ // of a parenthetical assertion if either we need to correct
+ // the input index, or the assertion was inverted.
+ if (op.m_checkAdjust || term->invert()) {
+ m_backtrackingState.link(this);
+
+ if (op.m_checkAdjust)
+ add32(Imm32(op.m_checkAdjust), index);
+
+ // In an inverted assertion failure to match the subpattern
+ // is treated as a successful match - jump to the end of the
+ // subpattern. We already have adjusted the input position
+ // back to that before the assertion, which is correct.
+ if (term->invert())
+ jump(endOp.m_reentry);
+
+ m_backtrackingState.fallthrough();
+ }
+
+ // The End node's jump list will contain any backtracks into
+ // the end of the assertion. Also, if inverted, we will have
+ // added the failure caused by a successful match to this.
+ m_backtrackingState.append(endOp.m_jumps);
+
+ m_checked += op.m_checkAdjust;
+ break;
+ }
+ case OpParentheticalAssertionEnd: {
+ // FIXME: We should really be clearing any nested subpattern
+ // matches on bailing out from after the pattern. Firefox has
+ // this bug too (presumably because they use YARR!)
+
+ // Never backtrack into an assertion; later failures bail to before the begin.
+ m_backtrackingState.takeBacktracksToJumpList(op.m_jumps, this);
+
+ YarrOp& lastOp = m_ops[op.m_previousOp];
+ m_checked -= lastOp.m_checkAdjust;
+ break;
+ }
+
+ case OpMatchFailed:
+ break;
+ }
+
+ } while (opIndex);
+ }
+
+ // Compilation methods:
+ // ====================
+
+ // opCompileParenthesesSubpattern
+ // Emits ops for a subpattern (set of parentheses). These consist
+ // of a set of alternatives wrapped in an outer set of nodes for
+ // the parentheses.
+ // Supported types of parentheses are 'Once' (quantityCount == 1)
+ // and 'Terminal' (non-capturing parentheses quantified as greedy
+ // and infinite).
+ // Alternatives will use the 'Simple' set of ops if either the
+ // subpattern is terminal (in which case we will never need to
+ // backtrack), or if the subpattern only contains one alternative.
+ void opCompileParenthesesSubpattern(PatternTerm* term)
+ {
+ YarrOpCode parenthesesBeginOpCode;
+ YarrOpCode parenthesesEndOpCode;
+ YarrOpCode alternativeBeginOpCode = OpSimpleNestedAlternativeBegin;
+ YarrOpCode alternativeNextOpCode = OpSimpleNestedAlternativeNext;
+ YarrOpCode alternativeEndOpCode = OpSimpleNestedAlternativeEnd;
+
+ // We can currently only compile quantity 1 subpatterns that are
+ // not copies. We generate a copy in the case of a range quantifier,
+ // e.g. /(?:x){3,9}/, or /(?:x)+/ (These are effectively expanded to
+ // /(?:x){3,3}(?:x){0,6}/ and /(?:x)(?:x)*/ repectively). The problem
+ // comes where the subpattern is capturing, in which case we would
+ // need to restore the capture from the first subpattern upon a
+ // failure in the second.
+ if (term->quantityCount == 1 && !term->parentheses.isCopy) {
+ // Select the 'Once' nodes.
+ parenthesesBeginOpCode = OpParenthesesSubpatternOnceBegin;
+ parenthesesEndOpCode = OpParenthesesSubpatternOnceEnd;
+
+ // If there is more than one alternative we cannot use the 'simple' nodes.
+ if (term->parentheses.disjunction->m_alternatives.size() != 1) {
+ alternativeBeginOpCode = OpNestedAlternativeBegin;
+ alternativeNextOpCode = OpNestedAlternativeNext;
+ alternativeEndOpCode = OpNestedAlternativeEnd;
+ }
+ } else if (term->parentheses.isTerminal) {
+ // Select the 'Terminal' nodes.
+ parenthesesBeginOpCode = OpParenthesesSubpatternTerminalBegin;
+ parenthesesEndOpCode = OpParenthesesSubpatternTerminalEnd;
+ } else {
+ // This subpattern is not supported by the JIT.
+ m_shouldFallBack = true;
+ return;
+ }
+
+ size_t parenBegin = m_ops.size();
+ m_ops.append(parenthesesBeginOpCode);
+
+ m_ops.append(alternativeBeginOpCode);
+ m_ops.last().m_previousOp = notFound;
+ m_ops.last().m_term = term;
+ Vector<PatternAlternative*>& alternatives = term->parentheses.disjunction->m_alternatives;
+ for (unsigned i = 0; i < alternatives.size(); ++i) {
+ size_t lastOpIndex = m_ops.size() - 1;
+
+ PatternAlternative* nestedAlternative = alternatives[i];
+ opCompileAlternative(nestedAlternative);
+
+ size_t thisOpIndex = m_ops.size();
+ m_ops.append(YarrOp(alternativeNextOpCode));
+
+ YarrOp& lastOp = m_ops[lastOpIndex];
+ YarrOp& thisOp = m_ops[thisOpIndex];
+
+ lastOp.m_alternative = nestedAlternative;
+ lastOp.m_nextOp = thisOpIndex;
+ thisOp.m_previousOp = lastOpIndex;
+ thisOp.m_term = term;
+ }
+ YarrOp& lastOp = m_ops.last();
+ ASSERT(lastOp.m_op == alternativeNextOpCode);
+ lastOp.m_op = alternativeEndOpCode;
+ lastOp.m_alternative = 0;
+ lastOp.m_nextOp = notFound;
+
+ size_t parenEnd = m_ops.size();
+ m_ops.append(parenthesesEndOpCode);
+
+ m_ops[parenBegin].m_term = term;
+ m_ops[parenBegin].m_previousOp = notFound;
+ m_ops[parenBegin].m_nextOp = parenEnd;
+ m_ops[parenEnd].m_term = term;
+ m_ops[parenEnd].m_previousOp = parenBegin;
+ m_ops[parenEnd].m_nextOp = notFound;
+ }
+
+ // opCompileParentheticalAssertion
+ // Emits ops for a parenthetical assertion. These consist of an
+ // OpSimpleNestedAlternativeBegin/Next/End set of nodes wrapping
+ // the alternatives, with these wrapped by an outer pair of
+ // OpParentheticalAssertionBegin/End nodes.
+ // We can always use the OpSimpleNestedAlternative nodes in the
+ // case of parenthetical assertions since these only ever match
+ // once, and will never backtrack back into the assertion.
+ void opCompileParentheticalAssertion(PatternTerm* term)
+ {
+ size_t parenBegin = m_ops.size();
+ m_ops.append(OpParentheticalAssertionBegin);
+
+ m_ops.append(OpSimpleNestedAlternativeBegin);
+ m_ops.last().m_previousOp = notFound;
+ m_ops.last().m_term = term;
+ Vector<PatternAlternative*>& alternatives = term->parentheses.disjunction->m_alternatives;
+ for (unsigned i = 0; i < alternatives.size(); ++i) {
+ size_t lastOpIndex = m_ops.size() - 1;
+
+ PatternAlternative* nestedAlternative = alternatives[i];
+ opCompileAlternative(nestedAlternative);
+
+ size_t thisOpIndex = m_ops.size();
+ m_ops.append(YarrOp(OpSimpleNestedAlternativeNext));
+
+ YarrOp& lastOp = m_ops[lastOpIndex];
+ YarrOp& thisOp = m_ops[thisOpIndex];
+
+ lastOp.m_alternative = nestedAlternative;
+ lastOp.m_nextOp = thisOpIndex;
+ thisOp.m_previousOp = lastOpIndex;
+ thisOp.m_term = term;
+ }
+ YarrOp& lastOp = m_ops.last();
+ ASSERT(lastOp.m_op == OpSimpleNestedAlternativeNext);
+ lastOp.m_op = OpSimpleNestedAlternativeEnd;
+ lastOp.m_alternative = 0;
+ lastOp.m_nextOp = notFound;
+
+ size_t parenEnd = m_ops.size();
+ m_ops.append(OpParentheticalAssertionEnd);
+
+ m_ops[parenBegin].m_term = term;
+ m_ops[parenBegin].m_previousOp = notFound;
+ m_ops[parenBegin].m_nextOp = parenEnd;
+ m_ops[parenEnd].m_term = term;
+ m_ops[parenEnd].m_previousOp = parenBegin;
+ m_ops[parenEnd].m_nextOp = notFound;
+ }
+
+ // opCompileAlternative
+ // Called to emit nodes for all terms in an alternative.
+ void opCompileAlternative(PatternAlternative* alternative)
+ {
+ optimizeAlternative(alternative);
+
+ for (unsigned i = 0; i < alternative->m_terms.size(); ++i) {
+ PatternTerm* term = &alternative->m_terms[i];
+
+ switch (term->type) {
+ case PatternTerm::TypeParenthesesSubpattern:
+ opCompileParenthesesSubpattern(term);
+ break;
+
+ case PatternTerm::TypeParentheticalAssertion:
+ opCompileParentheticalAssertion(term);
+ break;
+
+ default:
+ m_ops.append(term);
+ }
+ }
+ }
+
+ // opCompileBody
+ // This method compiles the body disjunction of the regular expression.
+ // The body consists of two sets of alternatives - zero or more 'once
+ // through' (BOL anchored) alternatives, followed by zero or more
+ // repeated alternatives.
+ // For each of these two sets of alteratives, if not empty they will be
+ // wrapped in a set of OpBodyAlternativeBegin/Next/End nodes (with the
+ // 'begin' node referencing the first alternative, and 'next' nodes
+ // referencing any further alternatives. The begin/next/end nodes are
+ // linked together in a doubly linked list. In the case of repeating
+ // alternatives, the end node is also linked back to the beginning.
+ // If no repeating alternatives exist, then a OpMatchFailed node exists
+ // to return the failing result.
+ void opCompileBody(PatternDisjunction* disjunction)
+ {
+ Vector<PatternAlternative*>& alternatives = disjunction->m_alternatives;
+ size_t currentAlternativeIndex = 0;
+
+ // Emit the 'once through' alternatives.
+ if (alternatives.size() && alternatives[0]->onceThrough()) {
+ m_ops.append(YarrOp(OpBodyAlternativeBegin));
+ m_ops.last().m_previousOp = notFound;
+
+ do {
+ size_t lastOpIndex = m_ops.size() - 1;
+ PatternAlternative* alternative = alternatives[currentAlternativeIndex];
+ opCompileAlternative(alternative);
+
+ size_t thisOpIndex = m_ops.size();
+ m_ops.append(YarrOp(OpBodyAlternativeNext));
+
+ YarrOp& lastOp = m_ops[lastOpIndex];
+ YarrOp& thisOp = m_ops[thisOpIndex];
+
+ lastOp.m_alternative = alternative;
+ lastOp.m_nextOp = thisOpIndex;
+ thisOp.m_previousOp = lastOpIndex;
+
+ ++currentAlternativeIndex;
+ } while (currentAlternativeIndex < alternatives.size() && alternatives[currentAlternativeIndex]->onceThrough());
+
+ YarrOp& lastOp = m_ops.last();
+
+ ASSERT(lastOp.m_op == OpBodyAlternativeNext);
+ lastOp.m_op = OpBodyAlternativeEnd;
+ lastOp.m_alternative = 0;
+ lastOp.m_nextOp = notFound;
+ }
+
+ if (currentAlternativeIndex == alternatives.size()) {
+ m_ops.append(YarrOp(OpMatchFailed));
+ return;
+ }
+
+ // Emit the repeated alternatives.
+ size_t repeatLoop = m_ops.size();
+ m_ops.append(YarrOp(OpBodyAlternativeBegin));
+ m_ops.last().m_previousOp = notFound;
+ do {
+ size_t lastOpIndex = m_ops.size() - 1;
+ PatternAlternative* alternative = alternatives[currentAlternativeIndex];
+ ASSERT(!alternative->onceThrough());
+ opCompileAlternative(alternative);
+
+ size_t thisOpIndex = m_ops.size();
+ m_ops.append(YarrOp(OpBodyAlternativeNext));
+
+ YarrOp& lastOp = m_ops[lastOpIndex];
+ YarrOp& thisOp = m_ops[thisOpIndex];
+
+ lastOp.m_alternative = alternative;
+ lastOp.m_nextOp = thisOpIndex;
+ thisOp.m_previousOp = lastOpIndex;
+
+ ++currentAlternativeIndex;
+ } while (currentAlternativeIndex < alternatives.size());
+ YarrOp& lastOp = m_ops.last();
+ ASSERT(lastOp.m_op == OpBodyAlternativeNext);
+ lastOp.m_op = OpBodyAlternativeEnd;
+ lastOp.m_alternative = 0;
+ lastOp.m_nextOp = repeatLoop;
+ }
+
+ void generateEnter()
+ {
+#if CPU(X86_64)
+ push(X86Registers::ebp);
+ move(stackPointerRegister, X86Registers::ebp);
+ push(X86Registers::ebx);
+#elif CPU(X86)
+ push(X86Registers::ebp);
+ move(stackPointerRegister, X86Registers::ebp);
+ // TODO: do we need spill registers to fill the output pointer if there are no sub captures?
+ push(X86Registers::ebx);
+ push(X86Registers::edi);
+ push(X86Registers::esi);
+ // load output into edi (2 = saved ebp + return address).
+ #if COMPILER(MSVC)
+ loadPtr(Address(X86Registers::ebp, 2 * sizeof(void*)), input);
+ loadPtr(Address(X86Registers::ebp, 3 * sizeof(void*)), index);
+ loadPtr(Address(X86Registers::ebp, 4 * sizeof(void*)), length);
+ loadPtr(Address(X86Registers::ebp, 5 * sizeof(void*)), output);
+ #else
+ loadPtr(Address(X86Registers::ebp, 2 * sizeof(void*)), output);
+ #endif
+#elif CPU(ARM)
+ push(ARMRegisters::r4);
+ push(ARMRegisters::r5);
+ push(ARMRegisters::r6);
+#if CPU(ARM_TRADITIONAL)
+ push(ARMRegisters::r8); // scratch register
+#endif
+ move(ARMRegisters::r3, output);
+#elif CPU(SH4)
+ push(SH4Registers::r11);
+ push(SH4Registers::r13);
+#elif CPU(MIPS)
+ // Do nothing.
+#endif
+ }
+
+ void generateReturn()
+ {
+#if CPU(X86_64)
+ pop(X86Registers::ebx);
+ pop(X86Registers::ebp);
+#elif CPU(X86)
+ pop(X86Registers::esi);
+ pop(X86Registers::edi);
+ pop(X86Registers::ebx);
+ pop(X86Registers::ebp);
+#elif CPU(ARM)
+#if CPU(ARM_TRADITIONAL)
+ pop(ARMRegisters::r8); // scratch register
+#endif
+ pop(ARMRegisters::r6);
+ pop(ARMRegisters::r5);
+ pop(ARMRegisters::r4);
+#elif CPU(SH4)
+ pop(SH4Registers::r13);
+ pop(SH4Registers::r11);
+#elif CPU(MIPS)
+ // Do nothing
+#endif
+ ret();
+ }
+
+public:
+ YarrGenerator(YarrPattern& pattern)
+ : m_pattern(pattern)
+ , m_shouldFallBack(false)
+ , m_checked(0)
+ {
+ }
+
+ void compile(JSGlobalData* globalData, YarrCodeBlock& jitObject)
+ {
+ generateEnter();
+
+ if (!m_pattern.m_body->m_hasFixedSize)
+ store32(index, Address(output));
+
+ if (m_pattern.m_body->m_callFrameSize)
+ subPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister);
+
+ // Compile the pattern to the internal 'YarrOp' representation.
+ opCompileBody(m_pattern.m_body);
+
+ // If we encountered anything we can't handle in the JIT code
+ // (e.g. backreferences) then return early.
+ if (m_shouldFallBack) {
+ jitObject.setFallBack(true);
+ return;
+ }
+
+ generate();
+ backtrack();
+
+ // Link & finalize the code.
+ LinkBuffer linkBuffer(*globalData, this, globalData->regexAllocator);
+ m_backtrackingState.linkDataLabels(linkBuffer);
+ jitObject.set(linkBuffer.finalizeCode());
+ jitObject.setFallBack(m_shouldFallBack);
+ }
+
+private:
+ YarrPattern& m_pattern;
+
+ // Used to detect regular expression constructs that are not currently
+ // supported in the JIT; fall back to the interpreter when this is detected.
+ bool m_shouldFallBack;
+
+ // The regular expression expressed as a linear sequence of operations.
+ Vector<YarrOp, 128> m_ops;
+
+ // This records the current input offset being applied due to the current
+ // set of alternatives we are nested within. E.g. when matching the
+ // character 'b' within the regular expression /abc/, we will know that
+ // the minimum size for the alternative is 3, checked upon entry to the
+ // alternative, and that 'b' is at offset 1 from the start, and as such
+ // when matching 'b' we need to apply an offset of -2 to the load.
+ //
+ // FIXME: This should go away. Rather than tracking this value throughout
+ // code generation, we should gather this information up front & store it
+ // on the YarrOp structure.
+ int m_checked;
+
+ // This class records state whilst generating the backtracking path of code.
+ BacktrackingState m_backtrackingState;
+};
+
+void jitCompile(YarrPattern& pattern, JSGlobalData* globalData, YarrCodeBlock& jitObject)
+{
+ YarrGenerator(pattern).compile(globalData, jitObject);
+}
+
+int execute(YarrCodeBlock& jitObject, const UChar* input, unsigned start, unsigned length, int* output)
+{
+ return jitObject.execute(input, start, length, output);
+}
+
+}}
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef YarrJIT_h
+#define YarrJIT_h
+
+#if ENABLE(YARR_JIT)
+
+#include "JSGlobalData.h"
+#include "MacroAssembler.h"
+#include "UString.h"
+#include "YarrPattern.h"
+
+#if CPU(X86) && !COMPILER(MSVC)
+#define YARR_CALL __attribute__ ((regparm (3)))
+#else
+#define YARR_CALL
+#endif
+
+namespace JSC {
+
+class JSGlobalData;
+class ExecutablePool;
+
+namespace Yarr {
+
+class YarrCodeBlock {
+ typedef int (*YarrJITCode)(const UChar* input, unsigned start, unsigned length, int* output) YARR_CALL;
+
+public:
+ YarrCodeBlock()
+ : m_needFallBack(false)
+ {
+ }
+
+ ~YarrCodeBlock()
+ {
+ }
+
+ void setFallBack(bool fallback) { m_needFallBack = fallback; }
+ bool isFallBack() { return m_needFallBack; }
+ void set(MacroAssembler::CodeRef ref) { m_ref = ref; }
+
+ int execute(const UChar* input, unsigned start, unsigned length, int* output)
+ {
+ return reinterpret_cast<YarrJITCode>(m_ref.m_code.executableAddress())(input, start, length, output);
+ }
+
+#if ENABLE(REGEXP_TRACING)
+ void *getAddr() { return m_ref.m_code.executableAddress(); }
+#endif
+
+private:
+ MacroAssembler::CodeRef m_ref;
+ bool m_needFallBack;
+};
+
+void jitCompile(YarrPattern&, JSGlobalData*, YarrCodeBlock& jitObject);
+int execute(YarrCodeBlock& jitObject, const UChar* input, unsigned start, unsigned length, int* output);
+
+} } // namespace JSC::Yarr
+
+#endif
+
+#endif // YarrJIT_h
--- /dev/null
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef YarrParser_h
+#define YarrParser_h
+
+#include <runtime/UString.h>
+#include "Yarr.h"
+#include <wtf/ASCIICType.h>
+#include <wtf/unicode/Unicode.h>
+
+namespace JSC { namespace Yarr {
+
+#define REGEXP_ERROR_PREFIX "Invalid regular expression: "
+
+enum BuiltInCharacterClassID {
+ DigitClassID,
+ SpaceClassID,
+ WordClassID,
+ NewlineClassID,
+};
+
+// The Parser class should not be used directly - only via the Yarr::parse() method.
+template<class Delegate>
+class Parser {
+private:
+ template<class FriendDelegate>
+ friend const char* parse(FriendDelegate& delegate, const UString& pattern, unsigned backReferenceLimit);
+
+ enum ErrorCode {
+ NoError,
+ PatternTooLarge,
+ QuantifierOutOfOrder,
+ QuantifierWithoutAtom,
+ MissingParentheses,
+ ParenthesesUnmatched,
+ ParenthesesTypeInvalid,
+ CharacterClassUnmatched,
+ CharacterClassOutOfOrder,
+ EscapeUnterminated,
+ NumberOfErrorCodes
+ };
+
+ /*
+ * CharacterClassParserDelegate:
+ *
+ * The class CharacterClassParserDelegate is used in the parsing of character
+ * classes. This class handles detection of character ranges. This class
+ * implements enough of the delegate interface such that it can be passed to
+ * parseEscape() as an EscapeDelegate. This allows parseEscape() to be reused
+ * to perform the parsing of escape characters in character sets.
+ */
+ class CharacterClassParserDelegate {
+ public:
+ CharacterClassParserDelegate(Delegate& delegate, ErrorCode& err)
+ : m_delegate(delegate)
+ , m_err(err)
+ , m_state(Empty)
+ , m_character(0)
+ {
+ }
+
+ /*
+ * begin():
+ *
+ * Called at beginning of construction.
+ */
+ void begin(bool invert)
+ {
+ m_delegate.atomCharacterClassBegin(invert);
+ }
+
+ /*
+ * atomPatternCharacter():
+ *
+ * This method is called either from parseCharacterClass() (for an unescaped
+ * character in a character class), or from parseEscape(). In the former case
+ * the value true will be passed for the argument 'hyphenIsRange', and in this
+ * mode we will allow a hypen to be treated as indicating a range (i.e. /[a-z]/
+ * is different to /[a\-z]/).
+ */
+ void atomPatternCharacter(UChar ch, bool hyphenIsRange = false)
+ {
+ switch (m_state) {
+ case AfterCharacterClass:
+ // Following a builtin character class we need look out for a hyphen.
+ // We're looking for invalid ranges, such as /[\d-x]/ or /[\d-\d]/.
+ // If we see a hyphen following a charater class then unlike usual
+ // we'll report it to the delegate immediately, and put ourself into
+ // a poisoned state. Any following calls to add another character or
+ // character class will result in an error. (A hypen following a
+ // character-class is itself valid, but only at the end of a regex).
+ if (hyphenIsRange && ch == '-') {
+ m_delegate.atomCharacterClassAtom('-');
+ m_state = AfterCharacterClassHyphen;
+ return;
+ }
+ // Otherwise just fall through - cached character so treat this as Empty.
+
+ case Empty:
+ m_character = ch;
+ m_state = CachedCharacter;
+ return;
+
+ case CachedCharacter:
+ if (hyphenIsRange && ch == '-')
+ m_state = CachedCharacterHyphen;
+ else {
+ m_delegate.atomCharacterClassAtom(m_character);
+ m_character = ch;
+ }
+ return;
+
+ case CachedCharacterHyphen:
+ if (ch < m_character) {
+ m_err = CharacterClassOutOfOrder;
+ return;
+ }
+ m_delegate.atomCharacterClassRange(m_character, ch);
+ m_state = Empty;
+ return;
+
+ // See coment in atomBuiltInCharacterClass below.
+ // This too is technically an error, per ECMA-262, and again we
+ // we chose to allow this. Note a subtlely here that while we
+ // diverge from the spec's definition of CharacterRange we do
+ // remain in compliance with the grammar. For example, consider
+ // the expression /[\d-a-z]/. We comply with the grammar in
+ // this case by not allowing a-z to be matched as a range.
+ case AfterCharacterClassHyphen:
+ m_delegate.atomCharacterClassAtom(ch);
+ m_state = Empty;
+ return;
+ }
+ }
+
+ /*
+ * atomBuiltInCharacterClass():
+ *
+ * Adds a built-in character class, called by parseEscape().
+ */
+ void atomBuiltInCharacterClass(BuiltInCharacterClassID classID, bool invert)
+ {
+ switch (m_state) {
+ case CachedCharacter:
+ // Flush the currently cached character, then fall through.
+ m_delegate.atomCharacterClassAtom(m_character);
+
+ case Empty:
+ case AfterCharacterClass:
+ m_state = AfterCharacterClass;
+ m_delegate.atomCharacterClassBuiltIn(classID, invert);
+ return;
+
+ // If we hit either of these cases, we have an invalid range that
+ // looks something like /[x-\d]/ or /[\d-\d]/.
+ // According to ECMA-262 this should be a syntax error, but
+ // empirical testing shows this to break teh webz. Instead we
+ // comply with to the ECMA-262 grammar, and assume the grammar to
+ // have matched the range correctly, but tweak our interpretation
+ // of CharacterRange. Effectively we implicitly handle the hyphen
+ // as if it were escaped, e.g. /[\w-_]/ is treated as /[\w\-_]/.
+ case CachedCharacterHyphen:
+ m_delegate.atomCharacterClassAtom(m_character);
+ m_delegate.atomCharacterClassAtom('-');
+ // fall through
+ case AfterCharacterClassHyphen:
+ m_delegate.atomCharacterClassBuiltIn(classID, invert);
+ m_state = Empty;
+ return;
+ }
+ }
+
+ /*
+ * end():
+ *
+ * Called at end of construction.
+ */
+ void end()
+ {
+ if (m_state == CachedCharacter)
+ m_delegate.atomCharacterClassAtom(m_character);
+ else if (m_state == CachedCharacterHyphen) {
+ m_delegate.atomCharacterClassAtom(m_character);
+ m_delegate.atomCharacterClassAtom('-');
+ }
+ m_delegate.atomCharacterClassEnd();
+ }
+
+ // parseEscape() should never call these delegate methods when
+ // invoked with inCharacterClass set.
+ void assertionWordBoundary(bool) { ASSERT_NOT_REACHED(); }
+ void atomBackReference(unsigned) { ASSERT_NOT_REACHED(); }
+
+ private:
+ Delegate& m_delegate;
+ ErrorCode& m_err;
+ enum CharacterClassConstructionState {
+ Empty,
+ CachedCharacter,
+ CachedCharacterHyphen,
+ AfterCharacterClass,
+ AfterCharacterClassHyphen,
+ } m_state;
+ UChar m_character;
+ };
+
+ Parser(Delegate& delegate, const UString& pattern, unsigned backReferenceLimit)
+ : m_delegate(delegate)
+ , m_backReferenceLimit(backReferenceLimit)
+ , m_err(NoError)
+ , m_data(pattern.characters())
+ , m_size(pattern.length())
+ , m_index(0)
+ , m_parenthesesNestingDepth(0)
+ {
+ }
+
+ /*
+ * parseEscape():
+ *
+ * Helper for parseTokens() AND parseCharacterClass().
+ * Unlike the other parser methods, this function does not report tokens
+ * directly to the member delegate (m_delegate), instead tokens are
+ * emitted to the delegate provided as an argument. In the case of atom
+ * escapes, parseTokens() will call parseEscape() passing m_delegate as
+ * an argument, and as such the escape will be reported to the delegate.
+ *
+ * However this method may also be used by parseCharacterClass(), in which
+ * case a CharacterClassParserDelegate will be passed as the delegate that
+ * tokens should be added to. A boolean flag is also provided to indicate
+ * whether that an escape in a CharacterClass is being parsed (some parsing
+ * rules change in this context).
+ *
+ * The boolean value returned by this method indicates whether the token
+ * parsed was an atom (outside of a characted class \b and \B will be
+ * interpreted as assertions).
+ */
+ template<bool inCharacterClass, class EscapeDelegate>
+ bool parseEscape(EscapeDelegate& delegate)
+ {
+ ASSERT(!m_err);
+ ASSERT(peek() == '\\');
+ consume();
+
+ if (atEndOfPattern()) {
+ m_err = EscapeUnterminated;
+ return false;
+ }
+
+ switch (peek()) {
+ // Assertions
+ case 'b':
+ consume();
+ if (inCharacterClass)
+ delegate.atomPatternCharacter('\b');
+ else {
+ delegate.assertionWordBoundary(false);
+ return false;
+ }
+ break;
+ case 'B':
+ consume();
+ if (inCharacterClass)
+ delegate.atomPatternCharacter('B');
+ else {
+ delegate.assertionWordBoundary(true);
+ return false;
+ }
+ break;
+
+ // CharacterClassEscape
+ case 'd':
+ consume();
+ delegate.atomBuiltInCharacterClass(DigitClassID, false);
+ break;
+ case 's':
+ consume();
+ delegate.atomBuiltInCharacterClass(SpaceClassID, false);
+ break;
+ case 'w':
+ consume();
+ delegate.atomBuiltInCharacterClass(WordClassID, false);
+ break;
+ case 'D':
+ consume();
+ delegate.atomBuiltInCharacterClass(DigitClassID, true);
+ break;
+ case 'S':
+ consume();
+ delegate.atomBuiltInCharacterClass(SpaceClassID, true);
+ break;
+ case 'W':
+ consume();
+ delegate.atomBuiltInCharacterClass(WordClassID, true);
+ break;
+
+ // DecimalEscape
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': {
+ // To match Firefox, we parse an invalid backreference in the range [1-7] as an octal escape.
+ // First, try to parse this as backreference.
+ if (!inCharacterClass) {
+ ParseState state = saveState();
+
+ unsigned backReference = consumeNumber();
+ if (backReference <= m_backReferenceLimit) {
+ delegate.atomBackReference(backReference);
+ break;
+ }
+
+ restoreState(state);
+ }
+
+ // Not a backreference, and not octal.
+ if (peek() >= '8') {
+ delegate.atomPatternCharacter('\\');
+ break;
+ }
+
+ // Fall-through to handle this as an octal escape.
+ }
+
+ // Octal escape
+ case '0':
+ delegate.atomPatternCharacter(consumeOctal());
+ break;
+
+ // ControlEscape
+ case 'f':
+ consume();
+ delegate.atomPatternCharacter('\f');
+ break;
+ case 'n':
+ consume();
+ delegate.atomPatternCharacter('\n');
+ break;
+ case 'r':
+ consume();
+ delegate.atomPatternCharacter('\r');
+ break;
+ case 't':
+ consume();
+ delegate.atomPatternCharacter('\t');
+ break;
+ case 'v':
+ consume();
+ delegate.atomPatternCharacter('\v');
+ break;
+
+ // ControlLetter
+ case 'c': {
+ ParseState state = saveState();
+ consume();
+ if (!atEndOfPattern()) {
+ int control = consume();
+
+ // To match Firefox, inside a character class, we also accept numbers and '_' as control characters.
+ if (inCharacterClass ? WTF::isASCIIAlphanumeric(control) || (control == '_') : WTF::isASCIIAlpha(control)) {
+ delegate.atomPatternCharacter(control & 0x1f);
+ break;
+ }
+ }
+ restoreState(state);
+ delegate.atomPatternCharacter('\\');
+ break;
+ }
+
+ // HexEscape
+ case 'x': {
+ consume();
+ int x = tryConsumeHex(2);
+ if (x == -1)
+ delegate.atomPatternCharacter('x');
+ else
+ delegate.atomPatternCharacter(x);
+ break;
+ }
+
+ // UnicodeEscape
+ case 'u': {
+ consume();
+ int u = tryConsumeHex(4);
+ if (u == -1)
+ delegate.atomPatternCharacter('u');
+ else
+ delegate.atomPatternCharacter(u);
+ break;
+ }
+
+ // IdentityEscape
+ default:
+ delegate.atomPatternCharacter(consume());
+ }
+
+ return true;
+ }
+
+ /*
+ * parseAtomEscape(), parseCharacterClassEscape():
+ *
+ * These methods alias to parseEscape().
+ */
+ bool parseAtomEscape()
+ {
+ return parseEscape<false>(m_delegate);
+ }
+ void parseCharacterClassEscape(CharacterClassParserDelegate& delegate)
+ {
+ parseEscape<true>(delegate);
+ }
+
+ /*
+ * parseCharacterClass():
+ *
+ * Helper for parseTokens(); calls dirctly and indirectly (via parseCharacterClassEscape)
+ * to an instance of CharacterClassParserDelegate, to describe the character class to the
+ * delegate.
+ */
+ void parseCharacterClass()
+ {
+ ASSERT(!m_err);
+ ASSERT(peek() == '[');
+ consume();
+
+ CharacterClassParserDelegate characterClassConstructor(m_delegate, m_err);
+
+ characterClassConstructor.begin(tryConsume('^'));
+
+ while (!atEndOfPattern()) {
+ switch (peek()) {
+ case ']':
+ consume();
+ characterClassConstructor.end();
+ return;
+
+ case '\\':
+ parseCharacterClassEscape(characterClassConstructor);
+ break;
+
+ default:
+ characterClassConstructor.atomPatternCharacter(consume(), true);
+ }
+
+ if (m_err)
+ return;
+ }
+
+ m_err = CharacterClassUnmatched;
+ }
+
+ /*
+ * parseParenthesesBegin():
+ *
+ * Helper for parseTokens(); checks for parentheses types other than regular capturing subpatterns.
+ */
+ void parseParenthesesBegin()
+ {
+ ASSERT(!m_err);
+ ASSERT(peek() == '(');
+ consume();
+
+ if (tryConsume('?')) {
+ if (atEndOfPattern()) {
+ m_err = ParenthesesTypeInvalid;
+ return;
+ }
+
+ switch (consume()) {
+ case ':':
+ m_delegate.atomParenthesesSubpatternBegin(false);
+ break;
+
+ case '=':
+ m_delegate.atomParentheticalAssertionBegin();
+ break;
+
+ case '!':
+ m_delegate.atomParentheticalAssertionBegin(true);
+ break;
+
+ default:
+ m_err = ParenthesesTypeInvalid;
+ }
+ } else
+ m_delegate.atomParenthesesSubpatternBegin();
+
+ ++m_parenthesesNestingDepth;
+ }
+
+ /*
+ * parseParenthesesEnd():
+ *
+ * Helper for parseTokens(); checks for parse errors (due to unmatched parentheses).
+ */
+ void parseParenthesesEnd()
+ {
+ ASSERT(!m_err);
+ ASSERT(peek() == ')');
+ consume();
+
+ if (m_parenthesesNestingDepth > 0)
+ m_delegate.atomParenthesesEnd();
+ else
+ m_err = ParenthesesUnmatched;
+
+ --m_parenthesesNestingDepth;
+ }
+
+ /*
+ * parseQuantifier():
+ *
+ * Helper for parseTokens(); checks for parse errors and non-greedy quantifiers.
+ */
+ void parseQuantifier(bool lastTokenWasAnAtom, unsigned min, unsigned max)
+ {
+ ASSERT(!m_err);
+ ASSERT(min <= max);
+
+ if (lastTokenWasAnAtom)
+ m_delegate.quantifyAtom(min, max, !tryConsume('?'));
+ else
+ m_err = QuantifierWithoutAtom;
+ }
+
+ /*
+ * parseTokens():
+ *
+ * This method loops over the input pattern reporting tokens to the delegate.
+ * The method returns when a parse error is detected, or the end of the pattern
+ * is reached. One piece of state is tracked around the loop, which is whether
+ * the last token passed to the delegate was an atom (this is necessary to detect
+ * a parse error when a quantifier provided without an atom to quantify).
+ */
+ void parseTokens()
+ {
+ bool lastTokenWasAnAtom = false;
+
+ while (!atEndOfPattern()) {
+ switch (peek()) {
+ case '|':
+ consume();
+ m_delegate.disjunction();
+ lastTokenWasAnAtom = false;
+ break;
+
+ case '(':
+ parseParenthesesBegin();
+ lastTokenWasAnAtom = false;
+ break;
+
+ case ')':
+ parseParenthesesEnd();
+ lastTokenWasAnAtom = true;
+ break;
+
+ case '^':
+ consume();
+ m_delegate.assertionBOL();
+ lastTokenWasAnAtom = false;
+ break;
+
+ case '$':
+ consume();
+ m_delegate.assertionEOL();
+ lastTokenWasAnAtom = false;
+ break;
+
+ case '.':
+ consume();
+ m_delegate.atomBuiltInCharacterClass(NewlineClassID, true);
+ lastTokenWasAnAtom = true;
+ break;
+
+ case '[':
+ parseCharacterClass();
+ lastTokenWasAnAtom = true;
+ break;
+
+ case '\\':
+ lastTokenWasAnAtom = parseAtomEscape();
+ break;
+
+ case '*':
+ consume();
+ parseQuantifier(lastTokenWasAnAtom, 0, quantifyInfinite);
+ lastTokenWasAnAtom = false;
+ break;
+
+ case '+':
+ consume();
+ parseQuantifier(lastTokenWasAnAtom, 1, quantifyInfinite);
+ lastTokenWasAnAtom = false;
+ break;
+
+ case '?':
+ consume();
+ parseQuantifier(lastTokenWasAnAtom, 0, 1);
+ lastTokenWasAnAtom = false;
+ break;
+
+ case '{': {
+ ParseState state = saveState();
+
+ consume();
+ if (peekIsDigit()) {
+ unsigned min = consumeNumber();
+ unsigned max = min;
+
+ if (tryConsume(','))
+ max = peekIsDigit() ? consumeNumber() : quantifyInfinite;
+
+ if (tryConsume('}')) {
+ if (min <= max)
+ parseQuantifier(lastTokenWasAnAtom, min, max);
+ else
+ m_err = QuantifierOutOfOrder;
+ lastTokenWasAnAtom = false;
+ break;
+ }
+ }
+
+ restoreState(state);
+ } // if we did not find a complete quantifer, fall through to the default case.
+
+ default:
+ m_delegate.atomPatternCharacter(consume());
+ lastTokenWasAnAtom = true;
+ }
+
+ if (m_err)
+ return;
+ }
+
+ if (m_parenthesesNestingDepth > 0)
+ m_err = MissingParentheses;
+ }
+
+ /*
+ * parse():
+ *
+ * This method calls parseTokens() to parse over the input and converts any
+ * error code to a const char* for a result.
+ */
+ const char* parse()
+ {
+ if (m_size > MAX_PATTERN_SIZE)
+ m_err = PatternTooLarge;
+ else
+ parseTokens();
+ ASSERT(atEndOfPattern() || m_err);
+
+ // The order of this array must match the ErrorCode enum.
+ static const char* errorMessages[NumberOfErrorCodes] = {
+ 0, // NoError
+ REGEXP_ERROR_PREFIX "regular expression too large",
+ REGEXP_ERROR_PREFIX "numbers out of order in {} quantifier",
+ REGEXP_ERROR_PREFIX "nothing to repeat",
+ REGEXP_ERROR_PREFIX "missing )",
+ REGEXP_ERROR_PREFIX "unmatched parentheses",
+ REGEXP_ERROR_PREFIX "unrecognized character after (?",
+ REGEXP_ERROR_PREFIX "missing terminating ] for character class",
+ REGEXP_ERROR_PREFIX "range out of order in character class",
+ REGEXP_ERROR_PREFIX "\\ at end of pattern"
+ };
+
+ return errorMessages[m_err];
+ }
+
+
+ // Misc helper functions:
+
+ typedef unsigned ParseState;
+
+ ParseState saveState()
+ {
+ return m_index;
+ }
+
+ void restoreState(ParseState state)
+ {
+ m_index = state;
+ }
+
+ bool atEndOfPattern()
+ {
+ ASSERT(m_index <= m_size);
+ return m_index == m_size;
+ }
+
+ int peek()
+ {
+ ASSERT(m_index < m_size);
+ return m_data[m_index];
+ }
+
+ bool peekIsDigit()
+ {
+ return !atEndOfPattern() && WTF::isASCIIDigit(peek());
+ }
+
+ unsigned peekDigit()
+ {
+ ASSERT(peekIsDigit());
+ return peek() - '0';
+ }
+
+ int consume()
+ {
+ ASSERT(m_index < m_size);
+ return m_data[m_index++];
+ }
+
+ unsigned consumeDigit()
+ {
+ ASSERT(peekIsDigit());
+ return consume() - '0';
+ }
+
+ unsigned consumeNumber()
+ {
+ unsigned n = consumeDigit();
+ // check for overflow.
+ for (unsigned newValue; peekIsDigit() && ((newValue = n * 10 + peekDigit()) >= n); ) {
+ n = newValue;
+ consume();
+ }
+ return n;
+ }
+
+ unsigned consumeOctal()
+ {
+ ASSERT(WTF::isASCIIOctalDigit(peek()));
+
+ unsigned n = consumeDigit();
+ while (n < 32 && !atEndOfPattern() && WTF::isASCIIOctalDigit(peek()))
+ n = n * 8 + consumeDigit();
+ return n;
+ }
+
+ bool tryConsume(UChar ch)
+ {
+ if (atEndOfPattern() || (m_data[m_index] != ch))
+ return false;
+ ++m_index;
+ return true;
+ }
+
+ int tryConsumeHex(int count)
+ {
+ ParseState state = saveState();
+
+ int n = 0;
+ while (count--) {
+ if (atEndOfPattern() || !WTF::isASCIIHexDigit(peek())) {
+ restoreState(state);
+ return -1;
+ }
+ n = (n << 4) | WTF::toASCIIHexValue(consume());
+ }
+ return n;
+ }
+
+ Delegate& m_delegate;
+ unsigned m_backReferenceLimit;
+ ErrorCode m_err;
+ const UChar* m_data;
+ unsigned m_size;
+ unsigned m_index;
+ unsigned m_parenthesesNestingDepth;
+
+ // Derived by empirical testing of compile time in PCRE and WREC.
+ static const unsigned MAX_PATTERN_SIZE = 1024 * 1024;
+};
+
+/*
+ * Yarr::parse():
+ *
+ * The parse method is passed a pattern to be parsed and a delegate upon which
+ * callbacks will be made to record the parsed tokens forming the regex.
+ * Yarr::parse() returns null on success, or a const C string providing an error
+ * message where a parse error occurs.
+ *
+ * The Delegate must implement the following interface:
+ *
+ * void assertionBOL();
+ * void assertionEOL();
+ * void assertionWordBoundary(bool invert);
+ *
+ * void atomPatternCharacter(UChar ch);
+ * void atomBuiltInCharacterClass(BuiltInCharacterClassID classID, bool invert);
+ * void atomCharacterClassBegin(bool invert)
+ * void atomCharacterClassAtom(UChar ch)
+ * void atomCharacterClassRange(UChar begin, UChar end)
+ * void atomCharacterClassBuiltIn(BuiltInCharacterClassID classID, bool invert)
+ * void atomCharacterClassEnd()
+ * void atomParenthesesSubpatternBegin(bool capture = true);
+ * void atomParentheticalAssertionBegin(bool invert = false);
+ * void atomParenthesesEnd();
+ * void atomBackReference(unsigned subpatternId);
+ *
+ * void quantifyAtom(unsigned min, unsigned max, bool greedy);
+ *
+ * void disjunction();
+ *
+ * The regular expression is described by a sequence of assertion*() and atom*()
+ * callbacks to the delegate, describing the terms in the regular expression.
+ * Following an atom a quantifyAtom() call may occur to indicate that the previous
+ * atom should be quantified. In the case of atoms described across multiple
+ * calls (parentheses and character classes) the call to quantifyAtom() will come
+ * after the call to the atom*End() method, never after atom*Begin().
+ *
+ * Character classes may either be described by a single call to
+ * atomBuiltInCharacterClass(), or by a sequence of atomCharacterClass*() calls.
+ * In the latter case, ...Begin() will be called, followed by a sequence of
+ * calls to ...Atom(), ...Range(), and ...BuiltIn(), followed by a call to ...End().
+ *
+ * Sequences of atoms and assertions are broken into alternatives via calls to
+ * disjunction(). Assertions, atoms, and disjunctions emitted between calls to
+ * atomParenthesesBegin() and atomParenthesesEnd() form the body of a subpattern.
+ * atomParenthesesBegin() is passed a subpatternId. In the case of a regular
+ * capturing subpattern, this will be the subpatternId associated with these
+ * parentheses, and will also by definition be the lowest subpatternId of these
+ * parentheses and of any nested paretheses. The atomParenthesesEnd() method
+ * is passed the subpatternId of the last capturing subexpression nested within
+ * these paretheses. In the case of a capturing subpattern with no nested
+ * capturing subpatterns, the same subpatternId will be passed to the begin and
+ * end functions. In the case of non-capturing subpatterns the subpatternId
+ * passed to the begin method is also the first possible subpatternId that might
+ * be nested within these paretheses. If a set of non-capturing parentheses does
+ * not contain any capturing subpatterns, then the subpatternId passed to begin
+ * will be greater than the subpatternId passed to end.
+ */
+
+template<class Delegate>
+const char* parse(Delegate& delegate, const UString& pattern, unsigned backReferenceLimit = quantifyInfinite)
+{
+ return Parser<Delegate>(delegate, pattern, backReferenceLimit).parse();
+}
+
+} } // namespace JSC::Yarr
+
+#endif // YarrParser_h
--- /dev/null
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Peter Varga (pvarga@inf.u-szeged.hu), University of Szeged
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "YarrPattern.h"
+
+#include "Yarr.h"
+#include "YarrParser.h"
+#include <wtf/Vector.h>
+
+using namespace WTF;
+
+namespace JSC { namespace Yarr {
+
+#include "RegExpJitTables.h"
+
+class CharacterClassConstructor {
+public:
+ CharacterClassConstructor(bool isCaseInsensitive = false)
+ : m_isCaseInsensitive(isCaseInsensitive)
+ {
+ }
+
+ void reset()
+ {
+ m_matches.clear();
+ m_ranges.clear();
+ m_matchesUnicode.clear();
+ m_rangesUnicode.clear();
+ }
+
+ void append(const CharacterClass* other)
+ {
+ for (size_t i = 0; i < other->m_matches.size(); ++i)
+ addSorted(m_matches, other->m_matches[i]);
+ for (size_t i = 0; i < other->m_ranges.size(); ++i)
+ addSortedRange(m_ranges, other->m_ranges[i].begin, other->m_ranges[i].end);
+ for (size_t i = 0; i < other->m_matchesUnicode.size(); ++i)
+ addSorted(m_matchesUnicode, other->m_matchesUnicode[i]);
+ for (size_t i = 0; i < other->m_rangesUnicode.size(); ++i)
+ addSortedRange(m_rangesUnicode, other->m_rangesUnicode[i].begin, other->m_rangesUnicode[i].end);
+ }
+
+ void putChar(UChar ch)
+ {
+ if (ch <= 0x7f) {
+ if (m_isCaseInsensitive && isASCIIAlpha(ch)) {
+ addSorted(m_matches, toASCIIUpper(ch));
+ addSorted(m_matches, toASCIILower(ch));
+ } else
+ addSorted(m_matches, ch);
+ } else {
+ UChar upper, lower;
+ if (m_isCaseInsensitive && ((upper = Unicode::toUpper(ch)) != (lower = Unicode::toLower(ch)))) {
+ addSorted(m_matchesUnicode, upper);
+ addSorted(m_matchesUnicode, lower);
+ } else
+ addSorted(m_matchesUnicode, ch);
+ }
+ }
+
+ // returns true if this character has another case, and 'ch' is the upper case form.
+ static inline bool isUnicodeUpper(UChar ch)
+ {
+ return ch != Unicode::toLower(ch);
+ }
+
+ // returns true if this character has another case, and 'ch' is the lower case form.
+ static inline bool isUnicodeLower(UChar ch)
+ {
+ return ch != Unicode::toUpper(ch);
+ }
+
+ void putRange(UChar lo, UChar hi)
+ {
+ if (lo <= 0x7f) {
+ char asciiLo = lo;
+ char asciiHi = std::min(hi, (UChar)0x7f);
+ addSortedRange(m_ranges, lo, asciiHi);
+
+ if (m_isCaseInsensitive) {
+ if ((asciiLo <= 'Z') && (asciiHi >= 'A'))
+ addSortedRange(m_ranges, std::max(asciiLo, 'A')+('a'-'A'), std::min(asciiHi, 'Z')+('a'-'A'));
+ if ((asciiLo <= 'z') && (asciiHi >= 'a'))
+ addSortedRange(m_ranges, std::max(asciiLo, 'a')+('A'-'a'), std::min(asciiHi, 'z')+('A'-'a'));
+ }
+ }
+ if (hi >= 0x80) {
+ uint32_t unicodeCurr = std::max(lo, (UChar)0x80);
+ addSortedRange(m_rangesUnicode, unicodeCurr, hi);
+
+ if (m_isCaseInsensitive) {
+ while (unicodeCurr <= hi) {
+ // If the upper bound of the range (hi) is 0xffff, the increments to
+ // unicodeCurr in this loop may take it to 0x10000. This is fine
+ // (if so we won't re-enter the loop, since the loop condition above
+ // will definitely fail) - but this does mean we cannot use a UChar
+ // to represent unicodeCurr, we must use a 32-bit value instead.
+ ASSERT(unicodeCurr <= 0xffff);
+
+ if (isUnicodeUpper(unicodeCurr)) {
+ UChar lowerCaseRangeBegin = Unicode::toLower(unicodeCurr);
+ UChar lowerCaseRangeEnd = lowerCaseRangeBegin;
+ while ((++unicodeCurr <= hi) && isUnicodeUpper(unicodeCurr) && (Unicode::toLower(unicodeCurr) == (lowerCaseRangeEnd + 1)))
+ lowerCaseRangeEnd++;
+ addSortedRange(m_rangesUnicode, lowerCaseRangeBegin, lowerCaseRangeEnd);
+ } else if (isUnicodeLower(unicodeCurr)) {
+ UChar upperCaseRangeBegin = Unicode::toUpper(unicodeCurr);
+ UChar upperCaseRangeEnd = upperCaseRangeBegin;
+ while ((++unicodeCurr <= hi) && isUnicodeLower(unicodeCurr) && (Unicode::toUpper(unicodeCurr) == (upperCaseRangeEnd + 1)))
+ upperCaseRangeEnd++;
+ addSortedRange(m_rangesUnicode, upperCaseRangeBegin, upperCaseRangeEnd);
+ } else
+ ++unicodeCurr;
+ }
+ }
+ }
+ }
+
+ CharacterClass* charClass()
+ {
+ CharacterClass* characterClass = new CharacterClass(0);
+
+ characterClass->m_matches.append(m_matches);
+ characterClass->m_ranges.append(m_ranges);
+ characterClass->m_matchesUnicode.append(m_matchesUnicode);
+ characterClass->m_rangesUnicode.append(m_rangesUnicode);
+
+ reset();
+
+ return characterClass;
+ }
+
+private:
+ void addSorted(Vector<UChar>& matches, UChar ch)
+ {
+ unsigned pos = 0;
+ unsigned range = matches.size();
+
+ // binary chop, find position to insert char.
+ while (range) {
+ unsigned index = range >> 1;
+
+ int val = matches[pos+index] - ch;
+ if (!val)
+ return;
+ else if (val > 0)
+ range = index;
+ else {
+ pos += (index+1);
+ range -= (index+1);
+ }
+ }
+
+ if (pos == matches.size())
+ matches.append(ch);
+ else
+ matches.insert(pos, ch);
+ }
+
+ void addSortedRange(Vector<CharacterRange>& ranges, UChar lo, UChar hi)
+ {
+ unsigned end = ranges.size();
+
+ // Simple linear scan - I doubt there are that many ranges anyway...
+ // feel free to fix this with something faster (eg binary chop).
+ for (unsigned i = 0; i < end; ++i) {
+ // does the new range fall before the current position in the array
+ if (hi < ranges[i].begin) {
+ // optional optimization: concatenate appending ranges? - may not be worthwhile.
+ if (hi == (ranges[i].begin - 1)) {
+ ranges[i].begin = lo;
+ return;
+ }
+ ranges.insert(i, CharacterRange(lo, hi));
+ return;
+ }
+ // Okay, since we didn't hit the last case, the end of the new range is definitely at or after the begining
+ // If the new range start at or before the end of the last range, then the overlap (if it starts one after the
+ // end of the last range they concatenate, which is just as good.
+ if (lo <= (ranges[i].end + 1)) {
+ // found an intersect! we'll replace this entry in the array.
+ ranges[i].begin = std::min(ranges[i].begin, lo);
+ ranges[i].end = std::max(ranges[i].end, hi);
+
+ // now check if the new range can subsume any subsequent ranges.
+ unsigned next = i+1;
+ // each iteration of the loop we will either remove something from the list, or break the loop.
+ while (next < ranges.size()) {
+ if (ranges[next].begin <= (ranges[i].end + 1)) {
+ // the next entry now overlaps / concatenates this one.
+ ranges[i].end = std::max(ranges[i].end, ranges[next].end);
+ ranges.remove(next);
+ } else
+ break;
+ }
+
+ return;
+ }
+ }
+
+ // CharacterRange comes after all existing ranges.
+ ranges.append(CharacterRange(lo, hi));
+ }
+
+ bool m_isCaseInsensitive;
+
+ Vector<UChar> m_matches;
+ Vector<CharacterRange> m_ranges;
+ Vector<UChar> m_matchesUnicode;
+ Vector<CharacterRange> m_rangesUnicode;
+};
+
+class YarrPatternConstructor {
+public:
+ YarrPatternConstructor(YarrPattern& pattern)
+ : m_pattern(pattern)
+ , m_characterClassConstructor(pattern.m_ignoreCase)
+ , m_invertParentheticalAssertion(false)
+ {
+ m_pattern.m_body = new PatternDisjunction();
+ m_alternative = m_pattern.m_body->addNewAlternative();
+ m_pattern.m_disjunctions.append(m_pattern.m_body);
+ }
+
+ ~YarrPatternConstructor()
+ {
+ }
+
+ void reset()
+ {
+ m_pattern.reset();
+ m_characterClassConstructor.reset();
+
+ m_pattern.m_body = new PatternDisjunction();
+ m_alternative = m_pattern.m_body->addNewAlternative();
+ m_pattern.m_disjunctions.append(m_pattern.m_body);
+ }
+
+ void assertionBOL()
+ {
+ if (!m_alternative->m_terms.size() & !m_invertParentheticalAssertion) {
+ m_alternative->m_startsWithBOL = true;
+ m_alternative->m_containsBOL = true;
+ m_pattern.m_containsBOL = true;
+ }
+ m_alternative->m_terms.append(PatternTerm::BOL());
+ }
+ void assertionEOL()
+ {
+ m_alternative->m_terms.append(PatternTerm::EOL());
+ }
+ void assertionWordBoundary(bool invert)
+ {
+ m_alternative->m_terms.append(PatternTerm::WordBoundary(invert));
+ }
+
+ void atomPatternCharacter(UChar ch)
+ {
+ // We handle case-insensitive checking of unicode characters which do have both
+ // cases by handling them as if they were defined using a CharacterClass.
+ if (m_pattern.m_ignoreCase && !isASCII(ch) && (Unicode::toUpper(ch) != Unicode::toLower(ch))) {
+ atomCharacterClassBegin();
+ atomCharacterClassAtom(ch);
+ atomCharacterClassEnd();
+ } else
+ m_alternative->m_terms.append(PatternTerm(ch));
+ }
+
+ void atomBuiltInCharacterClass(BuiltInCharacterClassID classID, bool invert)
+ {
+ switch (classID) {
+ case DigitClassID:
+ m_alternative->m_terms.append(PatternTerm(m_pattern.digitsCharacterClass(), invert));
+ break;
+ case SpaceClassID:
+ m_alternative->m_terms.append(PatternTerm(m_pattern.spacesCharacterClass(), invert));
+ break;
+ case WordClassID:
+ m_alternative->m_terms.append(PatternTerm(m_pattern.wordcharCharacterClass(), invert));
+ break;
+ case NewlineClassID:
+ m_alternative->m_terms.append(PatternTerm(m_pattern.newlineCharacterClass(), invert));
+ break;
+ }
+ }
+
+ void atomCharacterClassBegin(bool invert = false)
+ {
+ m_invertCharacterClass = invert;
+ }
+
+ void atomCharacterClassAtom(UChar ch)
+ {
+ m_characterClassConstructor.putChar(ch);
+ }
+
+ void atomCharacterClassRange(UChar begin, UChar end)
+ {
+ m_characterClassConstructor.putRange(begin, end);
+ }
+
+ void atomCharacterClassBuiltIn(BuiltInCharacterClassID classID, bool invert)
+ {
+ ASSERT(classID != NewlineClassID);
+
+ switch (classID) {
+ case DigitClassID:
+ m_characterClassConstructor.append(invert ? m_pattern.nondigitsCharacterClass() : m_pattern.digitsCharacterClass());
+ break;
+
+ case SpaceClassID:
+ m_characterClassConstructor.append(invert ? m_pattern.nonspacesCharacterClass() : m_pattern.spacesCharacterClass());
+ break;
+
+ case WordClassID:
+ m_characterClassConstructor.append(invert ? m_pattern.nonwordcharCharacterClass() : m_pattern.wordcharCharacterClass());
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ }
+
+ void atomCharacterClassEnd()
+ {
+ CharacterClass* newCharacterClass = m_characterClassConstructor.charClass();
+ m_pattern.m_userCharacterClasses.append(newCharacterClass);
+ m_alternative->m_terms.append(PatternTerm(newCharacterClass, m_invertCharacterClass));
+ }
+
+ void atomParenthesesSubpatternBegin(bool capture = true)
+ {
+ unsigned subpatternId = m_pattern.m_numSubpatterns + 1;
+ if (capture)
+ m_pattern.m_numSubpatterns++;
+
+ PatternDisjunction* parenthesesDisjunction = new PatternDisjunction(m_alternative);
+ m_pattern.m_disjunctions.append(parenthesesDisjunction);
+ m_alternative->m_terms.append(PatternTerm(PatternTerm::TypeParenthesesSubpattern, subpatternId, parenthesesDisjunction, capture, false));
+ m_alternative = parenthesesDisjunction->addNewAlternative();
+ }
+
+ void atomParentheticalAssertionBegin(bool invert = false)
+ {
+ PatternDisjunction* parenthesesDisjunction = new PatternDisjunction(m_alternative);
+ m_pattern.m_disjunctions.append(parenthesesDisjunction);
+ m_alternative->m_terms.append(PatternTerm(PatternTerm::TypeParentheticalAssertion, m_pattern.m_numSubpatterns + 1, parenthesesDisjunction, false, invert));
+ m_alternative = parenthesesDisjunction->addNewAlternative();
+ m_invertParentheticalAssertion = invert;
+ }
+
+ void atomParenthesesEnd()
+ {
+ ASSERT(m_alternative->m_parent);
+ ASSERT(m_alternative->m_parent->m_parent);
+
+ PatternDisjunction* parenthesesDisjunction = m_alternative->m_parent;
+ m_alternative = m_alternative->m_parent->m_parent;
+
+ PatternTerm& lastTerm = m_alternative->lastTerm();
+
+ unsigned numParenAlternatives = parenthesesDisjunction->m_alternatives.size();
+ unsigned numBOLAnchoredAlts = 0;
+
+ for (unsigned i = 0; i < numParenAlternatives; i++) {
+ // Bubble up BOL flags
+ if (parenthesesDisjunction->m_alternatives[i]->m_startsWithBOL)
+ numBOLAnchoredAlts++;
+ }
+
+ if (numBOLAnchoredAlts) {
+ m_alternative->m_containsBOL = true;
+ // If all the alternatives in parens start with BOL, then so does this one
+ if (numBOLAnchoredAlts == numParenAlternatives)
+ m_alternative->m_startsWithBOL = true;
+ }
+
+ lastTerm.parentheses.lastSubpatternId = m_pattern.m_numSubpatterns;
+ m_invertParentheticalAssertion = false;
+ }
+
+ void atomBackReference(unsigned subpatternId)
+ {
+ ASSERT(subpatternId);
+ m_pattern.m_containsBackreferences = true;
+ m_pattern.m_maxBackReference = std::max(m_pattern.m_maxBackReference, subpatternId);
+
+ if (subpatternId > m_pattern.m_numSubpatterns) {
+ m_alternative->m_terms.append(PatternTerm::ForwardReference());
+ return;
+ }
+
+ PatternAlternative* currentAlternative = m_alternative;
+ ASSERT(currentAlternative);
+
+ // Note to self: if we waited until the AST was baked, we could also remove forwards refs
+ while ((currentAlternative = currentAlternative->m_parent->m_parent)) {
+ PatternTerm& term = currentAlternative->lastTerm();
+ ASSERT((term.type == PatternTerm::TypeParenthesesSubpattern) || (term.type == PatternTerm::TypeParentheticalAssertion));
+
+ if ((term.type == PatternTerm::TypeParenthesesSubpattern) && term.capture() && (subpatternId == term.parentheses.subpatternId)) {
+ m_alternative->m_terms.append(PatternTerm::ForwardReference());
+ return;
+ }
+ }
+
+ m_alternative->m_terms.append(PatternTerm(subpatternId));
+ }
+
+ // deep copy the argument disjunction. If filterStartsWithBOL is true,
+ // skip alternatives with m_startsWithBOL set true.
+ PatternDisjunction* copyDisjunction(PatternDisjunction* disjunction, bool filterStartsWithBOL = false)
+ {
+ PatternDisjunction* newDisjunction = 0;
+ for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) {
+ PatternAlternative* alternative = disjunction->m_alternatives[alt];
+ if (!filterStartsWithBOL || !alternative->m_startsWithBOL) {
+ if (!newDisjunction) {
+ newDisjunction = new PatternDisjunction();
+ newDisjunction->m_parent = disjunction->m_parent;
+ }
+ PatternAlternative* newAlternative = newDisjunction->addNewAlternative();
+ for (unsigned i = 0; i < alternative->m_terms.size(); ++i)
+ newAlternative->m_terms.append(copyTerm(alternative->m_terms[i], filterStartsWithBOL));
+ }
+ }
+
+ if (newDisjunction)
+ m_pattern.m_disjunctions.append(newDisjunction);
+ return newDisjunction;
+ }
+
+ PatternTerm copyTerm(PatternTerm& term, bool filterStartsWithBOL = false)
+ {
+ if ((term.type != PatternTerm::TypeParenthesesSubpattern) && (term.type != PatternTerm::TypeParentheticalAssertion))
+ return PatternTerm(term);
+
+ PatternTerm termCopy = term;
+ termCopy.parentheses.disjunction = copyDisjunction(termCopy.parentheses.disjunction, filterStartsWithBOL);
+ return termCopy;
+ }
+
+ void quantifyAtom(unsigned min, unsigned max, bool greedy)
+ {
+ ASSERT(min <= max);
+ ASSERT(m_alternative->m_terms.size());
+
+ if (!max) {
+ m_alternative->removeLastTerm();
+ return;
+ }
+
+ PatternTerm& term = m_alternative->lastTerm();
+ ASSERT(term.type > PatternTerm::TypeAssertionWordBoundary);
+ ASSERT((term.quantityCount == 1) && (term.quantityType == QuantifierFixedCount));
+
+ // For any assertion with a zero minimum, not matching is valid and has no effect,
+ // remove it. Otherwise, we need to match as least once, but there is no point
+ // matching more than once, so remove the quantifier. It is not entirely clear
+ // from the spec whether or not this behavior is correct, but I believe this
+ // matches Firefox. :-/
+ if (term.type == PatternTerm::TypeParentheticalAssertion) {
+ if (!min)
+ m_alternative->removeLastTerm();
+ return;
+ }
+
+ if (min == 0)
+ term.quantify(max, greedy ? QuantifierGreedy : QuantifierNonGreedy);
+ else if (min == max)
+ term.quantify(min, QuantifierFixedCount);
+ else {
+ term.quantify(min, QuantifierFixedCount);
+ m_alternative->m_terms.append(copyTerm(term));
+ // NOTE: this term is interesting from an analysis perspective, in that it can be ignored.....
+ m_alternative->lastTerm().quantify((max == quantifyInfinite) ? max : max - min, greedy ? QuantifierGreedy : QuantifierNonGreedy);
+ if (m_alternative->lastTerm().type == PatternTerm::TypeParenthesesSubpattern)
+ m_alternative->lastTerm().parentheses.isCopy = true;
+ }
+ }
+
+ void disjunction()
+ {
+ m_alternative = m_alternative->m_parent->addNewAlternative();
+ }
+
+ unsigned setupAlternativeOffsets(PatternAlternative* alternative, unsigned currentCallFrameSize, unsigned initialInputPosition)
+ {
+ alternative->m_hasFixedSize = true;
+ unsigned currentInputPosition = initialInputPosition;
+
+ for (unsigned i = 0; i < alternative->m_terms.size(); ++i) {
+ PatternTerm& term = alternative->m_terms[i];
+
+ switch (term.type) {
+ case PatternTerm::TypeAssertionBOL:
+ case PatternTerm::TypeAssertionEOL:
+ case PatternTerm::TypeAssertionWordBoundary:
+ term.inputPosition = currentInputPosition;
+ break;
+
+ case PatternTerm::TypeBackReference:
+ term.inputPosition = currentInputPosition;
+ term.frameLocation = currentCallFrameSize;
+ currentCallFrameSize += YarrStackSpaceForBackTrackInfoBackReference;
+ alternative->m_hasFixedSize = false;
+ break;
+
+ case PatternTerm::TypeForwardReference:
+ break;
+
+ case PatternTerm::TypePatternCharacter:
+ term.inputPosition = currentInputPosition;
+ if (term.quantityType != QuantifierFixedCount) {
+ term.frameLocation = currentCallFrameSize;
+ currentCallFrameSize += YarrStackSpaceForBackTrackInfoPatternCharacter;
+ alternative->m_hasFixedSize = false;
+ } else
+ currentInputPosition += term.quantityCount;
+ break;
+
+ case PatternTerm::TypeCharacterClass:
+ term.inputPosition = currentInputPosition;
+ if (term.quantityType != QuantifierFixedCount) {
+ term.frameLocation = currentCallFrameSize;
+ currentCallFrameSize += YarrStackSpaceForBackTrackInfoCharacterClass;
+ alternative->m_hasFixedSize = false;
+ } else
+ currentInputPosition += term.quantityCount;
+ break;
+
+ case PatternTerm::TypeParenthesesSubpattern:
+ // Note: for fixed once parentheses we will ensure at least the minimum is available; others are on their own.
+ term.frameLocation = currentCallFrameSize;
+ if (term.quantityCount == 1 && !term.parentheses.isCopy) {
+ if (term.quantityType != QuantifierFixedCount)
+ currentCallFrameSize += YarrStackSpaceForBackTrackInfoParenthesesOnce;
+ currentCallFrameSize = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize, currentInputPosition);
+ // If quantity is fixed, then pre-check its minimum size.
+ if (term.quantityType == QuantifierFixedCount)
+ currentInputPosition += term.parentheses.disjunction->m_minimumSize;
+ term.inputPosition = currentInputPosition;
+ } else if (term.parentheses.isTerminal) {
+ currentCallFrameSize += YarrStackSpaceForBackTrackInfoParenthesesTerminal;
+ currentCallFrameSize = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize, currentInputPosition);
+ term.inputPosition = currentInputPosition;
+ } else {
+ term.inputPosition = currentInputPosition;
+ setupDisjunctionOffsets(term.parentheses.disjunction, 0, currentInputPosition);
+ currentCallFrameSize += YarrStackSpaceForBackTrackInfoParentheses;
+ }
+ // Fixed count of 1 could be accepted, if they have a fixed size *AND* if all alternatives are of the same length.
+ alternative->m_hasFixedSize = false;
+ break;
+
+ case PatternTerm::TypeParentheticalAssertion:
+ term.inputPosition = currentInputPosition;
+ term.frameLocation = currentCallFrameSize;
+ currentCallFrameSize = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize + YarrStackSpaceForBackTrackInfoParentheticalAssertion, currentInputPosition);
+ break;
+
+ case PatternTerm::TypeDotStarEnclosure:
+ alternative->m_hasFixedSize = false;
+ term.inputPosition = initialInputPosition;
+ break;
+ }
+ }
+
+ alternative->m_minimumSize = currentInputPosition - initialInputPosition;
+ return currentCallFrameSize;
+ }
+
+ unsigned setupDisjunctionOffsets(PatternDisjunction* disjunction, unsigned initialCallFrameSize, unsigned initialInputPosition)
+ {
+ if ((disjunction != m_pattern.m_body) && (disjunction->m_alternatives.size() > 1))
+ initialCallFrameSize += YarrStackSpaceForBackTrackInfoAlternative;
+
+ unsigned minimumInputSize = UINT_MAX;
+ unsigned maximumCallFrameSize = 0;
+ bool hasFixedSize = true;
+
+ for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) {
+ PatternAlternative* alternative = disjunction->m_alternatives[alt];
+ unsigned currentAlternativeCallFrameSize = setupAlternativeOffsets(alternative, initialCallFrameSize, initialInputPosition);
+ minimumInputSize = min(minimumInputSize, alternative->m_minimumSize);
+ maximumCallFrameSize = max(maximumCallFrameSize, currentAlternativeCallFrameSize);
+ hasFixedSize &= alternative->m_hasFixedSize;
+ }
+
+ ASSERT(minimumInputSize != UINT_MAX);
+ ASSERT(maximumCallFrameSize >= initialCallFrameSize);
+
+ disjunction->m_hasFixedSize = hasFixedSize;
+ disjunction->m_minimumSize = minimumInputSize;
+ disjunction->m_callFrameSize = maximumCallFrameSize;
+ return maximumCallFrameSize;
+ }
+
+ void setupOffsets()
+ {
+ setupDisjunctionOffsets(m_pattern.m_body, 0, 0);
+ }
+
+ // This optimization identifies sets of parentheses that we will never need to backtrack.
+ // In these cases we do not need to store state from prior iterations.
+ // We can presently avoid backtracking for:
+ // * where the parens are at the end of the regular expression (last term in any of the
+ // alternatives of the main body disjunction).
+ // * where the parens are non-capturing, and quantified unbounded greedy (*).
+ // * where the parens do not contain any capturing subpatterns.
+ void checkForTerminalParentheses()
+ {
+ // This check is much too crude; should be just checking whether the candidate
+ // node contains nested capturing subpatterns, not the whole expression!
+ if (m_pattern.m_numSubpatterns)
+ return;
+
+ Vector<PatternAlternative*>& alternatives = m_pattern.m_body->m_alternatives;
+ for (size_t i = 0; i < alternatives.size(); ++i) {
+ Vector<PatternTerm>& terms = alternatives[i]->m_terms;
+ if (terms.size()) {
+ PatternTerm& term = terms.last();
+ if (term.type == PatternTerm::TypeParenthesesSubpattern
+ && term.quantityType == QuantifierGreedy
+ && term.quantityCount == quantifyInfinite
+ && !term.capture())
+ term.parentheses.isTerminal = true;
+ }
+ }
+ }
+
+ void optimizeBOL()
+ {
+ // Look for expressions containing beginning of line (^) anchoring and unroll them.
+ // e.g. /^a|^b|c/ becomes /^a|^b|c/ which is executed once followed by /c/ which loops
+ // This code relies on the parsing code tagging alternatives with m_containsBOL and
+ // m_startsWithBOL and rolling those up to containing alternatives.
+ // At this point, this is only valid for non-multiline expressions.
+ PatternDisjunction* disjunction = m_pattern.m_body;
+
+ if (!m_pattern.m_containsBOL || m_pattern.m_multiline)
+ return;
+
+ PatternDisjunction* loopDisjunction = copyDisjunction(disjunction, true);
+
+ // Set alternatives in disjunction to "onceThrough"
+ for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt)
+ disjunction->m_alternatives[alt]->setOnceThrough();
+
+ if (loopDisjunction) {
+ // Move alternatives from loopDisjunction to disjunction
+ for (unsigned alt = 0; alt < loopDisjunction->m_alternatives.size(); ++alt)
+ disjunction->m_alternatives.append(loopDisjunction->m_alternatives[alt]);
+
+ loopDisjunction->m_alternatives.clear();
+ }
+ }
+
+ bool containsCapturingTerms(PatternAlternative* alternative, size_t firstTermIndex, size_t lastTermIndex)
+ {
+ Vector<PatternTerm>& terms = alternative->m_terms;
+
+ for (size_t termIndex = firstTermIndex; termIndex <= lastTermIndex; ++termIndex) {
+ PatternTerm& term = terms[termIndex];
+
+ if (term.m_capture)
+ return true;
+
+ if (term.type == PatternTerm::TypeParenthesesSubpattern) {
+ PatternDisjunction* nestedDisjunction = term.parentheses.disjunction;
+ for (unsigned alt = 0; alt < nestedDisjunction->m_alternatives.size(); ++alt) {
+ if (containsCapturingTerms(nestedDisjunction->m_alternatives[alt], 0, nestedDisjunction->m_alternatives[alt]->m_terms.size() - 1))
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ // This optimization identifies alternatives in the form of
+ // [^].*[?]<expression>.*[$] for expressions that don't have any
+ // capturing terms. The alternative is changed to <expression>
+ // followed by processing of the dot stars to find and adjust the
+ // beginning and the end of the match.
+ void optimizeDotStarWrappedExpressions()
+ {
+ Vector<PatternAlternative*>& alternatives = m_pattern.m_body->m_alternatives;
+ if (alternatives.size() != 1)
+ return;
+
+ PatternAlternative* alternative = alternatives[0];
+ Vector<PatternTerm>& terms = alternative->m_terms;
+ if (terms.size() >= 3) {
+ bool startsWithBOL = false;
+ bool endsWithEOL = false;
+ size_t termIndex, firstExpressionTerm, lastExpressionTerm;
+
+ termIndex = 0;
+ if (terms[termIndex].type == PatternTerm::TypeAssertionBOL) {
+ startsWithBOL = true;
+ ++termIndex;
+ }
+
+ PatternTerm& firstNonAnchorTerm = terms[termIndex];
+ if ((firstNonAnchorTerm.type != PatternTerm::TypeCharacterClass) || (firstNonAnchorTerm.characterClass != m_pattern.newlineCharacterClass()) || !((firstNonAnchorTerm.quantityType == QuantifierGreedy) || (firstNonAnchorTerm.quantityType == QuantifierNonGreedy)))
+ return;
+
+ firstExpressionTerm = termIndex + 1;
+
+ termIndex = terms.size() - 1;
+ if (terms[termIndex].type == PatternTerm::TypeAssertionEOL) {
+ endsWithEOL = true;
+ --termIndex;
+ }
+
+ PatternTerm& lastNonAnchorTerm = terms[termIndex];
+ if ((lastNonAnchorTerm.type != PatternTerm::TypeCharacterClass) || (lastNonAnchorTerm.characterClass != m_pattern.newlineCharacterClass()) || (lastNonAnchorTerm.quantityType != QuantifierGreedy))
+ return;
+
+ lastExpressionTerm = termIndex - 1;
+
+ if (firstExpressionTerm > lastExpressionTerm)
+ return;
+
+ if (!containsCapturingTerms(alternative, firstExpressionTerm, lastExpressionTerm)) {
+ for (termIndex = terms.size() - 1; termIndex > lastExpressionTerm; --termIndex)
+ terms.remove(termIndex);
+
+ for (termIndex = firstExpressionTerm; termIndex > 0; --termIndex)
+ terms.remove(termIndex - 1);
+
+ terms.append(PatternTerm(startsWithBOL, endsWithEOL));
+
+ m_pattern.m_containsBOL = false;
+ }
+ }
+ }
+
+private:
+ YarrPattern& m_pattern;
+ PatternAlternative* m_alternative;
+ CharacterClassConstructor m_characterClassConstructor;
+ bool m_invertCharacterClass;
+ bool m_invertParentheticalAssertion;
+};
+
+const char* YarrPattern::compile(const UString& patternString)
+{
+ YarrPatternConstructor constructor(*this);
+
+ if (const char* error = parse(constructor, patternString))
+ return error;
+
+ // If the pattern contains illegal backreferences reset & reparse.
+ // Quoting Netscape's "What's new in JavaScript 1.2",
+ // "Note: if the number of left parentheses is less than the number specified
+ // in \#, the \# is taken as an octal escape as described in the next row."
+ if (containsIllegalBackReference()) {
+ unsigned numSubpatterns = m_numSubpatterns;
+
+ constructor.reset();
+#if !ASSERT_DISABLED
+ const char* error =
+#endif
+ parse(constructor, patternString, numSubpatterns);
+
+ ASSERT(!error);
+ ASSERT(numSubpatterns == m_numSubpatterns);
+ }
+
+ constructor.checkForTerminalParentheses();
+ constructor.optimizeDotStarWrappedExpressions();
+ constructor.optimizeBOL();
+
+ constructor.setupOffsets();
+
+ return 0;
+}
+
+YarrPattern::YarrPattern(const UString& pattern, bool ignoreCase, bool multiline, const char** error)
+ : m_ignoreCase(ignoreCase)
+ , m_multiline(multiline)
+ , m_containsBackreferences(false)
+ , m_containsBOL(false)
+ , m_numSubpatterns(0)
+ , m_maxBackReference(0)
+ , newlineCached(0)
+ , digitsCached(0)
+ , spacesCached(0)
+ , wordcharCached(0)
+ , nondigitsCached(0)
+ , nonspacesCached(0)
+ , nonwordcharCached(0)
+{
+ *error = compile(pattern);
+}
+
+} }
--- /dev/null
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Peter Varga (pvarga@inf.u-szeged.hu), University of Szeged
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef YarrPattern_h
+#define YarrPattern_h
+
+#include <runtime/UString.h>
+#include <wtf/Vector.h>
+#include <wtf/unicode/Unicode.h>
+
+namespace JSC { namespace Yarr {
+
+struct PatternDisjunction;
+
+struct CharacterRange {
+ UChar begin;
+ UChar end;
+
+ CharacterRange(UChar begin, UChar end)
+ : begin(begin)
+ , end(end)
+ {
+ }
+};
+
+struct CharacterClassTable : RefCounted<CharacterClassTable> {
+ const char* m_table;
+ bool m_inverted;
+ static PassRefPtr<CharacterClassTable> create(const char* table, bool inverted)
+ {
+ return adoptRef(new CharacterClassTable(table, inverted));
+ }
+
+private:
+ CharacterClassTable(const char* table, bool inverted)
+ : m_table(table)
+ , m_inverted(inverted)
+ {
+ }
+};
+
+struct CharacterClass {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ // All CharacterClass instances have to have the full set of matches and ranges,
+ // they may have an optional table for faster lookups (which must match the
+ // specified matches and ranges)
+ CharacterClass(PassRefPtr<CharacterClassTable> table)
+ : m_table(table)
+ {
+ }
+ Vector<UChar> m_matches;
+ Vector<CharacterRange> m_ranges;
+ Vector<UChar> m_matchesUnicode;
+ Vector<CharacterRange> m_rangesUnicode;
+ RefPtr<CharacterClassTable> m_table;
+};
+
+enum QuantifierType {
+ QuantifierFixedCount,
+ QuantifierGreedy,
+ QuantifierNonGreedy,
+};
+
+struct PatternTerm {
+ enum Type {
+ TypeAssertionBOL,
+ TypeAssertionEOL,
+ TypeAssertionWordBoundary,
+ TypePatternCharacter,
+ TypeCharacterClass,
+ TypeBackReference,
+ TypeForwardReference,
+ TypeParenthesesSubpattern,
+ TypeParentheticalAssertion,
+ TypeDotStarEnclosure,
+ } type;
+ bool m_capture :1;
+ bool m_invert :1;
+ union {
+ UChar patternCharacter;
+ CharacterClass* characterClass;
+ unsigned backReferenceSubpatternId;
+ struct {
+ PatternDisjunction* disjunction;
+ unsigned subpatternId;
+ unsigned lastSubpatternId;
+ bool isCopy;
+ bool isTerminal;
+ } parentheses;
+ struct {
+ bool bolAnchor : 1;
+ bool eolAnchor : 1;
+ } anchors;
+ };
+ QuantifierType quantityType;
+ unsigned quantityCount;
+ int inputPosition;
+ unsigned frameLocation;
+
+ PatternTerm(UChar ch)
+ : type(PatternTerm::TypePatternCharacter)
+ , m_capture(false)
+ , m_invert(false)
+ {
+ patternCharacter = ch;
+ quantityType = QuantifierFixedCount;
+ quantityCount = 1;
+ }
+
+ PatternTerm(CharacterClass* charClass, bool invert)
+ : type(PatternTerm::TypeCharacterClass)
+ , m_capture(false)
+ , m_invert(invert)
+ {
+ characterClass = charClass;
+ quantityType = QuantifierFixedCount;
+ quantityCount = 1;
+ }
+
+ PatternTerm(Type type, unsigned subpatternId, PatternDisjunction* disjunction, bool capture = false, bool invert = false)
+ : type(type)
+ , m_capture(capture)
+ , m_invert(invert)
+ {
+ parentheses.disjunction = disjunction;
+ parentheses.subpatternId = subpatternId;
+ parentheses.isCopy = false;
+ parentheses.isTerminal = false;
+ quantityType = QuantifierFixedCount;
+ quantityCount = 1;
+ }
+
+ PatternTerm(Type type, bool invert = false)
+ : type(type)
+ , m_capture(false)
+ , m_invert(invert)
+ {
+ quantityType = QuantifierFixedCount;
+ quantityCount = 1;
+ }
+
+ PatternTerm(unsigned spatternId)
+ : type(TypeBackReference)
+ , m_capture(false)
+ , m_invert(false)
+ {
+ backReferenceSubpatternId = spatternId;
+ quantityType = QuantifierFixedCount;
+ quantityCount = 1;
+ }
+
+ PatternTerm(bool bolAnchor, bool eolAnchor)
+ : type(TypeDotStarEnclosure)
+ , m_capture(false)
+ , m_invert(false)
+ {
+ anchors.bolAnchor = bolAnchor;
+ anchors.eolAnchor = eolAnchor;
+ quantityType = QuantifierFixedCount;
+ quantityCount = 1;
+ }
+
+ static PatternTerm ForwardReference()
+ {
+ return PatternTerm(TypeForwardReference);
+ }
+
+ static PatternTerm BOL()
+ {
+ return PatternTerm(TypeAssertionBOL);
+ }
+
+ static PatternTerm EOL()
+ {
+ return PatternTerm(TypeAssertionEOL);
+ }
+
+ static PatternTerm WordBoundary(bool invert)
+ {
+ return PatternTerm(TypeAssertionWordBoundary, invert);
+ }
+
+ bool invert()
+ {
+ return m_invert;
+ }
+
+ bool capture()
+ {
+ return m_capture;
+ }
+
+ void quantify(unsigned count, QuantifierType type)
+ {
+ quantityCount = count;
+ quantityType = type;
+ }
+};
+
+struct PatternAlternative {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ PatternAlternative(PatternDisjunction* disjunction)
+ : m_parent(disjunction)
+ , m_onceThrough(false)
+ , m_hasFixedSize(false)
+ , m_startsWithBOL(false)
+ , m_containsBOL(false)
+ {
+ }
+
+ PatternTerm& lastTerm()
+ {
+ ASSERT(m_terms.size());
+ return m_terms[m_terms.size() - 1];
+ }
+
+ void removeLastTerm()
+ {
+ ASSERT(m_terms.size());
+ m_terms.shrink(m_terms.size() - 1);
+ }
+
+ void setOnceThrough()
+ {
+ m_onceThrough = true;
+ }
+
+ bool onceThrough()
+ {
+ return m_onceThrough;
+ }
+
+ Vector<PatternTerm> m_terms;
+ PatternDisjunction* m_parent;
+ unsigned m_minimumSize;
+ bool m_onceThrough : 1;
+ bool m_hasFixedSize : 1;
+ bool m_startsWithBOL : 1;
+ bool m_containsBOL : 1;
+};
+
+struct PatternDisjunction {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ PatternDisjunction(PatternAlternative* parent = 0)
+ : m_parent(parent)
+ , m_hasFixedSize(false)
+ {
+ }
+
+ ~PatternDisjunction()
+ {
+ deleteAllValues(m_alternatives);
+ }
+
+ PatternAlternative* addNewAlternative()
+ {
+ PatternAlternative* alternative = new PatternAlternative(this);
+ m_alternatives.append(alternative);
+ return alternative;
+ }
+
+ Vector<PatternAlternative*> m_alternatives;
+ PatternAlternative* m_parent;
+ unsigned m_minimumSize;
+ unsigned m_callFrameSize;
+ bool m_hasFixedSize;
+};
+
+// You probably don't want to be calling these functions directly
+// (please to be calling newlineCharacterClass() et al on your
+// friendly neighborhood YarrPattern instance to get nicely
+// cached copies).
+CharacterClass* newlineCreate();
+CharacterClass* digitsCreate();
+CharacterClass* spacesCreate();
+CharacterClass* wordcharCreate();
+CharacterClass* nondigitsCreate();
+CharacterClass* nonspacesCreate();
+CharacterClass* nonwordcharCreate();
+
+struct TermChain {
+ TermChain(PatternTerm term)
+ : term(term)
+ {}
+
+ PatternTerm term;
+ Vector<TermChain> hotTerms;
+};
+
+struct YarrPattern {
+ YarrPattern(const UString& pattern, bool ignoreCase, bool multiline, const char** error);
+
+ ~YarrPattern()
+ {
+ deleteAllValues(m_disjunctions);
+ deleteAllValues(m_userCharacterClasses);
+ }
+
+ void reset()
+ {
+ m_numSubpatterns = 0;
+ m_maxBackReference = 0;
+
+ m_containsBackreferences = false;
+ m_containsBOL = false;
+
+ newlineCached = 0;
+ digitsCached = 0;
+ spacesCached = 0;
+ wordcharCached = 0;
+ nondigitsCached = 0;
+ nonspacesCached = 0;
+ nonwordcharCached = 0;
+
+ deleteAllValues(m_disjunctions);
+ m_disjunctions.clear();
+ deleteAllValues(m_userCharacterClasses);
+ m_userCharacterClasses.clear();
+ }
+
+ bool containsIllegalBackReference()
+ {
+ return m_maxBackReference > m_numSubpatterns;
+ }
+
+ CharacterClass* newlineCharacterClass()
+ {
+ if (!newlineCached)
+ m_userCharacterClasses.append(newlineCached = newlineCreate());
+ return newlineCached;
+ }
+ CharacterClass* digitsCharacterClass()
+ {
+ if (!digitsCached)
+ m_userCharacterClasses.append(digitsCached = digitsCreate());
+ return digitsCached;
+ }
+ CharacterClass* spacesCharacterClass()
+ {
+ if (!spacesCached)
+ m_userCharacterClasses.append(spacesCached = spacesCreate());
+ return spacesCached;
+ }
+ CharacterClass* wordcharCharacterClass()
+ {
+ if (!wordcharCached)
+ m_userCharacterClasses.append(wordcharCached = wordcharCreate());
+ return wordcharCached;
+ }
+ CharacterClass* nondigitsCharacterClass()
+ {
+ if (!nondigitsCached)
+ m_userCharacterClasses.append(nondigitsCached = nondigitsCreate());
+ return nondigitsCached;
+ }
+ CharacterClass* nonspacesCharacterClass()
+ {
+ if (!nonspacesCached)
+ m_userCharacterClasses.append(nonspacesCached = nonspacesCreate());
+ return nonspacesCached;
+ }
+ CharacterClass* nonwordcharCharacterClass()
+ {
+ if (!nonwordcharCached)
+ m_userCharacterClasses.append(nonwordcharCached = nonwordcharCreate());
+ return nonwordcharCached;
+ }
+
+ bool m_ignoreCase : 1;
+ bool m_multiline : 1;
+ bool m_containsBackreferences : 1;
+ bool m_containsBOL : 1;
+ unsigned m_numSubpatterns;
+ unsigned m_maxBackReference;
+ PatternDisjunction* m_body;
+ Vector<PatternDisjunction*, 4> m_disjunctions;
+ Vector<CharacterClass*> m_userCharacterClasses;
+
+private:
+ const char* compile(const UString& patternString);
+
+ CharacterClass* newlineCached;
+ CharacterClass* digitsCached;
+ CharacterClass* spacesCached;
+ CharacterClass* wordcharCached;
+ CharacterClass* nondigitsCached;
+ CharacterClass* nonspacesCached;
+ CharacterClass* nonwordcharCached;
+};
+
+} } // namespace JSC::Yarr
+
+#endif // YarrPattern_h
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "YarrSyntaxChecker.h"
+
+#include "YarrParser.h"
+
+namespace JSC { namespace Yarr {
+
+class SyntaxChecker {
+public:
+ void assertionBOL() {}
+ void assertionEOL() {}
+ void assertionWordBoundary(bool) {}
+ void atomPatternCharacter(UChar) {}
+ void atomBuiltInCharacterClass(BuiltInCharacterClassID, bool) {}
+ void atomCharacterClassBegin(bool = false) {}
+ void atomCharacterClassAtom(UChar) {}
+ void atomCharacterClassRange(UChar, UChar) {}
+ void atomCharacterClassBuiltIn(BuiltInCharacterClassID, bool) {}
+ void atomCharacterClassEnd() {}
+ void atomParenthesesSubpatternBegin(bool = true) {}
+ void atomParentheticalAssertionBegin(bool = false) {}
+ void atomParenthesesEnd() {}
+ void atomBackReference(unsigned) {}
+ void quantifyAtom(unsigned, unsigned, bool) {}
+ void disjunction() {}
+};
+
+const char* checkSyntax(const UString& pattern)
+{
+ SyntaxChecker syntaxChecker;
+ return parse(syntaxChecker, pattern);
+}
+
+}} // JSC::YARR
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef YarrSyntaxChecker_h
+#define YarrSyntaxChecker_h
+
+#include <runtime/UString.h>
+
+namespace JSC { namespace Yarr {
+
+const char* checkSyntax(const UString& pattern);
+
+}} // JSC::YARR
+
+#endif // YarrSyntaxChecker_h
+
--- /dev/null
+# Yet Another Regex Runtime - Qt4 build info
+
+SOURCES += \
+ yarr/YarrInterpreter.cpp \
+ yarr/YarrPattern.cpp \
+ yarr/YarrSyntaxChecker.cpp
+