Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (106254 => 106255)
--- trunk/Source/_javascript_Core/ChangeLog 2012-01-30 18:22:50 UTC (rev 106254)
+++ trunk/Source/_javascript_Core/ChangeLog 2012-01-30 18:28:39 UTC (rev 106255)
@@ -1,3 +1,55 @@
+2012-01-30 Gavin Barraclough <[email protected]>
+
+ Clean up putDirect
+ https://bugs.webkit.org/show_bug.cgi?id=76232
+
+ Reviewed by Sam Weinig.
+
+ Part 3 - merge op_put_getter & op_put_setter.
+
+ Putting these separately is inefficient (and makes future optimiation,
+ e.g. making GetterSetter immutable) harder. Change to emit a single
+ op_put_getter_setter bytecode op. Ultimately we should probably be
+ able to merge this with put direct, to create a common op to initialize
+ object literal properties.
+
+ * bytecode/CodeBlock.cpp:
+ (JSC::CodeBlock::dump):
+ * bytecode/Opcode.h:
+ (JSC):
+ ():
+ * bytecompiler/BytecodeGenerator.cpp:
+ (JSC::BytecodeGenerator::emitPutGetterSetter):
+ * bytecompiler/BytecodeGenerator.h:
+ (BytecodeGenerator):
+ * bytecompiler/NodesCodegen.cpp:
+ (JSC::PropertyListNode::emitBytecode):
+ * interpreter/Interpreter.cpp:
+ (JSC::Interpreter::privateExecute):
+ * jit/JIT.cpp:
+ (JSC::JIT::privateCompileMainPass):
+ * jit/JIT.h:
+ (JIT):
+ * jit/JITPropertyAccess.cpp:
+ (JSC::JIT::emit_op_put_getter_setter):
+ * jit/JITPropertyAccess32_64.cpp:
+ (JSC::JIT::emit_op_put_getter_setter):
+ * jit/JITStubs.cpp:
+ (JSC::DEFINE_STUB_FUNCTION):
+ * jit/JITStubs.h:
+ ():
+ * runtime/JSObject.cpp:
+ (JSC::JSObject::putDirectVirtual):
+ (JSC::JSObject::putDirectAccessor):
+ (JSC):
+ (JSC::putDescriptor):
+ (JSC::JSObject::defineOwnProperty):
+ * runtime/JSObject.h:
+ ():
+ (JSC::JSObject::putDirectInternal):
+ (JSC::JSObject::putDirect):
+ (JSC::JSObject::putDirectWithoutTransition):
+
2012-01-30 Michael Saboff <[email protected]>
Dromaeo tests call parseSimpleLengthValue() on 8 bit strings
Modified: trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp (106254 => 106255)
--- trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp 2012-01-30 18:22:50 UTC (rev 106254)
+++ trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp 2012-01-30 18:28:39 UTC (rev 106255)
@@ -902,20 +902,14 @@
printPutByIdOp(exec, location, it, "put_by_id_generic");
break;
}
- case op_put_getter: {
+ case op_put_getter_setter: {
int r0 = (++it)->u.operand;
int id0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
- printf("[%4d] put_getter\t %s, %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), registerName(exec, r1).data());
+ int r2 = (++it)->u.operand;
+ printf("[%4d] put_getter_setter\t %s, %s, %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
break;
}
- case op_put_setter: {
- int r0 = (++it)->u.operand;
- int id0 = (++it)->u.operand;
- int r1 = (++it)->u.operand;
- printf("[%4d] put_setter\t %s, %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), registerName(exec, r1).data());
- break;
- }
case op_method_check: {
printf("[%4d] method_check\n", location);
break;
Modified: trunk/Source/_javascript_Core/bytecode/Opcode.h (106254 => 106255)
--- trunk/Source/_javascript_Core/bytecode/Opcode.h 2012-01-30 18:22:50 UTC (rev 106254)
+++ trunk/Source/_javascript_Core/bytecode/Opcode.h 2012-01-30 18:28:39 UTC (rev 106255)
@@ -132,8 +132,7 @@
macro(op_put_by_val, 4) \
macro(op_del_by_val, 4) \
macro(op_put_by_index, 4) \
- macro(op_put_getter, 4) \
- macro(op_put_setter, 4) \
+ macro(op_put_getter_setter, 5) \
\
macro(op_jmp, 2) \
macro(op_jtrue, 3) \
Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp (106254 => 106255)
--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp 2012-01-30 18:22:50 UTC (rev 106254)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp 2012-01-30 18:28:39 UTC (rev 106255)
@@ -1573,24 +1573,15 @@
return value;
}
-RegisterID* BytecodeGenerator::emitPutGetter(RegisterID* base, const Identifier& property, RegisterID* value)
+void BytecodeGenerator::emitPutGetterSetter(RegisterID* base, const Identifier& property, RegisterID* getter, RegisterID* setter)
{
- emitOpcode(op_put_getter);
+ emitOpcode(op_put_getter_setter);
instructions().append(base->index());
instructions().append(addConstant(property));
- instructions().append(value->index());
- return value;
+ instructions().append(getter->index());
+ instructions().append(setter->index());
}
-RegisterID* BytecodeGenerator::emitPutSetter(RegisterID* base, const Identifier& property, RegisterID* value)
-{
- emitOpcode(op_put_setter);
- instructions().append(base->index());
- instructions().append(addConstant(property));
- instructions().append(value->index());
- return value;
-}
-
RegisterID* BytecodeGenerator::emitDeleteById(RegisterID* dst, RegisterID* base, const Identifier& property)
{
emitOpcode(op_del_by_id);
Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h (106254 => 106255)
--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h 2012-01-30 18:22:50 UTC (rev 106254)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h 2012-01-30 18:28:39 UTC (rev 106255)
@@ -330,8 +330,7 @@
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);
+ void emitPutGetterSetter(RegisterID* base, const Identifier& property, RegisterID* getter, RegisterID* setter);
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);
Modified: trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp (106254 => 106255)
--- trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp 2012-01-30 18:22:50 UTC (rev 106254)
+++ trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp 2012-01-30 18:28:39 UTC (rev 106255)
@@ -236,27 +236,79 @@
generator.emitNewObject(newObj.get());
- for (PropertyListNode* p = this; p; p = p->m_next) {
- RegisterID* value = generator.emitNode(p->m_node->m_assign);
-
- switch (p->m_node->m_type) {
- case PropertyNode::Constant: {
- generator.emitDirectPutById(newObj.get(), p->m_node->name(), value);
- break;
+ // Fast case: this loop just handles regular value properties.
+ PropertyListNode* p = this;
+ for (; p && p->m_node->m_type == PropertyNode::Constant; p = p->m_next)
+ generator.emitDirectPutById(newObj.get(), p->m_node->name(), generator.emitNode(p->m_node->m_assign));
+
+ // Were there any get/set properties?
+ if (p) {
+ typedef std::pair<PropertyNode*, PropertyNode*> GetterSetterPair;
+ typedef HashMap<StringImpl*, GetterSetterPair> GetterSetterMap;
+ GetterSetterMap map;
+
+ // Build a map, pairing get/set values together.
+ for (PropertyListNode* q = p; q; q = q->m_next) {
+ PropertyNode* node = q->m_node;
+ if (node->m_type == PropertyNode::Constant)
+ continue;
+
+ GetterSetterPair pair(node, 0);
+ std::pair<GetterSetterMap::iterator, bool> result = map.add(node->name().impl(), pair);
+ if (!result.second)
+ result.first->second.second = node;
+ }
+
+ // Iterate over the remaining properties in the list.
+ for (; p; p = p->m_next) {
+ PropertyNode* node = p->m_node;
+ RegisterID* value = generator.emitNode(node->m_assign);
+
+ // Handle regular values.
+ if (node->m_type == PropertyNode::Constant) {
+ generator.emitDirectPutById(newObj.get(), node->name(), value);
+ continue;
}
- case PropertyNode::Getter: {
- generator.emitPutGetter(newObj.get(), p->m_node->name(), value);
- break;
+
+ // This is a get/set property, find its entry in the map.
+ ASSERT(node->m_type == PropertyNode::Getter || node->m_type == PropertyNode::Setter);
+ GetterSetterMap::iterator it = map.find(node->name().impl());
+ ASSERT(it != map.end());
+ GetterSetterPair& pair = it->second;
+
+ // Was this already generated as a part of its partner?
+ if (pair.second == node)
+ continue;
+
+ // Generate the paired node now.
+ RefPtr<RegisterID> getterReg;
+ RefPtr<RegisterID> setterReg;
+
+ if (node->m_type == PropertyNode::Getter) {
+ getterReg = value;
+ if (pair.second) {
+ ASSERT(pair.second->m_type == PropertyNode::Setter);
+ setterReg = generator.emitNode(pair.second->m_assign);
+ } else {
+ setterReg = generator.newTemporary();
+ generator.emitLoad(setterReg.get(), jsUndefined());
+ }
+ } else {
+ ASSERT(node->m_type == PropertyNode::Setter);
+ setterReg = value;
+ if (pair.second) {
+ ASSERT(pair.second->m_type == PropertyNode::Getter);
+ getterReg = generator.emitNode(pair.second->m_assign);
+ } else {
+ getterReg = generator.newTemporary();
+ generator.emitLoad(getterReg.get(), jsUndefined());
+ }
}
- case PropertyNode::Setter: {
- generator.emitPutSetter(newObj.get(), p->m_node->name(), value);
- break;
- }
- default:
- ASSERT_NOT_REACHED();
+
+ generator.emitPutGetterSetter(newObj.get(), node->name(), getterReg.get(), setterReg.get());
}
}
-
+
return generator.moveToDestinationIfNeeded(dst, newObj.get());
}
Modified: trunk/Source/_javascript_Core/interpreter/Interpreter.cpp (106254 => 106255)
--- trunk/Source/_javascript_Core/interpreter/Interpreter.cpp 2012-01-30 18:22:50 UTC (rev 106254)
+++ trunk/Source/_javascript_Core/interpreter/Interpreter.cpp 2012-01-30 18:28:39 UTC (rev 106255)
@@ -4961,52 +4961,41 @@
int result = vPC[1].u.operand;
return callFrame->r(result).jsValue();
}
- DEFINE_OPCODE(op_put_getter) {
- /* put_getter base(r) property(id) function(r)
+ DEFINE_OPCODE(op_put_getter_setter) {
+ /* put_getter_setter base(r) property(id) getter(r) setter(r)
- Sets register function on register base as the getter named
- by identifier property. Base and function are assumed to be
- objects as this op should only be used for getters defined
- in object literal form.
+ Puts accessor descriptor to register base as the named
+ identifier property. Base and function may be objects
+ or undefined, this op should only be used for accessors
+ defined in object literal form.
Unlike many opcodes, this one does not write any output to
the register file.
*/
int base = vPC[1].u.operand;
int property = vPC[2].u.operand;
- int function = vPC[3].u.operand;
+ int getterReg = vPC[3].u.operand;
+ int setterReg = vPC[4].u.operand;
ASSERT(callFrame->r(base).jsValue().isObject());
JSObject* baseObj = asObject(callFrame->r(base).jsValue());
Identifier& ident = codeBlock->identifier(property);
- ASSERT(callFrame->r(function).jsValue().isObject());
- baseObj->methodTable()->defineGetter(baseObj, callFrame, ident, asObject(callFrame->r(function).jsValue()), 0);
- vPC += OPCODE_LENGTH(op_put_getter);
- NEXT_INSTRUCTION();
- }
- DEFINE_OPCODE(op_put_setter) {
- /* put_setter base(r) property(id) function(r)
+ GetterSetter* accessor = GetterSetter::create(callFrame);
- Sets register function on register base as the setter named
- by identifier property. Base and function are assumed to be
- objects as this op should only be used for setters defined
- in object literal form.
+ JSValue getter = callFrame->r(getterReg).jsValue();
+ JSValue setter = callFrame->r(setterReg).jsValue();
+ ASSERT(getter.isObject() || getter.isUndefined());
+ ASSERT(setter.isObject() || setter.isUndefined());
+ ASSERT(getter.isObject() || setter.isObject());
- Unlike many opcodes, this one does not write any output to
- the register file.
- */
- int base = vPC[1].u.operand;
- int property = vPC[2].u.operand;
- int function = vPC[3].u.operand;
+ if (!getter.isUndefined())
+ accessor->setGetter(callFrame->globalData(), asObject(getter));
+ if (!setter.isUndefined())
+ accessor->setSetter(callFrame->globalData(), asObject(setter));
+ baseObj->putDirectAccessor(callFrame->globalData(), ident, accessor, Accessor);
- ASSERT(callFrame->r(base).jsValue().isObject());
- JSObject* baseObj = asObject(callFrame->r(base).jsValue());
- Identifier& ident = codeBlock->identifier(property);
- ASSERT(callFrame->r(function).jsValue().isObject());
- baseObj->methodTable()->defineSetter(baseObj, callFrame, ident, asObject(callFrame->r(function).jsValue()), 0);
-
- vPC += OPCODE_LENGTH(op_put_setter);
+ vPC += OPCODE_LENGTH(op_put_getter_setter);
NEXT_INSTRUCTION();
}
DEFINE_OPCODE(op_method_check) {
Modified: trunk/Source/_javascript_Core/jit/JIT.cpp (106254 => 106255)
--- trunk/Source/_javascript_Core/jit/JIT.cpp 2012-01-30 18:22:50 UTC (rev 106254)
+++ trunk/Source/_javascript_Core/jit/JIT.cpp 2012-01-30 18:28:39 UTC (rev 106255)
@@ -328,10 +328,9 @@
DEFINE_OP(op_put_by_id)
DEFINE_OP(op_put_by_index)
DEFINE_OP(op_put_by_val)
- DEFINE_OP(op_put_getter)
+ DEFINE_OP(op_put_getter_setter)
DEFINE_OP(op_put_global_var)
DEFINE_OP(op_put_scoped_var)
- DEFINE_OP(op_put_setter)
DEFINE_OP(op_resolve)
DEFINE_OP(op_resolve_base)
DEFINE_OP(op_ensure_property_exists)
Modified: trunk/Source/_javascript_Core/jit/JIT.h (106254 => 106255)
--- trunk/Source/_javascript_Core/jit/JIT.h 2012-01-30 18:22:50 UTC (rev 106254)
+++ trunk/Source/_javascript_Core/jit/JIT.h 2012-01-30 18:28:39 UTC (rev 106255)
@@ -857,10 +857,9 @@
void emit_op_put_by_id(Instruction*);
void emit_op_put_by_index(Instruction*);
void emit_op_put_by_val(Instruction*);
- void emit_op_put_getter(Instruction*);
+ void emit_op_put_getter_setter(Instruction*);
void emit_op_put_global_var(Instruction*);
void emit_op_put_scoped_var(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*);
Modified: trunk/Source/_javascript_Core/jit/JITPropertyAccess.cpp (106254 => 106255)
--- trunk/Source/_javascript_Core/jit/JITPropertyAccess.cpp 2012-01-30 18:22:50 UTC (rev 106254)
+++ trunk/Source/_javascript_Core/jit/JITPropertyAccess.cpp 2012-01-30 18:28:39 UTC (rev 106255)
@@ -261,24 +261,16 @@
stubCall.call();
}
-void JIT::emit_op_put_getter(Instruction* currentInstruction)
+void JIT::emit_op_put_getter_setter(Instruction* currentInstruction)
{
- JITStubCall stubCall(this, cti_op_put_getter);
+ JITStubCall stubCall(this, cti_op_put_getter_setter);
stubCall.addArgument(currentInstruction[1].u.operand, regT2);
stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
stubCall.addArgument(currentInstruction[3].u.operand, regT2);
+ stubCall.addArgument(currentInstruction[4].u.operand, regT2);
stubCall.call();
}
-void JIT::emit_op_put_setter(Instruction* currentInstruction)
-{
- JITStubCall stubCall(this, cti_op_put_setter);
- stubCall.addArgument(currentInstruction[1].u.operand, regT2);
- stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
- stubCall.addArgument(currentInstruction[3].u.operand, regT2);
- stubCall.call();
-}
-
void JIT::emit_op_del_by_id(Instruction* currentInstruction)
{
JITStubCall stubCall(this, cti_op_del_by_id);
Modified: trunk/Source/_javascript_Core/jit/JITPropertyAccess32_64.cpp (106254 => 106255)
--- trunk/Source/_javascript_Core/jit/JITPropertyAccess32_64.cpp 2012-01-30 18:22:50 UTC (rev 106254)
+++ trunk/Source/_javascript_Core/jit/JITPropertyAccess32_64.cpp 2012-01-30 18:28:39 UTC (rev 106255)
@@ -62,32 +62,21 @@
stubCall.call();
}
-void JIT::emit_op_put_getter(Instruction* currentInstruction)
+void JIT::emit_op_put_getter_setter(Instruction* currentInstruction)
{
unsigned base = currentInstruction[1].u.operand;
unsigned property = currentInstruction[2].u.operand;
- unsigned function = currentInstruction[3].u.operand;
+ unsigned getter = currentInstruction[3].u.operand;
+ unsigned setter = currentInstruction[4].u.operand;
- JITStubCall stubCall(this, cti_op_put_getter);
+ JITStubCall stubCall(this, cti_op_put_getter_setter);
stubCall.addArgument(base);
stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(property)));
- stubCall.addArgument(function);
+ stubCall.addArgument(getter);
+ stubCall.addArgument(setter);
stubCall.call();
}
-void JIT::emit_op_put_setter(Instruction* currentInstruction)
-{
- unsigned base = currentInstruction[1].u.operand;
- unsigned property = currentInstruction[2].u.operand;
- unsigned function = currentInstruction[3].u.operand;
-
- JITStubCall stubCall(this, cti_op_put_setter);
- stubCall.addArgument(base);
- stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(property)));
- stubCall.addArgument(function);
- stubCall.call();
-}
-
void JIT::emit_op_del_by_id(Instruction* currentInstruction)
{
unsigned dst = currentInstruction[1].u.operand;
Modified: trunk/Source/_javascript_Core/jit/JITStubs.cpp (106254 => 106255)
--- trunk/Source/_javascript_Core/jit/JITStubs.cpp 2012-01-30 18:22:50 UTC (rev 106254)
+++ trunk/Source/_javascript_Core/jit/JITStubs.cpp 2012-01-30 18:28:39 UTC (rev 106255)
@@ -3526,7 +3526,7 @@
return JSValue::encode(jsBoolean(result));
}
-DEFINE_STUB_FUNCTION(void, op_put_getter)
+DEFINE_STUB_FUNCTION(void, op_put_getter_setter)
{
STUB_INIT_STACK_FRAME(stackFrame);
@@ -3534,20 +3534,20 @@
ASSERT(stackFrame.args[0].jsValue().isObject());
JSObject* baseObj = asObject(stackFrame.args[0].jsValue());
- ASSERT(stackFrame.args[2].jsValue().isObject());
- baseObj->methodTable()->defineGetter(baseObj, callFrame, stackFrame.args[1].identifier(), asObject(stackFrame.args[2].jsValue()), 0);
-}
-DEFINE_STUB_FUNCTION(void, op_put_setter)
-{
- STUB_INIT_STACK_FRAME(stackFrame);
+ GetterSetter* accessor = GetterSetter::create(callFrame);
- CallFrame* callFrame = stackFrame.callFrame;
+ JSValue getter = stackFrame.args[2].jsValue();
+ JSValue setter = stackFrame.args[3].jsValue();
+ ASSERT(getter.isObject() || getter.isUndefined());
+ ASSERT(setter.isObject() || setter.isUndefined());
+ ASSERT(getter.isObject() || setter.isObject());
- ASSERT(stackFrame.args[0].jsValue().isObject());
- JSObject* baseObj = asObject(stackFrame.args[0].jsValue());
- ASSERT(stackFrame.args[2].jsValue().isObject());
- baseObj->methodTable()->defineSetter(baseObj, callFrame, stackFrame.args[1].identifier(), asObject(stackFrame.args[2].jsValue()), 0);
+ if (!getter.isUndefined())
+ accessor->setGetter(callFrame->globalData(), asObject(getter));
+ if (!setter.isUndefined())
+ accessor->setSetter(callFrame->globalData(), asObject(setter));
+ baseObj->putDirectAccessor(callFrame->globalData(), stackFrame.args[1].identifier(), accessor, Accessor);
}
DEFINE_STUB_FUNCTION(void, op_throw_reference_error)
Modified: trunk/Source/_javascript_Core/jit/JITStubs.h (106254 => 106255)
--- trunk/Source/_javascript_Core/jit/JITStubs.h 2012-01-30 18:22:50 UTC (rev 106254)
+++ trunk/Source/_javascript_Core/jit/JITStubs.h 2012-01-30 18:28:39 UTC (rev 106255)
@@ -434,8 +434,7 @@
void JIT_STUB cti_op_put_by_index(STUB_ARGS_DECLARATION);
void JIT_STUB cti_op_put_by_val(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_put_getter_setter(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_op_throw_reference_error(STUB_ARGS_DECLARATION);
Modified: trunk/Source/_javascript_Core/runtime/JSObject.cpp (106254 => 106255)
--- trunk/Source/_javascript_Core/runtime/JSObject.cpp 2012-01-30 18:22:50 UTC (rev 106254)
+++ trunk/Source/_javascript_Core/runtime/JSObject.cpp 2012-01-30 18:28:39 UTC (rev 106255)
@@ -224,10 +224,28 @@
void JSObject::putDirectVirtual(JSObject* object, ExecState* exec, const Identifier& propertyName, JSValue value, unsigned attributes)
{
+ ASSERT(!value.isGetterSetter() && !(attributes & Accessor));
PutPropertySlot slot;
object->putDirectInternal<PutModeDefineOwnProperty>(exec->globalData(), propertyName, value, attributes, slot, getJSFunction(value));
}
+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));
+
+ // 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)
+ setStructure(globalData, Structure::attributeChangeTransition(globalData, structure(), propertyName, attributes));
+
+ structure()->setHasGetterSetterProperties(true);
+}
+
bool JSObject::hasProperty(ExecState* exec, const Identifier& propertyName) const
{
PropertySlot slot;
@@ -692,15 +710,11 @@
if (descriptor.isGenericDescriptor() || descriptor.isDataDescriptor()) {
if (descriptor.isGenericDescriptor() && oldDescriptor.isAccessorDescriptor()) {
GetterSetter* accessor = GetterSetter::create(exec);
- if (oldDescriptor.getterPresent()) {
- attributes |= Accessor;
+ if (oldDescriptor.getterPresent())
accessor->setGetter(exec->globalData(), oldDescriptor.getterObject());
- }
- if (oldDescriptor.setterPresent()) {
- attributes |= Accessor;
+ if (oldDescriptor.setterPresent())
accessor->setSetter(exec->globalData(), oldDescriptor.setterObject());
- }
- target->methodTable()->putDirectVirtual(target, exec, propertyName, accessor, attributes);
+ target->putDirectAccessor(exec->globalData(), propertyName, accessor, attributes | Accessor);
return true;
}
JSValue newValue = jsUndefined();
@@ -708,21 +722,32 @@
newValue = descriptor.value();
else if (oldDescriptor.value())
newValue = oldDescriptor.value();
- target->methodTable()->putDirectVirtual(target, exec, propertyName, newValue, attributes & ~Accessor);
+ target->putDirect(exec->globalData(), propertyName, newValue, attributes & ~Accessor);
return true;
}
attributes &= ~ReadOnly;
+ GetterSetter* accessor = GetterSetter::create(exec);
+
if (descriptor.getterPresent())
- target->methodTable()->defineGetter(target, exec, propertyName, descriptor.getterObject(), attributes);
- if (exec->hadException())
- return false;
+ accessor->setGetter(exec->globalData(), descriptor.getterObject());
+ else if (oldDescriptor.getterPresent())
+ accessor->setGetter(exec->globalData(), oldDescriptor.getterObject());
if (descriptor.setterPresent())
- target->methodTable()->defineSetter(target, exec, propertyName, descriptor.setterObject(), attributes);
- return !exec->hadException();
+ accessor->setSetter(exec->globalData(), descriptor.setterObject());
+ else if (oldDescriptor.setterPresent())
+ accessor->setSetter(exec->globalData(), oldDescriptor.setterObject());
+
+ target->putDirectAccessor(exec->globalData(), propertyName, accessor, attributes | Accessor);
+ return true;
}
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;
+
// If we have a new property we can just put it on normally
PropertyDescriptor current;
if (!object->methodTable()->getOwnPropertyDescriptor(object, exec, propertyName, current)) {
@@ -832,9 +857,7 @@
}
object->methodTable()->deleteProperty(object, exec, propertyName);
unsigned attrs = current.attributesWithOverride(descriptor);
- if (descriptor.setterPresent() || descriptor.getterPresent())
- attrs |= Accessor;
- object->putDirect(exec->globalData(), propertyName, getterSetter, attrs);
+ object->putDirectAccessor(exec->globalData(), propertyName, getterSetter, attrs | Accessor);
return true;
}
Modified: trunk/Source/_javascript_Core/runtime/JSObject.h (106254 => 106255)
--- trunk/Source/_javascript_Core/runtime/JSObject.h 2012-01-30 18:22:50 UTC (rev 106254)
+++ trunk/Source/_javascript_Core/runtime/JSObject.h 2012-01-30 18:28:39 UTC (rev 106255)
@@ -118,6 +118,7 @@
void putDirect(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attributes = 0);
void putDirect(JSGlobalData&, const Identifier& propertyName, JSValue, PutPropertySlot&);
void putDirectWithoutTransition(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attributes = 0);
+ void putDirectAccessor(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attributes);
bool propertyIsEnumerable(ExecState*, const Identifier& propertyName) const;
@@ -642,6 +643,7 @@
inline bool JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes, PutPropertySlot& slot, JSCell* specificFunction)
{
ASSERT(value);
+ ASSERT(value.isGetterSetter() == !!(attributes & Accessor));
ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
if (structure()->isDictionary()) {
@@ -761,17 +763,20 @@
inline void JSObject::putDirect(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
{
+ ASSERT(!value.isGetterSetter() && !(attributes & Accessor));
PutPropertySlot slot;
putDirectInternal<PutModeDefineOwnProperty>(globalData, propertyName, value, attributes, slot, getJSFunction(value));
}
inline void JSObject::putDirect(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
{
+ ASSERT(!value.isGetterSetter());
putDirectInternal<PutModeDefineOwnProperty>(globalData, propertyName, value, 0, slot, getJSFunction(value));
}
inline void JSObject::putDirectWithoutTransition(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
{
+ ASSERT(!value.isGetterSetter() && !(attributes & Accessor));
size_t currentCapacity = structure()->propertyStorageCapacity();
size_t offset = structure()->addPropertyWithoutTransition(globalData, propertyName, attributes, getJSFunction(value));
if (currentCapacity != structure()->propertyStorageCapacity())