WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
[patch]
patch
c-backup.diff (text/plain), 58.34 KB, created by
Saam Barati
on 2015-07-23 18:55:47 PDT
(
hide
)
Description:
patch
Filename:
MIME Type:
Creator:
Saam Barati
Created:
2015-07-23 18:55:47 PDT
Size:
58.34 KB
patch
obsolete
>Index: Source/JavaScriptCore/ChangeLog >=================================================================== >--- Source/JavaScriptCore/ChangeLog (revision 187280) >+++ Source/JavaScriptCore/ChangeLog (working copy) >@@ -1,3 +1,88 @@ >+2015-07-23 Saam barati <saambarati1@gmail.com> >+ >+ [ES6] Add support for default parameters >+ https://bugs.webkit.org/show_bug.cgi?id=38409 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ 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): >+ * 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-23 Alex Christensen <achristensen@webkit.org> > > Remove compile and runtime flags for promises. >Index: Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp >=================================================================== >--- Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp (revision 187203) >+++ Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp (working copy) >@@ -63,7 +63,7 @@ void Label::setLocation(unsigned locatio > 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 @@ ParserError BytecodeGenerator::generate( > 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,14 @@ BytecodeGenerator::BytecodeGenerator(VM& > 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 have default parameters, these 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 +261,36 @@ BytecodeGenerator::BytecodeGenerator(VM& > > 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 +307,7 @@ BytecodeGenerator::BytecodeGenerator(VM& > 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 +322,7 @@ BytecodeGenerator::BytecodeGenerator(VM& > 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 +350,20 @@ BytecodeGenerator::BytecodeGenerator(VM& > // 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 +376,7 @@ BytecodeGenerator::BytecodeGenerator(VM& > > 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 +389,17 @@ BytecodeGenerator::BytecodeGenerator(VM& > } > } > >- 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 +412,7 @@ BytecodeGenerator::BytecodeGenerator(VM& > // 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 +477,7 @@ BytecodeGenerator::BytecodeGenerator(VM& > > 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 +490,7 @@ BytecodeGenerator::BytecodeGenerator(VM& > m_needToInitializeArguments = true; > } > } >- >+ > m_newTargetRegister = addVar(); > if (isConstructor()) { > emitMove(m_newTargetRegister, &m_thisRegister); >@@ -517,10 +508,8 @@ BytecodeGenerator::BytecodeGenerator(VM& > 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 +553,95 @@ BytecodeGenerator::~BytecodeGenerator() > { > } > >+void BytecodeGenerator::initializeDefaultParameterValuesAndSetupFunctionScopeStack( >+ FunctionParameters& parameters, FunctionNode* functionNode, SymbolTable* functionSymbolTable, >+ int symbolTableConstantIndex, const std::function<bool (UniquedStringImpl*)>& captures) >+{ >+ IdentifierSet parameterSet; >+ Vector<std::pair<Identifier, RefPtr<RegisterID>>> valuesToMoveIntoVars; >+ if (parameters.hasDefaultParameterValues()) { >+ // The "var" lexical environment should be allocated with the parameter activation >+ // as its parent scope. Hence, it should not be allocated yet. >+ VariableEnvironment environment; >+ Vector<Identifier> allParameterNames; >+ for (unsigned i = 0; i < parameters.size(); i++) >+ parameters.at(i).first->collectBoundIdentifiers(allParameterNames); >+ 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(); >+ } >+ >+ 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()); >+ } >+ >+ // FIXME: Add references in all default parameter code indicating the portion of the spec >+ // it is implementing. There is some weirdness here in our ordering because >+ // we require all addVar() to take place before allocating temporary registers. >+ 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)); >+ } >+ } >+ >+ // We can now initialize the "var" environment because the parameter >+ // environment has been created. >+ if (m_lexicalEnvironmentRegister) >+ initializeVarLexicalEnvironment(symbolTableConstantIndex); >+ } >+ >+ // 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. >+ >+ if (m_lexicalEnvironmentRegister) >+ pushScopedControlFlowContext(); >+ m_symbolTableStack.append(SymbolTableStackEntry{ Strong<SymbolTable>(*m_vm, functionSymbolTable), m_lexicalEnvironmentRegister, false, symbolTableConstantIndex }); >+ >+ if (!parameters.hasDefaultParameterValues()) { >+ // 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()); >+ } >+ } >+ } >+ >+ for (unsigned i = 0; i < valuesToMoveIntoVars.size(); i++) { >+ Variable var = variable(valuesToMoveIntoVars[i].first); >+ RegisterID* scope = emitResolveScope(nullptr, var); >+ emitPutToScope(scope, var, valuesToMoveIntoVars[i].second.get(), DoNotThrowIfNotFound); >+ } >+} >+ > RegisterID* BytecodeGenerator::initializeNextParameter() > { > VirtualRegister reg = virtualRegisterForArgument(m_codeBlock->numParameters()); >@@ -573,6 +651,21 @@ RegisterID* BytecodeGenerator::initializ > 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 +1351,8 @@ RegisterID* BytecodeGenerator::emitLoadG > 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 +1426,12 @@ void BytecodeGenerator::pushLexicalScope > } > } > >+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(); >Index: Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h >=================================================================== >--- Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h (revision 187203) >+++ Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h (working copy) >@@ -621,6 +621,9 @@ namespace JSC { > > 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); >@@ -709,6 +712,9 @@ namespace JSC { > 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&); >@@ -767,7 +773,6 @@ namespace JSC { > 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 }; >Index: Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp >=================================================================== >--- Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp (revision 187203) >+++ Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp (working copy) >@@ -3019,9 +3019,9 @@ void FunctionNode::emitBytecode(Bytecode > 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()); >Index: Source/JavaScriptCore/jit/JITOperations.cpp >=================================================================== >--- Source/JavaScriptCore/jit/JITOperations.cpp (revision 187203) >+++ Source/JavaScriptCore/jit/JITOperations.cpp (working copy) >@@ -687,10 +687,7 @@ void JIT_OPERATION operationDirectPutByV > > 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); > >Index: Source/JavaScriptCore/parser/ASTBuilder.h >=================================================================== >--- Source/JavaScriptCore/parser/ASTBuilder.h (revision 187203) >+++ Source/JavaScriptCore/parser/ASTBuilder.h (working copy) >@@ -418,7 +418,10 @@ public: > 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); } >Index: Source/JavaScriptCore/parser/Nodes.h >=================================================================== >--- Source/JavaScriptCore/parser/Nodes.h (revision 187203) >+++ Source/JavaScriptCore/parser/Nodes.h (working copy) >@@ -1625,12 +1625,20 @@ namespace JSC { > 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 { >Index: Source/JavaScriptCore/parser/Parser.cpp >=================================================================== >--- Source/JavaScriptCore/parser/Parser.cpp (revision 187203) >+++ Source/JavaScriptCore/parser/Parser.cpp (working copy) >@@ -576,7 +576,7 @@ template <class TreeBuilder> TreeExpress > } > } 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 <class TreeBuilder> TreeExpress > } > > 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 @@ template <class TreeBuilder> TreeDestruc > 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 @@ template <class TreeBuilder> TreeDestruc > 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. >+ // 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 <class TreeBuilder> TreeSourceE > 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 @@ template <class TreeBuilder> TreeDestruc > auto arrayPattern = context.createArrayPattern(m_token.m_location); > next(); > >+ if (hasDestructuringPattern) >+ *hasDestructuringPattern = true; >+ > bool restElementWasFound = false; > > do { >@@ -724,7 +724,7 @@ template <class TreeBuilder> TreeDestruc > 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 @@ template <class TreeBuilder> TreeDestruc > } > > 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 @@ template <class TreeBuilder> TreeDestruc > auto objectPattern = context.createObjectPattern(m_token.m_location); > next(); > >+ if (hasDestructuringPattern) >+ *hasDestructuringPattern = true; >+ > do { > bool wasString = false; > >@@ -772,9 +774,9 @@ template <class TreeBuilder> TreeDestruc > 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 @@ template <class TreeBuilder> TreeDestruc > > 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 @@ template <class TreeBuilder> TreeDestruc > 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 <class TreeBuilder> TreeStateme > 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 @@ template <typename LexerType> template < > 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 @@ template <typename LexerType> template < > 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"); >Index: Source/JavaScriptCore/parser/Parser.h >=================================================================== >--- Source/JavaScriptCore/parser/Parser.h (revision 187203) >+++ Source/JavaScriptCore/parser/Parser.h (working copy) >@@ -352,6 +352,8 @@ struct Scope { > result |= DeclarationResult::InvalidStrictMode; > if (isArgumentsIdent) > m_shadowsArguments = true; >+ if (!addResult.isNewEntry) >+ result |= DeclarationResult::InvalidDuplicateDeclaration; > > return result; > } >@@ -1048,8 +1050,8 @@ private: > 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&); > >Index: Source/JavaScriptCore/parser/SyntaxChecker.h >=================================================================== >--- Source/JavaScriptCore/parser/SyntaxChecker.h (revision 187203) >+++ Source/JavaScriptCore/parser/SyntaxChecker.h (working copy) >@@ -219,7 +219,7 @@ public: > 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; } >Index: Source/JavaScriptCore/tests/stress/es6-default-parameters.js >=================================================================== >--- Source/JavaScriptCore/tests/stress/es6-default-parameters.js (revision 0) >+++ Source/JavaScriptCore/tests/stress/es6-default-parameters.js (working copy) >@@ -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) {}"); >Index: LayoutTests/ChangeLog >=================================================================== >--- LayoutTests/ChangeLog (revision 187280) >+++ LayoutTests/ChangeLog (working copy) >@@ -1,3 +1,16 @@ >+2015-07-23 Saam barati <saambarati1@gmail.com> >+ >+ [ES6] Add support for default parameters >+ https://bugs.webkit.org/show_bug.cgi?id=38409 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * 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-23 Nan Wang <n_wang@apple.com> > > AX: AccessibilityNodeObject::childrenChanged() generates too many AXLiveRegionChanged notifications >Index: LayoutTests/js/destructuring-assignment-default-values-expected.txt >=================================================================== >--- LayoutTests/js/destructuring-assignment-default-values-expected.txt (revision 187203) >+++ LayoutTests/js/destructuring-assignment-default-values-expected.txt (working copy) >@@ -33,11 +33,6 @@ PASS 30,30 > 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 >Index: LayoutTests/js/parser-syntax-check-expected.txt >=================================================================== >--- LayoutTests/js/parser-syntax-check-expected.txt (revision 187203) >+++ LayoutTests/js/parser-syntax-check-expected.txt (working copy) >@@ -867,6 +867,34 @@ PASS Invalid: "({set [x](x){}})" > 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'" >Index: LayoutTests/js/script-tests/destructuring-assignment-default-values.js >=================================================================== >--- LayoutTests/js/script-tests/destructuring-assignment-default-values.js (revision 187203) >+++ LayoutTests/js/script-tests/destructuring-assignment-default-values.js (working copy) >@@ -105,21 +105,3 @@ function test8(x) { > 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]}) {})"); >Index: LayoutTests/js/script-tests/parser-syntax-check.js >=================================================================== >--- LayoutTests/js/script-tests/parser-syntax-check.js (revision 187203) >+++ LayoutTests/js/script-tests/parser-syntax-check.js (working copy) >@@ -526,6 +526,20 @@ invalid("({get [x](){}})") > 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 % +");
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Flags:
fpizlo
:
review+
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 38409
:
248635
|
249144
|
249648
|
257394
| 257418