[ESnext] Implement Object Spread
https://bugs.webkit.org/show_bug.cgi?id=167963

Patch by Caio Lima <ticaiolima@gmail.com> on 2017-03-16
Reviewed by Yusuke Suzuki.

JSTests:

* stress/object-spread.js: Added.
(let.assert):
(assert.sameValue):
(let.o.get a):
(let.obj.get c):
(cthulhu.get x):
(let.obj.set c):
(calls.o.get z):
(calls.o.get a):
(try.let.obj.get foo):
(get calls):

Source/JavaScriptCore:

This patch implements ECMA262 stage 3 Object Spread proposal [1].
It's implemented using CopyDataProperties to copy all enumerable keys
from object being spreaded.

It's also fixing CopyDataProperties that was using
Object.getOwnPropertyNames to list all keys to be copied, and now is
using Relect.ownKeys.

[1] - https://github.com/sebmarkbage/ecmascript-rest-spread

* builtins/GlobalOperations.js:
(globalPrivate.copyDataProperties):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::setConstantIdentifierSetRegisters):
* bytecode/UnlinkedCodeBlock.h:
(JSC::UnlinkedCodeBlock::addSetConstant):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitLoad):
* bytecompiler/BytecodeGenerator.h:
* bytecompiler/NodesCodegen.cpp:
(JSC::PropertyListNode::emitBytecode):
(JSC::ObjectPatternNode::bindValue):
(JSC::ObjectSpreadExpressionNode::emitBytecode):
* parser/ASTBuilder.h:
(JSC::ASTBuilder::createObjectSpreadExpression):
(JSC::ASTBuilder::createProperty):
* parser/NodeConstructors.h:
(JSC::PropertyNode::PropertyNode):
(JSC::ObjectSpreadExpressionNode::ObjectSpreadExpressionNode):
* parser/Nodes.h:
(JSC::ObjectSpreadExpressionNode::expression):
* parser/Parser.cpp:
(JSC::Parser<LexerType>::parseProperty):
* parser/SyntaxChecker.h:
(JSC::SyntaxChecker::createObjectSpreadExpression):
(JSC::SyntaxChecker::createProperty):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):
* runtime/JSGlobalObjectFunctions.cpp:
(JSC::privateToObject): Deleted.
* runtime/JSGlobalObjectFunctions.h:

LayoutTests:

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

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@214038 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
index bab452b..dd8e575 100644
--- a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
+++ b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
@@ -516,7 +516,7 @@
                 hasComputedProperty = true;
                 break;
             }
-            if (node->m_type & PropertyNode::Constant)
+            if (node->m_type & PropertyNode::Constant || node->m_type & PropertyNode::Spread)
                 continue;
 
             // Duplicates are possible.
@@ -538,6 +538,9 @@
             if (node->m_type & PropertyNode::Constant) {
                 emitPutConstantProperty(generator, dst, *node);
                 continue;
+            } else if (node->m_type & PropertyNode::Spread) {
+                generator.emitNode(dst, node->m_assign);
+                continue;
             }
 
             RefPtr<RegisterID> value = generator.emitNode(node->m_assign);
@@ -4030,7 +4033,7 @@
 {
     generator.emitRequireObjectCoercible(rhs, ASCIILiteral("Right side of assignment cannot be destructured"));
     
-    HashSet<UniquedStringImpl*> excludedSet;
+    IdentifierSet excludedSet;
 
     for (const auto& target : m_targetPatterns) {
         if (target.bindingType == BindingType::Element) {
@@ -4228,4 +4231,31 @@
     return 0;
 }
 
+RegisterID* ObjectSpreadExpressionNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
+{
+    RefPtr<RegisterID> src = generator.newTemporary();
+    generator.emitNode(src.get(), m_expression);
+    IdentifierSet excludedSet;
+    
+    RefPtr<RegisterID> excludedSetReg = generator.emitLoad(generator.newTemporary(), excludedSet);
+        
+    // 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++), dst);
+    generator.emitMove(args.argumentRegister(argumentCount++), src.get());
+    generator.emitMove(args.argumentRegister(argumentCount++), excludedSetReg.get());
+    
+    generator.emitCall(generator.newTemporary(), copyDataProperties.get(), NoExpectedFunction, args, divot(), divotStart(), divotEnd(), DebuggableCall::No);
+    
+    return 0;
+}
+
 } // namespace JSC