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