[ES6] Add support for default parameters
https://bugs.webkit.org/show_bug.cgi?id=38409
Reviewed by Filip Pizlo.
Source/JavaScriptCore:
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:
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@187351 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 109480c..37fba63 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,89 @@
+2015-07-24 Saam barati <saambarati1@gmail.com>
+
+ [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 <calvaris@igalia.com>
Remove JS Promise constructor unused piece of code
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
index 0f90d63..ed12a14 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
@@ -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 = ®isterFor(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 = ®isterFor(virtualRegisterForArgument(1 + i));
+ pattern->bindValue(*this, parameterValue.get());
+ }
+ }
+ }
+}
+
RegisterID* BytecodeGenerator::initializeNextParameter()
{
VirtualRegister reg = virtualRegisterForArgument(m_codeBlock->numParameters());
@@ -573,6 +655,21 @@
return ¶meter;
}
+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();
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
index 6d7ce7d..3adc510 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
@@ -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 };
diff --git a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
index b2f7350..da46b9f 100644
--- a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
+++ b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
@@ -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(®, ProfileTypeBytecodeFunctionArgument, nullptr);
generator.emitTypeProfilerExpressionInfo(parameter->divotStart(), parameter->divotEnd());
diff --git a/Source/JavaScriptCore/jit/JITOperations.cpp b/Source/JavaScriptCore/jit/JITOperations.cpp
index 31223a5..41c14b6 100644
--- a/Source/JavaScriptCore/jit/JITOperations.cpp
+++ b/Source/JavaScriptCore/jit/JITOperations.cpp
@@ -687,10 +687,7 @@
EncodedJSValue JIT_OPERATION operationCallEval(ExecState* exec, ExecState* execCallee)
{
-
- ASSERT_UNUSED(exec, exec->codeBlock()->codeType() != FunctionCode
- || !exec->codeBlock()->needsActivation()
- || exec->hasActivation());
+ UNUSED_PARAM(exec);
execCallee->setCodeBlock(0);
diff --git a/Source/JavaScriptCore/parser/ASTBuilder.h b/Source/JavaScriptCore/parser/ASTBuilder.h
index c1c7625..c28c62e 100644
--- a/Source/JavaScriptCore/parser/ASTBuilder.h
+++ b/Source/JavaScriptCore/parser/ASTBuilder.h
@@ -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); }
diff --git a/Source/JavaScriptCore/parser/Nodes.h b/Source/JavaScriptCore/parser/Nodes.h
index a2df6f9..92fa7e6 100644
--- a/Source/JavaScriptCore/parser/Nodes.h
+++ b/Source/JavaScriptCore/parser/Nodes.h
@@ -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 {
diff --git a/Source/JavaScriptCore/parser/Parser.cpp b/Source/JavaScriptCore/parser/Parser.cpp
index 5b5c575..e00a73a 100644
--- a/Source/JavaScriptCore/parser/Parser.cpp
+++ b/Source/JavaScriptCore/parser/Parser.cpp
@@ -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");
diff --git a/Source/JavaScriptCore/parser/Parser.h b/Source/JavaScriptCore/parser/Parser.h
index 97acd47..01941fc 100644
--- a/Source/JavaScriptCore/parser/Parser.h
+++ b/Source/JavaScriptCore/parser/Parser.h
@@ -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&);
diff --git a/Source/JavaScriptCore/parser/SyntaxChecker.h b/Source/JavaScriptCore/parser/SyntaxChecker.h
index 3951b8b..23f448f 100644
--- a/Source/JavaScriptCore/parser/SyntaxChecker.h
+++ b/Source/JavaScriptCore/parser/SyntaxChecker.h
@@ -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; }
diff --git a/Source/JavaScriptCore/tests/stress/es6-default-parameters.js b/Source/JavaScriptCore/tests/stress/es6-default-parameters.js
new file mode 100644
index 0000000..caddd9c
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/es6-default-parameters.js
@@ -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) {}");