1 /*
2  *  This file is part of the KDE libraries
3  *  Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
4  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
5  *  Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
6  *  Copyright (C) 2007, 2008 Maksim Orlovich (maksim@kde.org)
7  *
8  *  This library is free software; you can redistribute it and/or
9  *  modify it under the terms of the GNU Library General Public
10  *  License as published by the Free Software Foundation; either
11  *  version 2 of the License, or (at your option) any later version.
12  *
13  *  This library is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  *  Library General Public License for more details.
17  *
18  *  You should have received a copy of the GNU Library General Public License
19  *  along with this library; see the file COPYING.LIB.  If not, write to
20  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  *  Boston, MA 02110-1301, USA.
22  *
23  */
24 #include "nodes2bytecode.h"
25 #include <wtf/Assertions.h>
26 
27 #include <typeinfo>
28 #include <iostream>
29 
30 namespace KJS
31 {
32 
33 // A few helpers..
emitError(CompileState * comp,Node * node,ErrorType type,const char * msgStr)34 static void emitError(CompileState *comp, Node *node, ErrorType type, const char *msgStr)
35 {
36     OpValue me = OpValue::immNode(node);
37     OpValue se = OpValue::immInt32(type);
38     OpValue msg = OpValue::immCStr(msgStr);
39     CodeGen::emitOp(comp, Op_RaiseError, nullptr, &me, &se, &msg);
40 }
41 
emitSyntaxError(CompileState * comp,Node * node,const char * msgStr)42 static void emitSyntaxError(CompileState *comp, Node *node, const char *msgStr)
43 {
44     emitError(comp, node, SyntaxError, msgStr);
45 }
46 
emitReferenceError(CompileState * comp,Node * node,const char * msgStr)47 static void emitReferenceError(CompileState *comp, Node *node, const char *msgStr)
48 {
49     emitError(comp, node, ReferenceError, msgStr);
50 }
51 
generateEvalCode(CompileState *)52 OpValue Node::generateEvalCode(CompileState *)
53 {
54     std::cerr << "WARNING: no generateEvalCode for:" << typeid(*this).name() << "\n";
55     ASSERT(0);
56 
57     return OpValue::immInt32(42);
58 }
59 
generateExecCode(CompileState *)60 void StatementNode::generateExecCode(CompileState *)
61 {
62     std::cerr << "WARNING: no generateExecCode for:" << typeid(*this).name() << "\n";
63     ASSERT(0);
64 }
65 
generateDebugInfo(CompileState * comp)66 void StatementNode::generateDebugInfo(CompileState *comp)
67 {
68     OpValue me = OpValue::immNode(this);
69     CodeGen::emitOp(comp, Op_AtStatement, nullptr, &me);
70 }
71 
exitContextNeeded(CompileState * comp)72 static inline bool exitContextNeeded(CompileState *comp)
73 {
74     return comp->compileType() == Debug &&
75            comp->codeType()    == FunctionCode;
76 }
77 
generateExitContextIfNeeded(CompileState * comp)78 static void generateExitContextIfNeeded(CompileState *comp)
79 {
80     if (exitContextNeeded(comp)) {
81         OpValue ourNode = OpValue::immNode(comp->functionBody());
82         CodeGen::emitOp(comp, Op_ExitDebugContext, nullptr, &ourNode);
83     }
84 }
85 
86 // ------------------------------ Basic literals -----------------------------------------
87 
generateEvalCode(CompileState *)88 OpValue NullNode::generateEvalCode(CompileState *)
89 {
90     return OpValue::immValue(jsNull());
91 }
92 
generateEvalCode(CompileState *)93 OpValue BooleanNode::generateEvalCode(CompileState *)
94 {
95     return OpValue::immBool(value());
96 }
97 
generateEvalCode(CompileState *)98 OpValue NumberNode::generateEvalCode(CompileState *)
99 {
100     using namespace std;
101 #if 0
102     if (typeHint == OpType_Value) {
103         // Try to fit into a JSValue if at all possible..
104         JSValue *im = JSImmediate::from(value());
105         if (im) {
106             OpValue res = mkImmediateVal(OpType_value);
107             return res;
108         }
109     }
110 #endif
111 
112     // Numeric-like..
113     double d = value();
114     int32_t i32 = JSValue::toInt32(d);
115     if (double(i32) == d && !(i32 == 0 && signbit(d))) { // be careful with -0.0 here
116         return OpValue::immInt32(i32);
117     } else {
118         return OpValue::immNumber(d);
119     }
120 }
121 
generateEvalCode(CompileState * comp)122 OpValue StringNode::generateEvalCode(CompileState *comp)
123 {
124     // For now, just generate a JSValue
125     // We may want to permit string pointers as well, to help overload resolution,
126     // but it's not clear whether that's useful, since we can't MM them. Perhaps
127     // a special StringInstance type may be of use eventually.
128 
129     if (interned) { // we're re-compiling.. just reuse it
130         return OpValue::immValue(interned);
131     }
132 
133     // Intern shorter strings
134     if (val.size() < 16) {
135         interned = Interpreter::internString(val);
136         return OpValue::immValue(interned);
137     } else {
138         OpValue inStr = OpValue::immString(&val);
139 
140         OpValue out;
141         CodeGen::emitOp(comp, Op_OwnedString, &out, &inStr);
142         return out;
143     }
144 }
145 
~StringNode()146 StringNode::~StringNode()
147 {
148     if (interned) {
149         Interpreter::releaseInternedString(val);
150     }
151 }
152 
generateEvalCode(CompileState * comp)153 OpValue RegExpNode::generateEvalCode(CompileState *comp)
154 {
155     // ### TODO: cache the engine object?
156     OpValue out;
157     OpValue patternV = OpValue::immString(&pattern);
158     OpValue flagsV   = OpValue::immString(&flags);
159     CodeGen::emitOp(comp, Op_NewRegExp, &out, &patternV, &flagsV);
160     return out;
161 }
162 
generateEvalCode(CompileState * comp)163 OpValue ThisNode::generateEvalCode(CompileState *comp)
164 {
165     return *comp->thisValue();
166 }
167 
168 // ------------------------------ VarAccessNode ----------------------------------------
169 
classifyVariable(CompileState * comp,Classification & classify)170 size_t VarAccessNode::classifyVariable(CompileState *comp, Classification &classify)
171 {
172     // Are we inside a with or catch? In that case, it's all dynamic. Boo.
173     // Ditto for eval.
174     // ### actually that may be improvable if we can
175     // distinguish eval-from-global and eval-from-local, since
176     // we'd have an activation or global object available for access.
177     if (comp->inNestedScope() || comp->codeType() == EvalCode) {
178         classify = Dynamic;
179         return missingSymbolMarker();
180     }
181 
182     // If we're inside global scope (and as per above, not inside any nested scope!)
183     // we can always used the global object
184     if (comp->codeType() == GlobalCode) {
185         classify = Global;
186         return missingSymbolMarker();
187     }
188 
189     // We're inside a function...
190     if (ident == CommonIdentifiers::shared()->arguments) {
191         // arguments is too much of a pain to handle in general path..
192         classify = Dynamic;
193         return missingSymbolMarker();
194     }
195 
196     // Do we know this?
197     size_t index = comp->functionBody()->lookupSymbolID(ident);
198     if (index == missingSymbolMarker()) {
199         classify = NonLocal;
200     } else {
201         classify = Local;
202     }
203 
204     return index;
205 }
206 
generateEvalCode(CompileState * comp)207 OpValue VarAccessNode::generateEvalCode(CompileState *comp)
208 {
209     Classification classify;
210     size_t index = classifyVariable(comp, classify);
211 
212     OpValue out;
213     OpValue varName = OpValue::immIdent(&ident);
214     switch (classify) {
215     case Local: {
216         // Register read.
217         out = comp->localReadVal(index);
218         break;
219     }
220     case NonLocal:
221         CodeGen::emitOp(comp, Op_NonLocalVarGet, &out, &varName);
222         break;
223     case Global:
224         CodeGen::emitOp(comp, Op_GlobalObjectGet, &out, &varName);
225         break;
226     case Dynamic:
227         CodeGen::emitOp(comp, Op_VarGet, &out, &varName);
228         break;
229     }
230 
231     return out;
232 }
233 
valueForTypeOf(CompileState * comp)234 OpValue VarAccessNode::valueForTypeOf(CompileState *comp)
235 {
236     // ### some code dupe here.
237     Classification classify;
238     size_t index = classifyVariable(comp, classify);
239 
240     OpValue scopeTemp;
241     OpValue out, outReg;
242     OpValue varName = OpValue::immIdent(&ident);
243     switch (classify) {
244     case Local:
245         // Register read. Easy.
246         out = comp->localReadVal(index);
247         break;
248     case Global:
249         CodeGen::emitOp(comp, Op_SymGetKnownObject, &out, comp->globalScope(), &varName);
250         break;
251     case NonLocal:
252         comp->requestTemporary(OpType_value, &out, &outReg);
253         CodeGen::emitOp(comp, Op_NonLocalScopeLookupAndGet, &scopeTemp, &outReg, &varName);
254         break;
255     case Dynamic:
256         comp->requestTemporary(OpType_value, &out, &outReg);
257         CodeGen::emitOp(comp, Op_ScopeLookupAndGet, &scopeTemp, &outReg, &varName);
258         break;
259     }
260 
261     return out;
262 }
263 
generateRefBind(CompileState * comp)264 CompileReference *VarAccessNode::generateRefBind(CompileState *comp)
265 {
266     Classification classify;
267     classifyVariable(comp, classify);
268 
269     if (classify == Local || classify == Global) {
270         return nullptr;    // nothing to do, we know where it is
271     }
272 
273     // Otherwise, we need to find the scope for writing
274     CompileReference *ref = new CompileReference;
275 
276     OpValue quiet = OpValue::immNode(nullptr);
277     OpValue varName = OpValue::immIdent(&ident);
278     CodeGen::emitOp(comp, classify == Dynamic ? Op_ScopeLookup : Op_NonLocalScopeLookup,
279                     &ref->baseObj, &varName, &quiet);
280     return ref;
281 }
282 
generateRefRead(CompileState * comp,OpValue * out)283 CompileReference *VarAccessNode::generateRefRead(CompileState *comp, OpValue *out)
284 {
285     Classification classify;
286     classifyVariable(comp, classify);
287 
288     // We want to bind and read, also issuing an error.
289 
290     // If we don't need any binding, just use normal read code..
291     if (classify == Local || classify == Global) {
292         *out = generateEvalCode(comp);
293         return nullptr;
294     }
295 
296     // For others, use the lookup-and-fetch ops
297     CompileReference *ref = new CompileReference;
298 
299     OpValue readReg;
300     OpValue varName = OpValue::immIdent(&ident);
301     comp->requestTemporary(OpType_value, out, &readReg);
302 
303     OpName op;
304     if (classify == Dynamic) {
305         op = Op_ScopeLookupAndGetChecked;
306     } else {
307         op = Op_NonLocalScopeLookupAndGetChecked;
308     }
309     CodeGen::emitOp(comp, op, &ref->baseObj, &readReg, &varName);
310 
311     return ref;
312 }
313 
generateRefWrite(CompileState * comp,CompileReference * ref,OpValue & valToStore)314 void VarAccessNode::generateRefWrite(CompileState *comp,
315                                      CompileReference *ref, OpValue &valToStore)
316 {
317     Classification classify;
318     size_t index = classifyVariable(comp, classify);
319 
320     if (classify == Local) {
321         // Straight register put..
322         OpValue destReg = comp->localWriteRef(comp->codeBlock(), index);
323         CodeGen::emitOp(comp, Op_RegPutValue, nullptr, &destReg, &valToStore);
324     } else {
325         // Symbolic write to the appropriate scope..
326         OpValue varName = OpValue::immIdent(&ident);
327         CodeGen::emitOp(comp, Op_SymPutKnownObject, nullptr,
328                         (classify == Global ? comp->globalScope() : &ref->baseObj), &varName, &valToStore);
329     }
330 }
331 
generateRefDelete(CompileState * comp)332 OpValue VarAccessNode::generateRefDelete(CompileState *comp)
333 {
334     Classification classify;
335     classifyVariable(comp, classify);
336 
337     if (classify == Local) {
338         // Normal locals are DontDelete, so this always fails.
339         return OpValue::immBool(false);
340     }
341 
342     // Otherwise, fetch the appropriate scope
343     OpValue base;
344     if (classify == Global) {
345         base = *comp->globalScope();
346     } else {
347         OpValue varName = OpValue::immIdent(&ident);
348         OpValue silent  = OpValue::immNode(nullptr);
349         CodeGen::emitOp(comp, classify == Dynamic ? Op_ScopeLookup : Op_NonLocalScopeLookup,
350                         &base, &varName, &silent);
351     }
352 
353     // Remove the property..
354     OpValue out;
355     OpValue varName = OpValue::immIdent(&ident);
356     CodeGen::emitOp(comp, Op_SymDeleteKnownObject, &out, &base, &varName);
357     return out;
358 }
359 
generateRefFunc(CompileState * comp,OpValue * funOut,OpValue * thisOut)360 void VarAccessNode::generateRefFunc(CompileState *comp, OpValue *funOut, OpValue *thisOut)
361 {
362     Classification classify;
363     classifyVariable(comp, classify);
364 
365     OpValue varName = OpValue::immIdent(&ident);
366 
367     OpValue thisReg;
368     switch (classify) {
369     case Local:
370     case Global:
371         // Both of these use global object for this, and use straightforward lookup for value
372         *funOut  = generateEvalCode(comp);
373         *thisOut = *comp->globalScope();
374         break;
375     case NonLocal:
376         comp->requestTemporary(OpType_value, thisOut, &thisReg);
377         CodeGen::emitOp(comp, Op_NonLocalFunctionLookupAndGet, funOut, &thisReg, &varName);
378         break;
379     case Dynamic:
380         comp->requestTemporary(OpType_value, thisOut, &thisReg);
381         CodeGen::emitOp(comp, Op_FunctionLookupAndGet, funOut, &thisReg, &varName);
382         break;
383     }
384 }
385 
386 // ------------------------------ GroupNode----------------------------------------
387 
generateEvalCode(CompileState * comp)388 OpValue GroupNode::generateEvalCode(CompileState *comp)
389 {
390     return group->generateEvalCode(comp);
391 }
392 
393 // ------------------------------ Object + Array literals --------------------------
394 
generateEvalCode(CompileState * comp)395 OpValue ArrayNode::generateEvalCode(CompileState *comp)
396 {
397     OpValue arr;
398     CodeGen::emitOp(comp, Op_NewEmptyArray, &arr);
399 
400     OpValue und = OpValue::immValue(jsUndefined());
401 
402     int pos = 0;
403     for (ElementNode *el = element.get(); el; el = el->next.get()) {
404         if (!el->node) {
405             // Fill elision w/undefined, unless we can just skip over to a value
406             for (int i = 0; i < el->elision; i++) {
407                 OpValue ind = OpValue::immInt32(pos);
408                 CodeGen::emitOp(comp, Op_BracketPutKnownObject, nullptr, &arr, &ind, &und);
409                 ++pos;
410             }
411         } else {
412             pos += el->elision;
413         }
414 
415         if (el->node) {
416             OpValue val = el->node->generateEvalCode(comp);
417             OpValue ind = OpValue::immInt32(pos);
418             CodeGen::emitOp(comp, Op_BracketPutKnownObject, nullptr, &arr, &ind, &val);
419             ++pos;
420         }
421     }
422 
423     for (int i = 0; i < elision; i++) {
424         OpValue ind = OpValue::immInt32(pos);
425         CodeGen::emitOp(comp, Op_BracketPutKnownObject, nullptr, &arr, &ind, &und);
426         ++pos;
427     }
428 
429     return arr;
430 }
431 
generateEvalCode(CompileState * comp)432 OpValue ObjectLiteralNode::generateEvalCode(CompileState *comp)
433 {
434     OpValue obj;
435     CodeGen::emitOp(comp, Op_NewObject, &obj);
436 
437     for (PropertyListNode *entry = list.get(); entry; entry = entry->next.get()) {
438         PropertyNode *prop = entry->node.get();
439         OpValue name = OpValue::immIdent(&prop->name->str);
440         OpValue val  = prop->assign->generateEvalCode(comp);
441 
442         switch (prop->type) {
443         case PropertyNode::Getter:
444             CodeGen::emitOp(comp, Op_DefineGetter, nullptr, &obj, &name, &val);
445             break;
446         case PropertyNode::Setter:
447             CodeGen::emitOp(comp, Op_DefineSetter, nullptr, &obj, &name, &val);
448             break;
449         case PropertyNode::Constant:
450             CodeGen::emitOp(comp, Op_SymPutKnownObject, nullptr, &obj, &name, &val);
451             break;
452         }
453     }
454 
455     return obj;
456 }
457 
458 // ------------------------------ BracketAccessorNode --------------------------------
generateEvalCode(CompileState * comp)459 OpValue BracketAccessorNode::generateEvalCode(CompileState *comp)
460 {
461     OpValue ret;
462     OpValue base  = expr1->generateEvalCode(comp);
463     OpValue index = expr2->generateEvalCode(comp);
464 
465     // ### optimize foo["bar"] ?
466     CodeGen::emitOp(comp, Op_BracketGet, &ret, &base, &index);
467     return ret;
468 }
469 
generateRefBind(CompileState * comp)470 CompileReference *BracketAccessorNode::generateRefBind(CompileState *comp)
471 {
472     // Per 11.2.1, the following steps must happen when evaluating foo[bar]
473     // 1) eval foo
474     // 2) eval bar
475     // 3) call toObject on [[foo]]
476     // 4) call toString on [[bar]]
477     // ... all of which are part of reference evaluation. Fun.
478     // ### FIXME FIXME FIXME: we don't do step 4 in right spot yet!
479     CompileReference *ref = new CompileReference;
480     OpValue baseV = expr1->generateEvalCode(comp);
481     ref->indexVal = expr2->generateEvalCode(comp);
482     CodeGen::emitOp(comp, Op_ToObject, &ref->baseObj, &baseV);
483     return ref;
484 }
485 
generateRefRead(CompileState * comp,OpValue * out)486 CompileReference *BracketAccessorNode::generateRefRead(CompileState *comp, OpValue *out)
487 {
488     CompileReference *ref = new CompileReference;
489 
490     // ### As above, this sequence should store the toString on reference, if there will be a follow up
491     // write --- need a hint for that..
492     OpValue baseV = expr1->generateEvalCode(comp);
493     ref->indexVal = expr2->generateEvalCode(comp);
494 
495     // Store the object for future use.
496     OpValue baseReg;
497     comp->requestTemporary(OpType_value, &ref->baseObj, &baseReg);
498 
499     CodeGen::emitOp(comp, Op_BracketGetAndBind, out, &baseReg, &baseV, &ref->indexVal);
500     return ref;
501 }
502 
generateRefWrite(CompileState * comp,CompileReference * ref,OpValue & valToStore)503 void BracketAccessorNode::generateRefWrite(CompileState *comp,
504         CompileReference *ref, OpValue &valToStore)
505 {
506     CodeGen::emitOp(comp, Op_BracketPutKnownObject, nullptr, &ref->baseObj, &ref->indexVal, &valToStore);
507 }
508 
generateRefDelete(CompileState * comp)509 OpValue BracketAccessorNode::generateRefDelete(CompileState *comp)
510 {
511     OpValue base  = expr1->generateEvalCode(comp);
512     OpValue index = expr2->generateEvalCode(comp);
513 
514     OpValue out;
515     CodeGen::emitOp(comp, Op_BracketDelete, &out, &base, &index);
516     return out;
517 }
518 
generateRefFunc(CompileState * comp,OpValue * funOut,OpValue * thisOut)519 void BracketAccessorNode::generateRefFunc(CompileState *comp, OpValue *funOut, OpValue *thisOut)
520 {
521     OpValue baseV  = expr1->generateEvalCode(comp);
522     OpValue indexV = expr2->generateEvalCode(comp);
523 
524     // We need to memorize the toObject for 'this'
525     OpValue baseReg;
526     comp->requestTemporary(OpType_value, thisOut, &baseReg);
527 
528     CodeGen::emitOp(comp, Op_BracketGetAndBind, funOut, &baseReg, &baseV, &indexV);
529 }
530 
531 // ------------------------------ DotAccessorNode --------------------------------
532 
533 // ECMA 11.2.1b
generateEvalCode(CompileState * comp)534 OpValue DotAccessorNode::generateEvalCode(CompileState *comp)
535 {
536     OpValue ret;
537     OpValue base    = expr->generateEvalCode(comp);
538     OpValue varName = OpValue::immIdent(&ident);
539     CodeGen::emitOp(comp, Op_SymGet, &ret, &base, &varName);
540     return ret;
541 }
542 
generateRefBind(CompileState * comp)543 CompileReference *DotAccessorNode::generateRefBind(CompileState *comp)
544 {
545     CompileReference *ref = new CompileReference;
546     OpValue baseV = expr->generateEvalCode(comp);
547     CodeGen::emitOp(comp, Op_ToObject, &ref->baseObj, &baseV);
548     return ref;
549 }
550 
generateRefRead(CompileState * comp,OpValue * out)551 CompileReference *DotAccessorNode::generateRefRead(CompileState *comp, OpValue *out)
552 {
553     CompileReference *ref = new CompileReference;
554     OpValue baseV = expr->generateEvalCode(comp);
555     OpValue baseReg;
556     OpValue varName = OpValue::immIdent(&ident);
557     comp->requestTemporary(OpType_value, &ref->baseObj, &baseReg);
558     CodeGen::emitOp(comp, Op_SymGetAndBind, out, &baseReg, &baseV, &varName);
559     return ref;
560 }
561 
generateRefWrite(CompileState * comp,CompileReference * ref,OpValue & valToStore)562 void DotAccessorNode::generateRefWrite(CompileState *comp,
563                                        CompileReference *ref, OpValue &valToStore)
564 {
565     OpValue varName = OpValue::immIdent(&ident);
566     CodeGen::emitOp(comp, Op_SymPutKnownObject, nullptr, &ref->baseObj, &varName, &valToStore);
567 }
568 
generateRefDelete(CompileState * comp)569 OpValue DotAccessorNode::generateRefDelete(CompileState *comp)
570 {
571     OpValue base = expr->generateEvalCode(comp);
572     OpValue varName = OpValue::immIdent(&ident);
573     OpValue out;
574     CodeGen::emitOp(comp, Op_SymDelete, &out, &base, &varName);
575     return out;
576 }
577 
generateRefFunc(CompileState * comp,OpValue * funOut,OpValue * thisOut)578 void DotAccessorNode::generateRefFunc(CompileState *comp, OpValue *funOut, OpValue *thisOut)
579 {
580     OpValue baseV = expr->generateEvalCode(comp);
581     OpValue varName = OpValue::immIdent(&ident);
582 
583     OpValue baseReg;
584     comp->requestTemporary(OpType_value, thisOut, &baseReg);
585     CodeGen::emitOp(comp, Op_SymGetAndBind, funOut, &baseReg, &baseV, &varName);
586 }
587 
588 // ------------------ ........
589 
generateEvalArguments(CompileState * comp)590 void ArgumentsNode::generateEvalArguments(CompileState *comp)
591 {
592     WTF::Vector<OpValue> args;
593 
594     // We need evaluate arguments and push them in separate steps as there may be
595     // function/ctor calls inside.
596     for (ArgumentListNode *arg = list.get(); arg; arg = arg->next.get()) {
597         args.append(arg->expr->generateEvalCode(comp));
598     }
599 
600     CodeGen::emitOp(comp, Op_ClearArgs, nullptr);
601 
602     size_t c = 0;
603     while (c < args.size()) {
604         if (c + 3 <= args.size()) {
605             CodeGen::emitOp(comp, Op_Add3Arg, nullptr, &args[c], &args[c + 1], &args[c + 2]);
606             c += 3;
607         } else if (c + 2 <= args.size()) {
608             CodeGen::emitOp(comp, Op_Add2Arg, nullptr, &args[c], &args[c + 1]);
609             c += 2;
610         } else {
611             CodeGen::emitOp(comp, Op_AddArg, nullptr, &args[c]);
612             c += 1;
613         }
614     }
615 }
616 
generateEvalCode(CompileState * comp)617 OpValue NewExprNode::generateEvalCode(CompileState *comp)
618 {
619     OpValue v = expr->generateEvalCode(comp);
620 
621     if (args) {
622         args->generateEvalArguments(comp);
623     } else {
624         CodeGen::emitOp(comp, Op_ClearArgs, nullptr);
625     }
626 
627     OpValue out;
628     CodeGen::emitOp(comp, Op_CtorCall, &out, &v);
629     return out;
630 }
631 
generateEvalCode(CompileState * comp)632 OpValue FunctionCallValueNode::generateEvalCode(CompileState *comp)
633 {
634     OpValue v = expr->generateEvalCode(comp);
635     args->generateEvalArguments(comp);
636 
637     OpValue out;
638     CodeGen::emitOp(comp, Op_FunctionCall, &out, &v, comp->globalScope());
639     return out;
640 }
641 
generateEvalCode(CompileState * comp)642 OpValue FunctionCallReferenceNode::generateEvalCode(CompileState *comp)
643 {
644     Node *cand = expr->nodeInsideAllParens();
645     ASSERT(cand->isLocation());
646     LocationNode *loc = static_cast<LocationNode *>(cand);
647 
648     OpValue funVal, thisVal;
649     loc->generateRefFunc(comp, &funVal, &thisVal);
650     args->generateEvalArguments(comp);
651 
652     OpValue out;
653     CodeGen::emitOp(comp, Op_FunctionCall, &out, &funVal, &thisVal);
654     return out;
655 }
656 
generateEvalCode(CompileState * comp)657 OpValue PostfixNode::generateEvalCode(CompileState *comp)
658 {
659     Node *cand = m_loc->nodeInsideAllParens();
660     if (!cand->isLocation()) {
661         emitReferenceError(comp, this,
662                            m_oper == OpPlusPlus ?
663                            "Postfix ++ operator applied to value that is not a reference." :
664                            "Postfix -- operator applied to value that is not a reference.");
665         return OpValue::immValue(jsUndefined());
666     }
667 
668     LocationNode *loc = static_cast<LocationNode *>(cand);
669 
670     // ### we want to fold this in if the kid is a local -- any elegant way?
671 
672     //read current value
673     OpValue curV;
674     CompileReference *ref = loc->generateRefRead(comp, &curV);
675 
676     // We need it to be a number..
677     if (curV.type != OpType_number) {
678         OpValue numVal;
679         CodeGen::emitConvertTo(comp, &curV, OpType_number, &numVal);
680         curV = numVal;
681     }
682 
683     // Compute new one
684     OpValue newV;
685     CodeGen::emitOp(comp, (m_oper == OpPlusPlus) ? Op_Add1 : Op_Sub1,
686                     &newV, &curV);
687 
688     loc->generateRefWrite(comp, ref, newV);
689     delete ref;
690     return curV;
691 }
692 
generateEvalCode(CompileState * comp)693 OpValue DeleteReferenceNode::generateEvalCode(CompileState *comp)
694 {
695     return loc->generateRefDelete(comp);
696 }
697 
generateEvalCode(CompileState *)698 OpValue DeleteValueNode::generateEvalCode(CompileState *)
699 {
700     return OpValue::immBool(true);
701 }
702 
generateEvalCode(CompileState * comp)703 OpValue VoidNode::generateEvalCode(CompileState *comp)
704 {
705     (void)expr->generateEvalCode(comp);
706     return OpValue::immValue(jsUndefined());
707 }
708 
generateEvalCode(CompileState * comp)709 OpValue TypeOfVarNode::generateEvalCode(CompileState *comp)
710 {
711     OpValue v = loc->valueForTypeOf(comp);
712 
713     OpValue out;
714     CodeGen::emitOp(comp, Op_TypeOf, &out, &v);
715     return out;
716 }
717 
generateEvalCode(CompileState * comp)718 OpValue TypeOfValueNode::generateEvalCode(CompileState *comp)
719 {
720     OpValue v = m_expr->generateEvalCode(comp);
721     OpValue typeOfV;
722     CodeGen::emitOp(comp, Op_TypeOf, &typeOfV, &v);
723     return typeOfV;
724 }
725 
generateEvalCode(CompileState * comp)726 OpValue PrefixNode::generateEvalCode(CompileState *comp)
727 {
728     Node *cand = m_loc->nodeInsideAllParens();
729     if (!cand->isLocation()) {
730         emitReferenceError(comp, this,
731                            m_oper == OpPlusPlus ?
732                            "Prefix ++ operator applied to value that is not a reference." :
733                            "Prefix -- operator applied to value that is not a reference.");
734         return OpValue::immValue(jsUndefined());
735     }
736 
737     LocationNode *loc = static_cast<LocationNode *>(cand);
738 
739     // ### we want to fold this in if the kid is a local -- any elegant way?
740 
741     //read current value
742     OpValue curV;
743     CompileReference *ref = loc->generateRefRead(comp, &curV);
744 
745     OpValue newV;
746     CodeGen::emitOp(comp, (m_oper == OpPlusPlus) ? Op_Add1 : Op_Sub1,
747                     &newV, &curV);
748 
749     // Write out + return new value.
750     loc->generateRefWrite(comp, ref, newV);
751     delete ref;
752     return newV;
753 }
754 
generateEvalCode(CompileState * comp)755 OpValue UnaryPlusNode::generateEvalCode(CompileState *comp)
756 {
757     // This is basically just a number cast
758     OpValue curV = expr->generateEvalCode(comp);
759 
760     if (curV.type != OpType_number) {
761         OpValue numVal;
762         CodeGen::emitConvertTo(comp, &curV, OpType_number, &numVal);
763         curV = numVal;
764     }
765 
766     return curV;
767 }
768 
generateEvalCode(CompileState * comp)769 OpValue NegateNode::generateEvalCode(CompileState *comp)
770 {
771     OpValue v = expr->generateEvalCode(comp);
772     OpValue negV;
773     CodeGen::emitOp(comp, Op_Neg, &negV, &v);
774     return negV;
775 }
776 
generateEvalCode(CompileState * comp)777 OpValue BitwiseNotNode::generateEvalCode(CompileState *comp)
778 {
779     OpValue v = expr->generateEvalCode(comp);
780     OpValue out;
781     CodeGen::emitOp(comp, Op_BitNot, &out, &v);
782     return out;
783 }
784 
generateEvalCode(CompileState * comp)785 OpValue LogicalNotNode::generateEvalCode(CompileState *comp)
786 {
787     OpValue v = expr->generateEvalCode(comp);
788     OpValue out;
789     CodeGen::emitOp(comp, Op_LogicalNot, &out, &v);
790     return out;
791 }
792 
generateEvalCode(CompileState * comp)793 OpValue BinaryOperatorNode::generateEvalCode(CompileState *comp)
794 {
795     OpValue v1 = expr1->generateEvalCode(comp);
796     OpValue v2 = expr2->generateEvalCode(comp);
797 
798     OpName codeOp; // ### could perhaps skip conversion entirely,
799     // and set these in the parser?
800     switch (oper) {
801     case OpMult:
802         // operator *
803         codeOp = Op_Mult;
804         break;
805     case OpDiv:
806         // operator /
807         codeOp = Op_Div;
808         break;
809     case OpMod:
810         // operator %
811         codeOp = Op_Mod;
812         break;
813     case OpExp:
814         // operator **
815         codeOp = Op_Exp;
816         break;
817     case OpPlus:
818         // operator +
819         codeOp = Op_Add;
820         break;
821     case OpMinus:
822         // operator -
823         codeOp = Op_Sub;
824         break;
825     case OpLShift:
826         // operator <<
827         codeOp = Op_LShift;
828         break;
829     case OpRShift:
830         // operator >>
831         codeOp = Op_RShift;
832         break;
833     case OpURShift:
834         // operator >>>
835         codeOp = Op_URShift;
836         break;
837     case OpLess:
838         // operator <
839         codeOp = Op_Less;
840         break;
841     case OpGreaterEq:
842         // operator >=
843         codeOp = Op_GreaterEq;
844         break;
845     case OpGreater:
846         // operator >
847         codeOp = Op_Greater;
848         break;
849     case OpLessEq:
850         // operator <=
851         codeOp = Op_LessEq;
852         break;
853     case OpEqEq:
854         // operator ==
855         codeOp = Op_EqEq;
856         break;
857     case OpNotEq:
858         // operator !=
859         codeOp = Op_NotEq;
860         break;
861     case OpStrEq:
862         // operator ===
863         codeOp = Op_StrEq;
864         break;
865     case OpStrNEq:
866         // operator !==
867         codeOp = Op_StrNEq;
868         break;
869     case OpBitAnd:
870         // operator &
871         codeOp = Op_BitAnd;
872         break;
873     case OpBitXOr:
874         // operator ^
875         codeOp = Op_BitXOr;
876         break;
877     case OpBitOr:
878         // operator |
879         codeOp = Op_BitOr;
880         break;
881     case OpIn:
882         codeOp = Op_In;
883         break;
884     case OpInstanceOf:
885         codeOp = Op_InstanceOf;
886         break;
887 
888     default:
889         codeOp = Op_InstanceOf; // Initialize it to something just to silence -Wsometimes-uninitialized
890         assert(!"BinaryOperatorNode: unhandled switch case");
891     }
892 
893     OpValue out;
894     CodeGen::emitOp(comp, codeOp, &out, &v1, &v2);
895     return out;
896 }
897 
generateEvalCode(CompileState * comp)898 OpValue BinaryLogicalNode::generateEvalCode(CompileState *comp)
899 {
900     // This is somewhat ugly since we can't patchup labels in already generated
901     // code, and don't know the types in advance. It could also benefit from
902     // a type hint, since it's easier if we only want a bool, which is quite common
903 
904     OpValue a = expr1->generateEvalCode(comp);
905 
906     // Make a register for storing the result, and put 'a' there, as out first guess.
907     OpValue aVal, aReg;
908     comp->requestTemporary(a.type, &aVal, &aReg);
909     CodeGen::emitRegStore(comp, &aReg, &a);
910 
911     // Is this enough to shortcircuit?
912     // if op is && and a is false, we jump out, ditto
913     // for || and true.
914     Addr jumpToShortCircuit = CodeGen::emitOp(comp, oper == OpAnd ? Op_IfNotJump : Op_IfJump,
915                               nullptr, &a, OpValue::dummyAddr());
916 
917     // Now, generate the code for b...
918     OpValue b = expr2->generateEvalCode(comp);
919 
920     // Hopefully, either the types match, or the result slot is already a value,
921     // so we can just promote b (which will happen automatically to produce param for Op_RegPutVal)
922     if (a.type == b.type || a.type == OpType_value) {
923         if (a.type == OpType_value) {
924             CodeGen::emitOp(comp, Op_RegPutValue, nullptr, &aReg, &b);
925         } else {
926             CodeGen::emitRegStore(comp, &aReg, &b);
927         }
928         CodeGen::patchJumpToNext(comp, jumpToShortCircuit, 1);
929         return aVal;
930     } else {
931         // We need to promote 'a' as well, which means we need to skip over the code jumpToShortCircuit
932         // went to after handling store of 'b'.
933 
934         // Get a new register for the result, put b there..
935         OpValue resVal, resReg;
936         comp->requestTemporary(OpType_value, &resVal, &resReg);
937         CodeGen::emitOp(comp, Op_RegPutValue, nullptr, &resReg, &b);
938 
939         // skip to after a promotion..
940         Addr jumpToAfter = CodeGen::emitOp(comp, Op_Jump, nullptr, OpValue::dummyAddr());
941 
942         // a's promotion goes here..
943         CodeGen::patchJumpToNext(comp, jumpToShortCircuit, 1);
944         CodeGen::emitOp(comp, Op_RegPutValue, nullptr, &resReg, &a);
945 
946         // now we're after it..
947         CodeGen::patchJumpToNext(comp, jumpToAfter, 0);
948 
949         return resVal;
950     }
951 }
952 
generateEvalCode(CompileState * comp)953 OpValue ConditionalNode::generateEvalCode(CompileState *comp)
954 {
955     // As above, we have some difficulty here, since we do not have a way of knowing
956     // the types in advance, but since we can't reasonably speculate on them both being bool,
957     // we just always produce a value.
958     OpValue resVal, resReg;
959 
960     // Evaluate conditional, and jump..
961     OpValue v = logical->generateEvalCode(comp);
962     Addr jumpToElse = CodeGen::emitOp(comp, Op_IfNotJump, nullptr, &v, OpValue::dummyAddr());
963 
964     // True branch
965     OpValue v1out = expr1->generateEvalCode(comp);
966 
967     // Request a temporary for the result. (We can't reuse any, since it may be a variable!)
968     // ### perhaps do an isTemporary check here?
969     comp->requestTemporary(OpType_value, &resVal, &resReg);
970     CodeGen::emitOp(comp, Op_RegPutValue, nullptr, &resReg, &v1out);
971 
972     Addr jumpToAfter = CodeGen::emitOp(comp, Op_Jump, nullptr, OpValue::dummyAddr());
973 
974     // Jump to else goes here.
975     CodeGen::patchJumpToNext(comp, jumpToElse, 1);
976 
977     // : part..
978     OpValue v2out = expr2->generateEvalCode(comp);
979     CodeGen::emitOp(comp, Op_RegPutValue, nullptr, &resReg, &v2out);
980 
981     // After everything
982     CodeGen::patchJumpToNext(comp, jumpToAfter, 0);
983 
984     return resVal;
985 }
986 
generateEvalCode(CompileState * comp)987 OpValue FuncExprNode::generateEvalCode(CompileState *comp)
988 {
989     comp->setNeedsClosures();
990 
991     OpValue out;
992     OpValue nameV = OpValue::immIdent(&ident);
993     OpValue bodyV = OpValue::immNode(body.get());
994     CodeGen::emitOp(comp, Op_EvalFuncExpr, &out, &nameV, &bodyV);
995     return out;
996 }
997 
generateExecCode(CompileState * comp)998 void FuncDeclNode::generateExecCode(CompileState *comp)
999 {
1000     comp->setNeedsClosures();
1001 
1002     // No executable content...
1003 }
1004 
generateExecCode(CompileState * comp)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 
generateEvalCode(CompileState * comp)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 
generateEvalCode(CompileState * comp)1088 OpValue CommaNode::generateEvalCode(CompileState *comp)
1089 {
1090     expr1->generateEvalCode(comp);
1091     return expr2->generateEvalCode(comp);
1092 }
1093 
generateEvalCode(CompileState * comp)1094 OpValue AssignExprNode::generateEvalCode(CompileState *comp)
1095 {
1096     return expr->generateEvalCode(comp);
1097 }
1098 
generateCode(CompileState * comp)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 
generateEvalCode(CompileState * comp)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 
generateExecCode(CompileState * comp)1140 void VarStatementNode::generateExecCode(CompileState *comp)
1141 {
1142     generateDebugInfoIfNeeded(comp);
1143     next->generateEvalCode(comp);
1144 }
1145 
generateExecCode(CompileState * comp)1146 void BlockNode::generateExecCode(CompileState *comp)
1147 {
1148     if (source) {
1149         generateDebugInfoIfNeeded(comp);
1150         source->generateExecCode(comp);
1151     }
1152 }
1153 
generateExecCode(CompileState *)1154 void EmptyStatementNode::generateExecCode(CompileState *)
1155 {}
1156 
generateExecCode(CompileState * comp)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 
generateExecCode(CompileState * comp)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 
generateExecCode(CompileState * comp)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 
generateExecCode(CompileState * comp)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 
generateExecCode(CompileState * comp)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 
generateExecCode(CompileState * comp)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.
handleJumpOut(CompileState * comp,Node * dest,ComplType breakOrCont)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 
generateExecCode(CompileState * comp)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 
generateExecCode(CompileState * comp)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 
generateExecCode(CompileState * comp)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 
generateExecCode(CompileState * comp)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 
generateExecCode(CompileState * comp)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 
generateExecCode(CompileState * comp)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 
generateExecCode(CompileState * comp)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 
generateExecCode(CompileState * comp)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 
generateExecCode(CompileState * comp)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 
generateExecCode(CompileState *)1705 void ImportStatement::generateExecCode(CompileState *)
1706 {} // handled as a declaration..
1707 
1708 }
1709 
1710