Ignore:
Timestamp:
Sep 26, 2013, 9:52:32 AM (12 years ago)
Author:
[email protected]
Message:

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

Reviewed by Mark Hahnenberg.

Source/JavaScriptCore:

This is mostly simple - the semantics of deconstruction are already
present in the language, so most of the complexity (if you call it
that) is addition of new AST nodes, and parsing the syntax.

In order to get correct semantics for the parameter lists, FunctionParameters
now needs to store refcounted references to the parameter patterns.
There's also a little work to ensure that variable creation and assignment
occurs in the correct order while the BytecodeGenerator is being constructed.

  • bytecode/UnlinkedCodeBlock.cpp:

(JSC::UnlinkedFunctionExecutable::paramString):

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::BytecodeGenerator):

  • bytecompiler/BytecodeGenerator.h:

(JSC::BytecodeGenerator::emitExpressionInfo):

  • bytecompiler/NodesCodegen.cpp:

(JSC::ForInNode::emitBytecode):
(JSC::DeconstructingAssignmentNode::emitBytecode):
(JSC::DeconstructionPatternNode::~DeconstructionPatternNode):
(JSC::ArrayPatternNode::emitBytecode):
(JSC::ArrayPatternNode::emitDirectBinding):
(JSC::ArrayPatternNode::toString):
(JSC::ArrayPatternNode::collectBoundIdentifiers):
(JSC::ObjectPatternNode::toString):
(JSC::ObjectPatternNode::emitBytecode):
(JSC::ObjectPatternNode::collectBoundIdentifiers):
(JSC::BindingNode::emitBytecode):
(JSC::BindingNode::toString):
(JSC::BindingNode::collectBoundIdentifiers):

  • parser/ASTBuilder.h:

(JSC::ASTBuilder::createFormalParameterList):
(JSC::ASTBuilder::createForInLoop):
(JSC::ASTBuilder::addVar):
(JSC::ASTBuilder::createDeconstructingAssignment):
(JSC::ASTBuilder::createArrayPattern):
(JSC::ASTBuilder::appendArrayPatternSkipEntry):
(JSC::ASTBuilder::appendArrayPatternEntry):
(JSC::ASTBuilder::createObjectPattern):
(JSC::ASTBuilder::appendObjectPatternEntry):
(JSC::ASTBuilder::createBindingLocation):

  • parser/NodeConstructors.h:

(JSC::CommaNode::CommaNode):
(JSC::ParameterNode::ParameterNode):
(JSC::ForInNode::ForInNode):
(JSC::DeconstructionPatternNode::DeconstructionPatternNode):
(JSC::ArrayPatternNode::ArrayPatternNode):
(JSC::ArrayPatternNode::create):
(JSC::ObjectPatternNode::ObjectPatternNode):
(JSC::ObjectPatternNode::create):
(JSC::BindingNode::create):
(JSC::BindingNode::BindingNode):
(JSC::DeconstructingAssignmentNode::DeconstructingAssignmentNode):

  • parser/Nodes.cpp:

(JSC::FunctionParameters::create):
(JSC::FunctionParameters::FunctionParameters):
(JSC::FunctionParameters::~FunctionParameters):

  • parser/Nodes.h:

(JSC::ExpressionNode::isDeconstructionNode):
(JSC::ArrayNode::elements):
(JSC::CommaNode::append):
(JSC::ParameterNode::pattern):
(JSC::FunctionParameters::at):
(JSC::FunctionParameters::patterns):
(JSC::DeconstructionPatternNode::isBindingNode):
(JSC::DeconstructionPatternNode::emitDirectBinding):
(JSC::ArrayPatternNode::appendIndex):
(JSC::ObjectPatternNode::appendEntry):
(JSC::ObjectPatternNode::Entry::Entry):
(JSC::BindingNode::boundProperty):
(JSC::BindingNode::isBindingNode):
(JSC::DeconstructingAssignmentNode::bindings):
(JSC::DeconstructingAssignmentNode::isLocation):
(JSC::DeconstructingAssignmentNode::isDeconstructionNode):

  • parser/Parser.cpp:

(JSC::::Parser):
(JSC::::parseVarDeclaration):
(JSC::::parseVarDeclarationList):
(JSC::::createBindingPattern):
(JSC::::parseDeconstructionPattern):
(JSC::::parseForStatement):
(JSC::::parseFormalParameters):
(JSC::::parseAssignmentExpression):

  • parser/Parser.h:

(JSC::Scope::declareBoundParameter):
(JSC::Parser::declareBoundParameter):

  • parser/SyntaxChecker.h:

(JSC::SyntaxChecker::createFormalParameterList):
(JSC::SyntaxChecker::addVar):
(JSC::SyntaxChecker::operatorStackPop):

  • runtime/JSONObject.cpp:

(JSC::escapeStringToBuilder):

  • runtime/JSONObject.h:

LayoutTests:

Add enw tests, and update old ones.

  • js/destructuring-assignment-expected.txt: Added.
  • js/destructuring-assignment.html: Added.
  • js/mozilla/strict/13.1-expected.txt:
  • js/mozilla/strict/regress-532254-expected.txt:
  • js/mozilla/strict/script-tests/13.1.js:
  • js/regress/destructuring-arguments-expected.txt: Added.
  • js/regress/destructuring-arguments-length-expected.txt: Added.
  • js/regress/destructuring-arguments-length.html: Added.
  • js/regress/destructuring-arguments.html: Added.
  • js/regress/destructuring-swap-expected.txt: Added.
  • js/regress/destructuring-swap.html: Added.
  • js/regress/script-tests/destructuring-arguments-length.js: Added.

(foo):

  • js/regress/script-tests/destructuring-arguments.js: Added.

(foo):

  • js/regress/script-tests/destructuring-swap.js: Added.

(foo):

  • js/script-tests/destructuring-assignment.js: Added.

(testDestructuring):
(testDeconstructArgs):
(testDeconstructArgLength):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp

    r156374 r156464  
    3636#include "JSGlobalObject.h"
    3737#include "JSNameScope.h"
     38#include "JSONObject.h"
    3839#include "LabelScope.h"
    3940#include "Lexer.h"
     
    17141715        generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStart(), assignNode->divotEnd());
    17151716        generator.emitPutById(base, ident, propertyName);
    1716     } else {
    1717         ASSERT(m_lexpr->isBracketAccessorNode());
     1717    } else if (m_lexpr->isBracketAccessorNode()) {
    17181718        BracketAccessorNode* assignNode = static_cast<BracketAccessorNode*>(m_lexpr);
    17191719        propertyName = generator.newTemporary();
     
    17241724        generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStart(), assignNode->divotEnd());
    17251725        generator.emitPutByVal(base.get(), subscript, propertyName);
    1726     }   
     1726    } else {
     1727        ASSERT(m_lexpr->isDeconstructionNode());
     1728        DeconstructingAssignmentNode* assignNode = static_cast<DeconstructingAssignmentNode*>(m_lexpr);
     1729        propertyName = generator.newTemporary();
     1730        RefPtr<RegisterID> protect(propertyName);
     1731        assignNode->bindings()->emitBytecode(generator, propertyName);
     1732    }
    17271733
    17281734    generator.emitNode(dst, m_statement);
     
    21802186    return generator.emitNewFunctionExpression(generator.finalDestination(dst), this);
    21812187}
     2188   
     2189// ------------------------------ DeconstructingAssignmentNode -----------------
     2190RegisterID* DeconstructingAssignmentNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
     2191{
     2192    if (RegisterID* result = m_bindings->emitDirectBinding(generator, dst, m_initializer))
     2193        return result;
     2194    RefPtr<RegisterID> initializer = generator.tempDestination(dst);
     2195    generator.emitNode(initializer.get(), m_initializer);
     2196    m_bindings->emitBytecode(generator, initializer.get());
     2197    return generator.moveToDestinationIfNeeded(dst, initializer.get());
     2198}
     2199
     2200DeconstructionPatternNode::~DeconstructionPatternNode()
     2201{
     2202}
     2203   
     2204void ArrayPatternNode::emitBytecode(BytecodeGenerator& generator, RegisterID* rhs) const
     2205{
     2206    for (size_t i = 0; i < m_targetPatterns.size(); i++) {
     2207        auto target = m_targetPatterns[i];
     2208        if (!target)
     2209            continue;
     2210        RefPtr<RegisterID> temp = generator.newTemporary();
     2211        generator.emitLoad(temp.get(), jsNumber(i));
     2212        generator.emitGetByVal(temp.get(), rhs, temp.get());
     2213        target->emitBytecode(generator, temp.get());
     2214    }
     2215}
     2216
     2217RegisterID* ArrayPatternNode::emitDirectBinding(BytecodeGenerator& generator, RegisterID* dst, ExpressionNode* rhs)
     2218{
     2219    if (rhs->isResolveNode()
     2220        && generator.willResolveToArguments(static_cast<ResolveNode*>(rhs)->identifier())
     2221        && !generator.symbolTable().slowArguments()) {
     2222        for (size_t i = 0; i < m_targetPatterns.size(); i++) {
     2223            auto target = m_targetPatterns[i];
     2224            if (!target)
     2225                continue;
     2226           
     2227            RefPtr<RegisterID> temp = generator.newTemporary();
     2228            generator.emitLoad(temp.get(), jsNumber(i));
     2229            generator.emitGetArgumentByVal(generator.finalDestination(dst), generator.uncheckedRegisterForArguments(), temp.get());
     2230            target->emitBytecode(generator, temp.get());
     2231        }
     2232    }
     2233    if (!rhs->isSimpleArray())
     2234        return 0;
     2235    ElementNode* elementNodes = static_cast<ArrayNode*>(rhs)->elements();
     2236    Vector<ExpressionNode*> elements;
     2237    for (; elementNodes; elementNodes = elementNodes->next())
     2238        elements.append(elementNodes->value());
     2239    if (m_targetPatterns.size() != elements.size())
     2240        return 0;
     2241    Vector<RefPtr<RegisterID>> registers;
     2242    registers.reserveCapacity(m_targetPatterns.size());
     2243    for (size_t i = 0; i < m_targetPatterns.size(); i++) {
     2244        registers.uncheckedAppend(generator.newTemporary());
     2245        generator.emitNode(registers.last().get(), elements[i]);
     2246    }
     2247   
     2248    for (size_t i = 0; i < m_targetPatterns.size(); i++) {
     2249        if (m_targetPatterns[i])
     2250            m_targetPatterns[i]->emitBytecode(generator, registers[i].get());
     2251    }
     2252    RefPtr<RegisterID> result = generator.finalDestination(dst);
     2253    return generator.emitLoad(result.get(), jsUndefined());
     2254}
     2255
     2256void ArrayPatternNode::toString(StringBuilder& builder) const
     2257{
     2258    builder.append('[');
     2259    for (size_t i = 0; i < m_targetPatterns.size(); i++) {
     2260        if (!m_targetPatterns[i]) {
     2261            builder.append(',');
     2262            continue;
     2263        }
     2264        m_targetPatterns[i]->toString(builder);
     2265        if (i < m_targetPatterns.size() - 1)
     2266            builder.append(',');
     2267    }
     2268    builder.append(']');
     2269}
     2270
     2271void ArrayPatternNode::collectBoundIdentifiers(Vector<Identifier>& identifiers) const
     2272{
     2273    for (size_t i = 0; i < m_targetPatterns.size(); i++) {
     2274        if (DeconstructionPatternNode* node = m_targetPatterns[i].get())
     2275            node->collectBoundIdentifiers(identifiers);
     2276    }
     2277}
     2278
     2279void ObjectPatternNode::toString(StringBuilder& builder) const
     2280{
     2281    builder.append('{');
     2282    for (size_t i = 0; i < m_targetPatterns.size(); i++) {
     2283        if (m_targetPatterns[i].wasString) {
     2284            builder.append('"');
     2285            escapeStringToBuilder(builder, m_targetPatterns[i].propertyName.string());
     2286            builder.append('"');
     2287        } else
     2288            builder.append(m_targetPatterns[i].propertyName.string());
     2289        builder.append(":");
     2290        m_targetPatterns[i].pattern->toString(builder);
     2291        if (i < m_targetPatterns.size() - 1)
     2292            builder.append(',');
     2293    }
     2294    builder.append('}');
     2295}
     2296   
     2297void ObjectPatternNode::emitBytecode(BytecodeGenerator& generator, RegisterID* rhs) const
     2298{
     2299    for (size_t i = 0; i < m_targetPatterns.size(); i++) {
     2300        auto& target = m_targetPatterns[i];
     2301        RefPtr<RegisterID> temp = generator.newTemporary();
     2302        generator.emitGetById(temp.get(), rhs, target.propertyName);
     2303        target.pattern->emitBytecode(generator, temp.get());
     2304    }
     2305}
     2306
     2307void ObjectPatternNode::collectBoundIdentifiers(Vector<Identifier>& identifiers) const
     2308{
     2309    for (size_t i = 0; i < m_targetPatterns.size(); i++)
     2310        m_targetPatterns[i].pattern->collectBoundIdentifiers(identifiers);
     2311}
     2312
     2313void BindingNode::emitBytecode(BytecodeGenerator& generator, RegisterID* value) const
     2314{
     2315    if (Local local = generator.local(m_boundProperty)) {
     2316        if (local.isReadOnly()) {
     2317            generator.emitReadOnlyExceptionIfNeeded();
     2318            return;
     2319        }
     2320        generator.emitMove(local.get(), value);
     2321        return;
     2322    }
     2323    if (generator.isStrictMode())
     2324        generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
     2325    RegisterID* scope = generator.emitResolveScope(generator.newTemporary(), m_boundProperty);
     2326    generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
     2327    generator.emitPutToScope(scope, m_boundProperty, value, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound);
     2328    return;
     2329}
     2330
     2331void BindingNode::toString(StringBuilder& builder) const
     2332{
     2333    builder.append(m_boundProperty.string());
     2334}
     2335
     2336void BindingNode::collectBoundIdentifiers(Vector<Identifier>& identifiers) const
     2337{
     2338    identifiers.append(m_boundProperty);
     2339}
    21822340
    21832341} // namespace JSC
Note: See TracChangeset for help on using the changeset viewer.