File indexing completed on 2024-05-12 15:43:29

0001 /*
0002  *  This file is part of the KDE libraries
0003  *  Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
0004  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
0005  *  Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
0006  *  Copyright (C) 2007, 2008 Maksim Orlovich (maksim@kde.org)
0007  *
0008  *  This library is free software; you can redistribute it and/or
0009  *  modify it under the terms of the GNU Library General Public
0010  *  License as published by the Free Software Foundation; either
0011  *  version 2 of the License, or (at your option) any later version.
0012  *
0013  *  This library is distributed in the hope that it will be useful,
0014  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0015  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0016  *  Library General Public License for more details.
0017  *
0018  *  You should have received a copy of the GNU Library General Public License
0019  *  along with this library; see the file COPYING.LIB.  If not, write to
0020  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0021  *  Boston, MA 02110-1301, USA.
0022  *
0023  */
0024 #include "nodes2bytecode.h"
0025 #include <wtf/Assertions.h>
0026 
0027 #include <typeinfo>
0028 #include <iostream>
0029 
0030 namespace KJS
0031 {
0032 
0033 // A few helpers..
0034 static void emitError(CompileState *comp, Node *node, ErrorType type, const char *msgStr)
0035 {
0036     OpValue me = OpValue::immNode(node);
0037     OpValue se = OpValue::immInt32(type);
0038     OpValue msg = OpValue::immCStr(msgStr);
0039     CodeGen::emitOp(comp, Op_RaiseError, nullptr, &me, &se, &msg);
0040 }
0041 
0042 static void emitSyntaxError(CompileState *comp, Node *node, const char *msgStr)
0043 {
0044     emitError(comp, node, SyntaxError, msgStr);
0045 }
0046 
0047 static void emitReferenceError(CompileState *comp, Node *node, const char *msgStr)
0048 {
0049     emitError(comp, node, ReferenceError, msgStr);
0050 }
0051 
0052 OpValue Node::generateEvalCode(CompileState *)
0053 {
0054     std::cerr << "WARNING: no generateEvalCode for:" << typeid(*this).name() << "\n";
0055     ASSERT(0);
0056 
0057     return OpValue::immInt32(42);
0058 }
0059 
0060 void StatementNode::generateExecCode(CompileState *)
0061 {
0062     std::cerr << "WARNING: no generateExecCode for:" << typeid(*this).name() << "\n";
0063     ASSERT(0);
0064 }
0065 
0066 void StatementNode::generateDebugInfo(CompileState *comp)
0067 {
0068     OpValue me = OpValue::immNode(this);
0069     CodeGen::emitOp(comp, Op_AtStatement, nullptr, &me);
0070 }
0071 
0072 static inline bool exitContextNeeded(CompileState *comp)
0073 {
0074     return comp->compileType() == Debug &&
0075            comp->codeType()    == FunctionCode;
0076 }
0077 
0078 static void generateExitContextIfNeeded(CompileState *comp)
0079 {
0080     if (exitContextNeeded(comp)) {
0081         OpValue ourNode = OpValue::immNode(comp->functionBody());
0082         CodeGen::emitOp(comp, Op_ExitDebugContext, nullptr, &ourNode);
0083     }
0084 }
0085 
0086 // ------------------------------ Basic literals -----------------------------------------
0087 
0088 OpValue NullNode::generateEvalCode(CompileState *)
0089 {
0090     return OpValue::immValue(jsNull());
0091 }
0092 
0093 OpValue BooleanNode::generateEvalCode(CompileState *)
0094 {
0095     return OpValue::immBool(value());
0096 }
0097 
0098 OpValue NumberNode::generateEvalCode(CompileState *)
0099 {
0100     using namespace std;
0101 #if 0
0102     if (typeHint == OpType_Value) {
0103         // Try to fit into a JSValue if at all possible..
0104         JSValue *im = JSImmediate::from(value());
0105         if (im) {
0106             OpValue res = mkImmediateVal(OpType_value);
0107             return res;
0108         }
0109     }
0110 #endif
0111 
0112     // Numeric-like..
0113     double d = value();
0114     int32_t i32 = JSValue::toInt32(d);
0115     if (double(i32) == d && !(i32 == 0 && signbit(d))) { // be careful with -0.0 here
0116         return OpValue::immInt32(i32);
0117     } else {
0118         return OpValue::immNumber(d);
0119     }
0120 }
0121 
0122 OpValue StringNode::generateEvalCode(CompileState *comp)
0123 {
0124     // For now, just generate a JSValue
0125     // We may want to permit string pointers as well, to help overload resolution,
0126     // but it's not clear whether that's useful, since we can't MM them. Perhaps
0127     // a special StringInstance type may be of use eventually.
0128 
0129     if (interned) { // we're re-compiling.. just reuse it
0130         return OpValue::immValue(interned);
0131     }
0132 
0133     // Intern shorter strings
0134     if (val.size() < 16) {
0135         interned = Interpreter::internString(val);
0136         return OpValue::immValue(interned);
0137     } else {
0138         OpValue inStr = OpValue::immString(&val);
0139 
0140         OpValue out;
0141         CodeGen::emitOp(comp, Op_OwnedString, &out, &inStr);
0142         return out;
0143     }
0144 }
0145 
0146 StringNode::~StringNode()
0147 {
0148     if (interned) {
0149         Interpreter::releaseInternedString(val);
0150     }
0151 }
0152 
0153 OpValue RegExpNode::generateEvalCode(CompileState *comp)
0154 {
0155     // ### TODO: cache the engine object?
0156     OpValue out;
0157     OpValue patternV = OpValue::immString(&pattern);
0158     OpValue flagsV   = OpValue::immString(&flags);
0159     CodeGen::emitOp(comp, Op_NewRegExp, &out, &patternV, &flagsV);
0160     return out;
0161 }
0162 
0163 OpValue ThisNode::generateEvalCode(CompileState *comp)
0164 {
0165     return *comp->thisValue();
0166 }
0167 
0168 // ------------------------------ VarAccessNode ----------------------------------------
0169 
0170 size_t VarAccessNode::classifyVariable(CompileState *comp, Classification &classify)
0171 {
0172     // Are we inside a with or catch? In that case, it's all dynamic. Boo.
0173     // Ditto for eval.
0174     // ### actually that may be improvable if we can
0175     // distinguish eval-from-global and eval-from-local, since
0176     // we'd have an activation or global object available for access.
0177     if (comp->inNestedScope() || comp->codeType() == EvalCode) {
0178         classify = Dynamic;
0179         return missingSymbolMarker();
0180     }
0181 
0182     // If we're inside global scope (and as per above, not inside any nested scope!)
0183     // we can always used the global object
0184     if (comp->codeType() == GlobalCode) {
0185         classify = Global;
0186         return missingSymbolMarker();
0187     }
0188 
0189     // We're inside a function...
0190     if (ident == CommonIdentifiers::shared()->arguments) {
0191         // arguments is too much of a pain to handle in general path..
0192         classify = Dynamic;
0193         return missingSymbolMarker();
0194     }
0195 
0196     // Do we know this?
0197     size_t index = comp->functionBody()->lookupSymbolID(ident);
0198     if (index == missingSymbolMarker()) {
0199         classify = NonLocal;
0200     } else {
0201         classify = Local;
0202     }
0203 
0204     return index;
0205 }
0206 
0207 OpValue VarAccessNode::generateEvalCode(CompileState *comp)
0208 {
0209     Classification classify;
0210     size_t index = classifyVariable(comp, classify);
0211 
0212     OpValue out;
0213     OpValue varName = OpValue::immIdent(&ident);
0214     switch (classify) {
0215     case Local: {
0216         // Register read.
0217         out = comp->localReadVal(index);
0218         break;
0219     }
0220     case NonLocal:
0221         CodeGen::emitOp(comp, Op_NonLocalVarGet, &out, &varName);
0222         break;
0223     case Global:
0224         CodeGen::emitOp(comp, Op_GlobalObjectGet, &out, &varName);
0225         break;
0226     case Dynamic:
0227         CodeGen::emitOp(comp, Op_VarGet, &out, &varName);
0228         break;
0229     }
0230 
0231     return out;
0232 }
0233 
0234 OpValue VarAccessNode::valueForTypeOf(CompileState *comp)
0235 {
0236     // ### some code dupe here.
0237     Classification classify;
0238     size_t index = classifyVariable(comp, classify);
0239 
0240     OpValue scopeTemp;
0241     OpValue out, outReg;
0242     OpValue varName = OpValue::immIdent(&ident);
0243     switch (classify) {
0244     case Local:
0245         // Register read. Easy.
0246         out = comp->localReadVal(index);
0247         break;
0248     case Global:
0249         CodeGen::emitOp(comp, Op_SymGetKnownObject, &out, comp->globalScope(), &varName);
0250         break;
0251     case NonLocal:
0252         comp->requestTemporary(OpType_value, &out, &outReg);
0253         CodeGen::emitOp(comp, Op_NonLocalScopeLookupAndGet, &scopeTemp, &outReg, &varName);
0254         break;
0255     case Dynamic:
0256         comp->requestTemporary(OpType_value, &out, &outReg);
0257         CodeGen::emitOp(comp, Op_ScopeLookupAndGet, &scopeTemp, &outReg, &varName);
0258         break;
0259     }
0260 
0261     return out;
0262 }
0263 
0264 CompileReference *VarAccessNode::generateRefBind(CompileState *comp)
0265 {
0266     Classification classify;
0267     classifyVariable(comp, classify);
0268 
0269     if (classify == Local || classify == Global) {
0270         return nullptr;    // nothing to do, we know where it is
0271     }
0272 
0273     // Otherwise, we need to find the scope for writing
0274     CompileReference *ref = new CompileReference;
0275 
0276     OpValue quiet = OpValue::immNode(nullptr);
0277     OpValue varName = OpValue::immIdent(&ident);
0278     CodeGen::emitOp(comp, classify == Dynamic ? Op_ScopeLookup : Op_NonLocalScopeLookup,
0279                     &ref->baseObj, &varName, &quiet);
0280     return ref;
0281 }
0282 
0283 CompileReference *VarAccessNode::generateRefRead(CompileState *comp, OpValue *out)
0284 {
0285     Classification classify;
0286     classifyVariable(comp, classify);
0287 
0288     // We want to bind and read, also issuing an error.
0289 
0290     // If we don't need any binding, just use normal read code..
0291     if (classify == Local || classify == Global) {
0292         *out = generateEvalCode(comp);
0293         return nullptr;
0294     }
0295 
0296     // For others, use the lookup-and-fetch ops
0297     CompileReference *ref = new CompileReference;
0298 
0299     OpValue readReg;
0300     OpValue varName = OpValue::immIdent(&ident);
0301     comp->requestTemporary(OpType_value, out, &readReg);
0302 
0303     OpName op;
0304     if (classify == Dynamic) {
0305         op = Op_ScopeLookupAndGetChecked;
0306     } else {
0307         op = Op_NonLocalScopeLookupAndGetChecked;
0308     }
0309     CodeGen::emitOp(comp, op, &ref->baseObj, &readReg, &varName);
0310 
0311     return ref;
0312 }
0313 
0314 void VarAccessNode::generateRefWrite(CompileState *comp,
0315                                      CompileReference *ref, OpValue &valToStore)
0316 {
0317     Classification classify;
0318     size_t index = classifyVariable(comp, classify);
0319 
0320     if (classify == Local) {
0321         // Straight register put..
0322         OpValue destReg = comp->localWriteRef(comp->codeBlock(), index);
0323         CodeGen::emitOp(comp, Op_RegPutValue, nullptr, &destReg, &valToStore);
0324     } else {
0325         // Symbolic write to the appropriate scope..
0326         OpValue varName = OpValue::immIdent(&ident);
0327         CodeGen::emitOp(comp, Op_SymPutKnownObject, nullptr,
0328                         (classify == Global ? comp->globalScope() : &ref->baseObj), &varName, &valToStore);
0329     }
0330 }
0331 
0332 OpValue VarAccessNode::generateRefDelete(CompileState *comp)
0333 {
0334     Classification classify;
0335     classifyVariable(comp, classify);
0336 
0337     if (classify == Local) {
0338         // Normal locals are DontDelete, so this always fails.
0339         return OpValue::immBool(false);
0340     }
0341 
0342     // Otherwise, fetch the appropriate scope
0343     OpValue base;
0344     if (classify == Global) {
0345         base = *comp->globalScope();
0346     } else {
0347         OpValue varName = OpValue::immIdent(&ident);
0348         OpValue silent  = OpValue::immNode(nullptr);
0349         CodeGen::emitOp(comp, classify == Dynamic ? Op_ScopeLookup : Op_NonLocalScopeLookup,
0350                         &base, &varName, &silent);
0351     }
0352 
0353     // Remove the property..
0354     OpValue out;
0355     OpValue varName = OpValue::immIdent(&ident);
0356     CodeGen::emitOp(comp, Op_SymDeleteKnownObject, &out, &base, &varName);
0357     return out;
0358 }
0359 
0360 void VarAccessNode::generateRefFunc(CompileState *comp, OpValue *funOut, OpValue *thisOut)
0361 {
0362     Classification classify;
0363     classifyVariable(comp, classify);
0364 
0365     OpValue varName = OpValue::immIdent(&ident);
0366 
0367     OpValue thisReg;
0368     switch (classify) {
0369     case Local:
0370     case Global:
0371         // Both of these use global object for this, and use straightforward lookup for value
0372         *funOut  = generateEvalCode(comp);
0373         *thisOut = *comp->globalScope();
0374         break;
0375     case NonLocal:
0376         comp->requestTemporary(OpType_value, thisOut, &thisReg);
0377         CodeGen::emitOp(comp, Op_NonLocalFunctionLookupAndGet, funOut, &thisReg, &varName);
0378         break;
0379     case Dynamic:
0380         comp->requestTemporary(OpType_value, thisOut, &thisReg);
0381         CodeGen::emitOp(comp, Op_FunctionLookupAndGet, funOut, &thisReg, &varName);
0382         break;
0383     }
0384 }
0385 
0386 // ------------------------------ GroupNode----------------------------------------
0387 
0388 OpValue GroupNode::generateEvalCode(CompileState *comp)
0389 {
0390     return group->generateEvalCode(comp);
0391 }
0392 
0393 // ------------------------------ Object + Array literals --------------------------
0394 
0395 OpValue ArrayNode::generateEvalCode(CompileState *comp)
0396 {
0397     OpValue arr;
0398     CodeGen::emitOp(comp, Op_NewEmptyArray, &arr);
0399 
0400     OpValue und = OpValue::immValue(jsUndefined());
0401 
0402     int pos = 0;
0403     for (ElementNode *el = element.get(); el; el = el->next.get()) {
0404         if (!el->node) {
0405             // Fill elision w/undefined, unless we can just skip over to a value
0406             for (int i = 0; i < el->elision; i++) {
0407                 OpValue ind = OpValue::immInt32(pos);
0408                 CodeGen::emitOp(comp, Op_BracketPutKnownObject, nullptr, &arr, &ind, &und);
0409                 ++pos;
0410             }
0411         } else {
0412             pos += el->elision;
0413         }
0414 
0415         if (el->node) {
0416             OpValue val = el->node->generateEvalCode(comp);
0417             OpValue ind = OpValue::immInt32(pos);
0418             CodeGen::emitOp(comp, Op_BracketPutKnownObject, nullptr, &arr, &ind, &val);
0419             ++pos;
0420         }
0421     }
0422 
0423     for (int i = 0; i < elision; i++) {
0424         OpValue ind = OpValue::immInt32(pos);
0425         CodeGen::emitOp(comp, Op_BracketPutKnownObject, nullptr, &arr, &ind, &und);
0426         ++pos;
0427     }
0428 
0429     return arr;
0430 }
0431 
0432 OpValue ObjectLiteralNode::generateEvalCode(CompileState *comp)
0433 {
0434     OpValue obj;
0435     CodeGen::emitOp(comp, Op_NewObject, &obj);
0436 
0437     for (PropertyListNode *entry = list.get(); entry; entry = entry->next.get()) {
0438         PropertyNode *prop = entry->node.get();
0439         OpValue name = OpValue::immIdent(&prop->name->str);
0440         OpValue val  = prop->assign->generateEvalCode(comp);
0441 
0442         switch (prop->type) {
0443         case PropertyNode::Getter:
0444             CodeGen::emitOp(comp, Op_DefineGetter, nullptr, &obj, &name, &val);
0445             break;
0446         case PropertyNode::Setter:
0447             CodeGen::emitOp(comp, Op_DefineSetter, nullptr, &obj, &name, &val);
0448             break;
0449         case PropertyNode::Constant:
0450             CodeGen::emitOp(comp, Op_SymPutKnownObject, nullptr, &obj, &name, &val);
0451             break;
0452         }
0453     }
0454 
0455     return obj;
0456 }
0457 
0458 // ------------------------------ BracketAccessorNode --------------------------------
0459 OpValue BracketAccessorNode::generateEvalCode(CompileState *comp)
0460 {
0461     OpValue ret;
0462     OpValue base  = expr1->generateEvalCode(comp);
0463     OpValue index = expr2->generateEvalCode(comp);
0464 
0465     // ### optimize foo["bar"] ?
0466     CodeGen::emitOp(comp, Op_BracketGet, &ret, &base, &index);
0467     return ret;
0468 }
0469 
0470 CompileReference *BracketAccessorNode::generateRefBind(CompileState *comp)
0471 {
0472     // Per 11.2.1, the following steps must happen when evaluating foo[bar]
0473     // 1) eval foo
0474     // 2) eval bar
0475     // 3) call toObject on [[foo]]
0476     // 4) call toString on [[bar]]
0477     // ... all of which are part of reference evaluation. Fun.
0478     // ### FIXME FIXME FIXME: we don't do step 4 in right spot yet!
0479     CompileReference *ref = new CompileReference;
0480     OpValue baseV = expr1->generateEvalCode(comp);
0481     ref->indexVal = expr2->generateEvalCode(comp);
0482     CodeGen::emitOp(comp, Op_ToObject, &ref->baseObj, &baseV);
0483     return ref;
0484 }
0485 
0486 CompileReference *BracketAccessorNode::generateRefRead(CompileState *comp, OpValue *out)
0487 {
0488     CompileReference *ref = new CompileReference;
0489 
0490     // ### As above, this sequence should store the toString on reference, if there will be a follow up
0491     // write --- need a hint for that..
0492     OpValue baseV = expr1->generateEvalCode(comp);
0493     ref->indexVal = expr2->generateEvalCode(comp);
0494 
0495     // Store the object for future use.
0496     OpValue baseReg;
0497     comp->requestTemporary(OpType_value, &ref->baseObj, &baseReg);
0498 
0499     CodeGen::emitOp(comp, Op_BracketGetAndBind, out, &baseReg, &baseV, &ref->indexVal);
0500     return ref;
0501 }
0502 
0503 void BracketAccessorNode::generateRefWrite(CompileState *comp,
0504         CompileReference *ref, OpValue &valToStore)
0505 {
0506     CodeGen::emitOp(comp, Op_BracketPutKnownObject, nullptr, &ref->baseObj, &ref->indexVal, &valToStore);
0507 }
0508 
0509 OpValue BracketAccessorNode::generateRefDelete(CompileState *comp)
0510 {
0511     OpValue base  = expr1->generateEvalCode(comp);
0512     OpValue index = expr2->generateEvalCode(comp);
0513 
0514     OpValue out;
0515     CodeGen::emitOp(comp, Op_BracketDelete, &out, &base, &index);
0516     return out;
0517 }
0518 
0519 void BracketAccessorNode::generateRefFunc(CompileState *comp, OpValue *funOut, OpValue *thisOut)
0520 {
0521     OpValue baseV  = expr1->generateEvalCode(comp);
0522     OpValue indexV = expr2->generateEvalCode(comp);
0523 
0524     // We need to memorize the toObject for 'this'
0525     OpValue baseReg;
0526     comp->requestTemporary(OpType_value, thisOut, &baseReg);
0527 
0528     CodeGen::emitOp(comp, Op_BracketGetAndBind, funOut, &baseReg, &baseV, &indexV);
0529 }
0530 
0531 // ------------------------------ DotAccessorNode --------------------------------
0532 
0533 // ECMA 11.2.1b
0534 OpValue DotAccessorNode::generateEvalCode(CompileState *comp)
0535 {
0536     OpValue ret;
0537     OpValue base    = expr->generateEvalCode(comp);
0538     OpValue varName = OpValue::immIdent(&ident);
0539     CodeGen::emitOp(comp, Op_SymGet, &ret, &base, &varName);
0540     return ret;
0541 }
0542 
0543 CompileReference *DotAccessorNode::generateRefBind(CompileState *comp)
0544 {
0545     CompileReference *ref = new CompileReference;
0546     OpValue baseV = expr->generateEvalCode(comp);
0547     CodeGen::emitOp(comp, Op_ToObject, &ref->baseObj, &baseV);
0548     return ref;
0549 }
0550 
0551 CompileReference *DotAccessorNode::generateRefRead(CompileState *comp, OpValue *out)
0552 {
0553     CompileReference *ref = new CompileReference;
0554     OpValue baseV = expr->generateEvalCode(comp);
0555     OpValue baseReg;
0556     OpValue varName = OpValue::immIdent(&ident);
0557     comp->requestTemporary(OpType_value, &ref->baseObj, &baseReg);
0558     CodeGen::emitOp(comp, Op_SymGetAndBind, out, &baseReg, &baseV, &varName);
0559     return ref;
0560 }
0561 
0562 void DotAccessorNode::generateRefWrite(CompileState *comp,
0563                                        CompileReference *ref, OpValue &valToStore)
0564 {
0565     OpValue varName = OpValue::immIdent(&ident);
0566     CodeGen::emitOp(comp, Op_SymPutKnownObject, nullptr, &ref->baseObj, &varName, &valToStore);
0567 }
0568 
0569 OpValue DotAccessorNode::generateRefDelete(CompileState *comp)
0570 {
0571     OpValue base = expr->generateEvalCode(comp);
0572     OpValue varName = OpValue::immIdent(&ident);
0573     OpValue out;
0574     CodeGen::emitOp(comp, Op_SymDelete, &out, &base, &varName);
0575     return out;
0576 }
0577 
0578 void DotAccessorNode::generateRefFunc(CompileState *comp, OpValue *funOut, OpValue *thisOut)
0579 {
0580     OpValue baseV = expr->generateEvalCode(comp);
0581     OpValue varName = OpValue::immIdent(&ident);
0582 
0583     OpValue baseReg;
0584     comp->requestTemporary(OpType_value, thisOut, &baseReg);
0585     CodeGen::emitOp(comp, Op_SymGetAndBind, funOut, &baseReg, &baseV, &varName);
0586 }
0587 
0588 // ------------------ ........
0589 
0590 void ArgumentsNode::generateEvalArguments(CompileState *comp)
0591 {
0592     WTF::Vector<OpValue> args;
0593 
0594     // We need evaluate arguments and push them in separate steps as there may be
0595     // function/ctor calls inside.
0596     for (ArgumentListNode *arg = list.get(); arg; arg = arg->next.get()) {
0597         args.append(arg->expr->generateEvalCode(comp));
0598     }
0599 
0600     CodeGen::emitOp(comp, Op_ClearArgs, nullptr);
0601 
0602     size_t c = 0;
0603     while (c < args.size()) {
0604         if (c + 3 <= args.size()) {
0605             CodeGen::emitOp(comp, Op_Add3Arg, nullptr, &args[c], &args[c + 1], &args[c + 2]);
0606             c += 3;
0607         } else if (c + 2 <= args.size()) {
0608             CodeGen::emitOp(comp, Op_Add2Arg, nullptr, &args[c], &args[c + 1]);
0609             c += 2;
0610         } else {
0611             CodeGen::emitOp(comp, Op_AddArg, nullptr, &args[c]);
0612             c += 1;
0613         }
0614     }
0615 }
0616 
0617 OpValue NewExprNode::generateEvalCode(CompileState *comp)
0618 {
0619     OpValue v = expr->generateEvalCode(comp);
0620 
0621     if (args) {
0622         args->generateEvalArguments(comp);
0623     } else {
0624         CodeGen::emitOp(comp, Op_ClearArgs, nullptr);
0625     }
0626 
0627     OpValue out;
0628     CodeGen::emitOp(comp, Op_CtorCall, &out, &v);
0629     return out;
0630 }
0631 
0632 OpValue FunctionCallValueNode::generateEvalCode(CompileState *comp)
0633 {
0634     OpValue v = expr->generateEvalCode(comp);
0635     args->generateEvalArguments(comp);
0636 
0637     OpValue out;
0638     CodeGen::emitOp(comp, Op_FunctionCall, &out, &v, comp->globalScope());
0639     return out;
0640 }
0641 
0642 OpValue FunctionCallReferenceNode::generateEvalCode(CompileState *comp)
0643 {
0644     Node *cand = expr->nodeInsideAllParens();
0645     ASSERT(cand->isLocation());
0646     LocationNode *loc = static_cast<LocationNode *>(cand);
0647 
0648     OpValue funVal, thisVal;
0649     loc->generateRefFunc(comp, &funVal, &thisVal);
0650     args->generateEvalArguments(comp);
0651 
0652     OpValue out;
0653     CodeGen::emitOp(comp, Op_FunctionCall, &out, &funVal, &thisVal);
0654     return out;
0655 }
0656 
0657 OpValue PostfixNode::generateEvalCode(CompileState *comp)
0658 {
0659     Node *cand = m_loc->nodeInsideAllParens();
0660     if (!cand->isLocation()) {
0661         emitReferenceError(comp, this,
0662                            m_oper == OpPlusPlus ?
0663                            "Postfix ++ operator applied to value that is not a reference." :
0664                            "Postfix -- operator applied to value that is not a reference.");
0665         return OpValue::immValue(jsUndefined());
0666     }
0667 
0668     LocationNode *loc = static_cast<LocationNode *>(cand);
0669 
0670     // ### we want to fold this in if the kid is a local -- any elegant way?
0671 
0672     //read current value
0673     OpValue curV;
0674     CompileReference *ref = loc->generateRefRead(comp, &curV);
0675 
0676     // We need it to be a number..
0677     if (curV.type != OpType_number) {
0678         OpValue numVal;
0679         CodeGen::emitConvertTo(comp, &curV, OpType_number, &numVal);
0680         curV = numVal;
0681     }
0682 
0683     // Compute new one
0684     OpValue newV;
0685     CodeGen::emitOp(comp, (m_oper == OpPlusPlus) ? Op_Add1 : Op_Sub1,
0686                     &newV, &curV);
0687 
0688     loc->generateRefWrite(comp, ref, newV);
0689     delete ref;
0690     return curV;
0691 }
0692 
0693 OpValue DeleteReferenceNode::generateEvalCode(CompileState *comp)
0694 {
0695     return loc->generateRefDelete(comp);
0696 }
0697 
0698 OpValue DeleteValueNode::generateEvalCode(CompileState *)
0699 {
0700     return OpValue::immBool(true);
0701 }
0702 
0703 OpValue VoidNode::generateEvalCode(CompileState *comp)
0704 {
0705     (void)expr->generateEvalCode(comp);
0706     return OpValue::immValue(jsUndefined());
0707 }
0708 
0709 OpValue TypeOfVarNode::generateEvalCode(CompileState *comp)
0710 {
0711     OpValue v = loc->valueForTypeOf(comp);
0712 
0713     OpValue out;
0714     CodeGen::emitOp(comp, Op_TypeOf, &out, &v);
0715     return out;
0716 }
0717 
0718 OpValue TypeOfValueNode::generateEvalCode(CompileState *comp)
0719 {
0720     OpValue v = m_expr->generateEvalCode(comp);
0721     OpValue typeOfV;
0722     CodeGen::emitOp(comp, Op_TypeOf, &typeOfV, &v);
0723     return typeOfV;
0724 }
0725 
0726 OpValue PrefixNode::generateEvalCode(CompileState *comp)
0727 {
0728     Node *cand = m_loc->nodeInsideAllParens();
0729     if (!cand->isLocation()) {
0730         emitReferenceError(comp, this,
0731                            m_oper == OpPlusPlus ?
0732                            "Prefix ++ operator applied to value that is not a reference." :
0733                            "Prefix -- operator applied to value that is not a reference.");
0734         return OpValue::immValue(jsUndefined());
0735     }
0736 
0737     LocationNode *loc = static_cast<LocationNode *>(cand);
0738 
0739     // ### we want to fold this in if the kid is a local -- any elegant way?
0740 
0741     //read current value
0742     OpValue curV;
0743     CompileReference *ref = loc->generateRefRead(comp, &curV);
0744 
0745     OpValue newV;
0746     CodeGen::emitOp(comp, (m_oper == OpPlusPlus) ? Op_Add1 : Op_Sub1,
0747                     &newV, &curV);
0748 
0749     // Write out + return new value.
0750     loc->generateRefWrite(comp, ref, newV);
0751     delete ref;
0752     return newV;
0753 }
0754 
0755 OpValue UnaryPlusNode::generateEvalCode(CompileState *comp)
0756 {
0757     // This is basically just a number cast
0758     OpValue curV = expr->generateEvalCode(comp);
0759 
0760     if (curV.type != OpType_number) {
0761         OpValue numVal;
0762         CodeGen::emitConvertTo(comp, &curV, OpType_number, &numVal);
0763         curV = numVal;
0764     }
0765 
0766     return curV;
0767 }
0768 
0769 OpValue NegateNode::generateEvalCode(CompileState *comp)
0770 {
0771     OpValue v = expr->generateEvalCode(comp);
0772     OpValue negV;
0773     CodeGen::emitOp(comp, Op_Neg, &negV, &v);
0774     return negV;
0775 }
0776 
0777 OpValue BitwiseNotNode::generateEvalCode(CompileState *comp)
0778 {
0779     OpValue v = expr->generateEvalCode(comp);
0780     OpValue out;
0781     CodeGen::emitOp(comp, Op_BitNot, &out, &v);
0782     return out;
0783 }
0784 
0785 OpValue LogicalNotNode::generateEvalCode(CompileState *comp)
0786 {
0787     OpValue v = expr->generateEvalCode(comp);
0788     OpValue out;
0789     CodeGen::emitOp(comp, Op_LogicalNot, &out, &v);
0790     return out;
0791 }
0792 
0793 OpValue BinaryOperatorNode::generateEvalCode(CompileState *comp)
0794 {
0795     OpValue v1 = expr1->generateEvalCode(comp);
0796     OpValue v2 = expr2->generateEvalCode(comp);
0797 
0798     OpName codeOp; // ### could perhaps skip conversion entirely,
0799     // and set these in the parser?
0800     switch (oper) {
0801     case OpMult:
0802         // operator *
0803         codeOp = Op_Mult;
0804         break;
0805     case OpDiv:
0806         // operator /
0807         codeOp = Op_Div;
0808         break;
0809     case OpMod:
0810         // operator %
0811         codeOp = Op_Mod;
0812         break;
0813     case OpExp:
0814         // operator **
0815         codeOp = Op_Exp;
0816         break;
0817     case OpPlus:
0818         // operator +
0819         codeOp = Op_Add;
0820         break;
0821     case OpMinus:
0822         // operator -
0823         codeOp = Op_Sub;
0824         break;
0825     case OpLShift:
0826         // operator <<
0827         codeOp = Op_LShift;
0828         break;
0829     case OpRShift:
0830         // operator >>
0831         codeOp = Op_RShift;
0832         break;
0833     case OpURShift:
0834         // operator >>>
0835         codeOp = Op_URShift;
0836         break;
0837     case OpLess:
0838         // operator <
0839         codeOp = Op_Less;
0840         break;
0841     case OpGreaterEq:
0842         // operator >=
0843         codeOp = Op_GreaterEq;
0844         break;
0845     case OpGreater:
0846         // operator >
0847         codeOp = Op_Greater;
0848         break;
0849     case OpLessEq:
0850         // operator <=
0851         codeOp = Op_LessEq;
0852         break;
0853     case OpEqEq:
0854         // operator ==
0855         codeOp = Op_EqEq;
0856         break;
0857     case OpNotEq:
0858         // operator !=
0859         codeOp = Op_NotEq;
0860         break;
0861     case OpStrEq:
0862         // operator ===
0863         codeOp = Op_StrEq;
0864         break;
0865     case OpStrNEq:
0866         // operator !==
0867         codeOp = Op_StrNEq;
0868         break;
0869     case OpBitAnd:
0870         // operator &
0871         codeOp = Op_BitAnd;
0872         break;
0873     case OpBitXOr:
0874         // operator ^
0875         codeOp = Op_BitXOr;
0876         break;
0877     case OpBitOr:
0878         // operator |
0879         codeOp = Op_BitOr;
0880         break;
0881     case OpIn:
0882         codeOp = Op_In;
0883         break;
0884     case OpInstanceOf:
0885         codeOp = Op_InstanceOf;
0886         break;
0887 
0888     default:
0889         codeOp = Op_InstanceOf; // Initialize it to something just to silence -Wsometimes-uninitialized
0890         assert(!"BinaryOperatorNode: unhandled switch case");
0891     }
0892 
0893     OpValue out;
0894     CodeGen::emitOp(comp, codeOp, &out, &v1, &v2);
0895     return out;
0896 }
0897 
0898 OpValue BinaryLogicalNode::generateEvalCode(CompileState *comp)
0899 {
0900     // This is somewhat ugly since we can't patchup labels in already generated
0901     // code, and don't know the types in advance. It could also benefit from
0902     // a type hint, since it's easier if we only want a bool, which is quite common
0903 
0904     OpValue a = expr1->generateEvalCode(comp);
0905 
0906     // Make a register for storing the result, and put 'a' there, as out first guess.
0907     OpValue aVal, aReg;
0908     comp->requestTemporary(a.type, &aVal, &aReg);
0909     CodeGen::emitRegStore(comp, &aReg, &a);
0910 
0911     // Is this enough to shortcircuit?
0912     // if op is && and a is false, we jump out, ditto
0913     // for || and true.
0914     Addr jumpToShortCircuit = CodeGen::emitOp(comp, oper == OpAnd ? Op_IfNotJump : Op_IfJump,
0915                               nullptr, &a, OpValue::dummyAddr());
0916 
0917     // Now, generate the code for b...
0918     OpValue b = expr2->generateEvalCode(comp);
0919 
0920     // Hopefully, either the types match, or the result slot is already a value,
0921     // so we can just promote b (which will happen automatically to produce param for Op_RegPutVal)
0922     if (a.type == b.type || a.type == OpType_value) {
0923         if (a.type == OpType_value) {
0924             CodeGen::emitOp(comp, Op_RegPutValue, nullptr, &aReg, &b);
0925         } else {
0926             CodeGen::emitRegStore(comp, &aReg, &b);
0927         }
0928         CodeGen::patchJumpToNext(comp, jumpToShortCircuit, 1);
0929         return aVal;
0930     } else {
0931         // We need to promote 'a' as well, which means we need to skip over the code jumpToShortCircuit
0932         // went to after handling store of 'b'.
0933 
0934         // Get a new register for the result, put b there..
0935         OpValue resVal, resReg;
0936         comp->requestTemporary(OpType_value, &resVal, &resReg);
0937         CodeGen::emitOp(comp, Op_RegPutValue, nullptr, &resReg, &b);
0938 
0939         // skip to after a promotion..
0940         Addr jumpToAfter = CodeGen::emitOp(comp, Op_Jump, nullptr, OpValue::dummyAddr());
0941 
0942         // a's promotion goes here..
0943         CodeGen::patchJumpToNext(comp, jumpToShortCircuit, 1);
0944         CodeGen::emitOp(comp, Op_RegPutValue, nullptr, &resReg, &a);
0945 
0946         // now we're after it..
0947         CodeGen::patchJumpToNext(comp, jumpToAfter, 0);
0948 
0949         return resVal;
0950     }
0951 }
0952 
0953 OpValue ConditionalNode::generateEvalCode(CompileState *comp)
0954 {
0955     // As above, we have some difficulty here, since we do not have a way of knowing
0956     // the types in advance, but since we can't reasonably speculate on them both being bool,
0957     // we just always produce a value.
0958     OpValue resVal, resReg;
0959 
0960     // Evaluate conditional, and jump..
0961     OpValue v = logical->generateEvalCode(comp);
0962     Addr jumpToElse = CodeGen::emitOp(comp, Op_IfNotJump, nullptr, &v, OpValue::dummyAddr());
0963 
0964     // True branch
0965     OpValue v1out = expr1->generateEvalCode(comp);
0966 
0967     // Request a temporary for the result. (We can't reuse any, since it may be a variable!)
0968     // ### perhaps do an isTemporary check here?
0969     comp->requestTemporary(OpType_value, &resVal, &resReg);
0970     CodeGen::emitOp(comp, Op_RegPutValue, nullptr, &resReg, &v1out);
0971 
0972     Addr jumpToAfter = CodeGen::emitOp(comp, Op_Jump, nullptr, OpValue::dummyAddr());
0973 
0974     // Jump to else goes here.
0975     CodeGen::patchJumpToNext(comp, jumpToElse, 1);
0976 
0977     // : part..
0978     OpValue v2out = expr2->generateEvalCode(comp);
0979     CodeGen::emitOp(comp, Op_RegPutValue, nullptr, &resReg, &v2out);
0980 
0981     // After everything
0982     CodeGen::patchJumpToNext(comp, jumpToAfter, 0);
0983 
0984     return resVal;
0985 }
0986 
0987 OpValue FuncExprNode::generateEvalCode(CompileState *comp)
0988 {
0989     comp->setNeedsClosures();
0990 
0991     OpValue out;
0992     OpValue nameV = OpValue::immIdent(&ident);
0993     OpValue bodyV = OpValue::immNode(body.get());
0994     CodeGen::emitOp(comp, Op_EvalFuncExpr, &out, &nameV, &bodyV);
0995     return out;
0996 }
0997 
0998 void FuncDeclNode::generateExecCode(CompileState *comp)
0999 {
1000     comp->setNeedsClosures();
1001 
1002     // No executable content...
1003 }
1004 
1005 void SourceElementsNode::generateExecCode(CompileState *comp)
1006 {
1007     node->generateExecCode(comp);
1008 
1009     // ### FIXME: how do we do proper completion?
1010     for (SourceElementsNode *n = next.get(); n; n = n->next.get()) {
1011         n->node->generateExecCode(comp);
1012     }
1013 }
1014 
1015 OpValue AssignNode::generateEvalCode(CompileState *comp)
1016 {
1017     Node *cand = m_loc->nodeInsideAllParens();
1018     if (!cand->isLocation()) {
1019         emitReferenceError(comp, this, "Left side of assignment is not a reference.");
1020         return OpValue::immValue(jsUndefined());
1021     }
1022 
1023     LocationNode *loc = static_cast<LocationNode *>(cand);
1024 
1025     CompileReference *ref;
1026 
1027     OpValue v;
1028     if (m_oper == OpEqual) {
1029         ref = loc->generateRefBind(comp);
1030         v = m_right->generateEvalCode(comp);
1031     } else {
1032         OpValue v1;
1033         ref = loc->generateRefRead(comp, &v1);
1034         OpValue v2 = m_right->generateEvalCode(comp);
1035 
1036         OpName codeOp;
1037         switch (m_oper) {
1038         case OpMultEq:
1039             codeOp = Op_Mult;
1040             break;
1041         case OpDivEq:
1042             codeOp = Op_Div;
1043             break;
1044         case OpModEq:
1045             codeOp = Op_Mod;
1046             break;
1047         case OpExpEq:
1048             codeOp = Op_Exp;
1049             break;
1050         case OpPlusEq:
1051             codeOp = Op_Add;
1052             break;
1053         case OpMinusEq:
1054             codeOp = Op_Sub;
1055             break;
1056         case OpLShift:
1057             codeOp = Op_LShift;
1058             break;
1059         case OpRShift:
1060             codeOp = Op_RShift;
1061             break;
1062         case OpURShift:
1063             codeOp = Op_URShift;
1064             break;
1065         case OpAndEq:
1066             codeOp = Op_BitAnd;
1067             break;
1068         case OpXOrEq:
1069             codeOp = Op_BitXOr;
1070             break;
1071         case OpOrEq:
1072             codeOp = Op_BitOr;
1073             break;
1074         default:
1075             codeOp = Op_BitOr; // Initialize it to something just to silence -Wsometimes-uninitialized
1076             ASSERT(0);
1077         }
1078 
1079         CodeGen::emitOp(comp, codeOp, &v, &v1, &v2);
1080     }
1081 
1082     loc->generateRefWrite(comp, ref, v);
1083 
1084     delete ref;
1085     return v;
1086 }
1087 
1088 OpValue CommaNode::generateEvalCode(CompileState *comp)
1089 {
1090     expr1->generateEvalCode(comp);
1091     return expr2->generateEvalCode(comp);
1092 }
1093 
1094 OpValue AssignExprNode::generateEvalCode(CompileState *comp)
1095 {
1096     return expr->generateEvalCode(comp);
1097 }
1098 
1099 void VarDeclNode::generateCode(CompileState *comp)
1100 {
1101     // We only care about things which have an initializer ---
1102     // everything else is a no-op at execution time,
1103     // and only makes a difference at processVarDecl time
1104     if (init) {
1105         if (comp->inNestedScope()) {
1106             // We need to do the full lookup mess, which includes doing split binding and store
1107             OpValue quiet   = OpValue::immNode(nullptr);
1108             OpValue varName = OpValue::immIdent(&ident);
1109             OpValue base;
1110             CodeGen::emitOp(comp, Op_ScopeLookup, &base, &varName, &quiet);
1111 
1112             OpValue val = init->generateEvalCode(comp);
1113             CodeGen::emitOp(comp, Op_SymPutKnownObject, nullptr, &base, &varName, &val);
1114             return;
1115         }
1116 
1117         OpValue val = init->generateEvalCode(comp);
1118         size_t localID = comp->functionBody()->lookupSymbolID(ident);
1119         if (localID == missingSymbolMarker()) {
1120             // Generate a symbolic assignment, always to local scope
1121             OpValue identV = OpValue::immIdent(&ident);
1122             CodeGen::emitOp(comp, Op_SymPutKnownObject, nullptr, comp->localScope(), &identV, &val);
1123         } else {
1124             // Store to the local..
1125             OpValue dest = comp->localWriteRef(comp->codeBlock(), localID);
1126             CodeGen::emitOp(comp, Op_RegPutValue, nullptr, &dest, &val);
1127         }
1128     } // if initializer..
1129 }
1130 
1131 OpValue VarDeclListNode::generateEvalCode(CompileState *comp)
1132 {
1133     for (VarDeclListNode *n = this; n; n = n->next.get()) {
1134         n->var->generateCode(comp);
1135     }
1136 
1137     return OpValue::immInt32(0); // unused..
1138 }
1139 
1140 void VarStatementNode::generateExecCode(CompileState *comp)
1141 {
1142     generateDebugInfoIfNeeded(comp);
1143     next->generateEvalCode(comp);
1144 }
1145 
1146 void BlockNode::generateExecCode(CompileState *comp)
1147 {
1148     if (source) {
1149         generateDebugInfoIfNeeded(comp);
1150         source->generateExecCode(comp);
1151     }
1152 }
1153 
1154 void EmptyStatementNode::generateExecCode(CompileState *)
1155 {}
1156 
1157 void ExprStatementNode::generateExecCode(CompileState *comp)
1158 {
1159     generateDebugInfoIfNeeded(comp);
1160     OpValue val = expr->generateEvalCode(comp);
1161 
1162     // Update the result for eval or global code
1163     if (comp->codeType() != FunctionCode) {
1164         CodeGen::emitOp(comp, Op_RegPutValue, nullptr, comp->evalResultReg(), &val);
1165     }
1166 }
1167 
1168 void IfNode::generateExecCode(CompileState *comp)
1169 {
1170     generateDebugInfoIfNeeded(comp);
1171 
1172     // eval the condition
1173     OpValue cond = expr->generateEvalCode(comp);
1174 
1175     // If condition is not true, jump to after or else..
1176     Addr afterTrueJmp = CodeGen::emitOp(comp, Op_IfNotJump, nullptr, &cond, OpValue::dummyAddr());
1177 
1178     // Emit the body of true...
1179     statement1->generateExecCode(comp);
1180 
1181     // If we have an else, add in a jump to skip over it.
1182     Addr afterAllJmp = 0;
1183     if (statement2) {
1184         afterAllJmp = CodeGen::emitOp(comp, Op_Jump, nullptr, OpValue::dummyAddr());
1185     }
1186 
1187     // This is where we go if true fails --- else, or afterwards.
1188     CodeGen::patchJumpToNext(comp, afterTrueJmp, 1);
1189 
1190     if (statement2) {
1191         // Body of else
1192         statement2->generateExecCode(comp);
1193 
1194         // Fix up the jump-over code
1195         CodeGen::patchJumpToNext(comp, afterAllJmp, 0);
1196     }
1197 }
1198 
1199 void DoWhileNode::generateExecCode(CompileState *comp)
1200 {
1201     generateDebugInfoIfNeeded(comp);
1202     comp->enterLoop(this);
1203 
1204     // Body
1205     OpValue beforeBody = OpValue::immAddr(CodeGen::nextPC(comp));
1206     statement->generateExecCode(comp);
1207 
1208     // continues go to just before the test..
1209     comp->resolvePendingContinues(this, CodeGen::nextPC(comp));
1210 
1211     // test
1212     OpValue cond = expr->generateEvalCode(comp);
1213     CodeGen::emitOp(comp, Op_IfJump, nullptr, &cond, &beforeBody);
1214 
1215     comp->exitLoop(this);
1216 }
1217 
1218 void WhileNode::generateExecCode(CompileState *comp)
1219 {
1220     generateDebugInfoIfNeeded(comp);
1221     comp->enterLoop(this);
1222 
1223     // Jump to test.
1224     Addr  jumpToTest = CodeGen::emitOp(comp, Op_Jump, nullptr, OpValue::dummyAddr());
1225 
1226     // Body
1227     OpValue beforeBody = OpValue::immAddr(CodeGen::nextPC(comp));
1228     statement->generateExecCode(comp);
1229 
1230     // continues go to just before the test..
1231     comp->resolvePendingContinues(this, CodeGen::nextPC(comp));
1232 
1233     // patch up the destination of the initial jump to test
1234     CodeGen::patchJumpToNext(comp, jumpToTest, 0);
1235 
1236     // test
1237     OpValue cond = expr->generateEvalCode(comp);
1238     CodeGen::emitOp(comp, Op_IfJump, nullptr, &cond, &beforeBody);
1239 
1240     comp->exitLoop(this);
1241 }
1242 
1243 void ForNode::generateExecCode(CompileState *comp)
1244 {
1245     generateDebugInfoIfNeeded(comp);
1246     comp->enterLoop(this);
1247 
1248     // Initializer, if any..
1249     if (expr1) {
1250         expr1->generateEvalCode(comp);
1251     }
1252 
1253     // Insert a jump to the loop test (address not yet known)
1254     Addr jumpToTest = CodeGen::emitOp(comp, Op_Jump, nullptr, OpValue::dummyAddr());
1255 
1256     // Generate loop body..
1257     OpValue bodyAddr = OpValue::immAddr(CodeGen::nextPC(comp));
1258     statement->generateExecCode(comp);
1259 
1260     // We're about to generate the increment... The continues should go here..
1261     comp->resolvePendingContinues(this, CodeGen::nextPC(comp));
1262 
1263     // Generate increment...
1264     if (expr3) {
1265         expr3->generateEvalCode(comp);
1266     }
1267 
1268     // The test goes here, so patch up the previous jump..
1269     CodeGen::patchJumpToNext(comp, jumpToTest, 0);
1270 
1271     // Make the test itself --- if it exists..
1272     if (expr2) {
1273         OpValue cond = expr2->generateEvalCode(comp);
1274         CodeGen::emitOp(comp, Op_IfJump, nullptr, &cond, &bodyAddr);
1275     } else {
1276         // Just jump back to the body.
1277         CodeGen::emitOp(comp, Op_Jump, nullptr, &bodyAddr);
1278     }
1279 
1280     comp->exitLoop(this);
1281 }
1282 
1283 void ForInNode::generateExecCode(CompileState *comp)
1284 {
1285     generateDebugInfoIfNeeded(comp);
1286     if (varDecl) {
1287         varDecl->generateCode(comp);
1288     }
1289 
1290     OpValue val = expr->generateEvalCode(comp);
1291     OpValue obj; // version of val after toObject, returned by BeginForIn.
1292 
1293     OpValue stateVal, stateReg;
1294     comp->requestTemporary(OpType_value, &stateVal, &stateReg);
1295 
1296     // Fetch the property name array..
1297     CodeGen::emitOp(comp, Op_BeginForIn, &obj, &val, &stateReg);
1298 
1299     comp->enterLoop(this);
1300 
1301     // We put the test first here, since the test and the fetch are combined.
1302     OpValue sym;
1303     Addr fetchNext = CodeGen::emitOp(comp, Op_NextForInEntry, &sym, &obj,
1304                                      &stateVal, OpValue::dummyAddr());
1305 
1306     // Write to the variable
1307     assert(lexpr->isLocation());
1308     LocationNode *loc = static_cast<LocationNode *>(lexpr.get());
1309 
1310     CompileReference *ref = loc->generateRefBind(comp);
1311     loc->generateRefWrite(comp, ref, sym);
1312     delete ref;
1313 
1314     // Run the body.
1315     statement->generateExecCode(comp);
1316 
1317     // Can fix the continues to go back to the test...
1318     comp->resolvePendingContinues(this, fetchNext);
1319 
1320     // Jump back..
1321     OpValue backVal = OpValue::immAddr(fetchNext);
1322     CodeGen::emitOp(comp, Op_Jump, nullptr, &backVal);
1323 
1324     // The end address is here (3 argument + return val)
1325     CodeGen::patchJumpToNext(comp, fetchNext, 3);
1326 
1327     comp->exitLoop(this);
1328 }
1329 
1330 // Helper for continue/break -- emits stack cleanup call if needed,
1331 // and a jump either to the or an ??? exception.
1332 static void handleJumpOut(CompileState *comp, Node *dest, ComplType breakOrCont)
1333 {
1334     // We scan up the nest stack until we get to the target or
1335     // a try-finally.
1336     int toUnwind = 0;
1337 
1338     const WTF::Vector<CompileState::NestInfo> &nests = comp->nestStack();
1339 
1340     for (int pos = nests.size() - 1; pos >= 0; --pos) {
1341         switch (nests[pos].type) {
1342         case CompileState::Scope:
1343         case CompileState::OtherCleanup:
1344             ++toUnwind;
1345             break;
1346         case CompileState::TryFinally: {
1347             // Uh-oh. We have to handle this via exception machinery, giving it the
1348             // original address
1349             Addr    pc    = CodeGen::nextPC(comp);
1350             CodeGen::emitOp(comp, Op_ContBreakInTryFinally, nullptr, OpValue::dummyAddr());
1351 
1352             // Queue destination for resolution
1353             if (breakOrCont == Continue) {
1354                 comp->addPendingContinue(dest, pc);
1355             } else {
1356                 comp->addPendingBreak(dest, pc);
1357             }
1358 
1359             return;
1360         }
1361 
1362         case CompileState::ContBreakTarget:
1363             if (nests[pos].node == dest) {
1364                 // Great. We found where we're going! Emit the unwind instr (if needed),
1365                 // and the jump.
1366                 if (toUnwind) {
1367                     OpValue unwind = OpValue::immInt32(toUnwind);
1368                     CodeGen::emitOp(comp, Op_UnwindStacks, nullptr, &unwind);
1369                 }
1370 
1371                 // Emit a jump...
1372                 Addr    pc    = CodeGen::nextPC(comp);
1373                 CodeGen::emitOp(comp, Op_Jump, nullptr, OpValue::dummyAddr());
1374 
1375                 // Queue destination for resolution
1376                 if (breakOrCont == Continue) {
1377                     comp->addPendingContinue(dest, pc);
1378                 } else {
1379                     comp->addPendingBreak(dest, pc);
1380                 }
1381 
1382                 return;
1383             } // if matching destination..
1384         }
1385     }
1386 
1387     assert(!"Huh? Unable to find continue/break target in the nest stack");
1388 }
1389 
1390 void ContinueNode::generateExecCode(CompileState *comp)
1391 {
1392     generateDebugInfoIfNeeded(comp);
1393     Node *dest = comp->resolveContinueLabel(ident);
1394     if (!dest) {
1395         if (ident.isEmpty()) {
1396             emitSyntaxError(comp, this, "Illegal continue without target outside a loop.");
1397         } else {
1398             emitSyntaxError(comp, this, "Invalid label in continue.");
1399         }
1400     } else {
1401         // Continue can only be used for a loop
1402         if (dest->isIterationStatement()) {
1403             handleJumpOut(comp, dest, Continue);
1404         } else {
1405             emitSyntaxError(comp, this, "Invalid continue target; must be a loop.");
1406         }
1407     }
1408 }
1409 
1410 void BreakNode::generateExecCode(CompileState *comp)
1411 {
1412     generateDebugInfoIfNeeded(comp);
1413     Node *dest = comp->resolveBreakLabel(ident);
1414     if (!dest) {
1415         if (ident.isEmpty()) {
1416             emitSyntaxError(comp, this, "Illegal break without target outside a loop or switch.");
1417         } else {
1418             emitSyntaxError(comp, this, "Invalid label in break.");
1419         }
1420     } else {
1421         handleJumpOut(comp, dest, Break);
1422     }
1423 }
1424 
1425 void ReturnNode::generateExecCode(CompileState *comp)
1426 {
1427     generateDebugInfoIfNeeded(comp);
1428     OpValue arg;
1429 
1430     // Return is invalid in non-function..
1431     if (comp->codeType() != FunctionCode) {
1432         emitSyntaxError(comp, this, "Invalid return.");
1433         return;
1434     }
1435 
1436     if (!value) {
1437         arg = OpValue::immValue(jsUndefined());
1438     } else {
1439         arg = value->generateEvalCode(comp);
1440     }
1441 
1442     if (!comp->inTryFinally()) {
1443         generateExitContextIfNeeded(comp);
1444     }
1445 
1446     CodeGen::emitOp(comp, comp->inTryFinally() ? Op_ReturnInTryFinally : Op_Return, nullptr, &arg);
1447 }
1448 
1449 void WithNode::generateExecCode(CompileState *comp)
1450 {
1451     generateDebugInfoIfNeeded(comp);
1452     // ### this may be too conservative --- it only applies if there is
1453     // a function call within
1454     comp->setNeedsClosures();
1455 
1456     OpValue scopeObj = expr->generateEvalCode(comp);
1457 
1458     comp->pushNest(CompileState::Scope, this);
1459     CodeGen::emitOp(comp, Op_PushScope, nullptr, &scopeObj);
1460 
1461     statement->generateExecCode(comp);
1462 
1463     CodeGen::emitOp(comp, Op_PopScope, nullptr);
1464     comp->popNest();
1465 }
1466 
1467 void LabelNode::generateExecCode(CompileState *comp)
1468 {
1469     if (!comp->pushLabel(label)) {
1470         emitSyntaxError(comp, this, "Duplicated label found.");
1471         return;
1472     }
1473 
1474     if (!statement->isLabelNode()) { // we're the last label..
1475         comp->pushNest(CompileState::ContBreakTarget, statement.get());
1476         comp->bindLabels(statement.get());
1477     }
1478 
1479     // Generate code for stuff inside the label...
1480     statement->generateExecCode(comp);
1481 
1482     // Fix up any breaks..
1483     if (!statement->isLabelNode()) {
1484         comp->popNest();
1485         comp->resolvePendingBreaks(statement.get(), CodeGen::nextPC(comp));
1486     }
1487 
1488     comp->popLabel();
1489 }
1490 
1491 void ThrowNode::generateExecCode(CompileState *comp)
1492 {
1493     generateDebugInfoIfNeeded(comp);
1494     OpValue projectile = expr->generateEvalCode(comp);
1495     CodeGen::emitOp(comp, Op_Throw, nullptr, &projectile);
1496 }
1497 
1498 void TryNode::generateExecCode(CompileState *comp)
1499 {
1500     generateDebugInfoIfNeeded(comp);
1501     // ### this may be too conservative --- it only applies if there is
1502     // a function call within the catch
1503     comp->setNeedsClosures();
1504 
1505     // Set the catch handler, run the try clause, pop the try handler..
1506     Addr setCatchHandler = CodeGen::emitOp(comp, Op_PushExceptionHandler, nullptr, OpValue::dummyAddr());
1507     comp->pushNest(finallyBlock ? CompileState::TryFinally : CompileState::OtherCleanup);
1508 
1509     tryBlock->generateExecCode(comp);
1510 
1511     CodeGen::emitOp(comp, Op_PopExceptionHandler);
1512     comp->popNest();
1513 
1514     // Jump over the catch if try is OK
1515     Addr jumpOverCatch = 0;
1516     if (catchBlock) {
1517         jumpOverCatch = CodeGen::emitOp(comp, Op_Jump, nullptr, OpValue::dummyAddr());
1518     }
1519 
1520     // Exceptions would go here --- either in a catch or a finally.
1521     CodeGen::patchJumpToNext(comp, setCatchHandler, 0);
1522 
1523     Addr catchToFinallyEH = 0;
1524     if (catchBlock) {
1525         // If there is a finally block, that acts as an exception handler for the catch;
1526         // we need to set it before entering the catch scope, so the cleanup entries for that
1527         // are on top. Also, that's needed because if the inside raised a non-exception
1528         // continuation, EnterCatch will re-raise it.
1529         if (finallyBlock) {
1530             catchToFinallyEH = CodeGen::emitOp(comp, Op_PushExceptionHandler, nullptr, OpValue::dummyAddr());
1531             comp->pushNest(CompileState::TryFinally);
1532         }
1533 
1534         // Emit the catch.. Note: the unwinder has already popped the catch handler entry,
1535         // but the exception object is still set, since we need to make a scope for it.
1536         // EnterCatch would do that for us, given the name
1537         OpValue catchVar = OpValue::immIdent(&exceptionIdent);
1538         CodeGen::emitOp(comp, Op_EnterCatch, nullptr, &catchVar);
1539         comp->pushNest(CompileState::Scope);
1540 
1541         catchBlock->generateExecCode(comp);
1542 
1543         // If needed, cleanup the binding to finally, and always cleans the catch scope
1544         CodeGen::emitOp(comp, Op_ExitCatch);
1545         comp->popNest();
1546 
1547         if (finallyBlock) {
1548             CodeGen::emitOp(comp, Op_PopExceptionHandler);
1549             comp->popNest();
1550         }
1551 
1552         // after an OK 'try', we always go to finally, if any, which needs an op if there is a catch block
1553         CodeGen::patchJumpToNext(comp, jumpOverCatch, 0);
1554     }
1555 
1556     if (finallyBlock) {
1557         if (catchBlock) { // if a catch was using us an EH, patch that instruction to here
1558             CodeGen::patchJumpToNext(comp, catchToFinallyEH, 0);
1559         }
1560 
1561         CodeGen::emitOp(comp, Op_DeferCompletion);
1562         comp->pushNest(CompileState::OtherCleanup);
1563 
1564         finallyBlock->generateExecCode(comp);
1565 
1566         OpValue otherTryFinally = OpValue::immBool(comp->inTryFinally());
1567 
1568         if (exitContextNeeded(comp)) {
1569             OpValue ourNode = OpValue::immNode(comp->functionBody());
1570             CodeGen::emitOp(comp, Op_ReactivateCompletionDebug, nullptr, &otherTryFinally, &ourNode);
1571         } else {
1572             CodeGen::emitOp(comp, Op_ReactivateCompletion, nullptr, &otherTryFinally);
1573         }
1574         comp->popNest();
1575     }
1576 }
1577 
1578 void FunctionBodyNode::generateExecCode(CompileState *comp)
1579 {
1580     // Load scope, global and 'this' pointers.
1581     OpValue scopeVal,  scopeReg,
1582             globalVal, globalReg,
1583             thisVal,   thisReg;
1584 
1585     comp->requestTemporary(OpType_value, &scopeVal,  &scopeReg);
1586     comp->requestTemporary(OpType_value, &globalVal, &globalReg);
1587     comp->requestTemporary(OpType_value, &thisVal,   &thisReg);
1588 
1589     CodeGen::emitOp(comp, Op_Preamble, nullptr, &scopeReg, &globalReg, &thisReg);
1590 
1591     comp->setPreloadRegs(&scopeVal, &globalVal, &thisVal);
1592 
1593     OpValue evalResReg, evalResVal;
1594     if (comp->codeType() != FunctionCode) {
1595         comp->requestTemporary(OpType_value, &evalResVal, &evalResReg);
1596         comp->setEvalResultRegister(&evalResReg);
1597 
1598         // There is no need to initialize this as everything will be set to undefined anyway
1599     } else {
1600         if (comp->compileType() == Debug) {
1601             OpValue ourNode = OpValue::immNode(this);
1602             CodeGen::emitOp(comp, Op_EnterDebugContext, nullptr, &ourNode);
1603         }
1604     }
1605 
1606     // Set unwind..
1607     Addr unwind = CodeGen::emitOp(comp, Op_PushExceptionHandler, nullptr, OpValue::dummyAddr());
1608 
1609     // Generate body...
1610     BlockNode::generateExecCode(comp);
1611 
1612     // Make sure we exit!
1613     if (comp->codeType() != FunctionCode) {
1614         CodeGen::emitOp(comp, Op_Return, nullptr, &evalResVal);
1615     } else {
1616         generateExitContextIfNeeded(comp);
1617         CodeGen::emitOp(comp, Op_Exit);
1618     }
1619 
1620     // Unwind stuff..
1621     CodeGen::patchJumpToNext(comp, unwind, 0);
1622     generateExitContextIfNeeded(comp);
1623     CodeGen::emitOp(comp, Op_PropagateException);
1624 }
1625 
1626 void SwitchNode::generateExecCode(CompileState *comp)
1627 {
1628     generateDebugInfoIfNeeded(comp);
1629     CaseBlockNode *caseBlock = this->block.get();
1630 
1631     // The code we produce has 2 stages: first, we emit all the conditionals, and pick
1632     // the label to jump to (with the jump to the default being last),
1633     // then we just emit all the clauses in the row. The breaks will be
1634     // resolved at the end --- for that, we bind ourselves for label'less break.
1635     comp->pushNest(CompileState::ContBreakTarget, this);
1636     comp->pushDefaultBreak(this);
1637 
1638     // What we compare with
1639     OpValue switchOn = expr->generateEvalCode(comp);
1640 
1641     WTF::Vector<Addr> list1jumps;
1642     WTF::Vector<Addr> list2jumps;
1643     Addr defJump;
1644 
1645     // Jumps for list 1..
1646     for (ClauseListNode *iter = caseBlock->list1.get(); iter; iter = iter->next.get()) {
1647         OpValue ref = iter->clause->expr->generateEvalCode(comp);
1648         OpValue match;
1649         CodeGen::emitOp(comp, Op_StrEq, &match, &switchOn, &ref);
1650 
1651         Addr jumpToClause = CodeGen::emitOp(comp, Op_IfJump, nullptr, &match, OpValue::dummyAddr());
1652         list1jumps.append(jumpToClause);
1653     }
1654 
1655     // Jumps for list 2..
1656     for (ClauseListNode *iter = caseBlock->list2.get(); iter; iter = iter->next.get()) {
1657         OpValue ref = iter->clause->expr->generateEvalCode(comp);
1658         OpValue match;
1659         CodeGen::emitOp(comp, Op_StrEq, &match, &switchOn, &ref);
1660 
1661         Addr jumpToClause = CodeGen::emitOp(comp, Op_IfJump, nullptr, &match, OpValue::dummyAddr());
1662         list2jumps.append(jumpToClause);
1663     }
1664 
1665     // Jump to default (or after, if there is no default)
1666     defJump = CodeGen::emitOp(comp, Op_Jump, nullptr, OpValue::dummyAddr());
1667 
1668     // Now, we can actually emit the bodies, fixing the addresses as we go
1669     int p = 0;
1670     for (ClauseListNode *iter = caseBlock->list1.get(); iter; iter = iter->next.get()) {
1671         CodeGen::patchJumpToNext(comp, list1jumps[p], 1);
1672         if (iter->clause->source) {
1673             iter->clause->source->generateExecCode(comp);
1674         }
1675         ++p;
1676     }
1677 
1678     if (caseBlock->def) {
1679         CodeGen::patchJumpToNext(comp, defJump, 0);
1680         if (caseBlock->def->source) {
1681             caseBlock->def->source->generateExecCode(comp);
1682         }
1683     }
1684 
1685     p = 0;
1686     for (ClauseListNode *iter = caseBlock->list2.get(); iter; iter = iter->next.get()) {
1687         CodeGen::patchJumpToNext(comp, list2jumps[p], 1);
1688         if (iter->clause->source) {
1689             iter->clause->source->generateExecCode(comp);
1690         }
1691         ++p;
1692     }
1693 
1694     // If we didn't have a default, that jump is to here..
1695     if (!caseBlock->def) {
1696         CodeGen::patchJumpToNext(comp, defJump, 0);
1697     }
1698 
1699     // Breaks should go after us..
1700     comp->popDefaultBreak();
1701     comp->popNest();
1702     comp->resolvePendingBreaks(this, CodeGen::nextPC(comp));
1703 }
1704 
1705 void ImportStatement::generateExecCode(CompileState *)
1706 {} // handled as a declaration..
1707 
1708 }
1709