summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/runtime/JSObject.cpp
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@nokia.com>2012-02-24 16:36:50 +0100
committerSimon Hausmann <simon.hausmann@nokia.com>2012-02-24 16:36:50 +0100
commitad0d549d4cc13433f77c1ac8f0ab379c83d93f28 (patch)
treeb34b0daceb7c8e7fdde4b4ec43650ab7caadb0a9 /Source/JavaScriptCore/runtime/JSObject.cpp
parent03e12282df9aa1e1fb05a8b90f1cfc2e08764cec (diff)
downloadqtwebkit-ad0d549d4cc13433f77c1ac8f0ab379c83d93f28.tar.gz
Imported WebKit commit bb52bf3c0119e8a128cd93afe5572413a8617de9 (http://svn.webkit.org/repository/webkit/trunk@108790)
Diffstat (limited to 'Source/JavaScriptCore/runtime/JSObject.cpp')
-rw-r--r--Source/JavaScriptCore/runtime/JSObject.cpp158
1 files changed, 86 insertions, 72 deletions
diff --git a/Source/JavaScriptCore/runtime/JSObject.cpp b/Source/JavaScriptCore/runtime/JSObject.cpp
index ba2d2a52a..acc4a181e 100644
--- a/Source/JavaScriptCore/runtime/JSObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSObject.cpp
@@ -24,7 +24,7 @@
#include "config.h"
#include "JSObject.h"
-#include "BumpSpaceInlineMethods.h"
+#include "CopiedSpaceInlineMethods.h"
#include "DatePrototype.h"
#include "ErrorConstructor.h"
#include "GetterSetter.h"
@@ -48,6 +48,7 @@ ASSERT_CLASS_FITS_IN_CELL(JSNonFinalObject);
ASSERT_CLASS_FITS_IN_CELL(JSFinalObject);
ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSObject);
+ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSFinalObject);
const char* StrictModeReadonlyPropertyWriteError = "Attempted to assign to readonly property.";
@@ -55,16 +56,6 @@ const ClassInfo JSObject::s_info = { "Object", 0, 0, 0, CREATE_METHOD_TABLE(JSOb
const ClassInfo JSFinalObject::s_info = { "Object", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSFinalObject) };
-void JSFinalObject::destroy(JSCell* cell)
-{
- jsCast<JSFinalObject*>(cell)->JSFinalObject::~JSFinalObject();
-}
-
-void JSNonFinalObject::destroy(JSCell* cell)
-{
- jsCast<JSNonFinalObject*>(cell)->JSNonFinalObject::~JSNonFinalObject();
-}
-
static inline void getClassPropertyNames(ExecState* exec, const ClassInfo* classInfo, PropertyNameArray& propertyNames, EnumerationMode mode)
{
// Add properties from the static hashtables of properties
@@ -84,11 +75,6 @@ static inline void getClassPropertyNames(ExecState* exec, const ClassInfo* class
}
}
-void JSObject::destroy(JSCell* cell)
-{
- jsCast<JSObject*>(cell)->JSObject::~JSObject();
-}
-
void JSObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
JSObject* thisObject = jsCast<JSObject*>(cell);
@@ -146,47 +132,36 @@ void JSObject::put(JSCell* cell, ExecState* exec, const Identifier& propertyName
ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject));
JSGlobalData& globalData = exec->globalData();
- if (propertyName == exec->propertyNames().underscoreProto) {
- // Setting __proto__ to a non-object, non-null value is silently ignored to match Mozilla.
- if (!value.isObject() && !value.isNull())
- return;
-
- if (!thisObject->isExtensible()) {
- if (slot.isStrictMode())
- throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
- return;
- }
-
- if (!thisObject->setPrototypeWithCycleCheck(globalData, value))
- throwError(exec, createError(exec, "cyclic __proto__ value"));
- return;
- }
-
// Check if there are any setters or getters in the prototype chain
JSValue prototype;
- for (JSObject* obj = thisObject; !obj->structure()->hasGetterSetterProperties(); obj = asObject(prototype)) {
- prototype = obj->prototype();
- if (prototype.isNull()) {
- if (!thisObject->putDirectInternal<PutModePut>(globalData, propertyName, value, 0, slot, getJSFunction(value)) && slot.isStrictMode())
- throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
- return;
+ if (propertyName != exec->propertyNames().underscoreProto) {
+ for (JSObject* obj = thisObject; !obj->structure()->hasReadOnlyOrGetterSetterPropertiesExcludingProto(); obj = asObject(prototype)) {
+ prototype = obj->prototype();
+ if (prototype.isNull()) {
+ if (!thisObject->putDirectInternal<PutModePut>(globalData, propertyName, value, 0, slot, getJSFunction(value)) && slot.isStrictMode())
+ throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
+ return;
+ }
}
}
-
- unsigned attributes;
- JSCell* specificValue;
- if ((thisObject->structure()->get(globalData, propertyName, attributes, specificValue) != WTF::notFound) && attributes & ReadOnly) {
- if (slot.isStrictMode())
- throwError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError));
- return;
- }
for (JSObject* obj = thisObject; ; obj = asObject(prototype)) {
- if (JSValue gs = obj->getDirect(globalData, propertyName)) {
+ unsigned attributes;
+ JSCell* specificValue;
+ size_t offset = obj->structure()->get(globalData, propertyName, attributes, specificValue);
+ if (offset != WTF::notFound) {
+ if (attributes & ReadOnly) {
+ if (slot.isStrictMode())
+ throwError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError));
+ return;
+ }
+
+ JSValue gs = obj->getDirectOffset(offset);
if (gs.isGetterSetter()) {
JSObject* setterFunc = asGetterSetter(gs)->setter();
if (!setterFunc) {
- throwSetterError(exec);
+ if (slot.isStrictMode())
+ throwSetterError(exec);
return;
}
@@ -229,10 +204,31 @@ void JSObject::putDirectVirtual(JSObject* object, ExecState* exec, const Identif
object->putDirectInternal<PutModeDefineOwnProperty>(exec->globalData(), propertyName, value, attributes, slot, getJSFunction(value));
}
+bool JSObject::setPrototypeWithCycleCheck(JSGlobalData& globalData, JSValue prototype)
+{
+ JSValue checkFor = this;
+ if (this->isGlobalObject())
+ checkFor = static_cast<JSGlobalObject*>(this)->globalExec()->thisValue();
+
+ JSValue nextPrototype = prototype;
+ while (nextPrototype && nextPrototype.isObject()) {
+ if (nextPrototype == checkFor)
+ return false;
+ nextPrototype = asObject(nextPrototype)->prototype();
+ }
+ setPrototype(globalData, prototype);
+ return true;
+}
+
+bool JSObject::allowsAccessFrom(ExecState* exec)
+{
+ JSGlobalObject* globalObject = isGlobalThis() ? static_cast<JSGlobalThis*>(this)->unwrappedObject() : this->globalObject();
+ return globalObject->globalObjectMethodTable()->allowsAccessFrom(globalObject, exec);
+}
+
void JSObject::putDirectAccessor(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
{
ASSERT(value.isGetterSetter() && (attributes & Accessor));
- ASSERT(propertyName != globalData.propertyNames->underscoreProto);
PutPropertySlot slot;
putDirectInternal<PutModeDefineOwnProperty>(globalData, propertyName, value, attributes, slot, getJSFunction(value));
@@ -243,7 +239,10 @@ void JSObject::putDirectAccessor(JSGlobalData& globalData, const Identifier& pro
if (slot.type() != PutPropertySlot::NewProperty)
setStructure(globalData, Structure::attributeChangeTransition(globalData, structure(), propertyName, attributes));
- structure()->setHasGetterSetterProperties(true);
+ if (attributes & ReadOnly)
+ structure()->setContainsReadOnlyProperties();
+
+ structure()->setHasGetterSetterProperties(propertyName == globalData.propertyNames->underscoreProto);
}
bool JSObject::hasProperty(ExecState* exec, const Identifier& propertyName) const
@@ -269,7 +268,7 @@ bool JSObject::deleteProperty(JSCell* cell, ExecState* exec, const Identifier& p
unsigned attributes;
JSCell* specificValue;
if (thisObject->structure()->get(exec->globalData(), propertyName, attributes, specificValue) != WTF::notFound) {
- if ((attributes & DontDelete))
+ if (attributes & DontDelete && !exec->globalData().isInDefineOwnProperty())
return false;
thisObject->removeDirect(exec->globalData(), propertyName);
return true;
@@ -277,7 +276,7 @@ bool JSObject::deleteProperty(JSCell* cell, ExecState* exec, const Identifier& p
// Look in the static hashtable of properties
const HashEntry* entry = thisObject->findPropertyHashEntry(exec, propertyName);
- if (entry && entry->attributes() & DontDelete)
+ if (entry && entry->attributes() & DontDelete && !exec->globalData().isInDefineOwnProperty())
return false; // this builtin property can't be deleted
// FIXME: Should the code here actually do some deletion?
@@ -479,6 +478,8 @@ void JSObject::freeze(JSGlobalData& globalData)
void JSObject::preventExtensions(JSGlobalData& globalData)
{
+ if (isJSArray(this))
+ asArray(this)->enterDictionaryMode(globalData);
if (isExtensible())
setStructure(globalData, Structure::preventExtensionsTransition(globalData, structure()));
}
@@ -623,6 +624,8 @@ static bool putDescriptor(ExecState* exec, JSObject* target, const Identifier& p
else if (oldDescriptor.value())
newValue = oldDescriptor.value();
target->putDirect(exec->globalData(), propertyName, newValue, attributes & ~Accessor);
+ if (attributes & ReadOnly)
+ target->structure()->setContainsReadOnlyProperties();
return true;
}
attributes &= ~ReadOnly;
@@ -641,12 +644,30 @@ static bool putDescriptor(ExecState* exec, JSObject* target, const Identifier& p
return true;
}
+class DefineOwnPropertyScope {
+public:
+ DefineOwnPropertyScope(ExecState* exec)
+ : m_globalData(exec->globalData())
+ {
+ m_globalData.setInDefineOwnProperty(true);
+ }
+
+ ~DefineOwnPropertyScope()
+ {
+ m_globalData.setInDefineOwnProperty(false);
+ }
+
+private:
+ JSGlobalData& m_globalData;
+};
+
bool JSObject::defineOwnProperty(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor, bool throwException)
{
- // __proto__ is magic; we don't currently support setting it as a regular property.
- // Silent filter out calls to set __proto__ at an early stage; pretend all is okay.
- if (propertyName == exec->propertyNames().underscoreProto)
- return true;
+ // Track on the globaldata that we're in define property.
+ // Currently DefineOwnProperty uses delete to remove properties when they are being replaced
+ // (particularly when changing attributes), however delete won't allow non-configurable (i.e.
+ // DontDelete) properties to be deleted. For now, we can use this flag to make this work.
+ DefineOwnPropertyScope scope(exec);
// If we have a new property we can just put it on normally
PropertyDescriptor current;
@@ -711,21 +732,15 @@ bool JSObject::defineOwnProperty(JSObject* object, ExecState* exec, const Identi
return false;
}
if (!current.writable()) {
- if (descriptor.value() || !sameValue(exec, current.value(), descriptor.value())) {
+ if (descriptor.value() && !sameValue(exec, current.value(), descriptor.value())) {
if (throwException)
throwError(exec, createTypeError(exec, "Attempting to change value of a readonly property."));
return false;
}
}
- } else if (current.attributesEqual(descriptor)) {
- if (!descriptor.value())
- return true;
- PutPropertySlot slot;
- object->methodTable()->put(object, exec, propertyName, descriptor.value(), slot);
- if (exec->hadException())
- return false;
- return true;
}
+ if (current.attributesEqual(descriptor) && !descriptor.value())
+ return true;
object->methodTable()->deleteProperty(object, exec, propertyName);
return putDescriptor(exec, object, propertyName, descriptor, current.attributesWithOverride(descriptor), current);
}
@@ -748,15 +763,14 @@ bool JSObject::defineOwnProperty(JSObject* object, ExecState* exec, const Identi
if (!accessor)
return false;
GetterSetter* getterSetter = asGetterSetter(accessor);
- if (current.attributesEqual(descriptor)) {
- if (descriptor.setterPresent())
- getterSetter->setSetter(exec->globalData(), descriptor.setterObject());
- if (descriptor.getterPresent())
- getterSetter->setGetter(exec->globalData(), descriptor.getterObject());
+ if (descriptor.setterPresent())
+ getterSetter->setSetter(exec->globalData(), descriptor.setterObject());
+ if (descriptor.getterPresent())
+ getterSetter->setGetter(exec->globalData(), descriptor.getterObject());
+ if (current.attributesEqual(descriptor))
return true;
- }
object->methodTable()->deleteProperty(object, exec, propertyName);
- unsigned attrs = current.attributesWithOverride(descriptor);
+ unsigned attrs = descriptor.attributesOverridingCurrent(current);
object->putDirectAccessor(exec->globalData(), propertyName, getterSetter, attrs | Accessor);
return true;
}