Implement prefixed-destructuring assignment
https://bugs.webkit.org/show_bug.cgi?id=121930

Reviewed by Mark Hahnenberg.

Source/JavaScriptCore:

Relanding with fix after rollout - it helps to not completely destroy
optimisations for no reason.

LayoutTests:

Relanding with fix after rollout - it helps to not completely destroy
optimisations for no reason.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@156785 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index b8663e2..1669635 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,13 @@
+2013-09-25  Oliver Hunt  <oliver@apple.com>
+
+        Implement prefixed-destructuring assignment
+        https://bugs.webkit.org/show_bug.cgi?id=121930
+
+        Reviewed by Mark Hahnenberg.
+
+        Relanding with fix after rollout - it helps to not completely destroy
+        optimisations for no reason.
+
 2013-10-02  Nadav Rotem  <nrotem@apple.com>
 
         FTL: Refactor compileArithDiv and compileArithMod into one function.
diff --git a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp
index c4067e3..d13aa65 100644
--- a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp
+++ b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp
@@ -183,7 +183,7 @@
     for (size_t pos = 0; pos < parameters.size(); ++pos) {
         if (!builder.isEmpty())
             builder.appendLiteral(", ");
-        builder.append(parameters.at(pos).string());
+        parameters.at(pos)->toString(builder);
     }
     return builder.toString();
 }
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
index be0fcb3..c9632eb 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
@@ -180,7 +180,7 @@
     }
 
     for (size_t i = 0; i < varStack.size(); ++i)
-        codeBlock->addVariableDeclaration(*varStack[i].first, !!(varStack[i].second & DeclarationStacks::IsConstant));
+        codeBlock->addVariableDeclaration(varStack[i].first, !!(varStack[i].second & DeclarationStacks::IsConstant));
 
 }
 
@@ -215,6 +215,15 @@
         m_codeBlock->setNeedsFullScopeChain(true);
 
     m_symbolTable->setUsesNonStrictEval(codeBlock->usesEval() && !codeBlock->isStrictMode());
+    Vector<Identifier> boundParameterProperties;
+    FunctionParameters& parameters = *functionBody->parameters();
+    for (size_t i = 0; i < parameters.size(); i++) {
+        auto pattern = parameters.at(i);
+        if (pattern->isBindingNode())
+            continue;
+        pattern->collectBoundIdentifiers(boundParameterProperties);
+        continue;
+    }
     m_symbolTable->setParameterCountIncludingThis(functionBody->parameters()->size() + 1);
 
     emitOpcode(op_enter);
@@ -254,7 +263,11 @@
         capturedArguments.resize(parameters.size());
         for (size_t i = 0; i < parameters.size(); ++i) {
             capturedArguments[i] = 0;
-            if (!functionBody->captures(parameters.at(i)) && !shouldCaptureAllTheThings)
+            auto pattern = parameters.at(i);
+            if (!pattern->isBindingNode())
+                continue;
+            const Identifier& ident = static_cast<const BindingNode*>(pattern)->boundProperty();
+            if (!functionBody->captures(ident) && !shouldCaptureAllTheThings)
                 continue;
             capturesAnyArgumentByName = true;
             capturedArguments[i] = addVar();
@@ -299,7 +312,7 @@
             }
         }
         for (size_t i = 0; i < varStack.size(); ++i) {
-            const Identifier& ident = *varStack[i].first;
+            const Identifier& ident = varStack[i].first;
             if (functionBody->captures(ident))
                 addVar(ident, varStack[i].second & DeclarationStacks::IsConstant);
         }
@@ -332,7 +345,7 @@
     }
     m_lastLazyFunction = canLazilyCreateFunctions ? codeBlock->m_numVars : m_firstLazyFunction;
     for (size_t i = 0; i < varStack.size(); ++i) {
-        const Identifier& ident = *varStack[i].first;
+        const Identifier& ident = varStack[i].first;
         if (!functionBody->captures(ident))
             addVar(ident, varStack[i].second & DeclarationStacks::IsConstant);
     }
@@ -340,23 +353,31 @@
     if (shouldCaptureAllTheThings)
         m_symbolTable->setCaptureEnd(virtualRegisterForLocal(codeBlock->m_numVars).offset());
 
-    FunctionParameters& parameters = *functionBody->parameters();
     m_parameters.grow(parameters.size() + 1); // reserve space for "this"
 
     // Add "this" as a parameter
     int nextParameterIndex = CallFrame::thisArgumentOffset();
     m_thisRegister.setIndex(nextParameterIndex++);
     m_codeBlock->addParameter();
-    
+    Vector<std::pair<RegisterID*, const DeconstructionPatternNode*>> deconstructedParameters;
     for (size_t i = 0; i < parameters.size(); ++i, ++nextParameterIndex) {
         int index = nextParameterIndex;
+        auto pattern = parameters.at(i);
+        if (!pattern->isBindingNode()) {
+            m_codeBlock->addParameter();
+            RegisterID& parameter = registerFor(index);
+            parameter.setIndex(index);
+            deconstructedParameters.append(make_pair(&parameter, pattern));
+            continue;
+        }
+        auto simpleParameter = static_cast<const BindingNode*>(pattern);
         if (capturedArguments.size() && capturedArguments[i]) {
-            ASSERT((functionBody->hasCapturedVariables() && functionBody->captures(parameters.at(i))) || shouldCaptureAllTheThings);
+            ASSERT((functionBody->hasCapturedVariables() && functionBody->captures(simpleParameter->boundProperty())) || shouldCaptureAllTheThings);
             index = capturedArguments[i]->index();
             RegisterID original(nextParameterIndex);
             emitMove(capturedArguments[i], &original);
         }
-        addParameter(parameters.at(i), index);
+        addParameter(simpleParameter->boundProperty(), index);
     }
     preserveLastVar();
 
@@ -370,6 +391,10 @@
         instructions().append(kill(&m_thisRegister));
         instructions().append(0);
     }
+    for (size_t i = 0; i < deconstructedParameters.size(); i++) {
+        auto& entry = deconstructedParameters[i];
+        entry.second->emitBytecode(*this, entry.first);
+    }
 }
 
 BytecodeGenerator::BytecodeGenerator(VM& vm, EvalNode* evalNode, UnlinkedEvalCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode)
@@ -414,8 +439,10 @@
     unsigned numVariables = varStack.size();
     Vector<Identifier, 0, UnsafeVectorOverflow> variables;
     variables.reserveCapacity(numVariables);
-    for (size_t i = 0; i < numVariables; ++i)
-        variables.append(*varStack[i].first);
+    for (size_t i = 0; i < numVariables; ++i) {
+        ASSERT(varStack[i].first.impl()->isIdentifier());
+        variables.append(varStack[i].first);
+    }
     codeBlock->adoptVariables(variables);
     preserveLastVar();
 }
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
index 06c0fe4..fcc17df 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
@@ -286,7 +286,10 @@
                 lineStart -= sourceOffset;
             else
                 lineStart = 0;
-            ASSERT(divotOffset >= lineStart);
+
+            if (divotOffset < lineStart)
+                return;
+
             unsigned column = divotOffset - lineStart;
 
             unsigned instructionOffset = instructions().size();
diff --git a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
index 633b296..7410216 100644
--- a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
+++ b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
@@ -35,6 +35,7 @@
 #include "JSFunction.h"
 #include "JSGlobalObject.h"
 #include "JSNameScope.h"
+#include "JSONObject.h"
 #include "LabelScope.h"
 #include "Lexer.h"
 #include "Operations.h"
@@ -1713,8 +1714,7 @@
 
         generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStart(), assignNode->divotEnd());
         generator.emitPutById(base, ident, propertyName);
-    } else {
-        ASSERT(m_lexpr->isBracketAccessorNode());
+    } else if (m_lexpr->isBracketAccessorNode()) {
         BracketAccessorNode* assignNode = static_cast<BracketAccessorNode*>(m_lexpr);
         propertyName = generator.newTemporary();
         RefPtr<RegisterID> protect = propertyName;
@@ -1723,7 +1723,30 @@
         
         generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStart(), assignNode->divotEnd());
         generator.emitPutByVal(base.get(), subscript, propertyName);
-    }   
+    } else {
+        ASSERT(m_lexpr->isDeconstructionNode());
+        DeconstructingAssignmentNode* assignNode = static_cast<DeconstructingAssignmentNode*>(m_lexpr);
+        auto binding = assignNode->bindings();
+        if (binding->isBindingNode()) {
+            auto simpleBinding = static_cast<BindingNode*>(binding);
+            Identifier ident = simpleBinding->boundProperty();
+            Local local = generator.local(ident);
+            propertyName = local.get();
+            if (!propertyName)
+                goto genericBinding;
+            expectedSubscript = generator.emitMove(generator.newTemporary(), propertyName);
+            generator.pushOptimisedForIn(expectedSubscript.get(), iter.get(), i.get(), propertyName);
+            optimizedForinAccess = true;
+            goto completedSimpleBinding;
+        } else {
+        genericBinding:
+            propertyName = generator.newTemporary();
+            RefPtr<RegisterID> protect(propertyName);
+            assignNode->bindings()->emitBytecode(generator, propertyName);
+        }
+        completedSimpleBinding:
+        ;
+    }
 
     generator.emitNode(dst, m_statement);
 
@@ -2179,5 +2202,157 @@
 {
     return generator.emitNewFunctionExpression(generator.finalDestination(dst), this);
 }
+    
+// ------------------------------ DeconstructingAssignmentNode -----------------
+RegisterID* DeconstructingAssignmentNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
+{
+    if (RegisterID* result = m_bindings->emitDirectBinding(generator, dst, m_initializer))
+        return result;
+    RefPtr<RegisterID> initializer = generator.tempDestination(dst);
+    generator.emitNode(initializer.get(), m_initializer);
+    m_bindings->emitBytecode(generator, initializer.get());
+    return generator.moveToDestinationIfNeeded(dst, initializer.get());
+}
+
+DeconstructionPatternNode::~DeconstructionPatternNode()
+{
+}
+    
+void ArrayPatternNode::emitBytecode(BytecodeGenerator& generator, RegisterID* rhs) const
+{
+    for (size_t i = 0; i < m_targetPatterns.size(); i++) {
+        auto target = m_targetPatterns[i];
+        if (!target)
+            continue;
+        RefPtr<RegisterID> temp = generator.newTemporary();
+        generator.emitLoad(temp.get(), jsNumber(i));
+        generator.emitGetByVal(temp.get(), rhs, temp.get());
+        target->emitBytecode(generator, temp.get());
+    }
+}
+
+RegisterID* ArrayPatternNode::emitDirectBinding(BytecodeGenerator& generator, RegisterID* dst, ExpressionNode* rhs)
+{
+    if (rhs->isResolveNode()
+        && generator.willResolveToArguments(static_cast<ResolveNode*>(rhs)->identifier())
+        && !generator.symbolTable().slowArguments()) {
+        for (size_t i = 0; i < m_targetPatterns.size(); i++) {
+            auto target = m_targetPatterns[i];
+            if (!target)
+                continue;
+            
+            RefPtr<RegisterID> temp = generator.newTemporary();
+            generator.emitLoad(temp.get(), jsNumber(i));
+            generator.emitGetArgumentByVal(generator.finalDestination(dst), generator.uncheckedRegisterForArguments(), temp.get());
+            target->emitBytecode(generator, temp.get());
+        }
+    }
+    if (!rhs->isSimpleArray())
+        return 0;
+    ElementNode* elementNodes = static_cast<ArrayNode*>(rhs)->elements();
+    Vector<ExpressionNode*> elements;
+    for (; elementNodes; elementNodes = elementNodes->next())
+        elements.append(elementNodes->value());
+    if (m_targetPatterns.size() != elements.size())
+        return 0;
+    Vector<RefPtr<RegisterID>> registers;
+    registers.reserveCapacity(m_targetPatterns.size());
+    for (size_t i = 0; i < m_targetPatterns.size(); i++) {
+        registers.uncheckedAppend(generator.newTemporary());
+        generator.emitNode(registers.last().get(), elements[i]);
+    }
+    
+    for (size_t i = 0; i < m_targetPatterns.size(); i++) {
+        if (m_targetPatterns[i])
+            m_targetPatterns[i]->emitBytecode(generator, registers[i].get());
+    }
+    RefPtr<RegisterID> result = generator.finalDestination(dst);
+    return generator.emitLoad(result.get(), jsUndefined());
+}
+
+void ArrayPatternNode::toString(StringBuilder& builder) const
+{
+    builder.append('[');
+    for (size_t i = 0; i < m_targetPatterns.size(); i++) {
+        if (!m_targetPatterns[i]) {
+            builder.append(',');
+            continue;
+        }
+        m_targetPatterns[i]->toString(builder);
+        if (i < m_targetPatterns.size() - 1)
+            builder.append(',');
+    }
+    builder.append(']');
+}
+
+void ArrayPatternNode::collectBoundIdentifiers(Vector<Identifier>& identifiers) const
+{
+    for (size_t i = 0; i < m_targetPatterns.size(); i++) {
+        if (DeconstructionPatternNode* node = m_targetPatterns[i].get())
+            node->collectBoundIdentifiers(identifiers);
+    }
+}
+
+void ObjectPatternNode::toString(StringBuilder& builder) const
+{
+    builder.append('{');
+    for (size_t i = 0; i < m_targetPatterns.size(); i++) {
+        if (m_targetPatterns[i].wasString) {
+            builder.append('"');
+            escapeStringToBuilder(builder, m_targetPatterns[i].propertyName.string());
+            builder.append('"');
+        } else
+            builder.append(m_targetPatterns[i].propertyName.string());
+        builder.append(":");
+        m_targetPatterns[i].pattern->toString(builder);
+        if (i < m_targetPatterns.size() - 1)
+            builder.append(',');
+    }
+    builder.append('}');
+}
+    
+void ObjectPatternNode::emitBytecode(BytecodeGenerator& generator, RegisterID* rhs) const
+{
+    for (size_t i = 0; i < m_targetPatterns.size(); i++) {
+        auto& target = m_targetPatterns[i];
+        RefPtr<RegisterID> temp = generator.newTemporary();
+        generator.emitGetById(temp.get(), rhs, target.propertyName);
+        target.pattern->emitBytecode(generator, temp.get());
+    }
+}
+
+void ObjectPatternNode::collectBoundIdentifiers(Vector<Identifier>& identifiers) const
+{
+    for (size_t i = 0; i < m_targetPatterns.size(); i++)
+        m_targetPatterns[i].pattern->collectBoundIdentifiers(identifiers);
+}
+
+void BindingNode::emitBytecode(BytecodeGenerator& generator, RegisterID* value) const
+{
+    if (Local local = generator.local(m_boundProperty)) {
+        if (local.isReadOnly()) {
+            generator.emitReadOnlyExceptionIfNeeded();
+            return;
+        }
+        generator.emitMove(local.get(), value);
+        return;
+    }
+    if (generator.isStrictMode())
+        generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
+    RegisterID* scope = generator.emitResolveScope(generator.newTemporary(), m_boundProperty);
+    generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
+    generator.emitPutToScope(scope, m_boundProperty, value, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound);
+    return;
+}
+
+void BindingNode::toString(StringBuilder& builder) const
+{
+    builder.append(m_boundProperty.string());
+}
+
+void BindingNode::collectBoundIdentifiers(Vector<Identifier>& identifiers) const
+{
+    identifiers.append(m_boundProperty);
+}
 
 } // namespace JSC
diff --git a/Source/JavaScriptCore/parser/ASTBuilder.h b/Source/JavaScriptCore/parser/ASTBuilder.h
index 95c98d0..a37cdc7 100644
--- a/Source/JavaScriptCore/parser/ASTBuilder.h
+++ b/Source/JavaScriptCore/parser/ASTBuilder.h
@@ -90,6 +90,7 @@
         UnaryExprContext(ASTBuilder&) {}
     };
 
+
     typedef SyntaxChecker FunctionBodyBuilder;
 
     typedef ExpressionNode* Expression;
@@ -107,7 +108,10 @@
     typedef CaseClauseNode* Clause;
     typedef ConstDeclNode* ConstDeclList;
     typedef std::pair<ExpressionNode*, BinaryOpInfo> BinaryOperand;
-    
+    typedef RefPtr<DeconstructionPatternNode> DeconstructionPattern;
+    typedef RefPtr<ArrayPatternNode> ArrayPattern;
+    typedef RefPtr<ObjectPatternNode> ObjectPattern;
+    typedef RefPtr<BindingNode> BindingPattern;
     static const bool CreatesAST = true;
     static const bool NeedsFreeVariableInfo = true;
     static const bool CanUseFunctionCache = true;
@@ -314,8 +318,8 @@
     ElementNode* createElementList(int elisions, ExpressionNode* expr) { return new (m_vm) ElementNode(elisions, expr); }
     ElementNode* createElementList(ElementNode* elems, int elisions, ExpressionNode* expr) { return new (m_vm) ElementNode(elems, elisions, expr); }
 
-    ParameterNode* createFormalParameterList(const Identifier& ident) { return new (m_vm) ParameterNode(ident); }
-    ParameterNode* createFormalParameterList(ParameterNode* list, const Identifier& ident) { return new (m_vm) ParameterNode(list, ident); }
+    ParameterNode* createFormalParameterList(DeconstructionPattern pattern) { return new (m_vm) ParameterNode(pattern); }
+    ParameterNode* createFormalParameterList(ParameterNode* list, DeconstructionPattern pattern) { return new (m_vm) ParameterNode(list, pattern); }
 
     CaseClauseNode* createClause(ExpressionNode* expr, JSC::SourceElements* statements) { return new (m_vm) CaseClauseNode(expr, statements); }
     ClauseListNode* createClauseList(CaseClauseNode* clause) { return new (m_vm) ClauseListNode(clause); }
@@ -361,14 +365,6 @@
         return result;
     }
 
-    StatementNode* createForInLoop(const JSTokenLocation& location, const Identifier* ident, ExpressionNode* iter, StatementNode* statements, const JSTextPosition& start, const JSTextPosition& divot, const JSTextPosition& end, int startLine, int endLine)
-    {
-        ForInNode* result = new (m_vm) ForInNode(m_vm, location, *ident, iter, statements, start);
-        result->setLoc(startLine, endLine, location.startOffset, location.lineStartOffset);
-        setExceptionLocation(result, start, divot + 1, end);
-        return result;
-    }
-
     StatementNode* createForInLoop(const JSTokenLocation& location, ExpressionNode* lhs, ExpressionNode* iter, StatementNode* statements, const JSTextPosition& eStart, const JSTextPosition& eDivot, const JSTextPosition& eEnd, int start, int end)
     {
         ForInNode* result = new (m_vm) ForInNode(location, lhs, iter, statements);
@@ -376,6 +372,14 @@
         setExceptionLocation(result, eStart, eDivot, eEnd);
         return result;
     }
+    
+    StatementNode* createForInLoop(const JSTokenLocation& location, PassRefPtr<DeconstructionPatternNode> pattern, ExpressionNode* iter, StatementNode* statements, const JSTextPosition& eStart, const JSTextPosition& eDivot, const JSTextPosition& eEnd, int start, int end)
+    {
+        ForInNode* result = new (m_vm) ForInNode(m_vm, location, pattern.get(), iter, statements);
+        result->setLoc(start, end, location.startOffset, location.lineStartOffset);
+        setExceptionLocation(result, eStart, eDivot, eEnd);
+        return result;
+    }
 
     StatementNode* createEmptyStatement(const JSTokenLocation& location) { return new (m_vm) EmptyStatementNode(location); }
 
@@ -515,7 +519,8 @@
     {
         if (m_vm->propertyNames->arguments == *ident)
             usesArguments();
-        m_scope.m_varDeclarations->data.append(std::make_pair(ident, attrs));
+        ASSERT(ident->impl()->isIdentifier());
+        m_scope.m_varDeclarations->data.append(std::make_pair(*ident, attrs));
     }
 
     ExpressionNode* combineCommaNodes(const JSTokenLocation& location, ExpressionNode* list, ExpressionNode* init)
@@ -615,6 +620,41 @@
 
     bool isResolve(ExpressionNode* expr) const { return expr->isResolveNode(); }
 
+    ExpressionNode* createDeconstructingAssignment(const JSTokenLocation& location, PassRefPtr<DeconstructionPatternNode> pattern, ExpressionNode* initializer)
+    {
+        return new (m_vm) DeconstructingAssignmentNode(location, pattern.get(), initializer);
+    }
+    
+    ArrayPattern createArrayPattern(const JSTokenLocation&)
+    {
+        return ArrayPatternNode::create(m_vm);
+    }
+    
+    void appendArrayPatternSkipEntry(ArrayPattern node, const JSTokenLocation& location)
+    {
+        node->appendIndex(location, 0);
+    }
+
+    void appendArrayPatternEntry(ArrayPattern node, const JSTokenLocation& location, DeconstructionPattern pattern)
+    {
+        node->appendIndex(location, pattern.get());
+    }
+    
+    ObjectPattern createObjectPattern(const JSTokenLocation&)
+    {
+        return ObjectPatternNode::create(m_vm);
+    }
+    
+    void appendObjectPatternEntry(ObjectPattern node, const JSTokenLocation& location, bool wasString, const Identifier& identifier, DeconstructionPattern pattern)
+    {
+        node->appendEntry(location, identifier, wasString, pattern.get());
+    }
+    
+    BindingPattern createBindingLocation(const JSTokenLocation&, const Identifier& boundProperty, const JSTextPosition& divot, const JSTextPosition& start, const JSTextPosition& end)
+    {
+        return BindingNode::create(m_vm, boundProperty, divot, start, end);
+    }
+    
 private:
     struct Scope {
         Scope(VM* vm)
diff --git a/Source/JavaScriptCore/parser/NodeConstructors.h b/Source/JavaScriptCore/parser/NodeConstructors.h
index 5ccc779..0ce20eb 100644
--- a/Source/JavaScriptCore/parser/NodeConstructors.h
+++ b/Source/JavaScriptCore/parser/NodeConstructors.h
@@ -603,6 +603,8 @@
     inline CommaNode::CommaNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2)
         : ExpressionNode(location)
     {
+        ASSERT(expr1);
+        ASSERT(expr2);
         m_expressions.append(expr1);
         m_expressions.append(expr2);
     }
@@ -732,17 +734,20 @@
     {
     }
 
-    inline ParameterNode::ParameterNode(const Identifier& ident)
-        : m_ident(ident)
+    inline ParameterNode::ParameterNode(PassRefPtr<DeconstructionPatternNode> pattern)
+        : m_pattern(pattern)
         , m_next(0)
     {
+        ASSERT(m_pattern);
     }
 
-    inline ParameterNode::ParameterNode(ParameterNode* l, const Identifier& ident)
-        : m_ident(ident)
+    inline ParameterNode::ParameterNode(ParameterNode* l, PassRefPtr<DeconstructionPatternNode> pattern)
+        : m_pattern(pattern)
         , m_next(0)
     {
         l->m_next = this;
+        ASSERT(m_pattern);
+        ASSERT(l->m_pattern);
     }
 
     inline FuncExprNode::FuncExprNode(const JSTokenLocation& location, const Identifier& ident, FunctionBodyNode* body, const SourceCode& source, ParameterNode* parameter)
@@ -812,16 +817,61 @@
         , m_expr(expr)
         , m_statement(statement)
     {
+        ASSERT(l);
     }
-
-    inline ForInNode::ForInNode(VM* vm, const JSTokenLocation& location, const Identifier& ident, ExpressionNode* expr, StatementNode* statement, const JSTextPosition& divotStart)
+    
+    inline ForInNode::ForInNode(VM* vm, const JSTokenLocation& location, DeconstructionPatternNode* pattern, ExpressionNode* expr, StatementNode* statement)
         : StatementNode(location)
-        , m_lexpr(new (vm) ResolveNode(location, ident, divotStart))
+        , m_lexpr(new (vm) DeconstructingAssignmentNode(location, pattern, 0))
         , m_expr(expr)
         , m_statement(statement)
     {
+        ASSERT(pattern);
+    }
+    
+    inline DeconstructionPatternNode::DeconstructionPatternNode(VM*)
+    {
     }
 
+    inline ArrayPatternNode::ArrayPatternNode(VM* vm)
+        : DeconstructionPatternNode(vm)
+    {
+    }
+    
+    inline PassRefPtr<ArrayPatternNode> ArrayPatternNode::create(VM* vm)
+    {
+        return adoptRef(new ArrayPatternNode(vm));
+    }
+    
+    inline ObjectPatternNode::ObjectPatternNode(VM* vm)
+        : DeconstructionPatternNode(vm)
+    {
+    }
+    
+    inline PassRefPtr<ObjectPatternNode> ObjectPatternNode::create(VM* vm)
+    {
+        return adoptRef(new ObjectPatternNode(vm));
+    }
+
+    inline PassRefPtr<BindingNode> BindingNode::create(VM* vm, const Identifier& boundProperty, const JSTextPosition& divot, const JSTextPosition& start, const JSTextPosition& end)
+    {
+        return adoptRef(new BindingNode(vm, boundProperty, divot, start, end));
+    }
+    
+    inline BindingNode::BindingNode(VM* vm, const Identifier& boundProperty, const JSTextPosition& divot, const JSTextPosition& start, const JSTextPosition& end)
+        : DeconstructionPatternNode(vm)
+        , ThrowableExpressionData(divot, start, end)
+        , m_boundProperty(boundProperty)
+    {
+    }
+    
+    inline DeconstructingAssignmentNode::DeconstructingAssignmentNode(const JSTokenLocation& location, PassRefPtr<DeconstructionPatternNode> bindings, ExpressionNode* initializer)
+        : ExpressionNode(location)
+        , m_bindings(bindings)
+        , m_initializer(initializer)
+    {
+    }
+    
 } // namespace JSC
 
 #endif // NodeConstructors_h
diff --git a/Source/JavaScriptCore/parser/Nodes.cpp b/Source/JavaScriptCore/parser/Nodes.cpp
index 36ded3863..d8ddeaf 100644
--- a/Source/JavaScriptCore/parser/Nodes.cpp
+++ b/Source/JavaScriptCore/parser/Nodes.cpp
@@ -157,7 +157,7 @@
     for (ParameterNode* parameter = firstParameter; parameter; parameter = parameter->nextParam())
         ++parameterCount;
 
-    size_t objectSize = sizeof(FunctionParameters) - sizeof(void*) + sizeof(StringImpl*) * parameterCount;
+    size_t objectSize = sizeof(FunctionParameters) - sizeof(void*) + sizeof(DeconstructionPatternNode*) * parameterCount;
     void* slot = fastMalloc(objectSize);
     return adoptRef(new (slot) FunctionParameters(firstParameter, parameterCount));
 }
@@ -166,14 +166,17 @@
     : m_size(size)
 {
     unsigned i = 0;
-    for (ParameterNode* parameter = firstParameter; parameter; parameter = parameter->nextParam())
-        new (&identifiers()[i++]) Identifier(parameter->ident());
+    for (ParameterNode* parameter = firstParameter; parameter; parameter = parameter->nextParam()) {
+        auto pattern = parameter->pattern();
+        pattern->ref();
+        patterns()[i++] = pattern;
+    }
 }
 
 FunctionParameters::~FunctionParameters()
 {
     for (unsigned i = 0; i < m_size; ++i)
-        identifiers()[i].~Identifier();
+        patterns()[i]->deref();
 }
 
 inline FunctionBodyNode::FunctionBodyNode(VM* vm, const JSTokenLocation& startLocation, const JSTokenLocation& endLocation, unsigned startColumn, bool inStrictContext)
diff --git a/Source/JavaScriptCore/parser/Nodes.h b/Source/JavaScriptCore/parser/Nodes.h
index d7bf28e..e702e3f 100644
--- a/Source/JavaScriptCore/parser/Nodes.h
+++ b/Source/JavaScriptCore/parser/Nodes.h
@@ -80,7 +80,7 @@
 
     namespace DeclarationStacks {
         enum VarAttrs { IsConstant = 1, HasInitializer = 2 };
-        typedef Vector<std::pair<const Identifier*, unsigned> > VarStack;
+        typedef Vector<std::pair<Identifier, unsigned> > VarStack;
         typedef Vector<FunctionBodyNode*> FunctionStack;
     }
 
@@ -154,6 +154,7 @@
         virtual bool isResolveNode() const { return false; }
         virtual bool isBracketAccessorNode() const { return false; }
         virtual bool isDotAccessorNode() const { return false; }
+        virtual bool isDeconstructionNode() const { return false; }
         virtual bool isFuncExprNode() const { return false; }
         virtual bool isCommaNode() const { return false; }
         virtual bool isSimpleArray() const { return false; }
@@ -461,6 +462,7 @@
 
         ArgumentListNode* toArgumentList(VM*, int, int) const;
 
+        ElementNode* elements() const { ASSERT(isSimpleArray()); return m_element; }
     private:
         virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
 
@@ -1080,7 +1082,7 @@
 
         using ParserArenaDeletable::operator new;
 
-        void append(ExpressionNode* expr) { m_expressions.append(expr); }
+        void append(ExpressionNode* expr) { ASSERT(expr); m_expressions.append(expr); }
 
     private:
         virtual bool isCommaNode() const { return true; }
@@ -1238,11 +1240,13 @@
         ExpressionNode* m_expr3;
         StatementNode* m_statement;
     };
+    
+    class DeconstructionPatternNode;
 
     class ForInNode : public StatementNode, public ThrowableExpressionData {
     public:
         ForInNode(const JSTokenLocation&, ExpressionNode*, ExpressionNode*, StatementNode*);
-        ForInNode(VM*, const JSTokenLocation&, const Identifier&, ExpressionNode*, StatementNode*, const JSTextPosition& divotStart);
+        ForInNode(VM*, const JSTokenLocation&, DeconstructionPatternNode*, ExpressionNode*, StatementNode*);
 
     private:
         virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0);
@@ -1341,14 +1345,14 @@
 
     class ParameterNode : public ParserArenaDeletable {
     public:
-        ParameterNode(const Identifier&);
-        ParameterNode(ParameterNode*, const Identifier&);
+        ParameterNode(PassRefPtr<DeconstructionPatternNode>);
+        ParameterNode(ParameterNode*, PassRefPtr<DeconstructionPatternNode>);
 
-        const Identifier& ident() const { return m_ident; }
+        DeconstructionPatternNode* pattern() const { return m_pattern.get(); }
         ParameterNode* nextParam() const { return m_next; }
 
     private:
-        const Identifier& m_ident;
+        RefPtr<DeconstructionPatternNode> m_pattern;
         ParameterNode* m_next;
     };
 
@@ -1460,21 +1464,21 @@
 
     class FunctionParameters : public RefCounted<FunctionParameters> {
         WTF_MAKE_FAST_ALLOCATED;
+        WTF_MAKE_NONCOPYABLE(FunctionParameters);
     public:
         static PassRefPtr<FunctionParameters> create(ParameterNode*);
         ~FunctionParameters();
 
         unsigned size() const { return m_size; }
-        const Identifier& at(unsigned index) const { ASSERT(index < m_size); return identifiers()[index]; }
+        DeconstructionPatternNode* at(unsigned index) { ASSERT(index < m_size); return patterns()[index]; }
 
     private:
         FunctionParameters(ParameterNode*, unsigned size);
 
-        Identifier* identifiers() { return reinterpret_cast<Identifier*>(&m_storage); }
-        const Identifier* identifiers() const { return reinterpret_cast<const Identifier*>(&m_storage); }
+        DeconstructionPatternNode** patterns() { return &m_storage; }
 
         unsigned m_size;
-        void* m_storage;
+        DeconstructionPatternNode* m_storage;
     };
 
     class FunctionBodyNode : public ScopeNode {
@@ -1530,6 +1534,102 @@
         FunctionBodyNode* m_body;
     };
 
+    class DeconstructionPatternNode : public RefCounted<DeconstructionPatternNode> {
+        WTF_MAKE_NONCOPYABLE(DeconstructionPatternNode);
+        WTF_MAKE_FAST_ALLOCATED;
+
+    public:
+        virtual void collectBoundIdentifiers(Vector<Identifier>&) const = 0;
+        virtual void emitBytecode(BytecodeGenerator&, RegisterID* source) const = 0;
+        virtual void toString(StringBuilder&) const = 0;
+
+        virtual bool isBindingNode() const { return false; }
+        virtual RegisterID* emitDirectBinding(BytecodeGenerator&, RegisterID*, ExpressionNode*) { return 0; }
+        
+        virtual ~DeconstructionPatternNode() = 0;
+        
+    protected:
+        DeconstructionPatternNode(VM*);
+    };
+
+    class ArrayPatternNode : public DeconstructionPatternNode {
+    public:
+        static PassRefPtr<ArrayPatternNode> create(VM*);
+        void appendIndex(const JSTokenLocation&, DeconstructionPatternNode* node)
+        {
+            m_targetPatterns.append(node);
+        }
+
+    private:
+        ArrayPatternNode(VM*);
+        void collectBoundIdentifiers(Vector<Identifier>&) const;
+        void emitBytecode(BytecodeGenerator&, RegisterID*) const;
+        RegisterID* emitDirectBinding(BytecodeGenerator&, RegisterID* dst, ExpressionNode*);
+        void toString(StringBuilder&) const;
+
+        Vector<RefPtr<DeconstructionPatternNode>> m_targetPatterns;
+    };
+    
+    class ObjectPatternNode : public DeconstructionPatternNode {
+    public:
+        static PassRefPtr<ObjectPatternNode> create(VM*);
+        void appendEntry(const JSTokenLocation&, const Identifier& identifier, bool wasString, DeconstructionPatternNode* pattern)
+        {
+            m_targetPatterns.append(Entry(identifier, wasString, pattern));
+        }
+        
+    private:
+        ObjectPatternNode(VM*);
+        void collectBoundIdentifiers(Vector<Identifier>&) const;
+        void emitBytecode(BytecodeGenerator&, RegisterID*) const;
+        void toString(StringBuilder&) const;
+        struct Entry {
+            Entry(const Identifier& propertyName, bool wasString, DeconstructionPatternNode* pattern)
+                : propertyName(propertyName)
+                , wasString(wasString)
+                , pattern(pattern)
+            {
+            }
+            Identifier propertyName;
+            bool wasString;
+            RefPtr<DeconstructionPatternNode> pattern;
+        };
+        Vector<Entry> m_targetPatterns;
+    };
+
+    class BindingNode : public DeconstructionPatternNode, ThrowableExpressionData {
+    public:
+        static PassRefPtr<BindingNode> create(VM*, const Identifier& boundProperty, const JSTextPosition& divot, const JSTextPosition& start, const JSTextPosition& end);
+        const Identifier& boundProperty() const { return m_boundProperty; }
+        
+    private:
+        BindingNode(VM*, const Identifier& boundProperty, const JSTextPosition& divot, const JSTextPosition& start, const JSTextPosition& end);
+
+        void collectBoundIdentifiers(Vector<Identifier>&) const;
+        void emitBytecode(BytecodeGenerator&, RegisterID*) const;
+        void toString(StringBuilder&) const;
+        
+        virtual bool isBindingNode() const { return true; }
+        
+        Identifier m_boundProperty;
+    };
+
+    class DeconstructingAssignmentNode : public ExpressionNode, public ParserArenaDeletable {
+    public:
+        DeconstructingAssignmentNode(const JSTokenLocation&, PassRefPtr<DeconstructionPatternNode>, ExpressionNode*);
+        DeconstructionPatternNode* bindings() { return m_bindings.get(); }
+        
+        using ParserArenaDeletable::operator new;
+
+    private:
+        virtual bool isLocation() const { return true; }
+        virtual bool isDeconstructionNode() const { return true; }
+        virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+        RefPtr<DeconstructionPatternNode> m_bindings;
+        ExpressionNode* m_initializer;
+    };
+
     class FuncDeclNode : public StatementNode {
     public:
         FuncDeclNode(const JSTokenLocation&, const Identifier&, FunctionBodyNode*, const SourceCode&, ParameterNode* = 0);
diff --git a/Source/JavaScriptCore/parser/Parser.cpp b/Source/JavaScriptCore/parser/Parser.cpp
index 6b90539..2619834 100644
--- a/Source/JavaScriptCore/parser/Parser.cpp
+++ b/Source/JavaScriptCore/parser/Parser.cpp
@@ -84,7 +84,6 @@
     m_token.m_location.startOffset = source.startOffset();
     m_token.m_location.endOffset = source.startOffset();
     m_token.m_location.lineStartOffset = source.startOffset();
-
     m_functionCache = vm->addSourceProviderCache(source.provider());
     ScopeRef scope = pushScope();
     if (parserMode == JSParseFunctionCode)
@@ -92,8 +91,12 @@
     if (strictness == JSParseStrict)
         scope->setStrictMode();
     if (parameters) {
-        for (unsigned i = 0; i < parameters->size(); i++)
-            scope->declareParameter(&parameters->at(i));
+        for (unsigned i = 0; i < parameters->size(); i++) {
+            auto parameter = parameters->at(i);
+            if (!parameter->isBindingNode())
+                continue;
+            scope->declareParameter(&static_cast<BindingNode*>(parameter)->boundProperty());
+        }
     }
     if (!name.isNull())
         scope->declareCallee(&name);
@@ -203,7 +206,7 @@
     int start = tokenLine();
     int end = 0;
     int scratch;
-    const Identifier* scratch1 = 0;
+    TreeDeconstructionPattern scratch1 = 0;
     TreeExpression scratch2 = 0;
     JSTextPosition scratch3;
     TreeExpression varDecls = parseVarDeclarationList(context, scratch, scratch1, scratch2, scratch3, scratch3, scratch3);
@@ -271,43 +274,170 @@
 }
 
 template <typename LexerType>
-template <class TreeBuilder> TreeExpression Parser<LexerType>::parseVarDeclarationList(TreeBuilder& context, int& declarations, const Identifier*& lastIdent, TreeExpression& lastInitializer, JSTextPosition& identStart, JSTextPosition& initStart, JSTextPosition& initEnd)
+template <class TreeBuilder> TreeExpression Parser<LexerType>::parseVarDeclarationList(TreeBuilder& context, int& declarations, TreeDeconstructionPattern& lastPattern, TreeExpression& lastInitializer, JSTextPosition& identStart, JSTextPosition& initStart, JSTextPosition& initEnd)
 {
     TreeExpression varDecls = 0;
+    const Identifier* lastIdent;
     do {
-        declarations++;
+        lastIdent = 0;
+        lastPattern = 0;
         JSTokenLocation location(tokenLocation());
         next();
-        matchOrFail(IDENT);
+        TreeExpression node = 0;
+        declarations++;
+        bool hasInitializer = false;
+        if (match(IDENT)) {
+            JSTextPosition varStart = tokenStartPosition();
+            identStart = varStart;
+            const Identifier* name = m_token.m_data.ident;
+            lastIdent = name;
+            next();
+            hasInitializer = match(EQUAL);
+            failIfFalseIfStrictWithNameAndMessage(declareVariable(name), "Cannot declare a variable named", name->impl(), "in strict mode.");
+            context.addVar(name, (hasInitializer || (!m_allowsIn && match(INTOKEN))) ? DeclarationStacks::HasInitializer : 0);
+            if (hasInitializer) {
+                JSTextPosition varDivot = tokenStartPosition() + 1;
+                initStart = tokenStartPosition();
+                next(TreeBuilder::DontBuildStrings); // consume '='
+                TreeExpression initializer = parseAssignmentExpression(context);
+                initEnd = lastTokenEndPosition();
+                lastInitializer = initializer;
+                failIfFalse(initializer);
+                
+                node = context.createAssignResolve(location, *name, initializer, varStart, varDivot, lastTokenEndPosition());
+            }
+        } else {
+            lastIdent = 0;
+            auto pattern = parseDeconstructionPattern<DeconstructToVariables>(context);
+            failIfFalse(pattern);
+            hasInitializer = match(EQUAL);
+            lastPattern = pattern;
+            if (hasInitializer) {
+                next(TreeBuilder::DontBuildStrings); // consume '='
+                TreeExpression rhs = parseExpression(context);
+                node = context.createDeconstructingAssignment(location, pattern, rhs);
+            }
+            ASSERT(node);
+        }
         
-        JSTextPosition varStart = tokenStartPosition();
-        identStart = varStart;
-        const Identifier* name = m_token.m_data.ident;
-        lastIdent = name;
-        next();
-        bool hasInitializer = match(EQUAL);
-        failIfFalseIfStrictWithNameAndMessage(declareVariable(name), "Cannot declare a variable named", name->impl(), "in strict mode.");
-        context.addVar(name, (hasInitializer || (!m_allowsIn && match(INTOKEN))) ? DeclarationStacks::HasInitializer : 0);
         if (hasInitializer) {
-            JSTextPosition varDivot = tokenStartPosition() + 1;
-            initStart = tokenStartPosition();
-            next(TreeBuilder::DontBuildStrings); // consume '='
-            TreeExpression initializer = parseAssignmentExpression(context);
-            initEnd = lastTokenEndPosition();
-            lastInitializer = initializer;
-            failIfFalse(initializer);
-            
-            TreeExpression node = context.createAssignResolve(location, *name, initializer, varStart, varDivot, lastTokenEndPosition());
             if (!varDecls)
                 varDecls = node;
             else
                 varDecls = context.combineCommaNodes(location, varDecls, node);
         }
     } while (match(COMMA));
+    if (lastIdent)
+        lastPattern = createBindingPattern<DeconstructToVariables>(context, *lastIdent, 0);
     return varDecls;
 }
 
 template <typename LexerType>
+template <DeconstructionKind kind, class TreeBuilder> TreeDeconstructionPattern Parser<LexerType>::createBindingPattern(TreeBuilder& context, const Identifier& name, int depth)
+{
+    ASSERT(!name.isEmpty());
+    ASSERT(!name.isNull());
+    
+    ASSERT(name.impl()->isIdentifier());
+    if (depth) {
+        if (kind == DeconstructToVariables)
+            failIfFalseIfStrictWithNameAndMessage(declareVariable(&name), "Cannot deconstruct to a variable named", name.impl(), ".");
+        if (kind == DeconstructToParameters) {
+            auto bindingResult = declareBoundParameter(&name);
+            failIfFalseIfStrictWithNameAndMessage(bindingResult != Scope::StrictBindingFailed, "Cannot deconstruct to a parameter named", name.impl(), "in strict mode.");
+            failIfFalseWithNameAndMessage(bindingResult != Scope::BindingFailed, "Cannot deconstruct to a parameter named", name.impl(), ".");
+        }
+        context.addVar(&name, kind == DeconstructToParameters ? 0 : DeclarationStacks::HasInitializer);
+    } else {
+        if (kind == DeconstructToVariables) {
+            failIfFalseIfStrictWithNameAndMessage(declareVariable(&name), "Cannot declare a variable named", name.impl(), "in strict mode.");
+            context.addVar(&name, DeclarationStacks::HasInitializer);
+        }
+        
+        if (kind == DeconstructToParameters)
+            failIfFalseIfStrictWithNameAndMessage(declareParameter(&name), "Cannot declare a parameter named", name.impl(), "in strict mode.");
+    }
+    return context.createBindingLocation(m_token.m_location, name, m_token.m_endPosition, m_token.m_startPosition, m_token.m_endPosition);
+}
+
+template <typename LexerType>
+template <DeconstructionKind kind, class TreeBuilder> TreeDeconstructionPattern Parser<LexerType>::parseDeconstructionPattern(TreeBuilder& context, int depth)
+{
+    failIfStackOverflow();
+    int nonLHSCount = m_nonLHSCount;
+    TreeDeconstructionPattern pattern;
+    switch (m_token.m_type) {
+    case OPENBRACKET: {
+        auto arrayPattern = context.createArrayPattern(m_token.m_location);
+        next();
+        do {
+            while (match(COMMA)) {
+                context.appendArrayPatternSkipEntry(arrayPattern, m_token.m_location);
+                next();
+            }
+            failIfTrue(hasError());
+            JSTokenLocation location = m_token.m_location;
+            auto innerPattern = parseDeconstructionPattern<kind>(context, depth + 1);
+            failIfFalse(innerPattern);
+            context.appendArrayPatternEntry(arrayPattern, location, innerPattern);
+        } while (consume(COMMA));
+        consumeOrFail(CLOSEBRACKET);
+        pattern = arrayPattern;
+        break;
+    }
+    case OPENBRACE: {
+        next();
+        auto objectPattern = context.createObjectPattern(m_token.m_location);
+        bool wasString = false;
+        do {
+            Identifier propertyName;
+            TreeDeconstructionPattern innerPattern = 0;
+            JSTokenLocation location = m_token.m_location;
+            if (match(IDENT)) {
+                propertyName = *m_token.m_data.ident;
+                next();
+                if (consume(COLON))
+                    innerPattern = parseDeconstructionPattern<kind>(context, depth + 1);
+                else
+                    innerPattern = createBindingPattern<kind>(context, propertyName, depth);
+            } else {
+                switch (m_token.m_type) {
+                case NUMBER:
+                    propertyName = Identifier::from(m_vm, m_token.m_data.doubleValue);
+                    break;
+                case STRING:
+                    propertyName = *m_token.m_data.ident;
+                    wasString = true;
+                    break;
+                default:
+                    failIfTrue(!(m_token.m_type & KeywordTokenFlag));
+                    propertyName = *m_token.m_data.ident;
+                    break;
+                }
+                next();
+                consumeOrFail(COLON);
+                innerPattern = parseDeconstructionPattern<kind>(context, depth + 1);
+            }
+            failIfFalse(innerPattern);
+            context.appendObjectPatternEntry(objectPattern, location, wasString, propertyName, innerPattern);
+        } while (consume(COMMA));
+        consumeOrFail(CLOSEBRACE);
+        pattern = objectPattern;
+        break;
+    }
+
+    default: {
+        matchOrFail(IDENT);
+        pattern = createBindingPattern<kind>(context, *m_token.m_data.ident, depth);
+        next();
+        break;
+    }
+    }
+    m_nonLHSCount = nonLHSCount;
+    return pattern;
+}
+
+template <typename LexerType>
 template <class TreeBuilder> TreeConstDeclList Parser<LexerType>::parseConstDeclarationList(TreeBuilder& context)
 {
     failIfTrue(strictMode());
@@ -351,10 +481,9 @@
     if (match(VAR)) {
         /*
          for (var IDENT in expression) statement
-         for (var IDENT = expression in expression) statement
          for (var varDeclarationList; expressionOpt; expressionOpt)
          */
-        const Identifier* forInTarget = 0;
+        TreeDeconstructionPattern forInTarget = 0;
         TreeExpression forInInitializer = 0;
         m_allowsIn = false;
         JSTextPosition initStart;
@@ -369,7 +498,7 @@
         
         failIfFalse(declarations == 1);
         failIfTrueWithMessage(forInInitializer, "Cannot use initialiser syntax in a for-in loop");
-
+        
         // Handle for-in with var declaration
         JSTextPosition inLocation = tokenStartPosition();
         consumeOrFail(INTOKEN);
@@ -386,7 +515,6 @@
         TreeStatement statement = parseStatement(context, unused);
         endLoop();
         failIfFalse(statement);
-        
         return context.createForInLoop(location, forInTarget, expr, statement, declsStart, inLocation, exprEnd, startLine, endLine);
     }
     
@@ -772,18 +900,14 @@
 template <typename LexerType>
 template <class TreeBuilder> TreeFormalParameterList Parser<LexerType>::parseFormalParameters(TreeBuilder& context)
 {
-    matchOrFail(IDENT);
-    failIfFalseIfStrictWithNameAndMessage(declareParameter(m_token.m_data.ident), "Cannot declare a parameter named", m_token.m_data.ident->impl(), " in strict mode");
-    TreeFormalParameterList list = context.createFormalParameterList(*m_token.m_data.ident);
+    auto parameter = parseDeconstructionPattern<DeconstructToParameters>(context);
+    failIfFalse(parameter);
+    TreeFormalParameterList list = context.createFormalParameterList(parameter);
     TreeFormalParameterList tail = list;
-    next();
-    while (match(COMMA)) {
-        next();
-        matchOrFail(IDENT);
-        const Identifier* ident = m_token.m_data.ident;
-        failIfFalseIfStrictWithNameAndMessage(declareParameter(ident), "Cannot declare a parameter named", ident->impl(), "in strict mode");
-        next();
-        tail = context.createFormalParameterList(tail, *ident);
+    while (consume(COMMA)) {
+        parameter = parseDeconstructionPattern<DeconstructToParameters>(context);
+        failIfFalse(parameter);
+        tail = context.createFormalParameterList(tail, parameter);
     }
     return list;
 }
@@ -1155,7 +1279,7 @@
             declareWrite(m_lastIdentifier);
             m_lastIdentifier = 0;
         }
-        lhs = parseConditionalExpression(context);
+        lhs = parseAssignmentExpression(context);
         failIfFalse(lhs);
         if (initialNonLHSCount != m_nonLHSCount)
             break;
diff --git a/Source/JavaScriptCore/parser/Parser.h b/Source/JavaScriptCore/parser/Parser.h
index d72ae17..818948b 100644
--- a/Source/JavaScriptCore/parser/Parser.h
+++ b/Source/JavaScriptCore/parser/Parser.h
@@ -73,6 +73,7 @@
 #define TreeFunctionBody typename TreeBuilder::FunctionBody
 #define TreeProperty typename TreeBuilder::Property
 #define TreePropertyList typename TreeBuilder::PropertyList
+#define TreeDeconstructionPattern typename TreeBuilder::DeconstructionPattern
 
 COMPILE_ASSERT(LastUntaggedToken < 64, LessThan64UntaggedTokens);
 
@@ -228,6 +229,26 @@
             m_shadowsArguments = true;
         return isValidStrictMode;
     }
+    
+    enum BindingResult {
+        BindingFailed,
+        StrictBindingFailed,
+        BindingSucceeded
+    };
+    BindingResult declareBoundParameter(const Identifier* ident)
+    {
+        bool isArguments = m_vm->propertyNames->arguments == *ident;
+        bool newEntry = m_declaredVariables.add(ident->string().impl()).isNewEntry;
+        bool isValidStrictMode = newEntry && m_vm->propertyNames->eval != *ident && !isArguments;
+        m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode;
+    
+        if (isArguments)
+            m_shadowsArguments = true;
+        if (!newEntry)
+            return BindingFailed;
+        return isValidStrictMode ? BindingSucceeded : StrictBindingFailed;
+    }
+
 
     void useVariable(const Identifier* ident, bool isEval)
     {
@@ -861,6 +882,7 @@
     bool strictMode() { return currentScope()->strictMode(); }
     bool isValidStrictMode() { return currentScope()->isValidStrictMode(); }
     bool declareParameter(const Identifier* ident) { return currentScope()->declareParameter(ident); }
+    Scope::BindingResult declareBoundParameter(const Identifier* ident) { return currentScope()->declareBoundParameter(ident); }
     bool breakIsValid()
     {
         ScopeRef current = currentScope();
@@ -931,8 +953,11 @@
     template <bool strict, class TreeBuilder> ALWAYS_INLINE TreeProperty parseProperty(TreeBuilder&);
     template <class TreeBuilder> ALWAYS_INLINE TreeFunctionBody parseFunctionBody(TreeBuilder&);
     template <class TreeBuilder> ALWAYS_INLINE TreeFormalParameterList parseFormalParameters(TreeBuilder&);
-    template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseVarDeclarationList(TreeBuilder&, int& declarations, const Identifier*& lastIdent, TreeExpression& lastInitializer, JSTextPosition& identStart, JSTextPosition& initStart, JSTextPosition& initEnd);
-    template <class TreeBuilder> ALWAYS_INLINE TreeConstDeclList parseConstDeclarationList(TreeBuilder& context);
+    template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseVarDeclarationList(TreeBuilder&, int& declarations, TreeDeconstructionPattern& lastPattern, TreeExpression& lastInitializer, JSTextPosition& identStart, JSTextPosition& initStart, JSTextPosition& initEnd);
+    template <class TreeBuilder> ALWAYS_INLINE TreeConstDeclList parseConstDeclarationList(TreeBuilder&);
+
+    template <DeconstructionKind, class TreeBuilder> ALWAYS_INLINE TreeDeconstructionPattern createBindingPattern(TreeBuilder&, const Identifier&, int depth);
+    template <DeconstructionKind, class TreeBuilder> TreeDeconstructionPattern parseDeconstructionPattern(TreeBuilder&, int depth = 0);
     template <FunctionRequirements, bool nameIsInContainingScope, class TreeBuilder> bool parseFunctionInfo(TreeBuilder&, const Identifier*&, TreeFormalParameterList&, TreeFunctionBody&, unsigned& openBraceOffset, unsigned& closeBraceOffset, int& bodyStartLine, unsigned& bodyStartColumn);
     ALWAYS_INLINE int isBinaryOperator(JSTokenType);
     bool allowAutomaticSemicolon();
diff --git a/Source/JavaScriptCore/parser/SyntaxChecker.h b/Source/JavaScriptCore/parser/SyntaxChecker.h
index 9929caf..965ff0d 100644
--- a/Source/JavaScriptCore/parser/SyntaxChecker.h
+++ b/Source/JavaScriptCore/parser/SyntaxChecker.h
@@ -111,7 +111,10 @@
     typedef int Clause;
     typedef int ConstDeclList;
     typedef int BinaryOperand;
-    
+    typedef int DeconstructionPattern;
+    typedef int ArrayPattern;
+    typedef int ObjectPattern;
+
     static const bool CreatesAST = false;
     static const bool NeedsFreeVariableInfo = false;
     static const bool CanUseFunctionCache = true;
@@ -173,8 +176,8 @@
     int createPropertyList(const JSTokenLocation&, Property, int) { return 1; }
     int createElementList(int, int) { return 1; }
     int createElementList(int, int, int) { return 1; }
-    int createFormalParameterList(const Identifier&) { return 1; }
-    int createFormalParameterList(int, const Identifier&) { return 1; }
+    int createFormalParameterList(DeconstructionPattern) { return 1; }
+    int createFormalParameterList(int, DeconstructionPattern) { return 1; }
     int createClause(int, int) { return 1; }
     int createClauseList(int) { return 1; }
     int createClauseList(int, int) { return 1; }
@@ -185,7 +188,6 @@
     int createIfStatement(const JSTokenLocation&, int, int, int, int) { return 1; }
     int createIfStatement(const JSTokenLocation&, int, int, int, int, int) { return 1; }
     int createForLoop(const JSTokenLocation&, int, int, int, int, int, int) { return 1; }
-    int createForInLoop(const JSTokenLocation&, const Identifier*, int, int, int, int, int, int, int) { return 1; }
     int createForInLoop(const JSTokenLocation&, int, int, int, int, int, int, int, int) { return 1; }
     int createEmptyStatement(const JSTokenLocation&) { return 1; }
     int createVarStatement(const JSTokenLocation&, int, int, int) { return 1; }
@@ -250,7 +252,32 @@
     const Identifier& getName(const Property& property) const { ASSERT(property.name); return *property.name; }
     PropertyNode::Type getType(const Property& property) const { return property.type; }
     bool isResolve(ExpressionType expr) const { return expr == ResolveExpr || expr == ResolveEvalExpr; }
+    ExpressionType createDeconstructingAssignment(const JSTokenLocation&, int, ExpressionType)
+    {
+        return 1;
+    }
     
+    ArrayPattern createArrayPattern(const JSTokenLocation&)
+    {
+        return 1;
+    }
+    void appendArrayPatternSkipEntry(ArrayPattern, const JSTokenLocation&)
+    {
+    }
+    void appendArrayPatternEntry(ArrayPattern, const JSTokenLocation&, DeconstructionPattern)
+    {
+    }
+    ObjectPattern createObjectPattern(const JSTokenLocation&)
+    {
+        return 1;
+    }
+    void appendObjectPatternEntry(ArrayPattern, const JSTokenLocation&, bool, const Identifier&, DeconstructionPattern)
+    {
+    }
+    DeconstructionPattern createBindingLocation(const JSTokenLocation&, const Identifier&, const JSTextPosition&, const JSTextPosition&, const JSTextPosition&)
+    {
+        return 1;
+    }
 private:
     int m_topBinaryExpr;
     int m_topUnaryToken;
diff --git a/Source/JavaScriptCore/runtime/JSONObject.cpp b/Source/JavaScriptCore/runtime/JSONObject.cpp
index 1e14f3a..4f00d1f 100644
--- a/Source/JavaScriptCore/runtime/JSONObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSONObject.cpp
@@ -302,7 +302,15 @@
         }
     }
 }
-    
+
+void escapeStringToBuilder(StringBuilder& builder, const String& message)
+{
+    if (message.is8Bit())
+        appendStringToStringBuilder(builder, message.characters8(), message.length());
+    else
+        appendStringToStringBuilder(builder, message.characters16(), message.length());
+}
+
 void Stringifier::appendQuotedString(StringBuilder& builder, const String& value)
 {
     int length = value.length();
diff --git a/Source/JavaScriptCore/runtime/JSONObject.h b/Source/JavaScriptCore/runtime/JSONObject.h
index 59f19c1..732fe4d 100644
--- a/Source/JavaScriptCore/runtime/JSONObject.h
+++ b/Source/JavaScriptCore/runtime/JSONObject.h
@@ -63,6 +63,8 @@
     JS_EXPORT_PRIVATE JSValue JSONParse(ExecState*, const String&);
     String JSONStringify(ExecState*, JSValue, unsigned indent);
 
+    void escapeStringToBuilder(StringBuilder&, const String&);
+    
 } // namespace JSC
 
 #endif // JSONObject_h