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