[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/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
index b056116..e2f1c98 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
@@ -1934,9 +1934,9 @@
return constantID;
}
-RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, HashSet<UniquedStringImpl*>& set)
+RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, IdentifierSet& set)
{
- for (ConstantIndentifierSetEntry entry : m_codeBlock->constantIdentifierSets()) {
+ for (const auto& entry : m_codeBlock->constantIdentifierSets()) {
if (entry.first != set)
continue;
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
index 78dcb4a..0329213 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
@@ -587,7 +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* emitLoad(RegisterID* dst, IdentifierSet& excludedList);
RegisterID* emitLoadGlobalObject(RegisterID* dst);
RegisterID* emitUnaryOp(OpcodeID, RegisterID* dst, RegisterID* src);
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