Ignore:
Timestamp:
Nov 19, 2015, 6:37:47 PM (10 years ago)
Author:
[email protected]
Message:

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

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

This patch implements rest parameters from the ES6 spec.
http://www.ecma-international.org/ecma-262/6.0/index.html#sec-function-definitions

We implement the rest parameter as a new AST node. This AST node
lowers to "op_new_array X, op_copy_rest X". Note
that the op_copy_rest opcode does not have a result.
The bulk of this patch is implementing op_copy_rest.
This patch implements this in all four tiers in a straight forward way.
The opcode is implemented as a C call that will read the pertinent
arguments from the call frame and fill them into the array.

  • bytecode/BytecodeList.json:
  • bytecode/BytecodeUseDef.h:

(JSC::computeUsesForBytecodeOffset):
(JSC::computeDefsForBytecodeOffset):

  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::dumpBytecode):

  • bytecode/Instruction.h:

(JSC::Instruction::Instruction):

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::generate):
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::initializeDefaultParameterValuesAndSetupFunctionScopeStack):
(JSC::BytecodeGenerator::invalidateForInContextForLocal):
(JSC::BytecodeGenerator::emitRestParameter):

  • bytecompiler/BytecodeGenerator.h:
  • bytecompiler/NodesCodegen.cpp:

(JSC::AssignmentElementNode::toString):
(JSC::RestParameterNode::collectBoundIdentifiers):
(JSC::RestParameterNode::toString):
(JSC::RestParameterNode::bindValue):
(JSC::RestParameterNode::emit):
(JSC::SpreadExpressionNode::emitBytecode):

  • dfg/DFGAbstractInterpreterInlines.h:

(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::parseBlock):

  • dfg/DFGCapabilities.cpp:

(JSC::DFG::capabilityLevel):

  • dfg/DFGClobberize.h:

(JSC::DFG::clobberize):

  • dfg/DFGDoesGC.cpp:

(JSC::DFG::doesGC):

  • dfg/DFGFixupPhase.cpp:

(JSC::DFG::FixupPhase::fixupNode):

  • dfg/DFGNode.h:

(JSC::DFG::Node::setEpoch):
(JSC::DFG::Node::numberOfArgumentsToSkip):
(JSC::DFG::Node::dumpChildren):

  • dfg/DFGNodeType.h:
  • dfg/DFGOperations.cpp:
  • dfg/DFGOperations.h:
  • dfg/DFGPredictionPropagationPhase.cpp:

(JSC::DFG::PredictionPropagationPhase::propagate):

  • dfg/DFGSafeToExecute.h:

(JSC::DFG::safeToExecute):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compileCreateClonedArguments):
(JSC::DFG::SpeculativeJIT::compileCopyRest):
(JSC::DFG::SpeculativeJIT::compileNotifyWrite):

  • dfg/DFGSpeculativeJIT.h:

(JSC::DFG::SpeculativeJIT::callOperation):

  • dfg/DFGSpeculativeJIT32_64.cpp:

(JSC::DFG::SpeculativeJIT::compile):

  • dfg/DFGSpeculativeJIT64.cpp:

(JSC::DFG::SpeculativeJIT::compile):

  • ftl/FTLCapabilities.cpp:

(JSC::FTL::canCompile):

  • ftl/FTLIntrinsicRepository.h:
  • ftl/FTLLowerDFGToLLVM.cpp:

(JSC::FTL::DFG::LowerDFGToLLVM::compileNode):
(JSC::FTL::DFG::LowerDFGToLLVM::compileCreateClonedArguments):
(JSC::FTL::DFG::LowerDFGToLLVM::compileCopyRest):
(JSC::FTL::DFG::LowerDFGToLLVM::compileNewObject):

  • jit/JIT.cpp:

(JSC::JIT::privateCompileMainPass):

  • jit/JIT.h:
  • jit/JITOpcodes.cpp:

(JSC::JIT::emit_op_create_out_of_band_arguments):
(JSC::JIT::emit_op_copy_rest):

  • jit/JITOperations.h:
  • llint/LowLevelInterpreter.asm:
  • parser/ASTBuilder.h:

(JSC::ASTBuilder::createBindingLocation):
(JSC::ASTBuilder::createRestParameter):
(JSC::ASTBuilder::createAssignmentElement):

  • parser/NodeConstructors.h:

(JSC::AssignmentElementNode::AssignmentElementNode):
(JSC::RestParameterNode::RestParameterNode):
(JSC::DestructuringAssignmentNode::DestructuringAssignmentNode):

  • parser/Nodes.h:

(JSC::DestructuringPatternNode::isBindingNode):
(JSC::DestructuringPatternNode::isRestParameter):
(JSC::DestructuringPatternNode::emitDirectBinding):
(JSC::RestParameterNode::name):

  • parser/Parser.cpp:

(JSC::Parser<LexerType>::parseVariableDeclarationList):
(JSC::Parser<LexerType>::declareRestOrNormalParameter):
(JSC::Parser<LexerType>::createBindingPattern):
(JSC::Parser<LexerType>::parseFormalParameters):

  • parser/Parser.h:

(JSC::Parser::strictMode):
(JSC::Parser::isValidStrictMode):
(JSC::Parser::declareParameter):
(JSC::Parser::breakIsValid):

  • parser/SyntaxChecker.h:

(JSC::SyntaxChecker::operatorStackPop):

  • runtime/CommonSlowPaths.cpp:

(JSC::SLOW_PATH_DECL):

  • runtime/CommonSlowPaths.h:
  • tests/es6.yaml:
  • tests/stress/rest-parameter-and-default-arguments.js: Added.

(assert):
(shouldThrowTDZ):
(foo):
(baz):
(i.shouldThrowTDZ):

  • tests/stress/rest-parameter-basics.js: Added.

(assert):
(foo):
(bar):
(capture):
(baz):
(jaz):
(kaz):
(raz):
(restLength):
(testArgumentsObject):
(strictModeLikeArgumentsObject):

  • tests/stress/rest-parameter-inlined.js: Added.

(assert):
(bar):
(foo):
(baz):
(jaz):

LayoutTests:

  • js/parser-syntax-check-expected.txt:
  • js/script-tests/parser-syntax-check.js:

(catch):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/parser/Parser.cpp

    r192661 r192671  
    670670
    671671template <typename LexerType>
     672bool Parser<LexerType>::declareRestOrNormalParameter(const Identifier& name, const Identifier** duplicateIdentifier)
     673{
     674    DeclarationResultMask declarationResult = declareParameter(&name);
     675    if ((declarationResult & DeclarationResult::InvalidStrictMode) && strictMode()) {
     676        semanticFailIfTrue(isEvalOrArguments(&name), "Cannot destructure to a parameter name '", name.impl(), "' in strict mode");
     677        if (m_lastFunctionName && name == *m_lastFunctionName)
     678            semanticFail("Cannot declare a parameter named '", name.impl(), "' as it shadows the name of a strict mode function");
     679        semanticFailureDueToKeyword("parameter name");
     680        if (hasDeclaredParameter(name))
     681            semanticFail("Cannot declare a parameter named '", name.impl(), "' in strict mode as it has already been declared");
     682        semanticFail("Cannot declare a parameter named '", name.impl(), "' in strict mode");
     683    }
     684    if (declarationResult & DeclarationResult::InvalidDuplicateDeclaration) {
     685        // It's not always an error to define a duplicate parameter.
     686        // It's only an error when there are default parameter values or destructuring parameters.
     687        // We note this value now so we can check it later.
     688        if (duplicateIdentifier)
     689            *duplicateIdentifier = &name;
     690    }
     691
     692    return true;
     693}
     694
     695template <typename LexerType>
    672696template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::createBindingPattern(TreeBuilder& context, DestructuringKind kind, ExportType exportType, const Identifier& name, JSToken token, AssignmentContext bindingContext, const Identifier** duplicateIdentifier)
    673697{
     
    688712        }
    689713    } else if (kind == DestructureToParameters) {
    690         DeclarationResultMask declarationResult = declareParameter(&name);
    691         if ((declarationResult & DeclarationResult::InvalidStrictMode) && strictMode()) {
    692             semanticFailIfTrue(isEvalOrArguments(&name), "Cannot destructure to a parameter name '", name.impl(), "' in strict mode");
    693             if (m_lastFunctionName && name == *m_lastFunctionName)
    694                 semanticFail("Cannot declare a parameter named '", name.impl(), "' as it shadows the name of a strict mode function");
    695             semanticFailureDueToKeyword("parameter name");
    696             if (hasDeclaredParameter(name))
    697                 semanticFail("Cannot declare a parameter named '", name.impl(), "' in strict mode as it has already been declared");
    698             semanticFail("Cannot declare a parameter named '", name.impl(), "' in strict mode");
    699         }
    700         if (declarationResult & DeclarationResult::InvalidDuplicateDeclaration) {
    701             // It's not always an error to define a duplicate parameter.
    702             // It's only an error when there are default parameter values or destructuring parameters.
    703             // We note this value now so we can check it later.
    704             if (duplicateIdentifier)
    705                 *duplicateIdentifier = &name;
    706         }
     714        declareRestOrNormalParameter(name, duplicateIdentifier);
     715        propagateError();
    707716    }
    708717
     
    15371546template <class TreeBuilder> bool Parser<LexerType>::parseFormalParameters(TreeBuilder& context, TreeFormalParameterList list, unsigned& parameterCount)
    15381547{
    1539 #define failFromDuplicate() \
     1548#define failIfDuplicateIfViolation() \
    15401549    if (duplicateParameter) {\
    15411550        semanticFailIfTrue(defaultValue, "Duplicate parameter '", duplicateParameter->impl(), "' not allowed in function with default parameter values");\
    15421551        semanticFailIfTrue(hasDestructuringPattern, "Duplicate parameter '", duplicateParameter->impl(), "' not allowed in function with destructuring parameters");\
    1543     }
    1544 
     1552        semanticFailIfTrue(isRestParameter, "Duplicate parameter '", duplicateParameter->impl(), "' not allowed in function with a rest parameter");\
     1553    }
     1554
     1555    bool hasDestructuringPattern = false;
     1556    bool isRestParameter = false;
    15451557    const Identifier* duplicateParameter = nullptr;
    1546     bool hasDestructuringPattern = false;
    1547     auto parameter = parseDestructuringPattern(context, DestructureToParameters, ExportType::NotExported, &duplicateParameter, &hasDestructuringPattern);
    1548     failIfFalse(parameter, "Cannot parse parameter pattern");
    1549     auto defaultValue = parseDefaultValueForDestructuringPattern(context);
    1550     propagateError();
    1551     failFromDuplicate();
    1552     context.appendParameter(list, parameter, defaultValue);
    1553     parameterCount++;
    1554     while (consume(COMMA)) {
    1555         parameter = parseDestructuringPattern(context, DestructureToParameters, ExportType::NotExported, &duplicateParameter, &hasDestructuringPattern);
     1558    do {
     1559        TreeDestructuringPattern parameter = 0;
     1560        TreeExpression defaultValue = 0;
     1561
     1562        if (match(DOTDOTDOT)) {
     1563            next();
     1564            failIfFalse(matchSpecIdentifier(), "Rest parameter '...' should be followed by a variable identifier");
     1565            declareRestOrNormalParameter(*m_token.m_data.ident, &duplicateParameter);
     1566            propagateError();
     1567            JSTextPosition identifierStart = tokenStartPosition();
     1568            JSTextPosition identifierEnd = tokenEndPosition();
     1569            parameter = context.createRestParameter(*m_token.m_data.ident, parameterCount, identifierStart, identifierEnd);
     1570            next();
     1571            failIfTrue(match(COMMA), "Rest parameter should be the last parameter in a function declaration"); // Let's have a good error message for this common case.
     1572            isRestParameter = true;
     1573        } else
     1574            parameter = parseDestructuringPattern(context, DestructureToParameters, ExportType::NotExported, &duplicateParameter, &hasDestructuringPattern);
    15561575        failIfFalse(parameter, "Cannot parse parameter pattern");
    1557         defaultValue = parseDefaultValueForDestructuringPattern(context);
     1576        if (!isRestParameter)
     1577            defaultValue = parseDefaultValueForDestructuringPattern(context);
    15581578        propagateError();
    1559         failFromDuplicate();
     1579        failIfDuplicateIfViolation();
    15601580        context.appendParameter(list, parameter, defaultValue);
    1561         parameterCount++;
    1562     }
     1581        if (!isRestParameter)
     1582            parameterCount++;
     1583    } while (!isRestParameter && consume(COMMA));
     1584
    15631585    return true;
    1564 #undef failFromDuplicate
     1586#undef failIfDuplicateIfViolation
    15651587}
    15661588
Note: See TracChangeset for help on using the changeset viewer.