ParseNode *
ParseNode::append(ParseNodeKind kind, JSOp op, ParseNode *left, ParseNode *right,
                  FullParseHandler *handler)
{
    if (!left || !right)
        return nullptr;

    MOZ_ASSERT(left->isKind(kind) && left->isOp(op) && (js_CodeSpec[op].format & JOF_LEFTASSOC));

    ListNode *list;
    if (left->pn_arity == PN_LIST) {
        list = &left->as<ListNode>();
    } else {
        ParseNode *pn1 = left->pn_left, *pn2 = left->pn_right;
        list = handler->new_<ListNode>(kind, op, pn1);
        if (!list)
            return nullptr;
        list->append(pn2);
    }

    list->append(right);
    list->pn_pos.end = right->pn_pos.end;

    return list;
}
Beispiel #2
0
ParseNode*
ParseNode::appendOrCreateList(ParseNodeKind kind, JSOp op, ParseNode* left, ParseNode* right,
                              FullParseHandler* handler, ParseContext<FullParseHandler>* pc)
{
    // The asm.js specification is written in ECMAScript grammar terms that
    // specify *only* a binary tree.  It's a royal pain to implement the asm.js
    // spec to act upon n-ary lists as created below.  So for asm.js, form a
    // binary tree of lists exactly as ECMAScript would by skipping the
    // following optimization.
    if (!pc->useAsmOrInsideUseAsm()) {
        // Left-associative trees of a given operator (e.g. |a + b + c|) are
        // binary trees in the spec: (+ (+ a b) c) in Lisp terms.  Recursively
        // processing such a tree, exactly implemented that way, would blow the
        // the stack.  We use a list node that uses O(1) stack to represent
        // such operations: (+ a b c).
        if (left->isKind(kind) && left->isOp(op) && (js_CodeSpec[op].format & JOF_LEFTASSOC)) {
            ListNode* list = &left->as<ListNode>();

            list->append(right);
            list->pn_pos.end = right->pn_pos.end;

            return list;
        }
    }

    ParseNode* list = handler->new_<ListNode>(kind, op, left);
    if (!list)
        return nullptr;

    list->append(right);
    return list;
}
Beispiel #3
0
ParseNode *
ParseNode::append(ParseNodeKind kind, JSOp op, ParseNode *left, ParseNode *right,
                  FullParseHandler *handler)
{
    if (!left || !right)
        return NULL;

    JS_ASSERT(left->isKind(kind) && left->isOp(op) && (js_CodeSpec[op].format & JOF_LEFTASSOC));

    ListNode *list;
    if (left->pn_arity == PN_LIST) {
        list = &left->as<ListNode>();
    } else {
        ParseNode *pn1 = left->pn_left, *pn2 = left->pn_right;
        list = handler->new_<ListNode>(kind, op, pn1);
        if (!list)
            return NULL;
        list->append(pn2);
        if (kind == PNK_ADD) {
            if (pn1->isKind(PNK_STRING))
                list->pn_xflags |= PNX_STRCAT;
            else if (!pn1->isKind(PNK_NUMBER))
                list->pn_xflags |= PNX_CANTFOLD;
            if (pn2->isKind(PNK_STRING))
                list->pn_xflags |= PNX_STRCAT;
            else if (!pn2->isKind(PNK_NUMBER))
                list->pn_xflags |= PNX_CANTFOLD;
        }
    }

    list->append(right);
    list->pn_pos.end = right->pn_pos.end;
    if (kind == PNK_ADD) {
        if (right->isKind(PNK_STRING))
            list->pn_xflags |= PNX_STRCAT;
        else if (!right->isKind(PNK_NUMBER))
            list->pn_xflags |= PNX_CANTFOLD;
    }

    return list;
}
int BuiltinCallNode::foldOps(VSLDef *cdef, VSLNode** node)
{
    assert (this == *node);
    int changes = 0;

    // Apply on all arguments
    changes += CallNode::foldOps(cdef, node);

    // If non-associative, return
    if (!VSLBuiltin::isAssoc(_index))
	return changes;

    // If arg is not a list, return
    if (!arg()->isListNode())
	return changes;

    ListNode *args = (ListNode *)arg(); // dirty trick

    // First arg must be a builtin call
    if (!args->head()->isBuiltinCallNode())
	return changes;

    BuiltinCallNode *callee = (BuiltinCallNode *)args->head(); // dirty trick

    // First arg must call the same function
    if (_index != callee->_index)
	return changes;

    // Arg must be a list
    if (!callee->arg()->isListNode())
	return changes;

    ListNode *callArgs = (ListNode *)callee->arg(); // dirty trick

    // Insert list
    if (VSEFlags::show_optimize)
    {
	std::cout << "\n" << cdef->longname() << ": foldOps: replacing\n" 
	    << *this << '\n';
	std::cout.flush();
    }

    int err = callArgs->append(args->tail());
    if (err)
    {
	if (VSEFlags::show_optimize)
	{
	    std::cout << "ABORTING (no replace) since append impossible\n";
	    std::cout.flush();
	}
	return changes;
    }

    VSLNode *newArgs = callee->arg();
    callee->arg() = 0; args->tail() = 0; delete args;
    arg() = newArgs;

    if (VSEFlags::show_optimize)
    {
	std::cout << "by " << *this << '\n';
	std::cout.flush();
    }

    changes++;

    return changes;
}