Title: [187351] trunk
Revision
187351
Author
[email protected]
Date
2015-07-24 11:40:58 -0700 (Fri, 24 Jul 2015)

Log Message

[ES6] Add support for default parameters
https://bugs.webkit.org/show_bug.cgi?id=38409

Reviewed by Filip Pizlo.

Source/_javascript_Core:

This patch implements ES6 default parameters according to the ES6
specification. This patch builds off the components introduced with 
"let" scoping and parsing function parameters in the same parser
arena as the function itself. "let" scoping allows functions with default 
parameter values to place their parameters under the TDZ. Parsing function
parameters in the same parser arena allows the FunctionParameters AST node
refer to ExpressionNodes.

The most subtle part of this patch is how we allocate lexical environments
when functions have default parameter values. If a function has default
parameter values then there must be a separate lexical environment for
its parameters. Then, the function's "var" lexical environment must have
the parameter lexical environment as its parent. The BytecodeGenerator
takes great care to not allocate the "var" lexical environment before its
really needed.

The "arguments" object for a function with default parameters will never be 
a mapped arugments object. It will always be a cloned arugments object.

* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::generate):
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::~BytecodeGenerator):
(JSC::BytecodeGenerator::initializeDefaultParameterValuesAndSetupFunctionScopeStack):
(JSC::BytecodeGenerator::initializeNextParameter):
(JSC::BytecodeGenerator::initializeVarLexicalEnvironment):
(JSC::BytecodeGenerator::visibleNameForParameter):
(JSC::BytecodeGenerator::emitLoadGlobalObject):
(JSC::BytecodeGenerator::pushLexicalScopeInternal):
(JSC::BytecodeGenerator::pushLexicalScope):
(JSC::BytecodeGenerator::popLexicalScope):
* bytecompiler/BytecodeGenerator.h:
(JSC::BytecodeGenerator::lastOpcodeID):
* bytecompiler/NodesCodegen.cpp:
(JSC::FunctionNode::emitBytecode):
* jit/JITOperations.cpp:
* parser/ASTBuilder.h:
(JSC::ASTBuilder::createElementList):
(JSC::ASTBuilder::createFormalParameterList):
(JSC::ASTBuilder::appendParameter):
(JSC::ASTBuilder::createClause):
(JSC::ASTBuilder::createClauseList):
* parser/Nodes.h:
(JSC::FunctionParameters::size):
(JSC::FunctionParameters::at):
(JSC::FunctionParameters::hasDefaultParameterValues):
(JSC::FunctionParameters::append):
* parser/Parser.cpp:
(JSC::Parser<LexerType>::parseVariableDeclarationList):
(JSC::Parser<LexerType>::createBindingPattern):
(JSC::Parser<LexerType>::tryParseDestructuringPatternExpression):
(JSC::Parser<LexerType>::parseDestructuringPattern):
(JSC::Parser<LexerType>::parseFormalParameters):
(JSC::Parser<LexerType>::parseFunctionParameters):
* parser/Parser.h:
(JSC::Scope::declareParameter):
* parser/SyntaxChecker.h:
(JSC::SyntaxChecker::createElementList):
(JSC::SyntaxChecker::createFormalParameterList):
(JSC::SyntaxChecker::appendParameter):
(JSC::SyntaxChecker::createClause):
(JSC::SyntaxChecker::createClauseList):
* tests/stress/es6-default-parameters.js: Added.
(assert):
(shouldThrow):
(shouldThrowSyntaxError):
(shouldThrowTDZ):
(basic):
(basicFunctionCaptureInDefault.basicFunctionCaptureInDefault.basicCaptured):
(basicCaptured.basicCaptured.tricky):
(strict):
(playground):
(scoping):
(augmentsArguments1):
(augmentsArguments2):
(augmentsArguments3):
(augmentsArguments4):
(augmentsArguments5):

LayoutTests:

* js/destructuring-assignment-default-values-expected.txt:
* js/parser-syntax-check-expected.txt:
* js/script-tests/destructuring-assignment-default-values.js:
(shouldThrow): Deleted.
* js/script-tests/parser-syntax-check.js:

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (187350 => 187351)


--- trunk/LayoutTests/ChangeLog	2015-07-24 18:39:41 UTC (rev 187350)
+++ trunk/LayoutTests/ChangeLog	2015-07-24 18:40:58 UTC (rev 187351)
@@ -1,3 +1,16 @@
+2015-07-24  Saam barati  <[email protected]>
+
+        [ES6] Add support for default parameters
+        https://bugs.webkit.org/show_bug.cgi?id=38409
+
+        Reviewed by Filip Pizlo.
+
+        * js/destructuring-assignment-default-values-expected.txt:
+        * js/parser-syntax-check-expected.txt:
+        * js/script-tests/destructuring-assignment-default-values.js:
+        (shouldThrow): Deleted.
+        * js/script-tests/parser-syntax-check.js:
+
 2015-07-24  Joseph Pecoraro  <[email protected]>
 
         CSS "content" property is missing in getComputedStyles

Modified: trunk/LayoutTests/js/destructuring-assignment-default-values-expected.txt (187350 => 187351)


--- trunk/LayoutTests/js/destructuring-assignment-default-values-expected.txt	2015-07-24 18:39:41 UTC (rev 187350)
+++ trunk/LayoutTests/js/destructuring-assignment-default-values-expected.txt	2015-07-24 18:40:58 UTC (rev 187351)
@@ -33,11 +33,6 @@
 PASS 120,120
 PASS 3628800,3628800
 PASS 1,1
-PASS true,true
-PASS true,true
-PASS true,true
-PASS true,true
-PASS true,true
 PASS successfullyParsed is true
 
 TEST COMPLETE

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


--- trunk/LayoutTests/js/parser-syntax-check-expected.txt	2015-07-24 18:39:41 UTC (rev 187350)
+++ trunk/LayoutTests/js/parser-syntax-check-expected.txt	2015-07-24 18:40:58 UTC (rev 187351)
@@ -867,6 +867,34 @@
 PASS Invalid: "function f() { ({set [x](x){}}) }"
 PASS Invalid: "({[...x]: 1})"
 PASS Invalid: "function f() { ({[...x]: 1}) }"
+PASS Invalid: "function f({a, a}) {}"
+PASS Invalid: "function f() { function f({a, a}) {} }"
+PASS Invalid: "function f({a}, a) {}"
+PASS Invalid: "function f() { function f({a}, a) {} }"
+PASS Invalid: "function f([b, b]) {}"
+PASS Invalid: "function f() { function f([b, b]) {} }"
+PASS Invalid: "function f([b], b) {}"
+PASS Invalid: "function f() { function f([b], b) {} }"
+PASS Invalid: "function f({a: {b}}, b) {}"
+PASS Invalid: "function f() { function f({a: {b}}, b) {} }"
+PASS Valid:   "function f(a, b = 20) {}"
+PASS Valid:   "function f() { function f(a, b = 20) {} }"
+PASS Valid:   "function f(a = 20, b = a) {}"
+PASS Valid:   "function f() { function f(a = 20, b = a) {} }"
+PASS Valid:   "function f({a = 20} = {a: 40}, b = a) {}"
+PASS Valid:   "function f() { function f({a = 20} = {a: 40}, b = a) {} }"
+PASS Valid:   "function f([a,b,c] = [1,2,3]) {}"
+PASS Valid:   "function f() { function f([a,b,c] = [1,2,3]) {} }"
+PASS Invalid: "function f(a, a=20) {}"
+PASS Invalid: "function f() { function f(a, a=20) {} }"
+PASS Invalid: "function f({a} = 20, a=20) {}"
+PASS Invalid: "function f() { function f({a} = 20, a=20) {} }"
+PASS Invalid: "function f([a,b,a] = [1,2,3]) {}"
+PASS Invalid: "function f() { function f([a,b,a] = [1,2,3]) {} }"
+PASS Invalid: "function f([a,b,c] = [1,2,3], a) {}"
+PASS Invalid: "function f() { function f([a,b,c] = [1,2,3], a) {} }"
+PASS Invalid: "function f([a,b,c] = [1,2,3], {a}) {}"
+PASS Invalid: "function f() { function f([a,b,c] = [1,2,3], {a}) {} }"
 PASS Valid:   "( function(){ return this || eval('this'); }().x = 'y' )"
 PASS Valid:   "function f() { ( function(){ return this || eval('this'); }().x = 'y' ) }"
 PASS Invalid: "function(){ return this || eval('this'); }().x = 'y'"

Modified: trunk/LayoutTests/js/script-tests/destructuring-assignment-default-values.js (187350 => 187351)


--- trunk/LayoutTests/js/script-tests/destructuring-assignment-default-values.js	2015-07-24 18:39:41 UTC (rev 187350)
+++ trunk/LayoutTests/js/script-tests/destructuring-assignment-default-values.js	2015-07-24 18:40:58 UTC (rev 187351)
@@ -105,21 +105,3 @@
 assert(test8(5).p, 120);
 assert(test8(10).p, 3628800);
 assert(test8(0).p, 1);
-
-// FIXME: When we support default values in function parameters, we should remove this test.
-function shouldThrow(str) {
-    var thrown = false;
-    try {
-        eval(str);
-    } catch(e) {
-        thrown = true;
-    }
-
-    assert(true, thrown);
-}
-
-shouldThrow("(function({x = 40}) {})");
-shouldThrow("(function({y}, {x = 40}) {}");
-shouldThrow("(function([y], [x = 40]) {})");
-shouldThrow("(function({y}, {x: {z = 50}}) {})");
-shouldThrow("(function({y}, {x: [z = 50]}) {})");

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


--- trunk/LayoutTests/js/script-tests/parser-syntax-check.js	2015-07-24 18:39:41 UTC (rev 187350)
+++ trunk/LayoutTests/js/script-tests/parser-syntax-check.js	2015-07-24 18:40:58 UTC (rev 187351)
@@ -526,6 +526,20 @@
 invalid("({set [x](){}})")
 invalid("({set [x](x){}})")
 invalid("({[...x]: 1})")
+invalid("function f({a, a}) {}");
+invalid("function f({a}, a) {}");
+invalid("function f([b, b]) {}");
+invalid("function f([b], b) {}");
+invalid("function f({a: {b}}, b) {}");
+valid("function f(a, b = 20) {}");
+valid("function f(a = 20, b = a) {}");
+valid("function f({a = 20} = {a: 40}, b = a) {}");
+valid("function f([a,b,c] = [1,2,3]) {}");
+invalid("function f(a, a=20) {}");
+invalid("function f({a} = 20, a=20) {}");
+invalid("function f([a,b,a] = [1,2,3]) {}");
+invalid("function f([a,b,c] = [1,2,3], a) {}");
+invalid("function f([a,b,c] = [1,2,3], {a}) {}");
 valid("( function(){ return this || eval('this'); }().x = 'y' )");
 invalid("function(){ return this || eval('this'); }().x = 'y'");
 invalid("1 % +");

Modified: trunk/Source/_javascript_Core/ChangeLog (187350 => 187351)


--- trunk/Source/_javascript_Core/ChangeLog	2015-07-24 18:39:41 UTC (rev 187350)
+++ trunk/Source/_javascript_Core/ChangeLog	2015-07-24 18:40:58 UTC (rev 187351)
@@ -1,3 +1,89 @@
+2015-07-24  Saam barati  <[email protected]>
+
+        [ES6] Add support for default parameters
+        https://bugs.webkit.org/show_bug.cgi?id=38409
+
+        Reviewed by Filip Pizlo.
+
+        This patch implements ES6 default parameters according to the ES6
+        specification. This patch builds off the components introduced with 
+        "let" scoping and parsing function parameters in the same parser
+        arena as the function itself. "let" scoping allows functions with default 
+        parameter values to place their parameters under the TDZ. Parsing function
+        parameters in the same parser arena allows the FunctionParameters AST node
+        refer to ExpressionNodes.
+
+        The most subtle part of this patch is how we allocate lexical environments
+        when functions have default parameter values. If a function has default
+        parameter values then there must be a separate lexical environment for
+        its parameters. Then, the function's "var" lexical environment must have
+        the parameter lexical environment as its parent. The BytecodeGenerator
+        takes great care to not allocate the "var" lexical environment before its
+        really needed.
+
+        The "arguments" object for a function with default parameters will never be 
+        a mapped arugments object. It will always be a cloned arugments object.
+
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::generate):
+        (JSC::BytecodeGenerator::BytecodeGenerator):
+        (JSC::BytecodeGenerator::~BytecodeGenerator):
+        (JSC::BytecodeGenerator::initializeDefaultParameterValuesAndSetupFunctionScopeStack):
+        (JSC::BytecodeGenerator::initializeNextParameter):
+        (JSC::BytecodeGenerator::initializeVarLexicalEnvironment):
+        (JSC::BytecodeGenerator::visibleNameForParameter):
+        (JSC::BytecodeGenerator::emitLoadGlobalObject):
+        (JSC::BytecodeGenerator::pushLexicalScopeInternal):
+        (JSC::BytecodeGenerator::pushLexicalScope):
+        (JSC::BytecodeGenerator::popLexicalScope):
+        * bytecompiler/BytecodeGenerator.h:
+        (JSC::BytecodeGenerator::lastOpcodeID):
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::FunctionNode::emitBytecode):
+        * jit/JITOperations.cpp:
+        * parser/ASTBuilder.h:
+        (JSC::ASTBuilder::createElementList):
+        (JSC::ASTBuilder::createFormalParameterList):
+        (JSC::ASTBuilder::appendParameter):
+        (JSC::ASTBuilder::createClause):
+        (JSC::ASTBuilder::createClauseList):
+        * parser/Nodes.h:
+        (JSC::FunctionParameters::size):
+        (JSC::FunctionParameters::at):
+        (JSC::FunctionParameters::hasDefaultParameterValues):
+        (JSC::FunctionParameters::append):
+        * parser/Parser.cpp:
+        (JSC::Parser<LexerType>::parseVariableDeclarationList):
+        (JSC::Parser<LexerType>::createBindingPattern):
+        (JSC::Parser<LexerType>::tryParseDestructuringPatternExpression):
+        (JSC::Parser<LexerType>::parseDestructuringPattern):
+        (JSC::Parser<LexerType>::parseFormalParameters):
+        (JSC::Parser<LexerType>::parseFunctionParameters):
+        * parser/Parser.h:
+        (JSC::Scope::declareParameter):
+        * parser/SyntaxChecker.h:
+        (JSC::SyntaxChecker::createElementList):
+        (JSC::SyntaxChecker::createFormalParameterList):
+        (JSC::SyntaxChecker::appendParameter):
+        (JSC::SyntaxChecker::createClause):
+        (JSC::SyntaxChecker::createClauseList):
+        * tests/stress/es6-default-parameters.js: Added.
+        (assert):
+        (shouldThrow):
+        (shouldThrowSyntaxError):
+        (shouldThrowTDZ):
+        (basic):
+        (basicFunctionCaptureInDefault.basicFunctionCaptureInDefault.basicCaptured):
+        (basicCaptured.basicCaptured.tricky):
+        (strict):
+        (playground):
+        (scoping):
+        (augmentsArguments1):
+        (augmentsArguments2):
+        (augmentsArguments3):
+        (augmentsArguments4):
+        (augmentsArguments5):
+
 2015-07-24  Xabier Rodriguez Calvar  <[email protected]>
 
         Remove JS Promise constructor unused piece of code

Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp (187350 => 187351)


--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2015-07-24 18:39:41 UTC (rev 187350)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2015-07-24 18:40:58 UTC (rev 187351)
@@ -63,7 +63,7 @@
 ParserError BytecodeGenerator::generate()
 {
     SamplingRegion samplingRegion("Bytecode Generation");
-    
+
     m_codeBlock->setThisRegister(m_thisRegister.virtualRegister());
     
     // If we have declared a variable named "arguments" and we are using arguments then we should
@@ -71,11 +71,6 @@
     if (m_needToInitializeArguments)
         initializeVariable(variable(propertyNames().arguments), m_argumentsRegister);
 
-    for (size_t i = 0; i < m_destructuringParameters.size(); i++) {
-        auto& entry = m_destructuringParameters[i];
-        entry.second->bindValue(*this, entry.first.get());
-    }
-
     pushLexicalScope(m_scopeNode, true);
 
     {
@@ -215,13 +210,15 @@
     m_codeBlock->setSymbolTableConstantIndex(symbolTableConstantIndex);
 
     Vector<Identifier> boundParameterProperties;
-    FunctionParameters& parameters = *functionNode->parameters();
-    for (size_t i = 0; i < parameters.size(); i++) {
-        auto pattern = parameters.at(i);
-        if (pattern->isBindingNode())
-            continue;
-        pattern->collectBoundIdentifiers(boundParameterProperties);
-        continue;
+    FunctionParameters& parameters = *functionNode->parameters(); 
+    if (!parameters.hasDefaultParameterValues()) { 
+        // If we do have default parameters, they will be allocated in a separate scope.
+        for (size_t i = 0; i < parameters.size(); i++) {
+            auto pattern = parameters.at(i).first;
+            if (pattern->isBindingNode())
+                continue;
+            pattern->collectBoundIdentifiers(boundParameterProperties);
+        }
     }
 
     bool shouldCaptureSomeOfTheThings = m_shouldEmitDebugHooks || m_codeBlock->needsFullScopeChain();
@@ -265,45 +262,36 @@
     
     if (shouldCaptureSomeOfTheThings) {
         m_lexicalEnvironmentRegister = addVar();
-        m_codeBlock->setActivationRegister(m_lexicalEnvironmentRegister->virtualRegister());
-        emitOpcode(op_create_lexical_environment);
-        instructions().append(m_lexicalEnvironmentRegister->index());
-        instructions().append(scopeRegister()->index());
-        instructions().append(symbolTableConstantIndex);
-        instructions().append(addConstantValue(jsUndefined())->index());
-
-        emitOpcode(op_mov);
-        instructions().append(scopeRegister()->index());
-        instructions().append(m_lexicalEnvironmentRegister->index());
+        // We can allocate the "var" environment if we don't have default parameter expressions. If we have
+        // default parameter expressions, we have to hold off on allocating the "var" environment because
+        // the parent scope of the "var" environment is the parameter environment.
+        if (!parameters.hasDefaultParameterValues())
+            initializeVarLexicalEnvironment(symbolTableConstantIndex);
     }
 
     // Make sure the code block knows about all of our parameters, and make sure that parameters
     // needing destructuring are noted.
     m_parameters.grow(parameters.size() + 1); // reserve space for "this"
     m_thisRegister.setIndex(initializeNextParameter()->index()); // this
-    for (unsigned i = 0; i < parameters.size(); ++i) {
-        auto pattern = parameters.at(i);
-        RegisterID* reg = initializeNextParameter();
-        if (!pattern->isBindingNode())
-            m_destructuringParameters.append(std::make_pair(reg, pattern));
-    }
+    for (unsigned i = 0; i < parameters.size(); ++i)
+        initializeNextParameter();
     
     // Figure out some interesting facts about our arguments.
     bool capturesAnyArgumentByName = false;
     if (functionNode->hasCapturedVariables()) {
         FunctionParameters& parameters = *functionNode->parameters();
         for (size_t i = 0; i < parameters.size(); ++i) {
-            auto pattern = parameters.at(i);
+            auto pattern = parameters.at(i).first;
             if (!pattern->isBindingNode())
                 continue;
             const Identifier& ident = static_cast<const BindingNode*>(pattern)->boundProperty();
             capturesAnyArgumentByName |= captures(ident.impl());
         }
     }
-
+    
     if (capturesAnyArgumentByName)
         ASSERT(m_lexicalEnvironmentRegister);
-    
+
     // Need to know what our functions are called. Parameters have some goofy behaviors when it
     // comes to functions of the same name.
     for (FunctionBodyNode* function : functionNode->functionStack())
@@ -320,7 +308,7 @@
         m_argumentsRegister->ref();
     }
     
-    if (needsArguments && !codeBlock->isStrictMode()) {
+    if (needsArguments && !codeBlock->isStrictMode() && !parameters.hasDefaultParameterValues()) {
         // If we captured any formal parameter by name, then we use ScopedArguments. Otherwise we
         // use DirectArguments. With ScopedArguments, we lift all of our arguments into the
         // activation.
@@ -335,7 +323,7 @@
             for (unsigned i = 0; i < parameters.size(); ++i) {
                 ScopeOffset offset = functionSymbolTable->takeNextScopeOffset();
                 functionSymbolTable->setArgumentOffset(vm, i, offset);
-                if (UniquedStringImpl* name = visibleNameForParameter(parameters.at(i))) {
+                if (UniquedStringImpl* name = visibleNameForParameter(parameters.at(i).first)) {
                     VarOffset varOffset(offset);
                     SymbolTableEntry entry(varOffset);
                     // Stores to these variables via the ScopedArguments object will not do
@@ -363,18 +351,20 @@
             // We're going to put all parameters into the DirectArguments object. First ensure
             // that the symbol table knows that this is happening.
             for (unsigned i = 0; i < parameters.size(); ++i) {
-                if (UniquedStringImpl* name = visibleNameForParameter(parameters.at(i)))
+                if (UniquedStringImpl* name = visibleNameForParameter(parameters.at(i).first))
                     functionSymbolTable->set(name, SymbolTableEntry(VarOffset(DirectArgumentsOffset(i))));
             }
             
             emitOpcode(op_create_direct_arguments);
             instructions().append(m_argumentsRegister->index());
         }
-    } else {
+    } else if (!parameters.hasDefaultParameterValues()) {
         // Create the formal parameters the normal way. Any of them could be captured, or not. If
-        // captured, lift them into the scope.
+        // captured, lift them into the scope. We can not do this if we have default parameter expressions
+        // because when default parameter expressions exist, they belong in their own lexical environment
+        // separate from the "var" lexical environment.
         for (unsigned i = 0; i < parameters.size(); ++i) {
-            UniquedStringImpl* name = visibleNameForParameter(parameters.at(i));
+            UniquedStringImpl* name = visibleNameForParameter(parameters.at(i).first);
             if (!name)
                 continue;
             
@@ -387,7 +377,7 @@
             
             ScopeOffset offset = functionSymbolTable->takeNextScopeOffset();
             const Identifier& ident =
-                static_cast<const BindingNode*>(parameters.at(i))->boundProperty();
+                static_cast<const BindingNode*>(parameters.at(i).first)->boundProperty();
             functionSymbolTable->set(name, SymbolTableEntry(VarOffset(offset)));
             
             emitOpcode(op_put_to_scope);
@@ -400,15 +390,17 @@
         }
     }
     
-    if (needsArguments && codeBlock->isStrictMode()) {
+    if (needsArguments && (codeBlock->isStrictMode() || parameters.hasDefaultParameterValues())) {
         // Allocate an out-of-bands arguments object.
         emitOpcode(op_create_out_of_band_arguments);
         instructions().append(m_argumentsRegister->index());
     }
     
     // Now declare all variables.
-    for (const Identifier& ident : boundParameterProperties)
+    for (const Identifier& ident : boundParameterProperties) {
+        ASSERT(!parameters.hasDefaultParameterValues());
         createVariable(ident, varKind(ident.impl()), functionSymbolTable);
+    }
     for (FunctionBodyNode* function : functionNode->functionStack()) {
         const Identifier& ident = function->ident();
         createVariable(ident, varKind(ident.impl()), functionSymbolTable);
@@ -421,7 +413,7 @@
         // Variables named "arguments" are never const.
         createVariable(Identifier::fromUid(m_vm, entry.key.get()), varKind(entry.key.get()), functionSymbolTable, IgnoreExisting);
     }
-    
+
     // There are some variables that need to be preinitialized to something other than Undefined:
     //
     // - "arguments": unless it's used as a function or parameter, this should refer to the
@@ -486,7 +478,7 @@
         
         bool haveParameterNamedArguments = false;
         for (unsigned i = 0; i < parameters.size(); ++i) {
-            UniquedStringImpl* name = visibleNameForParameter(parameters.at(i));
+            UniquedStringImpl* name = visibleNameForParameter(parameters.at(i).first);
             if (name == propertyNames().arguments.impl()) {
                 haveParameterNamedArguments = true;
                 break;
@@ -499,7 +491,7 @@
             m_needToInitializeArguments = true;
         }
     }
-    
+
     m_newTargetRegister = addVar();
     if (isConstructor()) {
         emitMove(m_newTargetRegister, &m_thisRegister);
@@ -517,10 +509,8 @@
         instructions().append(0);
     }
 
-    if (m_lexicalEnvironmentRegister)
-        pushScopedControlFlowContext();
-    m_symbolTableStack.append(SymbolTableStackEntry{ Strong<SymbolTable>(*m_vm, functionSymbolTable), m_lexicalEnvironmentRegister, false, symbolTableConstantIndex });
     m_TDZStack.append(std::make_pair(*parentScopeTDZVariables, false));
+    initializeDefaultParameterValuesAndSetupFunctionScopeStack(parameters, functionNode, functionSymbolTable, symbolTableConstantIndex, captures);
 }
 
 BytecodeGenerator::BytecodeGenerator(VM& vm, EvalNode* evalNode, UnlinkedEvalCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode, const VariableEnvironment* parentScopeTDZVariables)
@@ -564,6 +554,98 @@
 {
 }
 
+void BytecodeGenerator::initializeDefaultParameterValuesAndSetupFunctionScopeStack(
+    FunctionParameters& parameters, FunctionNode* functionNode, SymbolTable* functionSymbolTable, 
+    int symbolTableConstantIndex, const std::function<bool (UniquedStringImpl*)>& captures)
+{
+    Vector<std::pair<Identifier, RefPtr<RegisterID>>> valuesToMoveIntoVars;
+    if (parameters.hasDefaultParameterValues()) {
+        // Refer to the ES6 spec section 9.2.12: http://www.ecma-international.org/ecma-262/6.0/index.html#sec-functiondeclarationinstantiation
+        // This implements step 21.
+        VariableEnvironment environment;
+        Vector<Identifier> allParameterNames; 
+        for (unsigned i = 0; i < parameters.size(); i++)
+            parameters.at(i).first->collectBoundIdentifiers(allParameterNames);
+        IdentifierSet parameterSet;
+        for (auto& ident : allParameterNames) {
+            parameterSet.add(ident.impl());
+            auto addResult = environment.add(ident);
+            addResult.iterator->value.setIsLet(); // When we have default parameter expressions, parameters act like "let" variables.
+            if (captures(ident.impl()))
+                addResult.iterator->value.setIsCaptured();
+        }
+        
+        // This implements step 25 of section 9.2.12.
+        pushLexicalScopeInternal(environment, true, nullptr);
+
+        RefPtr<RegisterID> temp = newTemporary();
+        for (unsigned i = 0; i < parameters.size(); i++) {
+            std::pair<DestructuringPatternNode*, ExpressionNode*> parameter = parameters.at(i);
+            RefPtr<RegisterID> parameterValue = &registerFor(virtualRegisterForArgument(1 + i));
+            emitMove(temp.get(), parameterValue.get());
+            if (parameter.second) {
+                RefPtr<RegisterID> condition = emitIsUndefined(newTemporary(), parameterValue.get());
+                RefPtr<Label> skipDefaultParameterBecauseNotUndefined = newLabel();
+                emitJumpIfFalse(condition.get(), skipDefaultParameterBecauseNotUndefined.get());
+                emitNode(temp.get(), parameter.second);
+                emitLabel(skipDefaultParameterBecauseNotUndefined.get());
+            }
+
+            parameter.first->bindValue(*this, temp.get());
+        }
+
+        // Final act of weirdness for default parameters. If a "var" also
+        // has the same name as a parameter, it should start out as the
+        // value of that parameter. Note, though, that they will be distinct
+        // bindings.
+        // This is step 28 of section 9.2.12. 
+        for (auto& entry : functionNode->varDeclarations()) {
+            if (!entry.value.isVar()) // This is either a parameter or callee.
+                continue;
+
+            if (parameterSet.contains(entry.key)) {
+                Identifier ident = Identifier::fromUid(m_vm, entry.key.get());
+                Variable var = variable(ident);
+                RegisterID* scope = emitResolveScope(nullptr, var);
+                RefPtr<RegisterID> value = emitGetFromScope(newTemporary(), scope, var, DoNotThrowIfNotFound);
+                valuesToMoveIntoVars.append(std::make_pair(ident, value));
+            }
+        }
+
+        // Functions with default parameter expressions must have a separate environment
+        // record for parameters and "var"s. The "var" environment record must have the
+        // parameter environment record as its parent.
+        // See step 28 of section 9.2.12.
+        if (m_lexicalEnvironmentRegister)
+            initializeVarLexicalEnvironment(symbolTableConstantIndex);
+    }
+
+    if (m_lexicalEnvironmentRegister)
+        pushScopedControlFlowContext();
+    m_symbolTableStack.append(SymbolTableStackEntry{ Strong<SymbolTable>(*m_vm, functionSymbolTable), m_lexicalEnvironmentRegister, false, symbolTableConstantIndex });
+
+    // This completes step 28 of section 9.2.12.
+    for (unsigned i = 0; i < valuesToMoveIntoVars.size(); i++) {
+        ASSERT(parameters.hasDefaultParameterValues());
+        Variable var = variable(valuesToMoveIntoVars[i].first);
+        RegisterID* scope = emitResolveScope(nullptr, var);
+        emitPutToScope(scope, var, valuesToMoveIntoVars[i].second.get(), DoNotThrowIfNotFound);
+    }
+
+    if (!parameters.hasDefaultParameterValues()) {
+        ASSERT(!valuesToMoveIntoVars.size());
+        // Initialize destructuring parameters the old way as if we don't have any default parameter values.
+        // If we have default parameter values, we handle this case above.
+        for (unsigned i = 0; i < parameters.size(); i++) {
+            DestructuringPatternNode* pattern = parameters.at(i).first;
+            if (!pattern->isBindingNode()) {
+                RefPtr<RegisterID> parameterValue = &registerFor(virtualRegisterForArgument(1 + i));
+                pattern->bindValue(*this, parameterValue.get());
+            }
+        }
+    }
+}
+
 RegisterID* BytecodeGenerator::initializeNextParameter()
 {
     VirtualRegister reg = virtualRegisterForArgument(m_codeBlock->numParameters());
@@ -573,6 +655,21 @@
     return &parameter;
 }
 
+void BytecodeGenerator::initializeVarLexicalEnvironment(int symbolTableConstantIndex)
+{
+    RELEASE_ASSERT(m_lexicalEnvironmentRegister);
+    m_codeBlock->setActivationRegister(m_lexicalEnvironmentRegister->virtualRegister());
+    emitOpcode(op_create_lexical_environment);
+    instructions().append(m_lexicalEnvironmentRegister->index());
+    instructions().append(scopeRegister()->index());
+    instructions().append(symbolTableConstantIndex);
+    instructions().append(addConstantValue(jsUndefined())->index());
+
+    emitOpcode(op_mov);
+    instructions().append(scopeRegister()->index());
+    instructions().append(m_lexicalEnvironmentRegister->index());
+}
+
 UniquedStringImpl* BytecodeGenerator::visibleNameForParameter(DestructuringPatternNode* pattern)
 {
     if (pattern->isBindingNode()) {
@@ -1258,9 +1355,8 @@
     return m_globalObjectRegister;
 }
 
-void BytecodeGenerator::pushLexicalScope(VariableEnvironmentNode* node, bool canOptimizeTDZChecks, RegisterID** constantSymbolTableResult)
+void BytecodeGenerator::pushLexicalScopeInternal(VariableEnvironment& environment, bool canOptimizeTDZChecks, RegisterID** constantSymbolTableResult)
 {
-    VariableEnvironment& environment = node->lexicalVariables();
     if (!environment.size())
         return;
 
@@ -1334,6 +1430,12 @@
     }
 }
 
+void BytecodeGenerator::pushLexicalScope(VariableEnvironmentNode* node, bool canOptimizeTDZChecks, RegisterID** constantSymbolTableResult)
+{
+    VariableEnvironment& environment = node->lexicalVariables();
+    pushLexicalScopeInternal(environment, canOptimizeTDZChecks, constantSymbolTableResult);
+}
+
 void BytecodeGenerator::popLexicalScope(VariableEnvironmentNode* node)
 {
     VariableEnvironment& environment = node->lexicalVariables();

Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h (187350 => 187351)


--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h	2015-07-24 18:39:41 UTC (rev 187350)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h	2015-07-24 18:40:58 UTC (rev 187351)
@@ -621,6 +621,9 @@
 
         OpcodeID lastOpcodeID() const { return m_lastOpcodeID; }
 
+    private:
+        void pushLexicalScopeInternal(VariableEnvironment&, bool canOptimizeTDZChecks, RegisterID** constantSymbolTableResult);
+    public:
         void pushLexicalScope(VariableEnvironmentNode*, bool canOptimizeTDZChecks, RegisterID** constantSymbolTableResult = nullptr);
         void popLexicalScope(VariableEnvironmentNode*);
         void prepareLexicalScopeForNextForLoopIteration(VariableEnvironmentNode*, RegisterID* loopSymbolTable);
@@ -715,6 +718,9 @@
         RegisterID* emitConstructVarargs(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, RegisterID* profileHookRegister, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
         RegisterID* emitCallVarargs(OpcodeID, RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, RegisterID* profileHookRegister, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
 
+        void initializeVarLexicalEnvironment(int symbolTableConstantIndex);
+        void initializeDefaultParameterValuesAndSetupFunctionScopeStack(FunctionParameters&, FunctionNode*, SymbolTable*, int symbolTableConstantIndex, const std::function<bool (UniquedStringImpl*)>& captures);
+
     public:
         JSString* addStringConstant(const Identifier&);
         JSTemplateRegistryKey* addTemplateRegistryKeyConstant(const TemplateRegistryKey&);
@@ -773,7 +779,6 @@
         Vector<SwitchInfo> m_switchContextStack;
         Vector<std::unique_ptr<ForInContext>> m_forInContextStack;
         Vector<TryContext> m_tryContextStack;
-        Vector<std::pair<RefPtr<RegisterID>, const DestructuringPatternNode*>> m_destructuringParameters;
         enum FunctionVariableType : uint8_t { NormalFunctionVariable, GlobalFunctionVariable };
         Vector<std::pair<FunctionBodyNode*, FunctionVariableType>> m_functionsToInitialize;
         bool m_needToInitializeArguments { false };

Modified: trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp (187350 => 187351)


--- trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp	2015-07-24 18:39:41 UTC (rev 187350)
+++ trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp	2015-07-24 18:40:58 UTC (rev 187351)
@@ -3019,9 +3019,9 @@
     if (generator.vm()->typeProfiler()) {
         for (size_t i = 0; i < m_parameters->size(); i++) {
             // FIXME: Handle Destructuring assignments into arguments.
-            if (!m_parameters->at(i)->isBindingNode())
+            if (!m_parameters->at(i).first->isBindingNode())
                 continue;
-            BindingNode* parameter = static_cast<BindingNode*>(m_parameters->at(i));
+            BindingNode* parameter = static_cast<BindingNode*>(m_parameters->at(i).first);
             RegisterID reg(CallFrame::argumentOffset(i));
             generator.emitProfileType(&reg, ProfileTypeBytecodeFunctionArgument, nullptr);
             generator.emitTypeProfilerExpressionInfo(parameter->divotStart(), parameter->divotEnd());

Modified: trunk/Source/_javascript_Core/jit/JITOperations.cpp (187350 => 187351)


--- trunk/Source/_javascript_Core/jit/JITOperations.cpp	2015-07-24 18:39:41 UTC (rev 187350)
+++ trunk/Source/_javascript_Core/jit/JITOperations.cpp	2015-07-24 18:40:58 UTC (rev 187351)
@@ -687,11 +687,8 @@
 
 EncodedJSValue JIT_OPERATION operationCallEval(ExecState* exec, ExecState* execCallee)
 {
+    UNUSED_PARAM(exec);
 
-    ASSERT_UNUSED(exec, exec->codeBlock()->codeType() != FunctionCode
-        || !exec->codeBlock()->needsActivation()
-        || exec->hasActivation());
-
     execCallee->setCodeBlock(0);
 
     if (!isHostFunction(execCallee->calleeAsValue(), globalFuncEval))

Modified: trunk/Source/_javascript_Core/parser/ASTBuilder.h (187350 => 187351)


--- trunk/Source/_javascript_Core/parser/ASTBuilder.h	2015-07-24 18:39:41 UTC (rev 187350)
+++ trunk/Source/_javascript_Core/parser/ASTBuilder.h	2015-07-24 18:40:58 UTC (rev 187351)
@@ -418,7 +418,10 @@
     ElementNode* createElementList(ElementNode* elems, int elisions, ExpressionNode* expr) { return new (m_parserArena) ElementNode(elems, elisions, expr); }
 
     FormalParameterList createFormalParameterList() { return new (m_parserArena) FunctionParameters(); }
-    void appendParameter(FormalParameterList list, DestructuringPattern pattern) { list->append(pattern); }
+    void appendParameter(FormalParameterList list, DestructuringPattern pattern, ExpressionNode* defaultValue) 
+    { 
+        list->append(pattern, defaultValue); 
+    }
 
     CaseClauseNode* createClause(ExpressionNode* expr, JSC::SourceElements* statements) { return new (m_parserArena) CaseClauseNode(expr, statements); }
     ClauseListNode* createClauseList(CaseClauseNode* clause) { return new (m_parserArena) ClauseListNode(clause); }

Modified: trunk/Source/_javascript_Core/parser/Nodes.h (187350 => 187351)


--- trunk/Source/_javascript_Core/parser/Nodes.h	2015-07-24 18:39:41 UTC (rev 187350)
+++ trunk/Source/_javascript_Core/parser/Nodes.h	2015-07-24 18:40:58 UTC (rev 187351)
@@ -1625,12 +1625,20 @@
     public:
         FunctionParameters();
         ALWAYS_INLINE unsigned size() const { return m_patterns.size(); }
-        ALWAYS_INLINE DestructuringPatternNode* at(unsigned index) { return m_patterns[index]; }
-        ALWAYS_INLINE void append(DestructuringPatternNode* pattern) { ASSERT(pattern); m_patterns.append(pattern); }
+        ALWAYS_INLINE std::pair<DestructuringPatternNode*, ExpressionNode*> at(unsigned index) { return m_patterns[index]; }
+        bool hasDefaultParameterValues() const { return m_hasDefaultParameterValues; }
+        ALWAYS_INLINE void append(DestructuringPatternNode* pattern, ExpressionNode* defaultValue) 
+        { 
+            ASSERT(pattern); 
+            m_patterns.append(std::make_pair(pattern, defaultValue));
+            if (defaultValue)
+                m_hasDefaultParameterValues = true;
+        }
 
     private:
 
-        Vector<DestructuringPatternNode*, 3> m_patterns;
+        Vector<std::pair<DestructuringPatternNode*, ExpressionNode*>, 3> m_patterns;
+        bool m_hasDefaultParameterValues { false };
     };
 
     class FunctionBodyNode final : public StatementNode, public ParserArenaDeletable {

Modified: trunk/Source/_javascript_Core/parser/Parser.cpp (187350 => 187351)


--- trunk/Source/_javascript_Core/parser/Parser.cpp	2015-07-24 18:39:41 UTC (rev 187350)
+++ trunk/Source/_javascript_Core/parser/Parser.cpp	2015-07-24 18:40:58 UTC (rev 187351)
@@ -576,7 +576,7 @@
             }
         } else {
             lastIdent = 0;
-            auto pattern = parseDestructuringPattern(context, destructuringKindFromDeclarationType(declarationType), assignmentContext);
+            auto pattern = parseDestructuringPattern(context, destructuringKindFromDeclarationType(declarationType), nullptr, nullptr, assignmentContext);
             failIfFalse(pattern, "Cannot parse this destructuring pattern");
             hasInitializer = match(EQUAL);
             failIfTrue(declarationListContext == VarDeclarationContext && !hasInitializer, "Expected an initializer in destructuring variable declaration");
@@ -604,21 +604,22 @@
 }
 
 template <typename LexerType>
-template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::createBindingPattern(TreeBuilder& context, DestructuringKind kind, const Identifier& name, int depth, JSToken token, AssignmentContext bindingContext)
+template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::createBindingPattern(TreeBuilder& context, DestructuringKind kind, const Identifier& name, int depth, JSToken token, AssignmentContext bindingContext, const Identifier** duplicateIdentifier)
 {
     ASSERT(!name.isNull());
     
     ASSERT(name.impl()->isAtomic() || name.impl()->isSymbol());
-    if (depth) {
-        if (kind == DestructureToVariables)
-            failIfTrueIfStrict(declareVariable(&name) & DeclarationResult::InvalidStrictMode, "Cannot deconstruct to a variable named '", name.impl(), "' in strict mode");
-        else if (kind == DestructureToLet || kind == DestructureToConst) {
-            DeclarationResultMask declarationResult = declareVariable(&name, kind == DestructureToLet ? DeclarationType::LetDeclaration : DeclarationType::ConstDeclaration);
-            if (declarationResult != DeclarationResult::Valid) {
-                failIfTrueIfStrict(declarationResult & DeclarationResult::InvalidStrictMode, "Cannot destructure to a variable named '", name.impl(), "' in strict mode");
-                failIfTrue(declarationResult & DeclarationResult::InvalidDuplicateDeclaration, "Cannot declare a lexical variable twice: '", name.impl(), "'");
-            }
-        } else if (kind == DestructureToParameters) {
+
+    if (kind == DestructureToVariables)
+        failIfTrueIfStrict(declareVariable(&name) & DeclarationResult::InvalidStrictMode, "Cannot declare a variable named '", name.impl(), "' in strict mode");
+    else if (kind == DestructureToLet || kind == DestructureToConst) {
+        DeclarationResultMask declarationResult = declareVariable(&name, kind == DestructureToLet ? DeclarationType::LetDeclaration : DeclarationType::ConstDeclaration);
+        if (declarationResult != DeclarationResult::Valid) {
+            failIfTrueIfStrict(declarationResult & DeclarationResult::InvalidStrictMode, "Cannot destructure to a variable named '", name.impl(), "' in strict mode");
+            failIfTrue(declarationResult & DeclarationResult::InvalidDuplicateDeclaration, "Cannot declare a lexical variable twice: '", name.impl(), "'");
+        }
+    } else if (kind == DestructureToParameters) {
+        if (depth) {
             auto bindingResult = declareBoundParameter(&name);
             if (bindingResult == Scope::StrictBindingFailed && strictMode()) {
                 semanticFailIfTrue(isEvalOrArguments(&name), "Cannot destructure to a parameter name '", name.impl(), "' in strict mode");
@@ -635,18 +636,7 @@
                     semanticFail("Cannot destructure to '", name.impl(), "' as it has already been declared");
                 semanticFail("Cannot destructure to a parameter named '", name.impl(), "'");
             }
-        }
-
-    } else {
-        if (kind == DestructureToVariables)
-            failIfTrueIfStrict(declareVariable(&name) & DeclarationResult::InvalidStrictMode, "Cannot declare a variable named '", name.impl(), "' in strict mode");
-        else if (kind == DestructureToLet || kind == DestructureToConst) {
-            DeclarationResultMask declarationResult = declareVariable(&name, kind == DestructureToLet ? DeclarationType::LetDeclaration : DeclarationType::ConstDeclaration);
-            if (declarationResult != DeclarationResult::Valid) {
-                failIfTrueIfStrict(declarationResult & DeclarationResult::InvalidStrictMode, "Cannot destructure to a variable named '", name.impl(), "' in strict mode");
-                failIfTrue(declarationResult & DeclarationResult::InvalidDuplicateDeclaration, "Cannot declare a lexical variable twice: '", name.impl(), "'");
-            }
-        } else if (kind == DestructureToParameters) {
+        } else {
             DeclarationResultMask declarationResult = declareParameter(&name);
             if ((declarationResult & DeclarationResult::InvalidStrictMode) && strictMode()) {
                 semanticFailIfTrue(isEvalOrArguments(&name), "Cannot destructure to a parameter name '", name.impl(), "' in strict mode");
@@ -657,6 +647,13 @@
                     semanticFail("Cannot declare a parameter named '", name.impl(), "' in strict mode as it has already been declared");
                 semanticFail("Cannot declare a parameter named '", name.impl(), "' in strict mode");
             }
+            if (declarationResult & DeclarationResult::InvalidDuplicateDeclaration) {
+                // It's not always an error to define a duplicate parameter.
+                // It's only an error when there are default parameter values or destructuring parameters.
+                // We note this value now so we can check it later.
+                if (duplicateIdentifier)
+                    *duplicateIdentifier = &name;
+            }
         }
     }
     return context.createBindingLocation(token.m_location, name, token.m_startPosition, token.m_endPosition, bindingContext);
@@ -694,11 +691,11 @@
 template <typename LexerType>
 template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::tryParseDestructuringPatternExpression(TreeBuilder& context, AssignmentContext bindingContext)
 {
-    return parseDestructuringPattern(context, DestructureToExpressions, bindingContext);
+    return parseDestructuringPattern(context, DestructureToExpressions, nullptr, nullptr, bindingContext);
 }
 
 template <typename LexerType>
-template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::parseDestructuringPattern(TreeBuilder& context, DestructuringKind kind, AssignmentContext bindingContext, int depth)
+template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::parseDestructuringPattern(TreeBuilder& context, DestructuringKind kind, const Identifier** duplicateIdentifier, bool* hasDestructuringPattern, AssignmentContext bindingContext, int depth)
 {
     failIfStackOverflow();
     int nonLHSCount = m_nonLHSCount;
@@ -709,6 +706,9 @@
         auto arrayPattern = context.createArrayPattern(m_token.m_location);
         next();
 
+        if (hasDestructuringPattern)
+            *hasDestructuringPattern = true;
+
         bool restElementWasFound = false;
 
         do {
@@ -724,7 +724,7 @@
             if (UNLIKELY(match(DOTDOTDOT))) {
                 JSTokenLocation location = m_token.m_location;
                 next();
-                auto innerPattern = parseDestructuringPattern(context, kind, bindingContext, depth + 1);
+                auto innerPattern = parseDestructuringPattern(context, kind, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
                 if (kind == DestructureToExpressions && !innerPattern)
                     return 0;
                 failIfFalse(innerPattern, "Cannot parse this destructuring pattern");
@@ -737,12 +737,11 @@
             }
 
             JSTokenLocation location = m_token.m_location;
-            auto innerPattern = parseDestructuringPattern(context, kind, bindingContext, depth + 1);
+            auto innerPattern = parseDestructuringPattern(context, kind, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
             if (kind == DestructureToExpressions && !innerPattern)
                 return 0;
             failIfFalse(innerPattern, "Cannot parse this destructuring pattern");
             TreeExpression defaultValue = parseDefaultValueForDestructuringPattern(context);
-            failIfTrue(kind == DestructureToParameters && defaultValue,  "Default values in destructuring parameters are currently not supported");
             context.appendArrayPatternEntry(arrayPattern, location, innerPattern, defaultValue);
         } while (consume(COMMA));
 
@@ -757,6 +756,9 @@
         auto objectPattern = context.createObjectPattern(m_token.m_location);
         next();
 
+        if (hasDestructuringPattern)
+            *hasDestructuringPattern = true;
+
         do {
             bool wasString = false;
 
@@ -772,9 +774,9 @@
                 JSToken identifierToken = m_token;
                 next();
                 if (consume(COLON))
-                    innerPattern = parseDestructuringPattern(context, kind, bindingContext, depth + 1);
+                    innerPattern = parseDestructuringPattern(context, kind, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
                 else
-                    innerPattern = createBindingPattern(context, kind, *propertyName, depth, identifierToken, bindingContext);
+                    innerPattern = createBindingPattern(context, kind, *propertyName, depth + 1, identifierToken, bindingContext, duplicateIdentifier);
             } else {
                 JSTokenType tokenType = m_token.m_type;
                 switch (m_token.m_type) {
@@ -805,13 +807,12 @@
                     
                     failWithMessage("Expected a ':' prior to a named destructuring property");
                 }
-                innerPattern = parseDestructuringPattern(context, kind, bindingContext, depth + 1);
+                innerPattern = parseDestructuringPattern(context, kind, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
             }
             if (kind == DestructureToExpressions && !innerPattern)
                 return 0;
             failIfFalse(innerPattern, "Cannot parse this destructuring pattern");
             TreeExpression defaultValue = parseDefaultValueForDestructuringPattern(context);
-            failIfTrue(kind == DestructureToParameters && defaultValue, "Default values in destructuring parameters are currently not supported");
             ASSERT(propertyName);
             context.appendObjectPatternEntry(objectPattern, location, wasString, *propertyName, innerPattern, defaultValue);
         } while (consume(COMMA));
@@ -831,7 +832,7 @@
             failWithMessage("Expected a parameter pattern or a ')' in parameter list");
         }
         failIfTrue(match(LET) && (kind == DestructureToLet || kind == DestructureToConst), "Can't use 'let' as an identifier name for a LexicalDeclaration");
-        pattern = createBindingPattern(context, kind, *m_token.m_data.ident, depth, m_token, bindingContext);
+        pattern = createBindingPattern(context, kind, *m_token.m_data.ident, depth, m_token, bindingContext, duplicateIdentifier);
         next();
         break;
     }
@@ -1446,17 +1447,32 @@
 template <typename LexerType>
 template <class TreeBuilder> bool Parser<LexerType>::parseFormalParameters(TreeBuilder& context, TreeFormalParameterList list, unsigned& parameterCount)
 {
-    auto parameter = parseDestructuringPattern(context, DestructureToParameters);
+#define failFromDuplicate() \
+    if (duplicateParameter) {\
+        semanticFailIfTrue(defaultValue, "Duplicate parameter '", duplicateParameter->impl(), "' not allowed in function with default parameter values");\
+        semanticFailIfTrue(hasDestructuringPattern, "Duplicate parameter '", duplicateParameter->impl(), "' not allowed in function with destructuring parameters");\
+    }
+
+    const Identifier* duplicateParameter = nullptr;
+    bool hasDestructuringPattern = false;
+    auto parameter = parseDestructuringPattern(context, DestructureToParameters, &duplicateParameter, &hasDestructuringPattern);
     failIfFalse(parameter, "Cannot parse parameter pattern");
-    context.appendParameter(list, parameter);
+    auto defaultValue = parseDefaultValueForDestructuringPattern(context);
+    propagateError();
+    failFromDuplicate();
+    context.appendParameter(list, parameter, defaultValue);
     parameterCount++;
     while (consume(COMMA)) {
-        parameter = parseDestructuringPattern(context, DestructureToParameters);
+        parameter = parseDestructuringPattern(context, DestructureToParameters, &duplicateParameter, &hasDestructuringPattern);
         failIfFalse(parameter, "Cannot parse parameter pattern");
-        context.appendParameter(list, parameter);
+        defaultValue = parseDefaultValueForDestructuringPattern(context);
+        propagateError();
+        failFromDuplicate();
+        context.appendParameter(list, parameter, defaultValue);
         parameterCount++;
     }
     return true;
+#undef failFromDuplicate
 }
 
 template <typename LexerType>
@@ -1530,7 +1546,7 @@
                 functionInfo.parameterCount = 1;
                 auto parameter = parseDestructuringPattern(context, DestructureToParameters);
                 failIfFalse(parameter, "Cannot parse parameter pattern");
-                context.appendParameter(parameterList, parameter);
+                context.appendParameter(parameterList, parameter, 0);
             }
         }
 
@@ -1547,9 +1563,13 @@
         functionInfo.parameterCount = 0;
     } else if (mode == SetterMode) {
         failIfTrue(match(CLOSEPAREN), "setter functions must have one parameter");
-        auto parameter = parseDestructuringPattern(context, DestructureToParameters);
+        const Identifier* duplicateParameter = nullptr;
+        auto parameter = parseDestructuringPattern(context, DestructureToParameters, &duplicateParameter);
         failIfFalse(parameter, "setter functions must have one parameter");
-        context.appendParameter(parameterList, parameter);
+        auto defaultValue = parseDefaultValueForDestructuringPattern(context);
+        propagateError();
+        semanticFailIfTrue(duplicateParameter && defaultValue, "Duplicate parameter '", duplicateParameter->impl(), "' not allowed in function with default parameter values");
+        context.appendParameter(parameterList, parameter, defaultValue);
         functionInfo.parameterCount = 1;
         failIfTrue(match(COMMA), "setter functions must have one parameter");
         consumeOrFail(CLOSEPAREN, "Expected a ')' after a parameter declaration");

Modified: trunk/Source/_javascript_Core/parser/Parser.h (187350 => 187351)


--- trunk/Source/_javascript_Core/parser/Parser.h	2015-07-24 18:39:41 UTC (rev 187350)
+++ trunk/Source/_javascript_Core/parser/Parser.h	2015-07-24 18:40:58 UTC (rev 187351)
@@ -352,6 +352,8 @@
             result |= DeclarationResult::InvalidStrictMode;
         if (isArgumentsIdent)
             m_shadowsArguments = true;
+        if (!addResult.isNewEntry)
+            result |= DeclarationResult::InvalidDuplicateDeclaration;
 
         return result;
     }
@@ -1048,8 +1050,8 @@
     template <class TreeBuilder> TreeExpression parseVariableDeclarationList(TreeBuilder&, int& declarations, TreeDestructuringPattern& lastPattern, TreeExpression& lastInitializer, JSTextPosition& identStart, JSTextPosition& initStart, JSTextPosition& initEnd, VarDeclarationListContext, DeclarationType, bool& forLoopConstDoesNotHaveInitializer);
     template <class TreeBuilder> TreeSourceElements parseArrowFunctionSingleExpressionBodySourceElements(TreeBuilder&);
     template <class TreeBuilder> TreeExpression parseArrowFunctionExpression(TreeBuilder&);
-    template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern createBindingPattern(TreeBuilder&, DestructuringKind, const Identifier&, int depth, JSToken, AssignmentContext);
-    template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern parseDestructuringPattern(TreeBuilder&, DestructuringKind, AssignmentContext = AssignmentContext::DeclarationStatement, int depth = 0);
+    template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern createBindingPattern(TreeBuilder&, DestructuringKind, const Identifier&, int depth, JSToken, AssignmentContext, const Identifier** duplicateIdentifier);
+    template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern parseDestructuringPattern(TreeBuilder&, DestructuringKind, const Identifier** duplicateIdentifier = nullptr, bool* hasDestructuringPattern = nullptr, AssignmentContext = AssignmentContext::DeclarationStatement, int depth = 0);
     template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern tryParseDestructuringPatternExpression(TreeBuilder&, AssignmentContext);
     template <class TreeBuilder> NEVER_INLINE TreeExpression parseDefaultValueForDestructuringPattern(TreeBuilder&);
 

Modified: trunk/Source/_javascript_Core/parser/SyntaxChecker.h (187350 => 187351)


--- trunk/Source/_javascript_Core/parser/SyntaxChecker.h	2015-07-24 18:39:41 UTC (rev 187350)
+++ trunk/Source/_javascript_Core/parser/SyntaxChecker.h	2015-07-24 18:40:58 UTC (rev 187351)
@@ -219,7 +219,7 @@
     int createElementList(int, int) { return ElementsListResult; }
     int createElementList(int, int, int) { return ElementsListResult; }
     int createFormalParameterList() { return FormalParameterListResult; }
-    void appendParameter(int, DestructuringPattern) { }
+    void appendParameter(int, DestructuringPattern, int) { }
     int createClause(int, int) { return ClauseResult; }
     int createClauseList(int) { return ClauseListResult; }
     int createClauseList(int, int) { return ClauseListResult; }

Added: trunk/Source/_javascript_Core/tests/stress/es6-default-parameters.js (0 => 187351)


--- trunk/Source/_javascript_Core/tests/stress/es6-default-parameters.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/es6-default-parameters.js	2015-07-24 18:40:58 UTC (rev 187351)
@@ -0,0 +1,244 @@
+function assert(cond, msg = "") {
+    if (!cond)
+        throw new Error(msg);
+}
+noInline(assert);
+
+function shouldThrow(func) {
+    var hadError = false;
+    try {
+        func()
+    } catch (e) {
+        hadError = true;
+    }
+    assert(hadError, "Did not throw");
+}
+noInline(shouldThrow);
+
+function shouldThrowSyntaxError(str) {
+    var hadError = false;
+    try {
+        eval(str);
+    } catch (e) {
+        if (e instanceof SyntaxError)
+            hadError = true;
+    }
+    assert(hadError, "Did not throw syntax error");
+}
+noInline(shouldThrowSyntaxError);
+
+function shouldThrowTDZ(func) {
+    var hasThrown = false;
+    try {
+        func();
+    } catch(e) {
+        if (e.name.indexOf("ReferenceError") !== -1)
+            hasThrown = true;
+    }
+    assert(hasThrown);
+}
+noInline(shouldThrowTDZ);
+
+function basic(x, y=x) {
+    assert(y === x, "basics don't work.")
+}
+basic(20);
+basic("hello");
+basic({foo: 20});
+basic(undefined);
+
+;(function(){
+    var scopeVariable = {hello: "world"};
+    function basicScope(x = scopeVariable) {
+        assert(x === scopeVariable);
+    }
+    basicScope();
+})();
+
+function basicFunctionCaptureInDefault(theArg = 20, y = function() {return theArg}) {
+    assert(theArg === y(), "y should return x.");
+    theArg = {};
+    assert(theArg === y(), "y should return x.");
+}
+basicFunctionCaptureInDefault()
+basicFunctionCaptureInDefault(undefined)
+
+function basicCaptured(x = 20, y = x) {
+    assert(x === y, "y should equal x");
+    function mutate() { x = "mutation"; }
+    mutate()
+    assert(x !== y, "y should not equal x");
+}
+basicCaptured()
+basicCaptured(undefined)
+
+function tricky(globalX = (globalX = "x"), y = (globalX = 20)) {
+    assert(globalX === 20);
+    assert(globalX === y);
+}
+shouldThrow(tricky);
+
+function strict(x, y = x) {
+    'use strict';
+    assert(x === y);
+}
+strict(20);
+strict(undefined);
+
+function playground(x = "foo", y = "bar") {
+    return {x, y}
+}
+assert(playground().x === "foo")
+assert(playground(undefined).x === "foo")
+assert(playground(undefined, 20).x === "foo")
+assert(playground(null).x === null)
+assert(playground().y === "bar")
+assert(playground(undefined, undefined).y === "bar")
+assert(playground("hello", undefined).y === "bar")
+assert(playground("bar").x === playground(undefined, undefined).y)
+assert(playground(10).x === 10)
+assert(playground(undefined, 20).y === 20)
+assert(playground(undefined, null).y === null)
+
+function scoping(f = function() { return local;}) {
+    shouldThrow(f);
+    var local = 10;
+    shouldThrow(f);
+}
+scoping();
+
+function augmentsArguments1(x = 20) {
+    assert(x === 20);
+
+    arguments[0] = 10;
+    assert(x === 20);
+
+    x = 15;
+    assert(x === 15);
+    assert(arguments[0] === 10);
+}
+augmentsArguments1(undefined);
+
+function augmentsArguments2(x = 20) {
+    assert(x === 20);
+
+    arguments[0] = 10;
+    assert(x === 20);
+    assert(arguments[0] === 10);
+
+    x = 15;
+    assert(x === 15);
+    assert(arguments[0] === 10);
+
+    function augment() { x = 40 }
+    augment()
+    assert(x === 40);
+    assert(arguments[0] === 10);
+}
+augmentsArguments2(undefined);
+
+function augmentsArguments3(x = 10) {
+    assert(x === 10);
+
+    assert(arguments[0] === undefined);
+    x = 20;
+    assert(arguments[0] === undefined);
+}
+augmentsArguments3();
+
+function augmentsArguments4(x = 10) {
+    "use strict";
+    assert(x === 10);
+
+    assert(arguments[0] === undefined);
+    x = 20;
+    assert(arguments[0] === undefined);
+}
+augmentsArguments4();
+augmentsArguments4(undefined);
+
+function augmentsArguments5(x = 10) {
+    "use strict";
+    assert(x === 20);
+
+    assert(arguments[0] === 20);
+    x = 20;
+    assert(arguments[0] === 20);
+}
+augmentsArguments5(20);
+
+;(function () {
+    var outer = "outer";
+    function foo(a = outer, b = function() { return a; }, c = function(v) { a = v; }) {
+        var a;
+        assert(a === "outer");
+        a = 20;
+        assert(a === 20);
+        assert(b() === "outer");
+        c("hello");
+        assert(b() === "hello");
+    }
+
+    function bar(a = outer, b = function() { return a; }, c = function(v) { a = v; }) {
+        with({}) {
+            var a;
+            assert(a === "outer");
+            a = 20;
+            assert(a === 20);
+            assert(b() === "outer");
+            c("hello");
+            assert(b() === "hello");
+        }
+    }
+
+    function baz(x = function() { return y; }, y = "y") {
+        assert(x() === "y");
+        assert(x() === y);
+        assert(y === y);
+    }
+
+    function jaz(x = function() { return y; }, y = "y") {
+        return x;
+    }
+
+    function taz(x = 10, y = eval("x + 1")) {
+        assert(y === 11);
+    }
+
+    for (var i = 0; i < 1000; i++) {
+        foo();
+        bar();
+        baz();
+        assert(jaz(undefined, 20)() === 20);
+        assert(jaz(undefined, undefined)() === "y");
+        assert(jaz(undefined, {x: "x"})().x === "x");
+        taz();
+    }
+})();
+
+// TDZ errors.
+;(function() {
+    function basicError(x = y, y) { }
+    function basicError2(x = x) { }
+    function baz(z = {p: x}, x = z) {}
+    function bar(x = {p: [x]}) {}
+    function jaz(x = eval("y"), y) { }
+    function kaz(x = eval(";(function() { return y})();"), y) { }
+    for (var i = 0; i < 1000; i++) {
+        shouldThrowTDZ(basicError);
+        shouldThrowTDZ(basicError2);
+        shouldThrowTDZ(baz);
+        shouldThrowTDZ(bar);
+        shouldThrowTDZ(jaz);
+        shouldThrowTDZ(kaz);
+    }
+})();
+
+
+
+// Syntax errors.
+shouldThrowSyntaxError("function b(a = 20, a = 40) {}");
+shouldThrowSyntaxError("function b(aaaaa = 20,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v, aaaaa = 40) {}");
+shouldThrowSyntaxError("function b(a = 20, {a}) {}");
+shouldThrowSyntaxError("function b({a, a} = 20) {}");
+shouldThrowSyntaxError("function b({a, a} = 20) {}");
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to