Title: [183316] trunk
Revision
183316
Author
[email protected]
Date
2015-04-25 15:03:30 -0700 (Sat, 25 Apr 2015)

Log Message

class methods should be non-enumerable
https://bugs.webkit.org/show_bug.cgi?id=143181

Reviewed by Darin Adler.

Source/_javascript_Core:

Fixed the bug by using Object.defineProperty to define methods.

This patch adds the concept of link time constants and uses it to resolve Object.defineProperty
inside CodeBlock's constructor since bytecode can be linked against multiple global objects.

* bytecode/CodeBlock.cpp: 
(JSC::CodeBlock::CodeBlock): Resolve link time constants that are used. Ignore ones with register
index of zero.
* bytecode/SpecialPointer.h: Added a new enum for link time constants. It currently contains
exactly one entry for Object.defineProperty.
* bytecode/UnlinkedCodeBlock.h:
(JSC::UnlinkedCodeBlock::addConstant): Added. Like addConstant that takes JSValue, allocate a new
constant register for the link time constant we're adding.
(JSC::UnlinkedCodeBlock::registerIndexForLinkTimeConstant): Added.
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitMoveLinkTimeConstant): Added. Like addConstantValue, allocate a new
register for the specified link time constant and notify UnlinkedCodeBlock about it.
(JSC::BytecodeGenerator::emitCallDefineProperty): Added. Create a new property descriptor and call
Object.defineProperty with it.
* bytecompiler/BytecodeGenerator.h:
* bytecompiler/NodesCodegen.cpp:
(JSC::PropertyListNode::emitBytecode): Make static and non-static getters and setters for classes
non-enumerable by using emitCallDefineProperty to define them.
(JSC::PropertyListNode::emitPutConstantProperty): Ditto for a non-accessor properties.
(JSC::ClassExprNode::emitBytecode): Make prototype.constructor non-enumerable and make prototype
property on the class non-writable, non-configurable, and non-enumerable by using defineProperty.
* runtime/CommonIdentifiers.h:
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init): Set m_definePropertyFunction.
(JSC::JSGlobalObject::visitChildren): Visit m_definePropertyFunction.
* runtime/JSGlobalObject.h:
(JSC::JSGlobalObject::definePropertyFunction): Added.
(JSC::JSGlobalObject::actualPointerFor): Added a variant that takes LinkTimeConstant.
(JSC::JSGlobalObject::jsCellForLinkTimeConstant): Like actualPointerFor, takes LinkTimeConstant and
returns a JSCell; e.g. Object.defineProperty.
* runtime/ObjectConstructor.cpp:
(JSC::ObjectConstructor::addDefineProperty): Added. Returns Object.defineProperty.
* runtime/ObjectConstructor.h:

LayoutTests:

Added a regression test.

Also fixed a test that previously relied on "prototype" property being writable
since this is no longer the case.

* js/class-syntax-extends-expected.txt:
* js/class-syntax-prototype.html: Added.
* js/script-tests/class-syntax-extends.js:
* js/script-tests/class-syntax-prototype.js: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (183315 => 183316)


--- trunk/LayoutTests/ChangeLog	2015-04-25 22:00:51 UTC (rev 183315)
+++ trunk/LayoutTests/ChangeLog	2015-04-25 22:03:30 UTC (rev 183316)
@@ -1,3 +1,20 @@
+2015-04-23  Ryosuke Niwa  <[email protected]>
+
+        class methods should be non-enumerable
+        https://bugs.webkit.org/show_bug.cgi?id=143181
+
+        Reviewed by Darin Adler.
+
+        Added a regression test.
+
+        Also fixed a test that previously relied on "prototype" property being writable
+        since this is no longer the case.
+
+        * js/class-syntax-extends-expected.txt:
+        * js/class-syntax-prototype.html: Added.
+        * js/script-tests/class-syntax-extends.js:
+        * js/script-tests/class-syntax-prototype.js: Added.
+
 2015-04-25  Yusuke Suzuki  <[email protected]>
 
         [ES6] Implement String.fromCodePoint

Modified: trunk/LayoutTests/js/class-syntax-extends-expected.txt (183315 => 183316)


--- trunk/LayoutTests/js/class-syntax-extends-expected.txt	2015-04-25 22:00:51 UTC (rev 183315)
+++ trunk/LayoutTests/js/class-syntax-extends-expected.txt	2015-04-25 22:03:30 UTC (rev 183316)
@@ -25,7 +25,7 @@
 PASS x.__proto__ is Function.prototype
 PASS x = class extends 3 { constructor() { } }; x.__proto__ threw exception TypeError: The superclass is not an object..
 PASS x = class extends "abc" { constructor() { } }; x.__proto__ threw exception TypeError: The superclass is not an object..
-PASS baseWithBadPrototype = class { constructor() { } }; baseWithBadPrototype.prototype = 3 did not throw exception.
+PASS baseWithBadPrototype = function () {}; baseWithBadPrototype.prototype = 3; new baseWithBadPrototype did not throw exception.
 PASS x = class extends baseWithBadPrototype { constructor() { } } threw exception TypeError: The superclass's prototype is not an object..
 PASS baseWithBadPrototype.prototype = "abc" did not throw exception.
 PASS x = class extends baseWithBadPrototype { constructor() { } } threw exception TypeError: The superclass's prototype is not an object..

Added: trunk/LayoutTests/js/class-syntax-prototype-expected.txt (0 => 183316)


--- trunk/LayoutTests/js/class-syntax-prototype-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/js/class-syntax-prototype-expected.txt	2015-04-25 22:03:30 UTC (rev 183316)
@@ -0,0 +1,51 @@
+Tests for the descriptors of the properties implicitly defined by ES6 class syntax
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS class A {}; descriptor(A, "prototype").writable is false
+PASS class A {}; var x = A.prototype; A.prototype = 3; A.prototype is x
+PASS class A {}; descriptor(A, "prototype").enumerable is false
+PASS class A {}; A.foo = "foo"; enumeratedProperties(A).includes("foo") is true
+PASS class A {}; enumeratedProperties(A).includes("prototype") is false
+PASS class A {}; descriptor(A, "prototype").configurable is false
+PASS class A {}; Object.defineProperty(A, "prototype", {value: "foo"}) threw exception TypeError: Attempting to change value of a readonly property..
+PASS class A { static foo() {} }; descriptor(A, "foo").writable is true
+PASS class A { static foo() {} }; A.foo = 3; A.foo is 3
+PASS class A { static foo() {} }; descriptor(A, "foo").enumerable is false
+PASS class A { static foo() {} }; enumeratedProperties(A).includes("foo") is false
+PASS class A { static foo() {} }; descriptor(A, "foo").configurable is true
+PASS class A { static foo() {} }; Object.defineProperty(A, "foo", {value: "bar"}); A.foo is "bar"
+PASS class A { static get foo() {} }; descriptor(A, "foo").writable is undefined
+PASS class A { static get foo() { return 5; } }; A.foo = 3; A.foo is 5
+PASS class A { static get foo() {} }; descriptor(A, "foo").enumerable is false
+PASS class A { static get foo() {} }; enumeratedProperties(A).includes("foo") is false
+PASS class A { static get foo() {} }; enumeratedProperties(new A).includes("foo") is false
+PASS class A { static get foo() {} }; descriptor(A, "foo").configurable is true
+PASS class A { static get foo() {} }; Object.defineProperty(A, "foo", {value: "bar"}); A.foo is "bar"
+PASS class A { foo() {} }; descriptor(A.prototype, "foo").writable is true
+PASS class A { foo() {} }; A.prototype.foo = 3; A.prototype.foo is 3
+PASS class A { foo() {} }; descriptor(A.prototype, "foo").enumerable is false
+PASS class A { foo() {} }; enumeratedProperties(A.prototype).includes("foo") is false
+PASS class A { foo() {} }; enumeratedProperties(new A).includes("foo") is false
+PASS class A { foo() {} }; descriptor(A.prototype, "foo").configurable is true
+PASS class A { foo() {} }; Object.defineProperty(A.prototype, "foo", {value: "bar"}); A.prototype.foo is "bar"
+PASS class A { get foo() {} }; descriptor(A.prototype, "foo").writable is undefined
+PASS class A { get foo() { return 5; } }; A.prototype.foo = 3; A.prototype.foo is 5
+PASS class A { get foo() {} }; descriptor(A.prototype, "foo").enumerable is false
+PASS class A { get foo() {} }; enumeratedProperties(A.prototype).includes("foo") is false
+PASS class A { get foo() {} }; enumeratedProperties(new A).includes("foo") is false
+PASS class A { get foo() {} }; descriptor(A.prototype, "foo").configurable is true
+PASS class A { get foo() {} }; Object.defineProperty(A.prototype, "foo", {value: "bar"}); A.prototype.foo is "bar"
+PASS class A { }; descriptor(A.prototype, "constructor").writable is true
+PASS class A { }; A.prototype.constructor = 3; A.prototype.constructor is 3
+PASS class A { }; x = {}; A.prototype.constructor = function () { return x; }; (new A) instanceof A is true
+PASS class A { }; descriptor(A.prototype, "constructor").enumerable is false
+PASS class A { }; enumeratedProperties(A.prototype).includes("constructor") is false
+PASS class A { }; enumeratedProperties(new A).includes("constructor") is false
+PASS class A { }; descriptor(A.prototype, "constructor").configurable is true
+PASS class A { }; Object.defineProperty(A.prototype, "constructor", {value: "bar"}); A.prototype.constructor is "bar"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/js/class-syntax-prototype.html (0 => 183316)


--- trunk/LayoutTests/js/class-syntax-prototype.html	                        (rev 0)
+++ trunk/LayoutTests/js/class-syntax-prototype.html	2015-04-25 22:03:30 UTC (rev 183316)
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src=""
+<script src=""
+<script src=""
+</body>
+</html>

Modified: trunk/LayoutTests/js/script-tests/class-syntax-extends.js (183315 => 183316)


--- trunk/LayoutTests/js/script-tests/class-syntax-extends.js	2015-04-25 22:00:51 UTC (rev 183315)
+++ trunk/LayoutTests/js/script-tests/class-syntax-extends.js	2015-04-25 22:03:30 UTC (rev 183316)
@@ -38,7 +38,7 @@
 shouldBe('x.__proto__', 'Function.prototype');
 shouldThrow('x = class extends 3 { constructor() { } }; x.__proto__', '"TypeError: The superclass is not an object."');
 shouldThrow('x = class extends "abc" { constructor() { } }; x.__proto__', '"TypeError: The superclass is not an object."');
-shouldNotThrow('baseWithBadPrototype = class { constructor() { } }; baseWithBadPrototype.prototype = 3');
+shouldNotThrow('baseWithBadPrototype = function () {}; baseWithBadPrototype.prototype = 3; new baseWithBadPrototype');
 shouldThrow('x = class extends baseWithBadPrototype { constructor() { } }', '"TypeError: The superclass\'s prototype is not an object."');
 shouldNotThrow('baseWithBadPrototype.prototype = "abc"');
 shouldThrow('x = class extends baseWithBadPrototype { constructor() { } }', '"TypeError: The superclass\'s prototype is not an object."');

Added: trunk/LayoutTests/js/script-tests/class-syntax-prototype.js (0 => 183316)


--- trunk/LayoutTests/js/script-tests/class-syntax-prototype.js	                        (rev 0)
+++ trunk/LayoutTests/js/script-tests/class-syntax-prototype.js	2015-04-25 22:03:30 UTC (rev 183316)
@@ -0,0 +1,62 @@
+description('Tests for the descriptors of the properties implicitly defined by ES6 class syntax');
+
+function descriptor(object, propertyName) {
+    return Object.getOwnPropertyDescriptor(object, propertyName);
+}
+
+function enumeratedProperties(object) {
+    var properties = [];
+    for (var propertyName in object)
+        properties.push(propertyName);
+    return properties;
+}
+
+shouldBeFalse('class A {}; descriptor(A, "prototype").writable');
+shouldBe('class A {}; var x = A.prototype; A.prototype = 3; A.prototype', 'x');
+shouldBeFalse('class A {}; descriptor(A, "prototype").enumerable');
+shouldBeTrue('class A {}; A.foo = "foo"; enumeratedProperties(A).includes("foo")');
+shouldBeFalse('class A {}; enumeratedProperties(A).includes("prototype")');
+shouldBeFalse('class A {}; descriptor(A, "prototype").configurable');
+shouldThrow('class A {}; Object.defineProperty(A, "prototype", {value: "foo"})', '"TypeError: Attempting to change value of a readonly property."');
+
+shouldBeTrue('class A { static foo() {} }; descriptor(A, "foo").writable');
+shouldBe('class A { static foo() {} }; A.foo = 3; A.foo', '3');
+shouldBeFalse('class A { static foo() {} }; descriptor(A, "foo").enumerable');
+shouldBeFalse('class A { static foo() {} }; enumeratedProperties(A).includes("foo")');
+shouldBeTrue('class A { static foo() {} }; descriptor(A, "foo").configurable');
+shouldBe('class A { static foo() {} }; Object.defineProperty(A, "foo", {value: "bar"}); A.foo', '"bar"');
+
+shouldBe('class A { static get foo() {} }; descriptor(A, "foo").writable', 'undefined');
+shouldBe('class A { static get foo() { return 5; } }; A.foo = 3; A.foo', '5');
+shouldBeFalse('class A { static get foo() {} }; descriptor(A, "foo").enumerable');
+shouldBeFalse('class A { static get foo() {} }; enumeratedProperties(A).includes("foo")');
+shouldBeFalse('class A { static get foo() {} }; enumeratedProperties(new A).includes("foo")');
+shouldBeTrue('class A { static get foo() {} }; descriptor(A, "foo").configurable');
+shouldBe('class A { static get foo() {} }; Object.defineProperty(A, "foo", {value: "bar"}); A.foo', '"bar"');
+
+shouldBeTrue('class A { foo() {} }; descriptor(A.prototype, "foo").writable');
+shouldBe('class A { foo() {} }; A.prototype.foo = 3; A.prototype.foo', '3');
+shouldBeFalse('class A { foo() {} }; descriptor(A.prototype, "foo").enumerable');
+shouldBeFalse('class A { foo() {} }; enumeratedProperties(A.prototype).includes("foo")');
+shouldBeFalse('class A { foo() {} }; enumeratedProperties(new A).includes("foo")');
+shouldBeTrue('class A { foo() {} }; descriptor(A.prototype, "foo").configurable');
+shouldBe('class A { foo() {} }; Object.defineProperty(A.prototype, "foo", {value: "bar"}); A.prototype.foo', '"bar"');
+
+shouldBe('class A { get foo() {} }; descriptor(A.prototype, "foo").writable', 'undefined');
+shouldBe('class A { get foo() { return 5; } }; A.prototype.foo = 3; A.prototype.foo', '5');
+shouldBeFalse('class A { get foo() {} }; descriptor(A.prototype, "foo").enumerable');
+shouldBeFalse('class A { get foo() {} }; enumeratedProperties(A.prototype).includes("foo")');
+shouldBeFalse('class A { get foo() {} }; enumeratedProperties(new A).includes("foo")');
+shouldBeTrue('class A { get foo() {} }; descriptor(A.prototype, "foo").configurable');
+shouldBe('class A { get foo() {} }; Object.defineProperty(A.prototype, "foo", {value: "bar"}); A.prototype.foo', '"bar"');
+
+shouldBeTrue('class A { }; descriptor(A.prototype, "constructor").writable');
+shouldBe('class A { }; A.prototype.constructor = 3; A.prototype.constructor', '3');
+shouldBeTrue('class A { }; x = {}; A.prototype.constructor = function () { return x; }; (new A) instanceof A');
+shouldBeFalse('class A { }; descriptor(A.prototype, "constructor").enumerable');
+shouldBeFalse('class A { }; enumeratedProperties(A.prototype).includes("constructor")');
+shouldBeFalse('class A { }; enumeratedProperties(new A).includes("constructor")');
+shouldBeTrue('class A { }; descriptor(A.prototype, "constructor").configurable');
+shouldBe('class A { }; Object.defineProperty(A.prototype, "constructor", {value: "bar"}); A.prototype.constructor', '"bar"');
+
+var successfullyParsed = true;

Modified: trunk/Source/_javascript_Core/ChangeLog (183315 => 183316)


--- trunk/Source/_javascript_Core/ChangeLog	2015-04-25 22:00:51 UTC (rev 183315)
+++ trunk/Source/_javascript_Core/ChangeLog	2015-04-25 22:03:30 UTC (rev 183316)
@@ -1,3 +1,49 @@
+2015-04-23  Ryosuke Niwa  <[email protected]>
+
+        class methods should be non-enumerable
+        https://bugs.webkit.org/show_bug.cgi?id=143181
+
+        Reviewed by Darin Adler.
+
+        Fixed the bug by using Object.defineProperty to define methods.
+
+        This patch adds the concept of link time constants and uses it to resolve Object.defineProperty
+        inside CodeBlock's constructor since bytecode can be linked against multiple global objects.
+
+        * bytecode/CodeBlock.cpp: 
+        (JSC::CodeBlock::CodeBlock): Resolve link time constants that are used. Ignore ones with register
+        index of zero.
+        * bytecode/SpecialPointer.h: Added a new enum for link time constants. It currently contains
+        exactly one entry for Object.defineProperty.
+        * bytecode/UnlinkedCodeBlock.h:
+        (JSC::UnlinkedCodeBlock::addConstant): Added. Like addConstant that takes JSValue, allocate a new
+        constant register for the link time constant we're adding.
+        (JSC::UnlinkedCodeBlock::registerIndexForLinkTimeConstant): Added.
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::emitMoveLinkTimeConstant): Added. Like addConstantValue, allocate a new
+        register for the specified link time constant and notify UnlinkedCodeBlock about it.
+        (JSC::BytecodeGenerator::emitCallDefineProperty): Added. Create a new property descriptor and call
+        Object.defineProperty with it.
+        * bytecompiler/BytecodeGenerator.h:
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::PropertyListNode::emitBytecode): Make static and non-static getters and setters for classes
+        non-enumerable by using emitCallDefineProperty to define them.
+        (JSC::PropertyListNode::emitPutConstantProperty): Ditto for a non-accessor properties.
+        (JSC::ClassExprNode::emitBytecode): Make prototype.constructor non-enumerable and make prototype
+        property on the class non-writable, non-configurable, and non-enumerable by using defineProperty.
+        * runtime/CommonIdentifiers.h:
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::init): Set m_definePropertyFunction.
+        (JSC::JSGlobalObject::visitChildren): Visit m_definePropertyFunction.
+        * runtime/JSGlobalObject.h:
+        (JSC::JSGlobalObject::definePropertyFunction): Added.
+        (JSC::JSGlobalObject::actualPointerFor): Added a variant that takes LinkTimeConstant.
+        (JSC::JSGlobalObject::jsCellForLinkTimeConstant): Like actualPointerFor, takes LinkTimeConstant and
+        returns a JSCell; e.g. Object.defineProperty.
+        * runtime/ObjectConstructor.cpp:
+        (JSC::ObjectConstructor::addDefineProperty): Added. Returns Object.defineProperty.
+        * runtime/ObjectConstructor.h:
+
 2015-04-25  Yusuke Suzuki  <[email protected]>
 
         [ES6] Implement String.fromCodePoint

Modified: trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp (183315 => 183316)


--- trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp	2015-04-25 22:00:51 UTC (rev 183315)
+++ trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp	2015-04-25 22:03:30 UTC (rev 183316)
@@ -1761,6 +1761,13 @@
     setConstantRegisters(unlinkedCodeBlock->constantRegisters(), unlinkedCodeBlock->constantsSourceCodeRepresentation());
     if (unlinkedCodeBlock->usesGlobalObject())
         m_constantRegisters[unlinkedCodeBlock->globalObjectRegister().toConstantIndex()].set(*m_vm, ownerExecutable, m_globalObject.get());
+
+    for (unsigned i = 0; i < LinkTimeConstantCount; i++) {
+        LinkTimeConstant type = static_cast<LinkTimeConstant>(i);
+        if (unsigned registerIndex = unlinkedCodeBlock->registerIndexForLinkTimeConstant(type))
+            m_constantRegisters[registerIndex].set(*m_vm, ownerExecutable, m_globalObject->jsCellForLinkTimeConstant(type));
+    }
+
     m_functionDecls.resizeToFit(unlinkedCodeBlock->numberOfFunctionDecls());
     for (size_t count = unlinkedCodeBlock->numberOfFunctionDecls(), i = 0; i < count; ++i) {
         UnlinkedFunctionExecutable* unlinkedExecutable = unlinkedCodeBlock->functionDecl(i);

Modified: trunk/Source/_javascript_Core/bytecode/SpecialPointer.h (183315 => 183316)


--- trunk/Source/_javascript_Core/bytecode/SpecialPointer.h	2015-04-25 22:00:51 UTC (rev 183315)
+++ trunk/Source/_javascript_Core/bytecode/SpecialPointer.h	2015-04-25 22:03:30 UTC (rev 183316)
@@ -41,6 +41,11 @@
 };
 } // namespace Special
 
+enum class LinkTimeConstant {
+    DefinePropertyFunction,
+};
+const unsigned LinkTimeConstantCount = 1;
+
 inline bool pointerIsFunction(Special::Pointer pointer)
 {
     ASSERT_UNUSED(pointer, pointer < Special::TableSize);

Modified: trunk/Source/_javascript_Core/bytecode/UnlinkedCodeBlock.cpp (183315 => 183316)


--- trunk/Source/_javascript_Core/bytecode/UnlinkedCodeBlock.cpp	2015-04-25 22:00:51 UTC (rev 183315)
+++ trunk/Source/_javascript_Core/bytecode/UnlinkedCodeBlock.cpp	2015-04-25 22:03:30 UTC (rev 183316)
@@ -261,6 +261,8 @@
     , m_bytecodeCommentIterator(0)
 #endif
 {
+    for (auto& constantRegisterIndex : m_linkTimeConstants)
+        constantRegisterIndex = 0;
     ASSERT(m_constructorKind == static_cast<unsigned>(info.constructorKind()));
 }
 

Modified: trunk/Source/_javascript_Core/bytecode/UnlinkedCodeBlock.h (183315 => 183316)


--- trunk/Source/_javascript_Core/bytecode/UnlinkedCodeBlock.h	2015-04-25 22:00:51 UTC (rev 183315)
+++ trunk/Source/_javascript_Core/bytecode/UnlinkedCodeBlock.h	2015-04-25 22:03:30 UTC (rev 183316)
@@ -331,6 +331,23 @@
         m_constantsSourceCodeRepresentation.append(sourceCodeRepresentation);
         return result;
     }
+    unsigned addConstant(LinkTimeConstant type)
+    {
+        unsigned result = m_constantRegisters.size();
+        ASSERT(result);
+        unsigned index = static_cast<unsigned>(type);
+        ASSERT(index < LinkTimeConstantCount);
+        m_linkTimeConstants[index] = result;
+        m_constantRegisters.append(WriteBarrier<Unknown>());
+        m_constantsSourceCodeRepresentation.append(SourceCodeRepresentation::Other);
+        return result;
+    }
+    unsigned registerIndexForLinkTimeConstant(LinkTimeConstant type)
+    {
+        unsigned index = static_cast<unsigned>(type);
+        ASSERT(index < LinkTimeConstantCount);
+        return m_linkTimeConstants[index];
+    }
     unsigned addOrFindConstant(JSValue);
     const Vector<WriteBarrier<Unknown>>& constantRegisters() { return m_constantRegisters; }
     const WriteBarrier<Unknown>& constantRegister(int index) const { return m_constantRegisters[index - FirstConstantRegisterIndex]; }
@@ -556,6 +573,7 @@
     Vector<Identifier> m_identifiers;
     Vector<WriteBarrier<Unknown>> m_constantRegisters;
     Vector<SourceCodeRepresentation> m_constantsSourceCodeRepresentation;
+    std::array<unsigned, LinkTimeConstantCount> m_linkTimeConstants;
     typedef Vector<WriteBarrier<UnlinkedFunctionExecutable>> FunctionExpressionVector;
     FunctionExpressionVector m_functionDecls;
     FunctionExpressionVector m_functionExprs;

Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp (183315 => 183316)


--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2015-04-25 22:00:51 UTC (rev 183315)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2015-04-25 22:03:30 UTC (rev 183316)
@@ -149,6 +149,9 @@
     , m_codeType(GlobalCode)
     , m_vm(&vm)
 {
+    for (auto& constantRegister : m_linkTimeConstantRegisters)
+        constantRegister = nullptr;
+
     m_codeBlock->setNumParameters(1); // Allocate space for "this"
 
     emitOpcode(op_enter);
@@ -179,6 +182,9 @@
     , m_vm(&vm)
     , m_isBuiltinFunction(codeBlock->isBuiltinFunction())
 {
+    for (auto& constantRegister : m_linkTimeConstantRegisters)
+        constantRegister = nullptr;
+
     if (m_isBuiltinFunction)
         m_shouldEmitDebugHooks = false;
     
@@ -494,6 +500,9 @@
     , m_codeType(EvalCode)
     , m_vm(&vm)
 {
+    for (auto& constantRegister : m_linkTimeConstantRegisters)
+        constantRegister = nullptr;
+
     m_symbolTable->setUsesNonStrictEval(codeBlock->usesEval() && !codeBlock->isStrictMode());
     m_codeBlock->setNumParameters(1);
 
@@ -984,6 +993,24 @@
     return &m_constantPoolRegisters[index];
 }
 
+RegisterID* BytecodeGenerator::emitMoveLinkTimeConstant(RegisterID* dst, LinkTimeConstant type)
+{
+    unsigned constantIndex = static_cast<unsigned>(type);
+    if (!m_linkTimeConstantRegisters[constantIndex]) {
+        int index = m_nextConstantOffset;
+        m_constantPoolRegisters.append(FirstConstantRegisterIndex + m_nextConstantOffset);
+        ++m_nextConstantOffset;
+        m_codeBlock->addConstant(type);
+        m_linkTimeConstantRegisters[constantIndex] = &m_constantPoolRegisters[index];
+    }
+
+    emitOpcode(op_mov);
+    instructions().append(dst->index());
+    instructions().append(m_linkTimeConstantRegisters[constantIndex]->index());
+
+    return dst;
+}
+
 unsigned BytecodeGenerator::addRegExp(RegExp* r)
 {
     return m_codeBlock->addRegExp(r);
@@ -1950,6 +1977,41 @@
     return dst;
 }
 
+void BytecodeGenerator::emitCallDefineProperty(RegisterID* newObj, RegisterID* propertyNameRegister,
+    RegisterID* valueRegister, RegisterID* getterRegister, RegisterID* setterRegister, unsigned options, const JSTextPosition& position)
+{
+    RefPtr<RegisterID> descriptorRegister = emitNewObject(newTemporary());
+
+    RefPtr<RegisterID> trueRegister = emitLoad(newTemporary(), true);
+    if (options & PropertyConfigurable)
+        emitDirectPutById(descriptorRegister.get(), propertyNames().configurable, trueRegister.get(), PropertyNode::Unknown);
+    if (options & PropertyWritable)
+        emitDirectPutById(descriptorRegister.get(), propertyNames().writable, trueRegister.get(), PropertyNode::Unknown);
+    else if (valueRegister) {
+        RefPtr<RegisterID> falseRegister = emitLoad(newTemporary(), false);
+        emitDirectPutById(descriptorRegister.get(), propertyNames().writable, falseRegister.get(), PropertyNode::Unknown);
+    }
+    if (options & PropertyEnumerable)
+        emitDirectPutById(descriptorRegister.get(), propertyNames().enumerable, trueRegister.get(), PropertyNode::Unknown);
+
+    if (valueRegister)
+        emitDirectPutById(descriptorRegister.get(), propertyNames().value, valueRegister, PropertyNode::Unknown);
+    if (getterRegister)
+        emitDirectPutById(descriptorRegister.get(), propertyNames().get, getterRegister, PropertyNode::Unknown);
+    if (setterRegister)
+        emitDirectPutById(descriptorRegister.get(), propertyNames().set, setterRegister, PropertyNode::Unknown);
+
+    RefPtr<RegisterID> definePropertyRegister = emitMoveLinkTimeConstant(newTemporary(), LinkTimeConstant::DefinePropertyFunction);
+
+    CallArguments callArguments(*this, nullptr, 3);
+    emitLoad(callArguments.thisRegister(), jsUndefined());
+    emitMove(callArguments.argumentRegister(0), newObj);
+    emitMove(callArguments.argumentRegister(1), propertyNameRegister);
+    emitMove(callArguments.argumentRegister(2), descriptorRegister.get());
+
+    emitCall(newTemporary(), definePropertyRegister.get(), NoExpectedFunction, callArguments, position, position, position);
+}
+
 RegisterID* BytecodeGenerator::emitReturn(RegisterID* src)
 {
     if (isConstructor()) {

Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h (183315 => 183316)


--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h	2015-04-25 22:00:51 UTC (rev 183315)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h	2015-04-25 22:03:30 UTC (rev 183316)
@@ -458,6 +458,7 @@
         RegisterID* emitNewDefaultConstructor(RegisterID* dst, ConstructorKind, const Identifier& name);
         RegisterID* emitNewRegExp(RegisterID* dst, RegExp*);
 
+        RegisterID* emitMoveLinkTimeConstant(RegisterID* dst, LinkTimeConstant);
         RegisterID* emitMoveEmptyValue(RegisterID* dst);
         RegisterID* emitMove(RegisterID* dst, RegisterID* src);
 
@@ -489,6 +490,14 @@
         RegisterID* emitCallEval(RegisterID* dst, RegisterID* func, CallArguments&, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
         RegisterID* emitCallVarargs(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, RegisterID* profileHookRegister, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
 
+        enum PropertyDescriptorOption {
+            PropertyConfigurable = 1,
+            PropertyWritable     = 1 << 1,
+            PropertyEnumerable   = 1 << 2,
+        };
+        void emitCallDefineProperty(RegisterID* newObj, RegisterID* propertyNameRegister,
+            RegisterID* valueRegister, RegisterID* getterRegister, RegisterID* setterRegister, unsigned options, const JSTextPosition&);
+
         void emitEnumeration(ThrowableExpressionData* enumerationNode, ExpressionNode* subjectNode, const std::function<void(BytecodeGenerator&, RegisterID*)>& callBack);
         
         RegisterID* emitReturn(RegisterID* src);
@@ -720,6 +729,7 @@
         RegisterID* m_emptyValueRegister { nullptr };
         RegisterID* m_globalObjectRegister { nullptr };
         RegisterID* m_newTargetRegister { nullptr };
+        RegisterID* m_linkTimeConstantRegisters[LinkTimeConstantCount];
 
         SegmentedVector<RegisterID, 32> m_constantPoolRegisters;
         SegmentedVector<RegisterID, 32> m_calleeRegisters;

Modified: trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp (183315 => 183316)


--- trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp	2015-04-25 22:00:51 UTC (rev 183315)
+++ trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp	2015-04-25 22:03:30 UTC (rev 183316)
@@ -362,7 +362,8 @@
             }
 
             RegisterID* value = generator.emitNode(node->m_assign);
-            if (node->needsSuperBinding())
+            bool isClassProperty = node->needsSuperBinding();
+            if (isClassProperty)
                 emitPutHomeObject(generator, value, dst);
 
             // This is a get/set property, find its entry in the map.
@@ -403,10 +404,16 @@
                 }
             }
 
-            if (pair.second && pair.second->needsSuperBinding())
+            ASSERT(!pair.second || isClassProperty == pair.second->needsSuperBinding());
+            if (isClassProperty && pair.second)
                 emitPutHomeObject(generator, secondReg, dst);
 
-            generator.emitPutGetterSetter(dst, *node->name(), getterReg.get(), setterReg.get());
+            if (isClassProperty) {
+                RefPtr<RegisterID> propertyNameRegister = generator.emitLoad(generator.newTemporary(), *node->name());
+                generator.emitCallDefineProperty(dst, propertyNameRegister.get(),
+                    nullptr, getterReg.get(), setterReg.get(), BytecodeGenerator::PropertyConfigurable, m_position);
+            } else
+                generator.emitPutGetterSetter(dst, *node->name(), getterReg.get(), setterReg.get());
         }
     }
 
@@ -416,8 +423,19 @@
 void PropertyListNode::emitPutConstantProperty(BytecodeGenerator& generator, RegisterID* newObj, PropertyNode& node)
 {
     RefPtr<RegisterID> value = generator.emitNode(node.m_assign);
-    if (node.needsSuperBinding())
+    if (node.needsSuperBinding()) {
         emitPutHomeObject(generator, value.get(), newObj);
+
+        RefPtr<RegisterID> propertyNameRegister;
+        if (node.name())
+            propertyNameRegister = generator.emitLoad(generator.newTemporary(), *node.name());
+        else
+            propertyNameRegister = generator.emitNode(node.m_expression);
+
+        generator.emitCallDefineProperty(newObj, propertyNameRegister.get(),
+            value.get(), nullptr, nullptr, BytecodeGenerator::PropertyConfigurable | BytecodeGenerator::PropertyWritable, m_position);
+        return;
+    }
     if (node.name()) {
         generator.emitDirectPutById(newObj, *node.name(), value.get(), node.putType());
         return;
@@ -2871,7 +2889,6 @@
     }
 
     RefPtr<RegisterID> constructor;
-    RefPtr<RegisterID> prototype;
 
     // FIXME: Make the prototype non-configurable & non-writable.
     if (m_constructorExpression)
@@ -2881,7 +2898,8 @@
             m_classHeritage ? ConstructorKind::Derived : ConstructorKind::Base, m_name);
     }
 
-    prototype = generator.emitGetById(generator.newTemporary(), constructor.get(), generator.propertyNames().prototype);
+    const auto& propertyNames = generator.propertyNames();
+    RefPtr<RegisterID> prototype = generator.emitNewObject(generator.newTemporary());
 
     if (superclass) {
         RefPtr<RegisterID> protoParent = generator.newTemporary();
@@ -2910,6 +2928,13 @@
         emitPutHomeObject(generator, constructor.get(), prototype.get());
     }
 
+    RefPtr<RegisterID> constructorNameRegister = generator.emitLoad(generator.newTemporary(), propertyNames.constructor);
+    generator.emitCallDefineProperty(prototype.get(), constructorNameRegister.get(), constructor.get(), nullptr, nullptr,
+        BytecodeGenerator::PropertyConfigurable | BytecodeGenerator::PropertyWritable, m_position);
+
+    RefPtr<RegisterID> prototypeNameRegister = generator.emitLoad(generator.newTemporary(), propertyNames.prototype);
+    generator.emitCallDefineProperty(constructor.get(), prototypeNameRegister.get(), prototype.get(), nullptr, nullptr, 0, m_position);
+
     if (m_staticMethods)
         generator.emitNode(constructor.get(), m_staticMethods);
 

Modified: trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h (183315 => 183316)


--- trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h	2015-04-25 22:00:51 UTC (rev 183315)
+++ trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h	2015-04-25 22:03:30 UTC (rev 183316)
@@ -91,6 +91,7 @@
     macro(constructor) \
     macro(count) \
     macro(counters) \
+    macro(defineProperty) \
     macro(description) \
     macro(descriptions) \
     macro(displayName) \

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp (183315 => 183316)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2015-04-25 22:00:51 UTC (rev 183315)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2015-04-25 22:03:30 UTC (rev 183316)
@@ -332,6 +332,10 @@
     
     ObjectConstructor* objectConstructor = ObjectConstructor::create(vm, this, ObjectConstructor::createStructure(vm, this, m_functionPrototype.get()), m_objectPrototype.get());
     m_objectConstructor.set(vm, this, objectConstructor);
+
+    JSFunction* definePropertyFunction = m_objectConstructor->addDefineProperty(exec, this);
+    m_definePropertyFunction.set(vm, this, definePropertyFunction);
+
     JSCell* functionConstructor = FunctionConstructor::create(vm, FunctionConstructor::createStructure(vm, this, m_functionPrototype.get()), m_functionPrototype.get());
     JSCell* arrayConstructor = ArrayConstructor::create(vm, ArrayConstructor::createStructure(vm, this, m_functionPrototype.get()), m_arrayPrototype.get());
     
@@ -458,7 +462,9 @@
     m_specialPointers[Special::ApplyFunction] = m_applyFunction.get();
     m_specialPointers[Special::ObjectConstructor] = objectConstructor;
     m_specialPointers[Special::ArrayConstructor] = arrayConstructor;
-    
+
+    m_linkTimeConstants[static_cast<unsigned>(LinkTimeConstant::DefinePropertyFunction)] = m_definePropertyFunction.get();
+
     ConsolePrototype* consolePrototype = ConsolePrototype::create(vm, this, ConsolePrototype::createStructure(vm, this, m_objectPrototype.get()));
     m_consoleStructure.set(vm, this, JSConsole::createStructure(vm, this, consolePrototype));
     JSConsole* consoleObject = JSConsole::create(vm, m_consoleStructure.get());
@@ -717,6 +723,7 @@
     visitor.append(&thisObject->m_evalFunction);
     visitor.append(&thisObject->m_callFunction);
     visitor.append(&thisObject->m_applyFunction);
+    visitor.append(&thisObject->m_definePropertyFunction);
     visitor.append(&thisObject->m_arrayProtoValuesFunction);
     visitor.append(&thisObject->m_throwTypeErrorGetterSetter);
 

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.h (183315 => 183316)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.h	2015-04-25 22:00:51 UTC (rev 183315)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.h	2015-04-25 22:03:30 UTC (rev 183316)
@@ -191,6 +191,7 @@
     WriteBarrier<JSFunction> m_evalFunction;
     WriteBarrier<JSFunction> m_callFunction;
     WriteBarrier<JSFunction> m_applyFunction;
+    WriteBarrier<JSFunction> m_definePropertyFunction;
     WriteBarrier<JSFunction> m_arrayProtoValuesFunction;
     WriteBarrier<GetterSetter> m_throwTypeErrorGetterSetter;
 
@@ -257,9 +258,10 @@
     };
     
     std::array<TypedArrayData, NUMBER_OF_TYPED_ARRAY_TYPES> m_typedArrays;
-        
-    void* m_specialPointers[Special::TableSize]; // Special pointers used by the LLInt and JIT.
 
+    JSCell* m_specialPointers[Special::TableSize]; // Special pointers used by the LLInt and JIT.
+    JSCell* m_linkTimeConstants[LinkTimeConstantCount];
+
     String m_name;
 
     Debugger* m_debugger;
@@ -400,6 +402,7 @@
     JSFunction* evalFunction() const { return m_evalFunction.get(); }
     JSFunction* callFunction() const { return m_callFunction.get(); }
     JSFunction* applyFunction() const { return m_applyFunction.get(); }
+    JSFunction* definePropertyFunction() const { return m_definePropertyFunction.get(); }
     JSFunction* arrayProtoValuesFunction() const { return m_arrayProtoValuesFunction.get(); }
     GetterSetter* throwTypeErrorGetterSetter(VM& vm)
     {
@@ -523,11 +526,17 @@
         return typedArrayStructure(type) == structure;
     }
 
-    void* actualPointerFor(Special::Pointer pointer)
+    JSCell* actualPointerFor(Special::Pointer pointer)
     {
         ASSERT(pointer < Special::TableSize);
         return m_specialPointers[pointer];
     }
+    JSCell* jsCellForLinkTimeConstant(LinkTimeConstant type)
+    {
+        unsigned index = static_cast<unsigned>(type);
+        ASSERT(index < LinkTimeConstantCount);
+        return m_linkTimeConstants[index];
+    }
 
     WatchpointSet* masqueradesAsUndefinedWatchpoint() { return m_masqueradesAsUndefinedWatchpoint.get(); }
     WatchpointSet* havingABadTimeWatchpoint() { return m_havingABadTimeWatchpoint.get(); }

Modified: trunk/Source/_javascript_Core/runtime/ObjectConstructor.cpp (183315 => 183316)


--- trunk/Source/_javascript_Core/runtime/ObjectConstructor.cpp	2015-04-25 22:00:51 UTC (rev 183315)
+++ trunk/Source/_javascript_Core/runtime/ObjectConstructor.cpp	2015-04-25 22:03:30 UTC (rev 183316)
@@ -98,6 +98,14 @@
         JSC_NATIVE_FUNCTION("getOwnPropertySymbols", objectConstructorGetOwnPropertySymbols, DontEnum, 1);
 }
 
+JSFunction* ObjectConstructor::addDefineProperty(ExecState* exec, JSGlobalObject* globalObject)
+{
+    VM& vm = exec->vm();
+    JSFunction* definePropertyFunction = JSFunction::create(vm, globalObject, 3, vm.propertyNames->defineProperty.string(), objectConstructorDefineProperty);
+    putDirectWithoutTransition(vm, vm.propertyNames->defineProperty, definePropertyFunction, DontEnum);
+    return definePropertyFunction;
+}
+
 bool ObjectConstructor::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot &slot)
 {
     return getStaticFunctionSlot<JSObject>(exec, objectConstructorTable, jsCast<ObjectConstructor*>(object), propertyName, slot);

Modified: trunk/Source/_javascript_Core/runtime/ObjectConstructor.h (183315 => 183316)


--- trunk/Source/_javascript_Core/runtime/ObjectConstructor.h	2015-04-25 22:00:51 UTC (rev 183315)
+++ trunk/Source/_javascript_Core/runtime/ObjectConstructor.h	2015-04-25 22:03:30 UTC (rev 183316)
@@ -54,6 +54,8 @@
         return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
     }
 
+    JSFunction* addDefineProperty(ExecState*, JSGlobalObject*);
+
 protected:
     void finishCreation(VM&, JSGlobalObject*, ObjectPrototype*);
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to