From 09a556801d501a8a4cfdb2a3c2a10a1b0cfeae83 Mon Sep 17 00:00:00 2001 From: "barraclough@apple.com" Date: Mon, 30 Jan 2012 18:28:39 +0000 Subject: [PATCH] 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): git-svn-id: http://svn.webkit.org/repository/webkit/trunk@106255 268f45cc-cd09-0410-ab3c-d52691b4dbfc --- Source/JavaScriptCore/ChangeLog | 52 +++++++++++++ Source/JavaScriptCore/bytecode/CodeBlock.cpp | 12 +-- Source/JavaScriptCore/bytecode/Opcode.h | 3 +- .../bytecompiler/BytecodeGenerator.cpp | 17 +---- .../bytecompiler/BytecodeGenerator.h | 3 +- .../JavaScriptCore/bytecompiler/NodesCodegen.cpp | 86 +++++++++++++++++----- Source/JavaScriptCore/interpreter/Interpreter.cpp | 51 +++++-------- Source/JavaScriptCore/jit/JIT.cpp | 3 +- Source/JavaScriptCore/jit/JIT.h | 3 +- Source/JavaScriptCore/jit/JITPropertyAccess.cpp | 14 +--- .../JavaScriptCore/jit/JITPropertyAccess32_64.cpp | 23 ++---- Source/JavaScriptCore/jit/JITStubs.cpp | 24 +++--- Source/JavaScriptCore/jit/JITStubs.h | 3 +- Source/JavaScriptCore/runtime/JSObject.cpp | 55 ++++++++++---- Source/JavaScriptCore/runtime/JSObject.h | 5 ++ 15 files changed, 218 insertions(+), 136 deletions(-) diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog index f78e6ac..4f19b82 100644 --- a/Source/JavaScriptCore/ChangeLog +++ b/Source/JavaScriptCore/ChangeLog @@ -1,3 +1,55 @@ +2012-01-30 Gavin Barraclough + + 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 Dromaeo tests call parseSimpleLengthValue() on 8 bit strings diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp index 0c3ab35..927c274 100644 --- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp +++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp @@ -902,18 +902,12 @@ void CodeBlock::dump(ExecState* exec, const Vector::const_iterator& 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()); - 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()); + 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_method_check: { diff --git a/Source/JavaScriptCore/bytecode/Opcode.h b/Source/JavaScriptCore/bytecode/Opcode.h index 0f94176..a56dc53 100644 --- a/Source/JavaScriptCore/bytecode/Opcode.h +++ b/Source/JavaScriptCore/bytecode/Opcode.h @@ -132,8 +132,7 @@ namespace JSC { 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) \ diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp index 2b1c164..6d161e0 100644 --- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp +++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp @@ -1573,22 +1573,13 @@ RegisterID* BytecodeGenerator::emitDirectPutById(RegisterID* base, const Identif 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; -} - -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; + instructions().append(getter->index()); + instructions().append(setter->index()); } RegisterID* BytecodeGenerator::emitDeleteById(RegisterID* dst, RegisterID* base, const Identifier& property) diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h index 59d776e..f8138d9 100644 --- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h +++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h @@ -330,8 +330,7 @@ namespace JSC { 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); diff --git a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp index 132f666..4ad5e5e 100644 --- a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp +++ b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp @@ -236,27 +236,79 @@ RegisterID* PropertyListNode::emitBytecode(BytecodeGenerator& generator, Registe 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; - } - case PropertyNode::Getter: { - generator.emitPutGetter(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 GetterSetterPair; + typedef HashMap 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 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::Setter: { - generator.emitPutSetter(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 getterReg; + RefPtr 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()); + } } - default: - ASSERT_NOT_REACHED(); + + generator.emitPutGetterSetter(newObj.get(), node->name(), getterReg.get(), setterReg.get()); } } - + return generator.moveToDestinationIfNeeded(dst, newObj.get()); } diff --git a/Source/JavaScriptCore/interpreter/Interpreter.cpp b/Source/JavaScriptCore/interpreter/Interpreter.cpp index 6271a90..2d8790e 100644 --- a/Source/JavaScriptCore/interpreter/Interpreter.cpp +++ b/Source/JavaScriptCore/interpreter/Interpreter.cpp @@ -4961,52 +4961,41 @@ skip_id_custom_self: 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; - - 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); + 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); - vPC += OPCODE_LENGTH(op_put_setter); + vPC += OPCODE_LENGTH(op_put_getter_setter); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_method_check) { diff --git a/Source/JavaScriptCore/jit/JIT.cpp b/Source/JavaScriptCore/jit/JIT.cpp index f810862..247495a 100644 --- a/Source/JavaScriptCore/jit/JIT.cpp +++ b/Source/JavaScriptCore/jit/JIT.cpp @@ -328,10 +328,9 @@ void JIT::privateCompileMainPass() 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) diff --git a/Source/JavaScriptCore/jit/JIT.h b/Source/JavaScriptCore/jit/JIT.h index 6688a45..c357e8c 100644 --- a/Source/JavaScriptCore/jit/JIT.h +++ b/Source/JavaScriptCore/jit/JIT.h @@ -857,10 +857,9 @@ namespace JSC { 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*); diff --git a/Source/JavaScriptCore/jit/JITPropertyAccess.cpp b/Source/JavaScriptCore/jit/JITPropertyAccess.cpp index 487f835..9fa29e2 100644 --- a/Source/JavaScriptCore/jit/JITPropertyAccess.cpp +++ b/Source/JavaScriptCore/jit/JITPropertyAccess.cpp @@ -261,21 +261,13 @@ void JIT::emit_op_put_by_index(Instruction* currentInstruction) 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); - 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_put_setter(Instruction* currentInstruction) -{ - JITStubCall stubCall(this, cti_op_put_setter); + 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(); } diff --git a/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp b/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp index 9865c48..2c81a5f 100644 --- a/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp +++ b/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp @@ -62,29 +62,18 @@ void JIT::emit_op_put_by_index(Instruction* currentInstruction) 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.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.addArgument(getter); + stubCall.addArgument(setter); stubCall.call(); } diff --git a/Source/JavaScriptCore/jit/JITStubs.cpp b/Source/JavaScriptCore/jit/JITStubs.cpp index 6a2b2b8..386d0df 100644 --- a/Source/JavaScriptCore/jit/JITStubs.cpp +++ b/Source/JavaScriptCore/jit/JITStubs.cpp @@ -3526,7 +3526,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_del_by_val) 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 @@ DEFINE_STUB_FUNCTION(void, op_put_getter) 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) diff --git a/Source/JavaScriptCore/jit/JITStubs.h b/Source/JavaScriptCore/jit/JITStubs.h index 13c46fc8..fe5f522 100644 --- a/Source/JavaScriptCore/jit/JITStubs.h +++ b/Source/JavaScriptCore/jit/JITStubs.h @@ -434,8 +434,7 @@ extern "C" { 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); diff --git a/Source/JavaScriptCore/runtime/JSObject.cpp b/Source/JavaScriptCore/runtime/JSObject.cpp index ad4a445..a443fda 100644 --- a/Source/JavaScriptCore/runtime/JSObject.cpp +++ b/Source/JavaScriptCore/runtime/JSObject.cpp @@ -224,10 +224,28 @@ void JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, void JSObject::putDirectVirtual(JSObject* object, ExecState* exec, const Identifier& propertyName, JSValue value, unsigned attributes) { + ASSERT(!value.isGetterSetter() && !(attributes & Accessor)); PutPropertySlot slot; object->putDirectInternal(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(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 @@ static bool putDescriptor(ExecState* exec, JSObject* target, const Identifier& p 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 @@ static bool putDescriptor(ExecState* exec, JSObject* target, const Identifier& p 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 @@ bool JSObject::defineOwnProperty(JSObject* object, ExecState* exec, const Identi } 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; } diff --git a/Source/JavaScriptCore/runtime/JSObject.h b/Source/JavaScriptCore/runtime/JSObject.h index 356135d..d9700b70 100644 --- a/Source/JavaScriptCore/runtime/JSObject.h +++ b/Source/JavaScriptCore/runtime/JSObject.h @@ -118,6 +118,7 @@ namespace JSC { 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 @@ template 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 bool JSObject::putOwnDataProperty(JSGlobalData& globalData, const Identif inline void JSObject::putDirect(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes) { + ASSERT(!value.isGetterSetter() && !(attributes & Accessor)); PutPropertySlot slot; putDirectInternal(globalData, propertyName, value, attributes, slot, getJSFunction(value)); } inline void JSObject::putDirect(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) { + ASSERT(!value.isGetterSetter()); putDirectInternal(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()) -- 2.7.4