Title: [213697] trunk
Revision
213697
Author
[email protected]
Date
2017-03-09 18:00:33 -0800 (Thu, 09 Mar 2017)

Log Message

[ESnext] Implement Object Rest - Implementing Object Rest Destructuring
https://bugs.webkit.org/show_bug.cgi?id=167962

Patch by Caio Lima <[email protected]> on 2017-03-09
Reviewed by Keith Miller.

JSTests:

* stress/object-rest-deconstruct.js: Added.
(let.assert):
(let.assertPropDescriptor):
(catch):
(get 3):
(foo):
(let.src.get y):
(let.src.set y):
(let.gen):

Source/_javascript_Core:

Object Rest/Spread Destructing proposal is in stage 3[1] and this
Patch is a prototype implementation of it. A simple change over the
parser was necessary to support the new '...' token on Object Pattern
destruction rule. In the bytecode generator side, We changed the
bytecode generated on ObjectPatternNode::bindValue to store in an
array identifiers of already destructed properties, following spec draft
section[2], and then pass it as excludedNames to CopyDataProperties.
The rest destruction the calls copyDataProperties to perform the
copy of rest properties in rhs.

We also implemented CopyDataProperties as private JS global operation
on builtins/GlobalOperations.js following it's specification on [3].
It is implemented using Set object to verify if a property is on
excludedNames to keep this algorithm with O(n + m) complexity, where n
= number of source's own properties and m = excludedNames.length.

As a requirement to use JSSets as constants, a change in
CodeBlock::create API was necessary, because JSSet creation can throws OOM
exception. Now, CodeBlock::finishCreation returns ```false``` if an
execption is throwed by
CodeBlock::setConstantIdentifierSetRegisters and then we return
nullptr to ScriptExecutable::newCodeBlockFor. It is responsible to
check if CodeBlock was constructed properly and then, throw OOM
exception to the correct scope.

[1] - https://github.com/sebmarkbage/ecmascript-rest-spread
[2] - http://sebmarkbage.github.io/ecmascript-rest-spread/#Rest-RuntimeSemantics-PropertyDestructuringAssignmentEvaluation
[3] - http://sebmarkbage.github.io/ecmascript-rest-spread/#AbstractOperations-CopyDataProperties

* builtins/BuiltinNames.h:
* builtins/GlobalOperations.js:
(globalPrivate.copyDataProperties):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::finishCreation):
(JSC::CodeBlock::setConstantIdentifierSetRegisters):
* bytecode/CodeBlock.h:
* bytecode/EvalCodeBlock.h:
(JSC::EvalCodeBlock::create):
* bytecode/FunctionCodeBlock.h:
(JSC::FunctionCodeBlock::create):
* bytecode/ModuleProgramCodeBlock.h:
(JSC::ModuleProgramCodeBlock::create):
* bytecode/ProgramCodeBlock.h:
(JSC::ProgramCodeBlock::create):
* bytecode/UnlinkedCodeBlock.h:
(JSC::UnlinkedCodeBlock::addSetConstant):
(JSC::UnlinkedCodeBlock::constantIdentifierSets):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitLoad):
* bytecompiler/BytecodeGenerator.h:
* bytecompiler/NodesCodegen.cpp:
(JSC::ObjectPatternNode::bindValue):
* parser/ASTBuilder.h:
(JSC::ASTBuilder::appendObjectPatternEntry):
(JSC::ASTBuilder::appendObjectPatternRestEntry):
(JSC::ASTBuilder::setContainsObjectRestElement):
* parser/Nodes.h:
(JSC::ObjectPatternNode::appendEntry):
(JSC::ObjectPatternNode::setContainsRestElement):
* parser/Parser.cpp:
(JSC::Parser<LexerType>::parseDestructuringPattern):
(JSC::Parser<LexerType>::parseProperty):
* parser/SyntaxChecker.h:
(JSC::SyntaxChecker::operatorStackPop):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):
* runtime/JSGlobalObjectFunctions.cpp:
(JSC::privateToObject):
* runtime/JSGlobalObjectFunctions.h:
* runtime/ScriptExecutable.cpp:
(JSC::ScriptExecutable::newCodeBlockFor):

Source/WTF:

* wtf/HashSet.h:
(WTF::=):

LayoutTests:

* js/parser-syntax-check-expected.txt:
* js/script-tests/parser-syntax-check.js:

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (213696 => 213697)


--- trunk/JSTests/ChangeLog	2017-03-10 01:48:30 UTC (rev 213696)
+++ trunk/JSTests/ChangeLog	2017-03-10 02:00:33 UTC (rev 213697)
@@ -1,3 +1,20 @@
+2017-03-09  Caio Lima  <[email protected]>
+
+        [ESnext] Implement Object Rest - Implementing Object Rest Destructuring
+        https://bugs.webkit.org/show_bug.cgi?id=167962
+
+        Reviewed by Keith Miller.
+
+        * stress/object-rest-deconstruct.js: Added.
+        (let.assert):
+        (let.assertPropDescriptor):
+        (catch):
+        (get 3):
+        (foo):
+        (let.src.get y):
+        (let.src.set y):
+        (let.gen):
+
 2017-03-09  Saam Barati  <[email protected]>
 
         WebAssembly: Make the Unity AngryBots demo run

Added: trunk/JSTests/stress/object-rest-deconstruct.js (0 => 213697)


--- trunk/JSTests/stress/object-rest-deconstruct.js	                        (rev 0)
+++ trunk/JSTests/stress/object-rest-deconstruct.js	2017-03-10 02:00:33 UTC (rev 213697)
@@ -0,0 +1,246 @@
+let assert = (e) => {
+    if (!e)
+        throw Error("Bad assertion!");
+}
+
+let assertPropDescriptor = (restObj, prop) => {
+    let desc = Object.getOwnPropertyDescriptor(restObj, prop);
+    assert(desc.enumerable);
+    assert(desc.writable);
+    assert(desc.configurable);
+}
+
+// Base Case
+(() => {
+    let obj = {x: 1, y: 2, a: 5, b: 3}
+
+    let {a, b, ...rest} = obj;
+
+    assert(a === 5);
+    assert(b === 3);
+
+    assert(rest.x === 1);
+    assert(rest.y === 2);
+
+    assertPropDescriptor(rest, 'x');
+    assertPropDescriptor(rest, 'y');
+})();
+
+// Empty Object
+(() => {
+    let obj = {}
+
+    let {a, b, ...rest} = obj;
+
+    assert(a === undefined);
+    assert(b === undefined);
+
+    assert(typeof rest === "object");
+})();
+
+// Number case
+(() => {
+    let obj = 3;
+
+    let {...rest} = obj;
+
+    assert(typeof rest === "object");
+})();
+
+// String case
+(() => {
+    let obj = "foo";
+
+    let {...rest} = obj;
+
+    assert(typeof rest === "object");
+})();
+
+// Symbol case
+(() => {
+    let obj = Symbol("foo");
+
+    let {...rest} = obj;
+
+    assert(typeof rest === "object");
+})();
+
+// null case
+(() => {
+    let obj = null;
+
+    try {
+        let {...rest} = obj;
+        assert(false);
+    } catch (e) {
+        assert(e.message == "Right side of assignment cannot be destructured");
+    }
+
+})();
+
+// undefined case
+(() => {
+    let obj = undefined;
+
+    try {
+        let {...rest} = obj;
+        assert(false);
+    } catch (e) {
+        assert(e.message == "Right side of assignment cannot be destructured");
+    }
+
+})();
+
+// getter case
+(() => {
+    let obj = {a: 3, b: 4};
+    Object.defineProperty(obj, "x", { get: () => 3, enumerable: true });
+
+    let {a, b, ...rest} = obj;
+
+    assert(a === 3);
+    assert(b === 4);
+
+    assert(rest.x === 3);
+    assertPropDescriptor(rest, 'x');
+})();
+
+// Skip non-enumerable case
+(() => {
+    let obj = {a: 3, b: 4};
+    Object.defineProperty(obj, "x", { value: 4, enumerable: false });
+
+    let {...rest} = obj;
+
+    assert(rest.a === 3);
+    assert(rest.b === 4);
+    assert(rest.x === undefined);
+})();
+
+// Don't copy descriptor case
+(() => {
+    let obj = {};
+    Object.defineProperty(obj, "a", { value: 3, configurable: false, enumerable: true });
+    Object.defineProperty(obj, "b", { value: 4, writable: false, enumerable: true });
+
+    let {...rest} = obj;
+
+    assert(rest.a === 3);
+    assert(rest.b === 4);
+
+    assertPropDescriptor(rest, 'a');
+    assertPropDescriptor(rest, 'b');
+})();
+
+// Nested base case
+(() => {
+    let obj = {a: 1, b: 2, c: 3, d: 4, e: 5};
+
+    let {a, b, ...{c, e}} = obj;
+
+    assert(a === 1);
+    assert(b === 2);
+    assert(c === 3);
+    assert(e === 5);
+})();
+
+// Nested rest case
+(() => {
+    let obj = {a: 1, b: 2, c: 3, d: 4, e: 5};
+
+    let {a, b, ...{c, ...rest}} = obj;
+
+    assert(a === 1);
+    assert(b === 2);
+    assert(c === 3);
+
+    assert(rest.d === 4);
+    assert(rest.e === 5);
+})();
+
+// Destructuring Only Own Properties
+(() => {
+    var o = Object.create({ x: 1, y: 2 });
+    o.z = 3;
+
+    var x, y, z;
+
+    // Destructuring assignment allows nested objects
+    ({ x, ...{y , z} } = o);
+
+    assert(x === 1);
+    assert(y === undefined);
+    assert(z === 3);
+})();
+
+// Destructuring function parameter
+
+(() => {
+
+    var o = { x: 1, y: 2, w: 3, z: 4 };
+    
+    function foo({ x, y, ...rest }) {
+        assert(x === 1);
+        assert(y === 2);
+        assert(rest.w === 3);
+        assert(rest.z === 4);
+    }
+    foo(o);
+})();
+
+// Destructuring arrow function parameter
+
+(() => {
+
+    var o = { x: 1, y: 2, w: 3, z: 4 };
+    
+    (({ x, y, ...rest }) => {
+        assert(x === 1);
+        assert(y === 2);
+        assert(rest.w === 3);
+        assert(rest.z === 4);
+    })(o);
+})();
+
+// Destructuring to a property
+(() => {
+
+    var o = { x: 1, y: 2};
+    
+    let settedValue;
+    let src = ""
+    ({...src.y} = o);
+    assert(src.y.x === 1);
+    assert(src.y.y === 2);
+})();
+
+// Destructuring with setter
+(() => {
+
+    var o = { x: 1, y: 2};
+    
+    let settedValue;
+    let src = {
+        get y() { throw Error("The property should not be accessed"); }, 
+        set y(v) {
+            settedValue = v;
+        }
+    }
+    src.y = undefined;
+    ({...src.y} = o);
+    assert(settedValue.x === 1);
+    assert(settedValue.y === 2);
+})();
+
+// Destructuring yield
+(() => {
+
+    var o = { x: 1, y: 2, w: 3, z: 4 };
+    
+    let gen = (function * (o) {
+        ({...{ x = yield }} = o);
+    })(o);
+    
+    assert(gen.next().value === undefined);
+})();
+

Modified: trunk/LayoutTests/ChangeLog (213696 => 213697)


--- trunk/LayoutTests/ChangeLog	2017-03-10 01:48:30 UTC (rev 213696)
+++ trunk/LayoutTests/ChangeLog	2017-03-10 02:00:33 UTC (rev 213697)
@@ -1,3 +1,13 @@
+2017-03-09  Caio Lima  <[email protected]>
+
+        [ESnext] Implement Object Rest - Implementing Object Rest Destructuring
+        https://bugs.webkit.org/show_bug.cgi?id=167962
+
+        Reviewed by Keith Miller.
+
+        * js/parser-syntax-check-expected.txt:
+        * js/script-tests/parser-syntax-check.js:
+
 2017-03-09  Matt Baker  <[email protected]>
 
         Web Inspector: Add XHR breakpoints UI

Modified: trunk/LayoutTests/js/parser-syntax-check-expected.txt (213696 => 213697)


--- trunk/LayoutTests/js/parser-syntax-check-expected.txt	2017-03-10 01:48:30 UTC (rev 213696)
+++ trunk/LayoutTests/js/parser-syntax-check-expected.txt	2017-03-10 02:00:33 UTC (rev 213697)
@@ -1167,8 +1167,32 @@
 PASS Valid:   "function f() { var {x: [y, {z: {z: [...z]}}]} = 20 }"
 PASS Invalid: "var [...y, ...z] = 20". Produced the following syntax error: "SyntaxError: Unexpected token ','. Expected a closing ']' following a rest element destructuring pattern."
 PASS Invalid: "function f() { var [...y, ...z] = 20 }". Produced the following syntax error: "SyntaxError: Unexpected token ','. Expected a closing ']' following a rest element destructuring pattern."
-PASS Invalid: "var [...{...y}] = 20". Produced the following syntax error: "SyntaxError: Unexpected token '...'. Expected a property name."
-PASS Invalid: "function f() { var [...{...y}] = 20 }". Produced the following syntax error: "SyntaxError: Unexpected token '...'. Expected a property name."
+PASS Valid:   "var [...{...y}] = 20" with TypeError
+PASS Valid:   "function f() { var [...{...y}] = 20 }"
+PASS Valid:   "var {a, b, ...r} = {a: 1, b: 2, c: 3};"
+PASS Valid:   "function f() { var {a, b, ...r} = {a: 1, b: 2, c: 3}; }"
+PASS Valid:   "var {a, b, ...{d}} = {a: 1, b: 2, c: 3, d: 4};"
+PASS Valid:   "function f() { var {a, b, ...{d}} = {a: 1, b: 2, c: 3, d: 4}; }"
+PASS Valid:   "var {a, b, ...{d = 15}} = {a: 1, b: 2, c: 3, d: 4};"
+PASS Valid:   "function f() { var {a, b, ...{d = 15}} = {a: 1, b: 2, c: 3, d: 4}; }"
+PASS Valid:   "var {a, b, ...{d = 15, ...r}} = {a: 1, b: 2, c: 3, d: 4};"
+PASS Valid:   "function f() { var {a, b, ...{d = 15, ...r}} = {a: 1, b: 2, c: 3, d: 4}; }"
+PASS Valid:   "(({a, b, ...r}) => {})({a: 1, b: 2, c: 3, d: 4});"
+PASS Valid:   "function f() { (({a, b, ...r}) => {})({a: 1, b: 2, c: 3, d: 4}); }"
+PASS Valid:   "(function ({a, b, ...r}) {})({a: 1, b: 2, c: 3, d: 4});"
+PASS Valid:   "function f() { (function ({a, b, ...r}) {})({a: 1, b: 2, c: 3, d: 4}); }"
+PASS Valid:   "var a, b, c; ({a, b, ...r} = {a: 1, b: 2, c: 3, d: 4});"
+PASS Valid:   "function f() { var a, b, c; ({a, b, ...r} = {a: 1, b: 2, c: 3, d: 4}); }"
+PASS Valid:   "function * foo(o) { ({...{ x = yield }} = o); }"
+PASS Valid:   "function f() { function * foo(o) { ({...{ x = yield }} = o); } }"
+PASS Invalid: "var {...r = {a: 2}} = {a: 1, b: 2};". Produced the following syntax error: "SyntaxError: Unexpected token '='. Expected a closing '}' following a rest element destructuring pattern."
+PASS Invalid: "function f() { var {...r = {a: 2}} = {a: 1, b: 2}; }". Produced the following syntax error: "SyntaxError: Unexpected token '='. Expected a closing '}' following a rest element destructuring pattern."
+PASS Invalid: "var {...r, b} = {a: 1, b: 2};". Produced the following syntax error: "SyntaxError: Unexpected token ','. Expected a closing '}' following a rest element destructuring pattern."
+PASS Invalid: "function f() { var {...r, b} = {a: 1, b: 2}; }". Produced the following syntax error: "SyntaxError: Unexpected token ','. Expected a closing '}' following a rest element destructuring pattern."
+PASS Invalid: "var {...r, ...e} = {a: 1, b: 2};". Produced the following syntax error: "SyntaxError: Unexpected token ','. Expected a closing '}' following a rest element destructuring pattern."
+PASS Invalid: "function f() { var {...r, ...e} = {a: 1, b: 2}; }". Produced the following syntax error: "SyntaxError: Unexpected token ','. Expected a closing '}' following a rest element destructuring pattern."
+PASS Invalid: "function * (o) { ({ ...{ x: yield } } = o); }". Produced the following syntax error: "SyntaxError: Unexpected token '('"
+PASS Invalid: "function f() { function * (o) { ({ ...{ x: yield } } = o); } }". Produced the following syntax error: "SyntaxError: Unexpected token '('"
 Rest parameter
 PASS Valid:   "function foo(...a) { }"
 PASS Valid:   "function f() { function foo(...a) { } }"
@@ -1236,8 +1260,8 @@
 PASS Valid:   "function f() { let x = (a = 20, ...[...[b = 40]]) => { } }"
 PASS Valid:   "let x = (a = 20, ...{b}) => { }"
 PASS Valid:   "function f() { let x = (a = 20, ...{b}) => { } }"
-PASS Invalid: "let x = (a = 20, ...{...b}) => { }". Produced the following syntax error: "SyntaxError: Unexpected token '...'"
-PASS Invalid: "function f() { let x = (a = 20, ...{...b}) => { } }". Produced the following syntax error: "SyntaxError: Unexpected token '...'"
+PASS Valid:   "let x = (a = 20, ...{...b}) => { }"
+PASS Valid:   "function f() { let x = (a = 20, ...{...b}) => { } }"
 PASS Invalid: "let x = (a = 20, ...{124}) => { }". Produced the following syntax error: "SyntaxError: Unexpected token '...'"
 PASS Invalid: "function f() { let x = (a = 20, ...{124}) => { } }". Produced the following syntax error: "SyntaxError: Unexpected token '...'"
 non-simple parameter list

Modified: trunk/LayoutTests/js/script-tests/parser-syntax-check.js (213696 => 213697)


--- trunk/LayoutTests/js/script-tests/parser-syntax-check.js	2017-03-10 01:48:30 UTC (rev 213696)
+++ trunk/LayoutTests/js/script-tests/parser-syntax-check.js	2017-03-10 02:00:33 UTC (rev 213697)
@@ -691,7 +691,19 @@
 valid("var {x: [y, ...[...[...{z: [...z]}]]]} = 20");
 valid("var {x: [y, {z: {z: [...z]}}]} = 20");
 invalid("var [...y, ...z] = 20");
-invalid("var [...{...y}] = 20");
+valid("var [...{...y}] = 20");
+valid("var {a, b, ...r} = {a: 1, b: 2, c: 3};");
+valid("var {a, b, ...{d}} = {a: 1, b: 2, c: 3, d: 4};");
+valid("var {a, b, ...{d = 15}} = {a: 1, b: 2, c: 3, d: 4};");
+valid("var {a, b, ...{d = 15, ...r}} = {a: 1, b: 2, c: 3, d: 4};");
+valid("(({a, b, ...r}) => {})({a: 1, b: 2, c: 3, d: 4});");
+valid("(function ({a, b, ...r}) {})({a: 1, b: 2, c: 3, d: 4});");
+valid("var a, b, c; ({a, b, ...r} = {a: 1, b: 2, c: 3, d: 4});");
+valid("function * foo(o) { ({...{ x = yield }} = o); }");
+invalid("var {...r = {a: 2}} = {a: 1, b: 2};");
+invalid("var {...r, b} = {a: 1, b: 2};");
+invalid("var {...r, ...e} = {a: 1, b: 2};");
+invalid("function * (o) { ({ ...{ x: yield } } = o); }");
 
 debug("Rest parameter");
 valid("function foo(...a) { }");
@@ -727,7 +739,7 @@
 valid("let x = (a = 20, ...[...b]) => { }");
 valid("let x = (a = 20, ...[...[b = 40]]) => { }");
 valid("let x = (a = 20, ...{b}) => { }");
-invalid("let x = (a = 20, ...{...b}) => { }");
+valid("let x = (a = 20, ...{...b}) => { }");
 invalid("let x = (a = 20, ...{124}) => { }");
 
 debug("non-simple parameter list")

Modified: trunk/Source/_javascript_Core/ChangeLog (213696 => 213697)


--- trunk/Source/_javascript_Core/ChangeLog	2017-03-10 01:48:30 UTC (rev 213696)
+++ trunk/Source/_javascript_Core/ChangeLog	2017-03-10 02:00:33 UTC (rev 213697)
@@ -1,3 +1,82 @@
+2017-03-09  Caio Lima  <[email protected]>
+
+        [ESnext] Implement Object Rest - Implementing Object Rest Destructuring
+        https://bugs.webkit.org/show_bug.cgi?id=167962
+
+        Reviewed by Keith Miller.
+
+        Object Rest/Spread Destructing proposal is in stage 3[1] and this
+        Patch is a prototype implementation of it. A simple change over the
+        parser was necessary to support the new '...' token on Object Pattern
+        destruction rule. In the bytecode generator side, We changed the
+        bytecode generated on ObjectPatternNode::bindValue to store in an
+        array identifiers of already destructed properties, following spec draft
+        section[2], and then pass it as excludedNames to CopyDataProperties.
+        The rest destruction the calls copyDataProperties to perform the
+        copy of rest properties in rhs.
+
+        We also implemented CopyDataProperties as private JS global operation
+        on builtins/GlobalOperations.js following it's specification on [3].
+        It is implemented using Set object to verify if a property is on
+        excludedNames to keep this algorithm with O(n + m) complexity, where n
+        = number of source's own properties and m = excludedNames.length. 
+
+        As a requirement to use JSSets as constants, a change in
+        CodeBlock::create API was necessary, because JSSet creation can throws OOM
+        exception. Now, CodeBlock::finishCreation returns ```false``` if an
+        execption is throwed by
+        CodeBlock::setConstantIdentifierSetRegisters and then we return
+        nullptr to ScriptExecutable::newCodeBlockFor. It is responsible to
+        check if CodeBlock was constructed properly and then, throw OOM
+        exception to the correct scope.
+
+        [1] - https://github.com/sebmarkbage/ecmascript-rest-spread
+        [2] - http://sebmarkbage.github.io/ecmascript-rest-spread/#Rest-RuntimeSemantics-PropertyDestructuringAssignmentEvaluation
+        [3] - http://sebmarkbage.github.io/ecmascript-rest-spread/#AbstractOperations-CopyDataProperties
+
+        * builtins/BuiltinNames.h:
+        * builtins/GlobalOperations.js:
+        (globalPrivate.copyDataProperties):
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::finishCreation):
+        (JSC::CodeBlock::setConstantIdentifierSetRegisters):
+        * bytecode/CodeBlock.h:
+        * bytecode/EvalCodeBlock.h:
+        (JSC::EvalCodeBlock::create):
+        * bytecode/FunctionCodeBlock.h:
+        (JSC::FunctionCodeBlock::create):
+        * bytecode/ModuleProgramCodeBlock.h:
+        (JSC::ModuleProgramCodeBlock::create):
+        * bytecode/ProgramCodeBlock.h:
+        (JSC::ProgramCodeBlock::create):
+        * bytecode/UnlinkedCodeBlock.h:
+        (JSC::UnlinkedCodeBlock::addSetConstant):
+        (JSC::UnlinkedCodeBlock::constantIdentifierSets):
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::emitLoad):
+        * bytecompiler/BytecodeGenerator.h:
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::ObjectPatternNode::bindValue):
+        * parser/ASTBuilder.h:
+        (JSC::ASTBuilder::appendObjectPatternEntry):
+        (JSC::ASTBuilder::appendObjectPatternRestEntry):
+        (JSC::ASTBuilder::setContainsObjectRestElement):
+        * parser/Nodes.h:
+        (JSC::ObjectPatternNode::appendEntry):
+        (JSC::ObjectPatternNode::setContainsRestElement):
+        * parser/Parser.cpp:
+        (JSC::Parser<LexerType>::parseDestructuringPattern):
+        (JSC::Parser<LexerType>::parseProperty):
+        * parser/SyntaxChecker.h:
+        (JSC::SyntaxChecker::operatorStackPop):
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::init):
+        * runtime/JSGlobalObjectFunctions.cpp:
+        (JSC::privateToObject):
+        * runtime/JSGlobalObjectFunctions.h:
+        * runtime/ScriptExecutable.cpp:
+        (JSC::ScriptExecutable::newCodeBlockFor):
+
 2017-03-09  Mark Lam  <[email protected]>
 
         Implement a StackTrace utility object that can capture stack traces for debugging.

Modified: trunk/Source/_javascript_Core/builtins/BuiltinNames.h (213696 => 213697)


--- trunk/Source/_javascript_Core/builtins/BuiltinNames.h	2017-03-10 01:48:30 UTC (rev 213696)
+++ trunk/Source/_javascript_Core/builtins/BuiltinNames.h	2017-03-10 02:00:33 UTC (rev 213697)
@@ -158,6 +158,7 @@
     macro(stringIncludesInternal) \
     macro(stringSplitFast) \
     macro(stringSubstrInternal) \
+    macro(toObject) \
     macro(makeBoundFunction) \
     macro(hasOwnLengthProperty) \
     macro(importModule) \

Modified: trunk/Source/_javascript_Core/builtins/GlobalOperations.js (213696 => 213697)


--- trunk/Source/_javascript_Core/builtins/GlobalOperations.js	2017-03-10 01:48:30 UTC (rev 213696)
+++ trunk/Source/_javascript_Core/builtins/GlobalOperations.js	2017-03-10 02:00:33 UTC (rev 213697)
@@ -79,3 +79,29 @@
         return constructor;
     @throwTypeError("|this|.constructor[Symbol.species] is not a constructor");
 }
+
+@globalPrivate
+function copyDataProperties(target, source, excludedSet)
+{
+    if (!@isObject(target))
+        @throwTypeError("target needs to be an object");
+    
+    if (source === @undefined || source === null)
+        return target;
+    
+    let from = @toObject(source);
+    let keys = @Object.@getOwnPropertyNames(from);
+    let keysLength = keys.length;
+    for (let i = 0; i < keysLength; i++) {
+        let nextKey = keys[i];
+        if (!excludedSet.@has(nextKey)) {
+            let desc = @Object.@getOwnPropertyDescriptor(from, nextKey);
+            if (desc.enumerable && desc !== @undefined) {
+                let propValue = from[nextKey];
+                @Object.@defineProperty(target, nextKey, {value: propValue, enumerable: true, writable: true, configurable: true});
+            }
+        }
+    }
+
+    return target;
+}

Modified: trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp (213696 => 213697)


--- trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp	2017-03-10 01:48:30 UTC (rev 213696)
+++ trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp	2017-03-10 02:00:33 UTC (rev 213697)
@@ -58,6 +58,8 @@
 #include "JSFunction.h"
 #include "JSLexicalEnvironment.h"
 #include "JSModuleEnvironment.h"
+#include "JSSet.h"
+#include "JSString.h"
 #include "LLIntData.h"
 #include "LLIntEntrypoint.h"
 #include "LLIntPrototypeLoadAdaptiveStructureWatchpoint.h"
@@ -393,7 +395,7 @@
     setNumParameters(unlinkedCodeBlock->numParameters());
 }
 
-void CodeBlock::finishCreation(VM& vm, ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlinkedCodeBlock,
+bool CodeBlock::finishCreation(VM& vm, ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlinkedCodeBlock,
     JSScope* scope)
 {
     Base::finishCreation(vm);
@@ -402,6 +404,8 @@
         vm.functionHasExecutedCache()->removeUnexecutedRange(ownerExecutable->sourceID(), ownerExecutable->typeProfilingStartOffset(), ownerExecutable->typeProfilingEndOffset());
 
     setConstantRegisters(unlinkedCodeBlock->constantRegisters(), unlinkedCodeBlock->constantsSourceCodeRepresentation());
+    if (!setConstantIdentifierSetRegisters(vm, unlinkedCodeBlock->constantIdentifierSets()))
+        return false;
     if (unlinkedCodeBlock->usesGlobalObject())
         m_constantRegisters[unlinkedCodeBlock->globalObjectRegister().toConstantIndex()].set(*m_vm, this, m_globalObject.get());
 
@@ -822,6 +826,8 @@
     
     heap()->m_codeBlocks->add(this);
     heap()->reportExtraMemoryAllocated(m_instructions.size() * sizeof(Instruction));
+    
+    return true;
 }
 
 CodeBlock::~CodeBlock()
@@ -857,6 +863,31 @@
 #endif // ENABLE(JIT)
 }
 
+bool CodeBlock::setConstantIdentifierSetRegisters(VM& vm, const Vector<ConstantIndentifierSetEntry>& constants)
+{
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    JSGlobalObject* globalObject = m_globalObject.get();
+    ExecState* exec = globalObject->globalExec();
+
+    for (const auto& entry : constants) {
+        Structure* setStructure = globalObject->setStructure();
+        RETURN_IF_EXCEPTION(scope, false);
+        JSSet* jsSet = JSSet::create(exec, vm, setStructure);
+        RETURN_IF_EXCEPTION(scope, false);
+
+        const HashSet<UniquedStringImpl*>& set = entry.first;
+        for (auto setEntry : set) {
+            JSString* jsString = jsOwnedString(&vm, setEntry);
+            jsSet->add(exec, JSValue(jsString));
+            RETURN_IF_EXCEPTION(scope, false);
+        }
+        m_constantRegisters[entry.second].set(vm, this, JSValue(jsSet));
+    }
+    
+    scope.release();
+    return true;
+}
+
 void CodeBlock::setConstantRegisters(const Vector<WriteBarrier<Unknown>>& constants, const Vector<SourceCodeRepresentation>& constantsSourceCodeRepresentation)
 {
     ASSERT(constants.size() == constantsSourceCodeRepresentation.size());

Modified: trunk/Source/_javascript_Core/bytecode/CodeBlock.h (213696 => 213697)


--- trunk/Source/_javascript_Core/bytecode/CodeBlock.h	2017-03-10 01:48:30 UTC (rev 213696)
+++ trunk/Source/_javascript_Core/bytecode/CodeBlock.h	2017-03-10 02:00:33 UTC (rev 213697)
@@ -121,7 +121,7 @@
     CodeBlock(VM*, Structure*, ScriptExecutable* ownerExecutable, UnlinkedCodeBlock*, JSScope*, RefPtr<SourceProvider>&&, unsigned sourceOffset, unsigned firstLineColumnOffset);
 
     void finishCreation(VM&, CopyParsedBlockTag, CodeBlock& other);
-    void finishCreation(VM&, ScriptExecutable* ownerExecutable, UnlinkedCodeBlock*, JSScope*);
+    bool finishCreation(VM&, ScriptExecutable* ownerExecutable, UnlinkedCodeBlock*, JSScope*);
 
     WriteBarrier<JSGlobalObject> m_globalObject;
 
@@ -917,6 +917,8 @@
 
     void updateAllPredictionsAndCountLiveness(unsigned& numberOfLiveNonArgumentValueProfiles, unsigned& numberOfSamplesInProfiles);
 
+    bool setConstantIdentifierSetRegisters(VM&, const Vector<ConstantIndentifierSetEntry>& constants);
+
     void setConstantRegisters(const Vector<WriteBarrier<Unknown>>& constants, const Vector<SourceCodeRepresentation>& constantsSourceCodeRepresentation);
 
     void replaceConstant(int index, JSValue value)

Modified: trunk/Source/_javascript_Core/bytecode/EvalCodeBlock.h (213696 => 213697)


--- trunk/Source/_javascript_Core/bytecode/EvalCodeBlock.h	2017-03-10 01:48:30 UTC (rev 213696)
+++ trunk/Source/_javascript_Core/bytecode/EvalCodeBlock.h	2017-03-10 02:00:33 UTC (rev 213697)
@@ -51,7 +51,8 @@
     {
         EvalCodeBlock* instance = new (NotNull, allocateCell<EvalCodeBlock>(vm->heap))
             EvalCodeBlock(vm, vm->evalCodeBlockStructure.get(), ownerExecutable, unlinkedCodeBlock, scope, WTFMove(sourceProvider));
-        instance->finishCreation(*vm, ownerExecutable, unlinkedCodeBlock, scope);
+        if (!instance->finishCreation(*vm, ownerExecutable, unlinkedCodeBlock, scope))
+            return nullptr;
         return instance;
     }
 

Modified: trunk/Source/_javascript_Core/bytecode/FunctionCodeBlock.h (213696 => 213697)


--- trunk/Source/_javascript_Core/bytecode/FunctionCodeBlock.h	2017-03-10 01:48:30 UTC (rev 213696)
+++ trunk/Source/_javascript_Core/bytecode/FunctionCodeBlock.h	2017-03-10 02:00:33 UTC (rev 213697)
@@ -52,7 +52,8 @@
     {
         FunctionCodeBlock* instance = new (NotNull, allocateCell<FunctionCodeBlock>(vm->heap))
             FunctionCodeBlock(vm, vm->functionCodeBlockStructure.get(), ownerExecutable, unlinkedCodeBlock, scope, WTFMove(sourceProvider), sourceOffset, firstLineColumnOffset);
-        instance->finishCreation(*vm, ownerExecutable, unlinkedCodeBlock, scope);
+        if (!instance->finishCreation(*vm, ownerExecutable, unlinkedCodeBlock, scope))
+            return nullptr;
         return instance;
     }
 

Modified: trunk/Source/_javascript_Core/bytecode/ModuleProgramCodeBlock.h (213696 => 213697)


--- trunk/Source/_javascript_Core/bytecode/ModuleProgramCodeBlock.h	2017-03-10 01:48:30 UTC (rev 213696)
+++ trunk/Source/_javascript_Core/bytecode/ModuleProgramCodeBlock.h	2017-03-10 02:00:33 UTC (rev 213697)
@@ -52,7 +52,8 @@
     {
         ModuleProgramCodeBlock* instance = new (NotNull, allocateCell<ModuleProgramCodeBlock>(vm->heap))
             ModuleProgramCodeBlock(vm, vm->moduleProgramCodeBlockStructure.get(), ownerExecutable, unlinkedCodeBlock, scope, WTFMove(sourceProvider), firstLineColumnOffset);
-        instance->finishCreation(*vm, ownerExecutable, unlinkedCodeBlock, scope);
+        if (!instance->finishCreation(*vm, ownerExecutable, unlinkedCodeBlock, scope))
+            return nullptr;
         return instance;
     }
 

Modified: trunk/Source/_javascript_Core/bytecode/ProgramCodeBlock.h (213696 => 213697)


--- trunk/Source/_javascript_Core/bytecode/ProgramCodeBlock.h	2017-03-10 01:48:30 UTC (rev 213696)
+++ trunk/Source/_javascript_Core/bytecode/ProgramCodeBlock.h	2017-03-10 02:00:33 UTC (rev 213697)
@@ -52,7 +52,8 @@
     {
         ProgramCodeBlock* instance = new (NotNull, allocateCell<ProgramCodeBlock>(vm->heap))
             ProgramCodeBlock(vm, vm->programCodeBlockStructure.get(), ownerExecutable, unlinkedCodeBlock, scope, WTFMove(sourceProvider), firstLineColumnOffset);
-        instance->finishCreation(*vm, ownerExecutable, unlinkedCodeBlock, scope);
+        if (!instance->finishCreation(*vm, ownerExecutable, unlinkedCodeBlock, scope))
+            return nullptr;
         return instance;
     }
 

Modified: trunk/Source/_javascript_Core/bytecode/UnlinkedCodeBlock.h (213696 => 213697)


--- trunk/Source/_javascript_Core/bytecode/UnlinkedCodeBlock.h	2017-03-10 01:48:30 UTC (rev 213696)
+++ trunk/Source/_javascript_Core/bytecode/UnlinkedCodeBlock.h	2017-03-10 02:00:33 UTC (rev 213697)
@@ -41,9 +41,12 @@
 #include "UnlinkedFunctionExecutable.h"
 #include "VariableEnvironment.h"
 #include "VirtualRegister.h"
+#include <algorithm>
 #include <wtf/BitVector.h>
+#include <wtf/HashSet.h>
 #include <wtf/TriState.h>
 #include <wtf/Vector.h>
+#include <wtf/text/UniquedStringImpl.h>
 
 namespace JSC {
 
@@ -65,6 +68,7 @@
 typedef unsigned UnlinkedArrayAllocationProfile;
 typedef unsigned UnlinkedObjectAllocationProfile;
 typedef unsigned UnlinkedLLIntCallLinkInfo;
+typedef std::pair<HashSet<UniquedStringImpl*>, unsigned> ConstantIndentifierSetEntry;
 
 struct UnlinkedStringJumpTable {
     struct OffsetLocation {
@@ -182,6 +186,16 @@
         m_bitVectors.append(WTFMove(bitVector));
         return m_bitVectors.size() - 1;
     }
+    
+    void addSetConstant(HashSet<UniquedStringImpl*>& set)
+    {
+        VM& vm = *this->vm();
+        auto locker = lockDuringMarking(vm.heap, *this);
+        unsigned result = m_constantRegisters.size();
+        m_constantRegisters.append(WriteBarrier<Unknown>());
+        m_constantsSourceCodeRepresentation.append(SourceCodeRepresentation::Other);
+        m_constantIdentifierSets.append(ConstantIndentifierSetEntry(set, result));
+    }
 
     unsigned addConstant(JSValue v, SourceCodeRepresentation sourceCodeRepresentation = SourceCodeRepresentation::Other)
     {
@@ -213,6 +227,7 @@
         return m_linkTimeConstants[index];
     }
     const Vector<WriteBarrier<Unknown>>& constantRegisters() { return m_constantRegisters; }
+    const Vector<ConstantIndentifierSetEntry>& constantIdentifierSets() { return m_constantIdentifierSets; }
     const WriteBarrier<Unknown>& constantRegister(int index) const { return m_constantRegisters[index - FirstConstantRegisterIndex]; }
     ALWAYS_INLINE bool isConstantRegisterIndex(int index) const { return index >= FirstConstantRegisterIndex; }
     ALWAYS_INLINE JSValue getConstant(int index) const { return m_constantRegisters[index - FirstConstantRegisterIndex].get(); }
@@ -446,6 +461,7 @@
     Vector<Identifier> m_identifiers;
     Vector<BitVector> m_bitVectors;
     Vector<WriteBarrier<Unknown>> m_constantRegisters;
+    Vector<ConstantIndentifierSetEntry> m_constantIdentifierSets;
     Vector<SourceCodeRepresentation> m_constantsSourceCodeRepresentation;
     typedef Vector<WriteBarrier<UnlinkedFunctionExecutable>> FunctionExpressionVector;
     FunctionExpressionVector m_functionDecls;

Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp (213696 => 213697)


--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2017-03-10 01:48:30 UTC (rev 213696)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2017-03-10 02:00:33 UTC (rev 213697)
@@ -1920,6 +1920,27 @@
     return constantID;
 }
 
+RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, HashSet<UniquedStringImpl*>& set)
+{
+    for (ConstantIndentifierSetEntry entry : m_codeBlock->constantIdentifierSets()) {
+        if (entry.first != set)
+            continue;
+        
+        return &m_constantPoolRegisters[entry.second];
+    }
+    
+    unsigned index = m_nextConstantOffset;
+    m_constantPoolRegisters.append(FirstConstantRegisterIndex + m_nextConstantOffset);
+    ++m_nextConstantOffset;
+    m_codeBlock->addSetConstant(set);
+    RegisterID* m_setRegister = &m_constantPoolRegisters[index];
+    
+    if (dst)
+        return emitMove(dst, m_setRegister);
+    
+    return m_setRegister;
+}
+
 RegisterID* BytecodeGenerator::emitLoadGlobalObject(RegisterID* dst)
 {
     if (!m_globalObjectRegister) {

Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h (213696 => 213697)


--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h	2017-03-10 01:48:30 UTC (rev 213696)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h	2017-03-10 02:00:33 UTC (rev 213697)
@@ -587,6 +587,7 @@
         RegisterID* emitLoad(RegisterID* dst, bool);
         RegisterID* emitLoad(RegisterID* dst, const Identifier&);
         RegisterID* emitLoad(RegisterID* dst, JSValue, SourceCodeRepresentation = SourceCodeRepresentation::Other);
+        RegisterID* emitLoad(RegisterID* dst, HashSet<UniquedStringImpl*>& excludedList);
         RegisterID* emitLoadGlobalObject(RegisterID* dst);
 
         RegisterID* emitUnaryOp(OpcodeID, RegisterID* dst, RegisterID* src);

Modified: trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp (213696 => 213697)


--- trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp	2017-03-10 01:48:30 UTC (rev 213696)
+++ trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp	2017-03-10 02:00:33 UTC (rev 213697)
@@ -41,8 +41,10 @@
 #include "Parser.h"
 #include "StackAlignment.h"
 #include <wtf/Assertions.h>
+#include <wtf/HashSet.h>
 #include <wtf/Threading.h>
 #include <wtf/text/StringBuilder.h>
+#include <wtf/text/UniquedStringImpl.h>
 
 using namespace WTF;
 
@@ -4027,25 +4029,56 @@
 void ObjectPatternNode::bindValue(BytecodeGenerator& generator, RegisterID* rhs) const
 {
     generator.emitRequireObjectCoercible(rhs, ASCIILiteral("Right side of assignment cannot be destructured"));
+    
+    HashSet<UniquedStringImpl*> excludedSet;
+
     for (const auto& target : m_targetPatterns) {
-        RefPtr<RegisterID> temp = generator.newTemporary();
-        if (!target.propertyExpression) {
-            // Should not emit get_by_id for indexed ones.
-            std::optional<uint32_t> optionalIndex = parseIndex(target.propertyName);
-            if (!optionalIndex)
-                generator.emitGetById(temp.get(), rhs, target.propertyName);
-            else {
-                RefPtr<RegisterID> index = generator.emitLoad(nullptr, jsNumber(optionalIndex.value()));
-                generator.emitGetByVal(temp.get(), rhs, index.get());
+        if (target.bindingType == BindingType::Element) {
+            RefPtr<RegisterID> temp = generator.newTemporary();
+            if (!target.propertyExpression) {
+                
+                // Should not emit get_by_id for indexed ones.
+                std::optional<uint32_t> optionalIndex = parseIndex(target.propertyName);
+                if (!optionalIndex)
+                    generator.emitGetById(temp.get(), rhs, target.propertyName);
+                else {
+                    RefPtr<RegisterID> pIndex = generator.emitLoad(nullptr, jsNumber(optionalIndex.value()));
+                    generator.emitGetByVal(temp.get(), rhs, pIndex.get());
+                }
+            } else {
+                RefPtr<RegisterID> propertyName = generator.emitNode(target.propertyExpression);
+                generator.emitGetByVal(temp.get(), rhs, propertyName.get());
             }
+            
+            if (UNLIKELY(m_containsRestElement))
+                excludedSet.add(target.propertyName.impl());
+            
+            if (target.defaultValue)
+                assignDefaultValueIfUndefined(generator, temp.get(), target.defaultValue);
+            target.pattern->bindValue(generator, temp.get());
         } else {
-            RefPtr<RegisterID> propertyName = generator.emitNode(target.propertyExpression);
-            generator.emitGetByVal(temp.get(), rhs, propertyName.get());
+            RefPtr<RegisterID> excludedSetReg = generator.emitLoad(generator.newTemporary(), excludedSet);
+        
+            RefPtr<RegisterID> newObject = generator.emitNewObject(generator.newTemporary());
+            
+            // load and call @copyDataProperties
+            auto var = generator.variable(generator.propertyNames().builtinNames().copyDataPropertiesPrivateName());
+            
+            RefPtr<RegisterID> scope = generator.newTemporary();
+            generator.moveToDestinationIfNeeded(scope.get(), generator.emitResolveScope(scope.get(), var));
+            RefPtr<RegisterID> copyDataProperties = generator.emitGetFromScope(generator.newTemporary(), scope.get(), var, ThrowIfNotFound);
+            
+            CallArguments args(generator, nullptr, 3);
+            unsigned argumentCount = 0;
+            generator.emitLoad(args.thisRegister(), jsUndefined());
+            generator.emitMove(args.argumentRegister(argumentCount++), newObject.get());
+            generator.emitMove(args.argumentRegister(argumentCount++), rhs);
+            generator.emitMove(args.argumentRegister(argumentCount++), excludedSetReg.get());
+
+            RefPtr<RegisterID> result = generator.newTemporary();
+            generator.emitCall(result.get(), copyDataProperties.get(), NoExpectedFunction, args, divot(), divotStart(), divotEnd(), DebuggableCall::No);
+            target.pattern->bindValue(generator, result.get());
         }
-
-        if (target.defaultValue)
-            assignDefaultValueIfUndefined(generator, temp.get(), target.defaultValue);
-        target.pattern->bindValue(generator, temp.get());
     }
 }
 

Modified: trunk/Source/_javascript_Core/parser/ASTBuilder.h (213696 => 213697)


--- trunk/Source/_javascript_Core/parser/ASTBuilder.h	2017-03-10 01:48:30 UTC (rev 213696)
+++ trunk/Source/_javascript_Core/parser/ASTBuilder.h	2017-03-10 02:00:33 UTC (rev 213697)
@@ -942,16 +942,26 @@
     
     void appendObjectPatternEntry(ObjectPattern node, const JSTokenLocation& location, bool wasString, const Identifier& identifier, DestructuringPattern pattern, ExpressionNode* defaultValue)
     {
-        node->appendEntry(location, identifier, wasString, pattern, defaultValue);
+        node->appendEntry(location, identifier, wasString, pattern, defaultValue, ObjectPatternNode::BindingType::Element);
         tryInferNameInPattern(pattern, defaultValue);
     }
 
     void appendObjectPatternEntry(ObjectPattern node, const JSTokenLocation& location, ExpressionNode* propertyExpression, DestructuringPattern pattern, ExpressionNode* defaultValue)
     {
-        node->appendEntry(location, propertyExpression, pattern, defaultValue);
+        node->appendEntry(location, propertyExpression, pattern, defaultValue, ObjectPatternNode::BindingType::Element);
         tryInferNameInPattern(pattern, defaultValue);
     }
+    
+    void appendObjectPatternRestEntry(ObjectPattern node, const JSTokenLocation& location, DestructuringPattern pattern)
+    {
+        node->appendEntry(location, nullptr, pattern, nullptr, ObjectPatternNode::BindingType::RestElement);
+    }
 
+    void setContainsObjectRestElement(ObjectPattern node, bool containsRestElement)
+    {
+        node->setContainsRestElement(containsRestElement);
+    }
+
     BindingPattern createBindingLocation(const JSTokenLocation&, const Identifier& boundProperty, const JSTextPosition& start, const JSTextPosition& end, AssignmentContext context)
     {
         return new (m_parserArena) BindingNode(boundProperty, start, end, context);

Modified: trunk/Source/_javascript_Core/parser/Nodes.h (213696 => 213697)


--- trunk/Source/_javascript_Core/parser/Nodes.h	2017-03-10 01:48:30 UTC (rev 213696)
+++ trunk/Source/_javascript_Core/parser/Nodes.h	2017-03-10 02:00:33 UTC (rev 213697)
@@ -2129,20 +2129,29 @@
         Vector<Entry> m_targetPatterns;
     };
     
-    class ObjectPatternNode : public DestructuringPatternNode, public ParserArenaDeletable {
+    class ObjectPatternNode : public DestructuringPatternNode, public ThrowableExpressionData, public ParserArenaDeletable {
     public:
         using ParserArenaDeletable::operator new;
         
         ObjectPatternNode();
-        void appendEntry(const JSTokenLocation&, const Identifier& identifier, bool wasString, DestructuringPatternNode* pattern, ExpressionNode* defaultValue)
+        enum class BindingType {
+            Element,
+            RestElement
+        };
+        void appendEntry(const JSTokenLocation&, const Identifier& identifier, bool wasString, DestructuringPatternNode* pattern, ExpressionNode* defaultValue, BindingType bindingType)
         {
-            m_targetPatterns.append(Entry{ identifier, nullptr, wasString, pattern, defaultValue });
+            m_targetPatterns.append(Entry{ identifier, nullptr, wasString, pattern, defaultValue, bindingType });
         }
 
-        void appendEntry(const JSTokenLocation&, ExpressionNode* propertyExpression, DestructuringPatternNode* pattern, ExpressionNode* defaultValue)
+        void appendEntry(const JSTokenLocation&, ExpressionNode* propertyExpression, DestructuringPatternNode* pattern, ExpressionNode* defaultValue, BindingType bindingType)
         {
-            m_targetPatterns.append(Entry{ Identifier(), propertyExpression, false, pattern, defaultValue });
+            m_targetPatterns.append(Entry{ Identifier(), propertyExpression, false, pattern, defaultValue, bindingType });
         }
+        
+        void setContainsRestElement(bool containsRestElement)
+        {
+            m_containsRestElement = containsRestElement;
+        }
 
     private:
         void collectBoundIdentifiers(Vector<Identifier>&) const override;
@@ -2154,7 +2163,9 @@
             bool wasString;
             DestructuringPatternNode* pattern;
             ExpressionNode* defaultValue;
+            BindingType bindingType;
         };
+        bool m_containsRestElement { false };
         Vector<Entry> m_targetPatterns;
     };
 

Modified: trunk/Source/_javascript_Core/parser/Parser.cpp (213696 => 213697)


--- trunk/Source/_javascript_Core/parser/Parser.cpp	2017-03-10 01:48:30 UTC (rev 213696)
+++ trunk/Source/_javascript_Core/parser/Parser.cpp	2017-03-10 02:00:33 UTC (rev 213697)
@@ -1002,6 +1002,8 @@
         if (hasDestructuringPattern)
             *hasDestructuringPattern = true;
 
+        bool restElementWasFound = false;
+
         do {
             bool wasString = false;
 
@@ -1008,6 +1010,19 @@
             if (match(CLOSEBRACE))
                 break;
 
+            if (UNLIKELY(match(DOTDOTDOT))) {
+                JSTokenLocation location = m_token.m_location;
+                next();
+                auto innerPattern = parseBindingOrAssignmentElement(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
+                if (kind == DestructuringKind::DestructureToExpressions && !innerPattern)
+                    return 0;
+                propagateError();
+                context.appendObjectPatternRestEntry(objectPattern, location, innerPattern);
+                restElementWasFound = true;
+                context.setContainsObjectRestElement(objectPattern, restElementWasFound);
+                break;
+            }
+
             const Identifier* propertyName = nullptr;
             TreeExpression propertyExpression = 0;
             TreeDestructuringPattern innerPattern = 0;
@@ -1082,7 +1097,7 @@
 
         if (kind == DestructuringKind::DestructureToExpressions && !match(CLOSEBRACE))
             return 0;
-        consumeOrFail(CLOSEBRACE, "Expected either a closing '}' or an ',' after a property destructuring pattern");
+        consumeOrFail(CLOSEBRACE, restElementWasFound ? "Expected a closing '}' following a rest element destructuring pattern" : "Expected either a closing '}' or an ',' after a property destructuring pattern");
         pattern = objectPattern;
         break;
     }
@@ -3763,6 +3778,10 @@
         context.setEndOffset(node, m_lexer->currentOffset());
         return context.createProperty(propertyName, node, static_cast<PropertyNode::Type>(PropertyNode::Constant | PropertyNode::Computed), PropertyNode::Unknown, complete, SuperBinding::NotNeeded, isClassProperty);
     }
+    case DOTDOTDOT: {
+        classifyExpressionError(ErrorIndicatesPattern);
+        FALLTHROUGH;
+    }
     default:
         failIfFalse(m_token.m_type & KeywordTokenFlag, "Expected a property name");
         wasIdent = true; // Treat keyword token as an identifier

Modified: trunk/Source/_javascript_Core/parser/SyntaxChecker.h (213696 => 213697)


--- trunk/Source/_javascript_Core/parser/SyntaxChecker.h	2017-03-10 01:48:30 UTC (rev 213696)
+++ trunk/Source/_javascript_Core/parser/SyntaxChecker.h	2017-03-10 02:00:33 UTC (rev 213697)
@@ -352,6 +352,12 @@
     void appendObjectPatternEntry(ArrayPattern, const JSTokenLocation&, _expression_, DestructuringPattern, _expression_)
     {
     }
+    void appendObjectPatternRestEntry(ObjectPattern, const JSTokenLocation&, DestructuringPattern)
+    {
+    }
+    void setContainsObjectRestElement(ObjectPattern, bool)
+    {
+    }
 
     DestructuringPattern createBindingLocation(const JSTokenLocation&, const Identifier&, const JSTextPosition&, const JSTextPosition&, AssignmentContext)
     {

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp (213696 => 213697)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2017-03-10 01:48:30 UTC (rev 213696)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2017-03-10 02:00:33 UTC (rev 213697)
@@ -735,6 +735,7 @@
 
     JSFunction* privateFuncGetTemplateObject = JSFunction::create(vm, this, 0, String(), getTemplateObject);
     JSFunction* privateFuncImportModule = JSFunction::create(vm, this, 0, String(), globalFuncImportModule);
+    JSFunction* privateFuncToObject = JSFunction::create(vm, this, 0, String(), privateToObject);
     JSFunction* privateFuncTypedArrayLength = JSFunction::create(vm, this, 0, String(), typedArrayViewPrivateFuncLength);
     JSFunction* privateFuncTypedArrayGetOriginalConstructor = JSFunction::create(vm, this, 0, String(), typedArrayViewPrivateFuncGetOriginalConstructor);
     JSFunction* privateFuncTypedArraySort = JSFunction::create(vm, this, 0, String(), typedArrayViewPrivateFuncSort);
@@ -789,6 +790,7 @@
         GlobalPropertyInfo(vm.propertyNames->builtinNames().ownEnumerablePropertyKeysPrivateName(), JSFunction::create(vm, this, 0, String(), ownEnumerablePropertyKeys), DontEnum | DontDelete | ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->builtinNames().getTemplateObjectPrivateName(), privateFuncGetTemplateObject, DontEnum | DontDelete | ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->builtinNames().importModulePrivateName(), privateFuncImportModule, DontEnum | DontDelete | ReadOnly),
+        GlobalPropertyInfo(vm.propertyNames->builtinNames().toObjectPrivateName(), privateFuncToObject, DontEnum | DontDelete | ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->builtinNames().enqueueJobPrivateName(), JSFunction::create(vm, this, 0, String(), enqueueJob), DontEnum | DontDelete | ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->builtinNames().ErrorPrivateName(), m_errorConstructor.get(), DontEnum | DontDelete | ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->builtinNames().RangeErrorPrivateName(), m_rangeErrorConstructor.get(), DontEnum | DontDelete | ReadOnly),

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.cpp (213696 => 213697)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.cpp	2017-03-10 01:48:30 UTC (rev 213696)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.cpp	2017-03-10 02:00:33 UTC (rev 213697)
@@ -735,6 +735,11 @@
     thisObject->setPrototype(vm, exec, value, shouldThrowIfCantSet);
     return JSValue::encode(jsUndefined());
 }
+
+EncodedJSValue JSC_HOST_CALL privateToObject(ExecState* exec)
+{
+    return JSValue::encode(JSValue(exec->argument(0).toObject(exec)));
+}
     
 EncodedJSValue JSC_HOST_CALL globalFuncBuiltinLog(ExecState* exec)
 {

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.h (213696 => 213697)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.h	2017-03-10 01:48:30 UTC (rev 213696)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.h	2017-03-10 02:00:33 UTC (rev 213697)
@@ -50,6 +50,7 @@
 EncodedJSValue JSC_HOST_CALL globalFuncProtoGetter(ExecState*);
 EncodedJSValue JSC_HOST_CALL globalFuncProtoSetter(ExecState*);
 EncodedJSValue JSC_HOST_CALL globalFuncBuiltinLog(ExecState*);
+EncodedJSValue JSC_HOST_CALL privateToObject(ExecState*);
 EncodedJSValue JSC_HOST_CALL globalFuncImportModule(ExecState*);
 
 double jsToNumber(StringView);

Modified: trunk/Source/_javascript_Core/runtime/ObjectConstructor.cpp (213696 => 213697)


--- trunk/Source/_javascript_Core/runtime/ObjectConstructor.cpp	2017-03-10 01:48:30 UTC (rev 213696)
+++ trunk/Source/_javascript_Core/runtime/ObjectConstructor.cpp	2017-03-10 02:00:33 UTC (rev 213697)
@@ -105,6 +105,7 @@
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().definePropertyPrivateName(), objectConstructorDefineProperty, DontEnum, 3);
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().getPrototypeOfPrivateName(), objectConstructorGetPrototypeOf, DontEnum, 1);
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().getOwnPropertyNamesPrivateName(), objectConstructorGetOwnPropertyNames, DontEnum, 1);
+    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().getOwnPropertyDescriptorPrivateName(), objectConstructorGetOwnPropertyDescriptor, DontEnum, 1);
 }
 
 // ES 19.1.1.1 Object([value])

Modified: trunk/Source/_javascript_Core/runtime/ScriptExecutable.cpp (213696 => 213697)


--- trunk/Source/_javascript_Core/runtime/ScriptExecutable.cpp	2017-03-10 01:48:30 UTC (rev 213696)
+++ trunk/Source/_javascript_Core/runtime/ScriptExecutable.cpp	2017-03-10 02:00:33 UTC (rev 213697)
@@ -176,14 +176,24 @@
     ASSERT(vm->heap.isDeferred());
     ASSERT(endColumn() != UINT_MAX);
 
+    JSGlobalObject* globalObject = scope->globalObject();
+    ExecState* exec = globalObject->globalExec();
+
     if (classInfo(*vm) == EvalExecutable::info()) {
         EvalExecutable* executable = jsCast<EvalExecutable*>(this);
         RELEASE_ASSERT(kind == CodeForCall);
         RELEASE_ASSERT(!executable->m_evalCodeBlock);
         RELEASE_ASSERT(!function);
-        return EvalCodeBlock::create(vm,
+        auto codeBlock = EvalCodeBlock::create(vm,
             executable, executable->m_unlinkedEvalCodeBlock.get(), scope,
             executable->source().provider());
+        if (!codeBlock) {
+            exception = throwException(
+                exec, throwScope,
+                createOutOfMemoryError(exec));
+            return nullptr;
+        }
+        return codeBlock;
     }
     
     if (classInfo(*vm) == ProgramExecutable::info()) {
@@ -191,9 +201,16 @@
         RELEASE_ASSERT(kind == CodeForCall);
         RELEASE_ASSERT(!executable->m_programCodeBlock);
         RELEASE_ASSERT(!function);
-        return ProgramCodeBlock::create(vm,
+        auto codeBlock = ProgramCodeBlock::create(vm,
             executable, executable->m_unlinkedProgramCodeBlock.get(), scope,
             executable->source().provider(), startColumn());
+        if (!codeBlock) {
+            exception = throwException(
+                exec, throwScope,
+                createOutOfMemoryError(exec));
+            return nullptr;
+        }
+        return codeBlock;
     }
 
     if (classInfo(*vm) == ModuleProgramExecutable::info()) {
@@ -201,9 +218,16 @@
         RELEASE_ASSERT(kind == CodeForCall);
         RELEASE_ASSERT(!executable->m_moduleProgramCodeBlock);
         RELEASE_ASSERT(!function);
-        return ModuleProgramCodeBlock::create(vm,
+        auto codeBlock = ModuleProgramCodeBlock::create(vm,
             executable, executable->m_unlinkedModuleProgramCodeBlock.get(), scope,
             executable->source().provider(), startColumn());
+        if (!codeBlock) {
+            exception = throwException(
+                exec, throwScope,
+                createOutOfMemoryError(exec));
+            return nullptr;
+        }
+        return codeBlock;
     }
 
     RELEASE_ASSERT(classInfo(*vm) == FunctionExecutable::info());
@@ -210,7 +234,6 @@
     RELEASE_ASSERT(function);
     FunctionExecutable* executable = jsCast<FunctionExecutable*>(this);
     RELEASE_ASSERT(!executable->codeBlockFor(kind));
-    JSGlobalObject* globalObject = scope->globalObject();
     ParserError error;
     DebuggerMode debuggerMode = globalObject->hasInteractiveDebugger() ? DebuggerOn : DebuggerOff;
     UnlinkedFunctionCodeBlock* unlinkedCodeBlock = 

Modified: trunk/Source/_javascript_Core/runtime/SetPrototype.cpp (213696 => 213697)


--- trunk/Source/_javascript_Core/runtime/SetPrototype.cpp	2017-03-10 01:48:30 UTC (rev 213696)
+++ trunk/Source/_javascript_Core/runtime/SetPrototype.cpp	2017-03-10 02:00:33 UTC (rev 213697)
@@ -67,6 +67,7 @@
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->clear, setProtoFuncClear, DontEnum, 0);
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->deleteKeyword, setProtoFuncDelete, DontEnum, 1);
     JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->has, setProtoFuncHas, DontEnum, 1, JSSetHasIntrinsic);
+    JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().hasPrivateName(), setProtoFuncHas, DontEnum, 1, JSSetHasIntrinsic);
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().entriesPublicName(), setProtoFuncEntries, DontEnum, 0);
 
     JSFunction* values = JSFunction::create(vm, globalObject, 0, vm.propertyNames->builtinNames().valuesPublicName().string(), setProtoFuncValues);

Modified: trunk/Source/WTF/ChangeLog (213696 => 213697)


--- trunk/Source/WTF/ChangeLog	2017-03-10 01:48:30 UTC (rev 213696)
+++ trunk/Source/WTF/ChangeLog	2017-03-10 02:00:33 UTC (rev 213697)
@@ -1,3 +1,13 @@
+2017-03-09  Caio Lima  <[email protected]>
+
+        [ESnext] Implement Object Rest - Implementing Object Rest Destructuring
+        https://bugs.webkit.org/show_bug.cgi?id=167962
+
+        Reviewed by Keith Miller.
+
+        * wtf/HashSet.h:
+        (WTF::=):
+
 2017-03-09  Youenn Fablet  <[email protected]>
 
         Activate VideoToolbox when WebRTC is enabled on iOS

Modified: trunk/Source/WTF/wtf/HashSet.h (213696 => 213697)


--- trunk/Source/WTF/wtf/HashSet.h	2017-03-10 01:48:30 UTC (rev 213696)
+++ trunk/Source/WTF/wtf/HashSet.h	2017-03-10 02:00:33 UTC (rev 213697)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2005, 2006, 2007, 2008, 2011, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2005, 2006, 2007, 2008, 2011, 2013, 2017 Apple Inc. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -120,6 +120,9 @@
 
         template<typename OtherCollection>
         bool operator==(const OtherCollection&) const;
+        
+        template<typename OtherCollection>
+        bool operator!=(const OtherCollection&) const;
 
     private:
         HashTableType m_impl;
@@ -362,6 +365,13 @@
         }
         return true;
     }
+    
+    template<typename T, typename U, typename V>
+    template<typename OtherCollection>
+    inline bool HashSet<T, U, V>::operator!=(const OtherCollection& otherCollection) const
+    {
+        return !(*this == otherCollection);
+    }
 
 } // namespace WTF
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to