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 "CompileState.h"
26 #include <wtf/Assertions.h>
27
28 #include <typeinfo>
29 #include <iostream>
30
31namespace KJS {
32
33// A few helpers..
34static 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, 0, &me, &se, &msg);
40}
41
42static void emitSyntaxError(CompileState* comp, Node* node, const char* msgStr)
43{
44 emitError(comp, node, SyntaxError, msgStr);
45}
46
47static void emitReferenceError(CompileState* comp, Node* node, const char* msgStr)
48{
49 emitError(comp, node, ReferenceError, msgStr);
50}
51
52
53OpValue Node::generateEvalCode(CompileState*)
54{
55 std::cerr << "WARNING: no generateEvalCode for:" << typeid(*this).name() << "\n";
56 ASSERT(0);
57
58 return OpValue::immInt32(42);
59}
60
61void StatementNode::generateExecCode(CompileState*)
62{
63 std::cerr << "WARNING: no generateExecCode for:" << typeid(*this).name() << "\n";
64 ASSERT(0);
65}
66
67void StatementNode::generateDebugInfo(CompileState* comp)
68{
69 OpValue me = OpValue::immNode(this);
70 CodeGen::emitOp(comp, Op_AtStatement, 0, &me);
71}
72
73static inline bool exitContextNeeded(CompileState* comp) {
74 return comp->compileType() == Debug &&
75 comp->codeType() == FunctionCode;
76}
77
78static void generateExitContextIfNeeded(CompileState* comp) {
79 if (exitContextNeeded(comp)) {
80 OpValue ourNode = OpValue::immNode(comp->functionBody());
81 CodeGen::emitOp(comp, Op_ExitDebugContext, 0, &ourNode);
82 }
83}
84
85// ------------------------------ Basic literals -----------------------------------------
86
87OpValue NullNode::generateEvalCode(CompileState*)
88{
89 return OpValue::immValue(jsNull());
90}
91
92OpValue BooleanNode::generateEvalCode(CompileState*)
93{
94 return OpValue::immBool(value());
95}
96
97OpValue NumberNode::generateEvalCode(CompileState*)
98{
99#if 0
100 if (typeHint == OpType_Value) {
101 // Try to fit into a JSValue if at all possible..
102 JSValue* im = JSImmediate::from(value());
103 if (im) {
104 OpValue res = mkImmediateVal(OpType_value);
105 return res;
106 }
107 }
108#endif
109
110 // Numeric-like..
111 double d = value();
112 int32_t i32 = JSValue::toInt32(d);
113 if (double(i32) == d && !(i32 == 0 && signbit(d))) // be careful with -0.0 here
114 return OpValue::immInt32(i32);
115 else
116 return OpValue::immNumber(d);
117}
118
119
120OpValue StringNode::generateEvalCode(CompileState* comp)
121{
122 // For now, just generate a JSValue
123 // We may want to permit string pointers as well, to help overload resolution,
124 // but it's not clear whether that's useful, since we can't MM them. Perhaps
125 // a special StringInstance type may be of use eventually.
126
127 if (interned) // we're re-compiling.. just reuse it
128 return OpValue::immValue(interned);
129
130 // Intern shorter strings
131 if (val.size() < 16) {
132 interned = Interpreter::internString(val);
133 return OpValue::immValue(interned);
134 } else {
135 OpValue inStr = OpValue::immString(&val);
136
137 OpValue out;
138 CodeGen::emitOp(comp, Op_OwnedString, &out, &inStr);
139 return out;
140 }
141}
142
143StringNode::~StringNode()
144{
145 if (interned)
146 Interpreter::releaseInternedString(val);
147}
148
149OpValue RegExpNode::generateEvalCode(CompileState* comp)
150{
151 // ### TODO: cache the engine object?
152 OpValue out;
153 OpValue patternV = OpValue::immString(&pattern);
154 OpValue flagsV = OpValue::immString(&flags);
155 CodeGen::emitOp(comp, Op_NewRegExp, &out, &patternV, &flagsV);
156 return out;
157}
158
159OpValue ThisNode::generateEvalCode(CompileState* comp)
160{
161 return *comp->thisValue();
162}
163
164// ------------------------------ VarAccessNode ----------------------------------------
165
166size_t VarAccessNode::classifyVariable(CompileState* comp, Classification& classify)
167{
168 // Are we inside a with or catch? In that case, it's all dynamic. Boo.
169 // Ditto for eval.
170 // ### actually that may be improvable if we can
171 // distinguish eval-from-global and eval-from-local, since
172 // we'd have an activation or global object available for access.
173 if (comp->inNestedScope() || comp->codeType() == EvalCode) {
174 classify = Dynamic;
175 return missingSymbolMarker();
176 }
177
178 // If we're inside global scope (and as per above, not inside any nested scope!)
179 // we can always used the global object
180 if (comp->codeType() == GlobalCode) {
181 classify = Global;
182 return missingSymbolMarker();
183 }
184
185 // We're inside a function...
186 if (ident == CommonIdentifiers::shared()->arguments) {
187 // arguments is too much of a pain to handle in general path..
188 classify = Dynamic;
189 return missingSymbolMarker();
190 }
191
192 // Do we know this?
193 size_t index = comp->functionBody()->lookupSymbolID(ident);
194 if (index == missingSymbolMarker())
195 classify = NonLocal;
196 else
197 classify = Local;
198
199 return index;
200}
201
202OpValue VarAccessNode::generateEvalCode(CompileState* comp)
203{
204 Classification classify;
205 size_t index = classifyVariable(comp, classify);
206
207 OpValue out;
208 OpValue varName = OpValue::immIdent(&ident);
209 switch (classify) {
210 case Local: {
211 // Register read.
212 out = comp->localReadVal(index);
213 break;
214 }
215 case NonLocal:
216 CodeGen::emitOp(comp, Op_NonLocalVarGet, &out, &varName);
217 break;
218 case Global:
219 CodeGen::emitOp(comp, Op_GlobalObjectGet, &out, &varName);
220 break;
221 case Dynamic:
222 CodeGen::emitOp(comp, Op_VarGet, &out, &varName);
223 break;
224 }
225
226 return out;
227}
228
229OpValue VarAccessNode::valueForTypeOf(CompileState* comp)
230{
231 // ### some code dupe here.
232 Classification classify;
233 size_t index = classifyVariable(comp, classify);
234
235 OpValue scopeTemp;
236 OpValue out, outReg;
237 OpValue varName = OpValue::immIdent(&ident);
238 switch (classify) {
239 case Local:
240 // Register read. Easy.
241 out = comp->localReadVal(index);
242 break;
243 case Global:
244 CodeGen::emitOp(comp, Op_SymGetKnownObject, &out, comp->globalScope(), &varName);
245 break;
246 case NonLocal:
247 comp->requestTemporary(OpType_value, &out, &outReg);
248 CodeGen::emitOp(comp, Op_NonLocalScopeLookupAndGet, &scopeTemp, &outReg, &varName);
249 break;
250 case Dynamic:
251 comp->requestTemporary(OpType_value, &out, &outReg);
252 CodeGen::emitOp(comp, Op_ScopeLookupAndGet, &scopeTemp, &outReg, &varName);
253 break;
254 }
255
256 return out;
257}
258
259CompileReference* VarAccessNode::generateRefBind(CompileState* comp)
260{
261 Classification classify;
262 classifyVariable(comp, classify);
263
264 if (classify == Local || classify == Global)
265 return 0; // nothing to do, we know where it is
266
267 // Otherwise, we need to find the scope for writing
268 CompileReference* ref = new CompileReference;
269
270 OpValue quiet = OpValue::immNode(0);
271 OpValue varName = OpValue::immIdent(&ident);
272 CodeGen::emitOp(comp, classify == Dynamic ? Op_ScopeLookup : Op_NonLocalScopeLookup,
273 &ref->baseObj, &varName, &quiet);
274 return ref;
275}
276
277CompileReference* VarAccessNode::generateRefRead(CompileState* comp, OpValue* out)
278{
279 Classification classify;
280 classifyVariable(comp, classify);
281
282 // We want to bind and read, also issuing an error.
283
284 // If we don't need any binding, just use normal read code..
285 if (classify == Local || classify == Global) {
286 *out = generateEvalCode(comp);
287 return 0;
288 }
289
290 // For others, use the lookup-and-fetch ops
291 CompileReference* ref = new CompileReference;
292
293 OpValue readReg;
294 OpValue varName = OpValue::immIdent(&ident);
295 comp->requestTemporary(OpType_value, out, &readReg);
296
297 OpName op;
298 if (classify == Dynamic)
299 op = Op_ScopeLookupAndGetChecked;
300 else
301 op = Op_NonLocalScopeLookupAndGetChecked;
302 CodeGen::emitOp(comp, op, &ref->baseObj, &readReg, &varName);
303
304 return ref;
305}
306
307void VarAccessNode::generateRefWrite(CompileState* comp,
308 CompileReference* ref, OpValue& valToStore)
309{
310 Classification classify;
311 size_t index = classifyVariable(comp, classify);
312
313 if (classify == Local) {
314 // Straight register put..
315 OpValue destReg = comp->localWriteRef(comp->codeBlock(), index);
316 CodeGen::emitOp(comp, Op_RegPutValue, 0, &destReg, &valToStore);
317 } else {
318 // Symbolic write to the appropriate scope..
319 OpValue varName = OpValue::immIdent(&ident);
320 CodeGen::emitOp(comp, Op_SymPutKnownObject, 0,
321 (classify == Global ? comp->globalScope() : &ref->baseObj), &varName, &valToStore);
322 }
323}
324
325OpValue VarAccessNode::generateRefDelete(CompileState* comp)
326{
327 Classification classify;
328 classifyVariable(comp, classify);
329
330 if (classify == Local) {
331 // Normal locals are DontDelete, so this always fails.
332 return OpValue::immBool(false);
333 }
334
335 // Otherwise, fetch the appropriate scope
336 OpValue base;
337 if (classify == Global) {
338 base = *comp->globalScope();
339 } else {
340 OpValue varName = OpValue::immIdent(&ident);
341 OpValue silent = OpValue::immNode(0);
342 CodeGen::emitOp(comp, classify == Dynamic ? Op_ScopeLookup : Op_NonLocalScopeLookup,
343 &base, &varName, &silent);
344 }
345
346 // Remove the property..
347 OpValue out;
348 OpValue varName = OpValue::immIdent(&ident);
349 CodeGen::emitOp(comp, Op_SymDeleteKnownObject, &out, &base, &varName);
350 return out;
351}
352
353void VarAccessNode::generateRefFunc(CompileState* comp, OpValue* funOut, OpValue* thisOut)
354{
355 Classification classify;
356 classifyVariable(comp, classify);
357
358 OpValue varName = OpValue::immIdent(&ident);
359
360 OpValue thisReg;
361 switch (classify) {
362 case Local:
363 case Global:
364 // Both of these use global object for this, and use straightforward lookup for value
365 *funOut = generateEvalCode(comp);
366 *thisOut = *comp->globalScope();
367 break;
368 case NonLocal:
369 comp->requestTemporary(OpType_value, thisOut, &thisReg);
370 CodeGen::emitOp(comp, Op_NonLocalFunctionLookupAndGet, funOut, &thisReg, &varName);
371 break;
372 case Dynamic:
373 comp->requestTemporary(OpType_value, thisOut, &thisReg);
374 CodeGen::emitOp(comp, Op_FunctionLookupAndGet, funOut, &thisReg, &varName);
375 break;
376 }
377}
378
379// ------------------------------ GroupNode----------------------------------------
380
381OpValue GroupNode::generateEvalCode(CompileState* comp)
382{
383 return group->generateEvalCode(comp);
384}
385
386// ------------------------------ Object + Array literals --------------------------
387
388OpValue ArrayNode::generateEvalCode(CompileState* comp)
389{
390 OpValue arr;
391 CodeGen::emitOp(comp, Op_NewEmptyArray, &arr);
392
393 OpValue und = OpValue::immValue(jsUndefined());
394
395 int pos = 0;
396 for (ElementNode* el = element.get(); el; el = el->next.get()) {
397 if (!el->node) {
398 // Fill elision w/undefined, unless we can just skip over to a value
399 for (int i = 0; i < el->elision; i++) {
400 OpValue ind = OpValue::immInt32(pos);
401 CodeGen::emitOp(comp, Op_BracketPutKnownObject, 0, &arr, &ind, &und);
402 ++pos;
403 }
404 } else {
405 pos += el->elision;
406 }
407
408 if (el->node) {
409 OpValue val = el->node->generateEvalCode(comp);
410 OpValue ind = OpValue::immInt32(pos);
411 CodeGen::emitOp(comp, Op_BracketPutKnownObject, 0, &arr, &ind, &val);
412 ++pos;
413 }
414 }
415
416 for (int i = 0; i < elision; i++) {
417 OpValue ind = OpValue::immInt32(pos);
418 CodeGen::emitOp(comp, Op_BracketPutKnownObject, 0, &arr, &ind, &und);
419 ++pos;
420 }
421
422 return arr;
423}
424
425OpValue ObjectLiteralNode::generateEvalCode(CompileState* comp)
426{
427 OpValue obj;
428 CodeGen::emitOp(comp, Op_NewObject, &obj);
429
430 for (PropertyListNode* entry = list.get(); entry; entry = entry->next.get()) {
431 PropertyNode* prop = entry->node.get();
432 OpValue name = OpValue::immIdent(&prop->name->str);
433 OpValue val = prop->assign->generateEvalCode(comp);
434
435 switch (prop->type) {
436 case PropertyNode::Getter:
437 CodeGen::emitOp(comp, Op_DefineGetter, 0, &obj, &name, &val);
438 break;
439 case PropertyNode::Setter:
440 CodeGen::emitOp(comp, Op_DefineSetter, 0, &obj, &name, &val);
441 break;
442 case PropertyNode::Constant:
443 CodeGen::emitOp(comp, Op_SymPutKnownObject, 0, &obj, &name, &val);
444 break;
445 }
446 }
447
448 return obj;
449}
450
451// ------------------------------ BracketAccessorNode --------------------------------
452OpValue BracketAccessorNode::generateEvalCode(CompileState* comp)
453{
454 OpValue ret;
455 OpValue base = expr1->generateEvalCode(comp);
456 OpValue index = expr2->generateEvalCode(comp);
457
458 // ### optimize foo["bar"] ?
459 CodeGen::emitOp(comp, Op_BracketGet, &ret, &base, &index);
460 return ret;
461}
462
463CompileReference* BracketAccessorNode::generateRefBind(CompileState* comp)
464{
465 // Per 11.2.1, the following steps must happen when evaluating foo[bar]
466 // 1) eval foo
467 // 2) eval bar
468 // 3) call toObject on [[foo]]
469 // 4) call toString on [[bar]]
470 // ... all of which are part of reference evaluation. Fun.
471 // ### FIXME FIXME FIXME: we don't do step 4 in right spot yet!
472 CompileReference* ref = new CompileReference;
473 OpValue baseV = expr1->generateEvalCode(comp);
474 ref->indexVal = expr2->generateEvalCode(comp);
475 CodeGen::emitOp(comp, Op_ToObject, &ref->baseObj, &baseV);
476 return ref;
477}
478
479CompileReference* BracketAccessorNode::generateRefRead(CompileState* comp, OpValue* out)
480{
481 CompileReference* ref = new CompileReference;
482
483 // ### As above, this sequence should store the toString on reference, if there will be a follow up
484 // write --- need a hint for that..
485 OpValue baseV = expr1->generateEvalCode(comp);
486 ref->indexVal = expr2->generateEvalCode(comp);
487
488 // Store the object for future use.
489 OpValue baseReg;
490 comp->requestTemporary(OpType_value, &ref->baseObj, &baseReg);
491
492 CodeGen::emitOp(comp, Op_BracketGetAndBind, out, &baseReg, &baseV, &ref->indexVal);
493 return ref;
494}
495
496void BracketAccessorNode::generateRefWrite(CompileState* comp,
497 CompileReference* ref, OpValue& valToStore)
498{
499 CodeGen::emitOp(comp, Op_BracketPutKnownObject, 0, &ref->baseObj, &ref->indexVal, &valToStore);
500}
501
502OpValue BracketAccessorNode::generateRefDelete(CompileState* comp)
503{
504 OpValue base = expr1->generateEvalCode(comp);
505 OpValue index = expr2->generateEvalCode(comp);
506
507 OpValue out;
508 CodeGen::emitOp(comp, Op_BracketDelete, &out, &base, &index);
509 return out;
510}
511
512void BracketAccessorNode::generateRefFunc(CompileState* comp, OpValue* funOut, OpValue* thisOut)
513{
514 OpValue baseV = expr1->generateEvalCode(comp);
515 OpValue indexV = expr2->generateEvalCode(comp);
516
517 // We need to memorize the toObject for 'this'
518 OpValue baseReg;
519 comp->requestTemporary(OpType_value, thisOut, &baseReg);
520
521 CodeGen::emitOp(comp, Op_BracketGetAndBind, funOut, &baseReg, &baseV, &indexV);
522}
523
524// ------------------------------ DotAccessorNode --------------------------------
525
526// ECMA 11.2.1b
527OpValue DotAccessorNode::generateEvalCode(CompileState* comp)
528{
529 OpValue ret;
530 OpValue base = expr->generateEvalCode(comp);
531 OpValue varName = OpValue::immIdent(&ident);
532 CodeGen::emitOp(comp, Op_SymGet, &ret, &base, &varName);
533 return ret;
534}
535
536CompileReference* DotAccessorNode::generateRefBind(CompileState* comp)
537{
538 CompileReference* ref = new CompileReference;
539 OpValue baseV = expr->generateEvalCode(comp);
540 CodeGen::emitOp(comp, Op_ToObject, &ref->baseObj, &baseV);
541 return ref;
542}
543
544CompileReference* DotAccessorNode::generateRefRead(CompileState* comp, OpValue* out)
545{
546 CompileReference* ref = new CompileReference;
547 OpValue baseV = expr->generateEvalCode(comp);
548 OpValue baseReg;
549 OpValue varName = OpValue::immIdent(&ident);
550 comp->requestTemporary(OpType_value, &ref->baseObj, &baseReg);
551 CodeGen::emitOp(comp, Op_SymGetAndBind, out, &baseReg, &baseV, &varName);
552 return ref;
553}
554
555void DotAccessorNode::generateRefWrite(CompileState* comp,
556 CompileReference* ref, OpValue& valToStore)
557{
558 OpValue varName = OpValue::immIdent(&ident);
559 CodeGen::emitOp(comp, Op_SymPutKnownObject, 0, &ref->baseObj, &varName, &valToStore);
560}
561
562OpValue DotAccessorNode::generateRefDelete(CompileState* comp)
563{
564 OpValue base = expr->generateEvalCode(comp);
565 OpValue varName = OpValue::immIdent(&ident);
566 OpValue out;
567 CodeGen::emitOp(comp, Op_SymDelete, &out, &base, &varName);
568 return out;
569}
570
571void DotAccessorNode::generateRefFunc(CompileState* comp, OpValue* funOut, OpValue* thisOut)
572{
573 OpValue baseV = expr->generateEvalCode(comp);
574 OpValue varName = OpValue::immIdent(&ident);
575
576 OpValue baseReg;
577 comp->requestTemporary(OpType_value, thisOut, &baseReg);
578 CodeGen::emitOp(comp, Op_SymGetAndBind, funOut, &baseReg, &baseV, &varName);
579}
580
581// ------------------ ........
582
583void ArgumentsNode::generateEvalArguments(CompileState* comp)
584{
585 WTF::Vector<OpValue> args;
586
587 // We need evaluate arguments and push them in separate steps as there may be
588 // function/ctor calls inside.
589 for (ArgumentListNode* arg = list.get(); arg; arg = arg->next.get()) {
590 args.append(arg->expr->generateEvalCode(comp));
591 }
592
593 CodeGen::emitOp(comp, Op_ClearArgs, 0);
594
595 size_t c = 0;
596 while (c < args.size()) {
597 if (c + 3 <= args.size()) {
598 CodeGen::emitOp(comp, Op_Add3Arg, 0, &args[c], &args[c+1], &args[c+2]);
599 c += 3;
600 } else if (c + 2 <= args.size()) {
601 CodeGen::emitOp(comp, Op_Add2Arg, 0, &args[c], &args[c+1]);
602 c += 2;
603 } else {
604 CodeGen::emitOp(comp, Op_AddArg, 0, &args[c]);
605 c += 1;
606 }
607 }
608}
609
610OpValue NewExprNode::generateEvalCode(CompileState* comp)
611{
612 OpValue v = expr->generateEvalCode(comp);
613
614 if (args)
615 args->generateEvalArguments(comp);
616 else
617 CodeGen::emitOp(comp, Op_ClearArgs, 0);
618
619 OpValue out;
620 CodeGen::emitOp(comp, Op_CtorCall, &out, &v);
621 return out;
622}
623
624OpValue FunctionCallValueNode::generateEvalCode(CompileState* comp)
625{
626 OpValue v = expr->generateEvalCode(comp);
627 args->generateEvalArguments(comp);
628
629 OpValue out;
630 CodeGen::emitOp(comp, Op_FunctionCall, &out, &v, comp->globalScope());
631 return out;
632}
633
634OpValue FunctionCallReferenceNode::generateEvalCode(CompileState* comp)
635{
636 Node* cand = expr->nodeInsideAllParens();
637 ASSERT(cand->isLocation());
638 LocationNode* loc = static_cast<LocationNode*>(cand);
639
640 OpValue funVal, thisVal;
641 loc->generateRefFunc(comp, &funVal, &thisVal);
642 args->generateEvalArguments(comp);
643
644 OpValue out;
645 CodeGen::emitOp(comp, Op_FunctionCall, &out, &funVal, &thisVal);
646 return out;
647}
648
649OpValue PostfixNode::generateEvalCode(CompileState* comp)
650{
651 Node* cand = m_loc->nodeInsideAllParens();
652 if (!cand->isLocation()) {
653 emitReferenceError(comp, this,
654 m_oper == OpPlusPlus ?
655 "Postfix ++ operator applied to value that is not a reference." :
656 "Postfix -- operator applied to value that is not a reference.");
657 return OpValue::immValue(jsUndefined());
658 }
659
660 LocationNode* loc = static_cast<LocationNode*>(cand);
661
662 // ### we want to fold this in if the kid is a local -- any elegant way?
663
664 //read current value
665 OpValue curV;
666 CompileReference* ref = loc->generateRefRead(comp, &curV);
667
668 // We need it to be a number..
669 if (curV.type != OpType_number) {
670 OpValue numVal;
671 CodeGen::emitConvertTo(comp, &curV, OpType_number, &numVal);
672 curV = numVal;
673 }
674
675 // Compute new one
676 OpValue newV;
677 CodeGen::emitOp(comp, (m_oper == OpPlusPlus) ? Op_Add1 : Op_Sub1,
678 &newV, &curV);
679
680 loc->generateRefWrite(comp, ref, newV);
681 delete ref;
682 return curV;
683}
684
685OpValue DeleteReferenceNode::generateEvalCode(CompileState* comp)
686{
687 return loc->generateRefDelete(comp);
688}
689
690OpValue DeleteValueNode::generateEvalCode(CompileState*)
691{
692 return OpValue::immBool(true);
693}
694
695OpValue VoidNode::generateEvalCode(CompileState* comp)
696{
697 (void)expr->generateEvalCode(comp);
698 return OpValue::immValue(jsUndefined());
699}
700
701OpValue TypeOfVarNode::generateEvalCode(CompileState* comp)
702{
703 OpValue v = loc->valueForTypeOf(comp);
704
705 OpValue out;
706 CodeGen::emitOp(comp, Op_TypeOf, &out, &v);
707 return out;
708}
709
710OpValue TypeOfValueNode::generateEvalCode(CompileState* comp)
711{
712 OpValue v = m_expr->generateEvalCode(comp);
713 OpValue typeOfV;
714 CodeGen::emitOp(comp, Op_TypeOf, &typeOfV, &v);
715 return typeOfV;
716}
717
718OpValue PrefixNode::generateEvalCode(CompileState* comp)
719{
720 Node* cand = m_loc->nodeInsideAllParens();
721 if (!cand->isLocation()) {
722 emitReferenceError(comp, this,
723 m_oper == OpPlusPlus ?
724 "Prefix ++ operator applied to value that is not a reference." :
725 "Prefix -- operator applied to value that is not a reference.");
726 return OpValue::immValue(jsUndefined());
727 }
728
729 LocationNode* loc = static_cast<LocationNode*>(cand);
730
731 // ### we want to fold this in if the kid is a local -- any elegant way?
732
733 //read current value
734 OpValue curV;
735 CompileReference* ref = loc->generateRefRead(comp, &curV);
736
737 OpValue newV;
738 CodeGen::emitOp(comp, (m_oper == OpPlusPlus) ? Op_Add1 : Op_Sub1,
739 &newV, &curV);
740
741 // Write out + return new value.
742 loc->generateRefWrite(comp, ref, newV);
743 delete ref;
744 return newV;
745}
746
747OpValue UnaryPlusNode::generateEvalCode(CompileState* comp)
748{
749 // This is basically just a number cast
750 OpValue curV = expr->generateEvalCode(comp);
751
752 if (curV.type != OpType_number) {
753 OpValue numVal;
754 CodeGen::emitConvertTo(comp, &curV, OpType_number, &numVal);
755 curV = numVal;
756 }
757
758 return curV;
759}
760
761OpValue NegateNode::generateEvalCode(CompileState* comp)
762{
763 OpValue v = expr->generateEvalCode(comp);
764 OpValue negV;
765 CodeGen::emitOp(comp, Op_Neg, &negV, &v);
766 return negV;
767}
768
769OpValue BitwiseNotNode::generateEvalCode(CompileState* comp)
770{
771 OpValue v = expr->generateEvalCode(comp);
772 OpValue out;
773 CodeGen::emitOp(comp, Op_BitNot, &out, &v);
774 return out;
775}
776
777OpValue LogicalNotNode::generateEvalCode(CompileState* comp)
778{
779 OpValue v = expr->generateEvalCode(comp);
780 OpValue out;
781 CodeGen::emitOp(comp, Op_LogicalNot, &out, &v);
782 return out;
783}
784
785OpValue BinaryOperatorNode::generateEvalCode(CompileState* comp)
786{
787 OpValue v1 = expr1->generateEvalCode(comp);
788 OpValue v2 = expr2->generateEvalCode(comp);
789
790 OpName codeOp; // ### could perhaps skip conversion entirely,
791 // and set these in the parser?
792 switch (oper) {
793 case OpMult:
794 // operator *
795 codeOp = Op_Mult;
796 break;
797 case OpDiv:
798 // operator /
799 codeOp = Op_Div;
800 break;
801 case OpMod:
802 // operator %
803 codeOp = Op_Mod;
804 break;
805 case OpPlus:
806 // operator +
807 codeOp = Op_Add;
808 break;
809 case OpMinus:
810 // operator -
811 codeOp = Op_Sub;
812 break;
813 case OpLShift:
814 // operator <<
815 codeOp = Op_LShift;
816 break;
817 case OpRShift:
818 // operator >>
819 codeOp = Op_RShift;
820 break;
821 case OpURShift:
822 // operator >>>
823 codeOp = Op_URShift;
824 break;
825 case OpLess:
826 // operator <
827 codeOp = Op_Less;
828 break;
829 case OpGreaterEq:
830 // operator >=
831 codeOp = Op_GreaterEq;
832 break;
833 case OpGreater:
834 // operator >
835 codeOp = Op_Greater;
836 break;
837 case OpLessEq:
838 // operator <=
839 codeOp = Op_LessEq;
840 break;
841 case OpEqEq:
842 // operator ==
843 codeOp = Op_EqEq;
844 break;
845 case OpNotEq:
846 // operator !=
847 codeOp = Op_NotEq;
848 break;
849 case OpStrEq:
850 // operator ===
851 codeOp = Op_StrEq;
852 break;
853 case OpStrNEq:
854 // operator !==
855 codeOp = Op_StrNEq;
856 break;
857 case OpBitAnd:
858 // operator &
859 codeOp = Op_BitAnd;
860 break;
861 case OpBitXOr:
862 // operator ^
863 codeOp = Op_BitXOr;
864 break;
865 case OpBitOr:
866 // operator |
867 codeOp = Op_BitOr;
868 break;
869 case OpIn:
870 codeOp = Op_In;
871 break;
872 case OpInstanceOf:
873 codeOp = Op_InstanceOf;
874 break;
875
876 default:
877 assert(!"BinaryOperatorNode: unhandled switch case");
878 }
879
880 OpValue out;
881 CodeGen::emitOp(comp, codeOp, &out, &v1, &v2);
882 return out;
883}
884
885OpValue BinaryLogicalNode::generateEvalCode(CompileState* comp)
886{
887 // This is somewhat ugly since we can't patchup labels in already generated
888 // code, and don't know the types in advance. It could also benefit from
889 // a type hint, since it's easier if we only want a bool, which is quite common
890
891 OpValue a = expr1->generateEvalCode(comp);
892
893 // Make a register for storing the result, and put 'a' there, as out first guess.
894 OpValue aVal, aReg;
895 comp->requestTemporary(a.type, &aVal, &aReg);
896 CodeGen::emitRegStore(comp, &aReg, &a);
897
898 // Is this enough to shortcircuit?
899 // if op is && and a is false, we jump out, ditto
900 // for || and true.
901 Addr jumpToShortCircuit = CodeGen::emitOp(comp, oper == OpAnd ? Op_IfNotJump : Op_IfJump,
902 0, &a, OpValue::dummyAddr());
903
904 // Now, generate the code for b...
905 OpValue b = expr2->generateEvalCode(comp);
906
907 // Hopefully, either the types match, or the result slot is already a value,
908 // so we can just promote b (which will happen automatically to produce param for Op_RegPutVal)
909 if (a.type == b.type || a.type == OpType_value) {
910 if (a.type == OpType_value)
911 CodeGen::emitOp(comp, Op_RegPutValue, 0, &aReg, &b);
912 else
913 CodeGen::emitRegStore(comp, &aReg, &b);
914 CodeGen::patchJumpToNext(comp, jumpToShortCircuit, 1);
915 return aVal;
916 } else {
917 // We need to promote 'a' as well, which means we need to skip over the code jumpToShortCircuit
918 // went to after handling store of 'b'.
919
920 // Get a new register for the result, put b there..
921 OpValue resVal, resReg;
922 comp->requestTemporary(OpType_value, &resVal, &resReg);
923 CodeGen::emitOp(comp, Op_RegPutValue, 0, &resReg, &b);
924
925 // skip to after a promotion..
926 Addr jumpToAfter = CodeGen::emitOp(comp, Op_Jump, 0, OpValue::dummyAddr());
927
928 // a's promotion goes here..
929 CodeGen::patchJumpToNext(comp, jumpToShortCircuit, 1);
930 CodeGen::emitOp(comp, Op_RegPutValue, 0, &resReg, &a);
931
932 // now we're after it..
933 CodeGen::patchJumpToNext(comp, jumpToAfter, 0);
934
935 return resVal;
936 }
937}
938
939OpValue ConditionalNode::generateEvalCode(CompileState* comp)
940{
941 // As above, we have some difficulty here, since we do not have a way of knowing
942 // the types in advance, but since we can't reasonably speculate on them both being bool,
943 // we just always produce a value.
944 OpValue resVal, resReg;
945
946 // Evaluate conditional, and jump..
947 OpValue v = logical->generateEvalCode(comp);
948 Addr jumpToElse = CodeGen::emitOp(comp, Op_IfNotJump, 0, &v, OpValue::dummyAddr());
949
950 // True branch
951 OpValue v1out = expr1->generateEvalCode(comp);
952
953 // Request a temporary for the result. (We can't reuse any, since it may be a variable!)
954 // ### perhaps do an isTemporary check here?
955 comp->requestTemporary(OpType_value, &resVal, &resReg);
956 CodeGen::emitOp(comp, Op_RegPutValue, 0, &resReg, &v1out);
957
958 Addr jumpToAfter = CodeGen::emitOp(comp, Op_Jump, 0, OpValue::dummyAddr());
959
960 // Jump to else goes here.
961 CodeGen::patchJumpToNext(comp, jumpToElse, 1);
962
963 // : part..
964 OpValue v2out = expr2->generateEvalCode(comp);
965 CodeGen::emitOp(comp, Op_RegPutValue, 0, &resReg, &v2out);
966
967 // After everything
968 CodeGen::patchJumpToNext(comp, jumpToAfter, 0);
969
970 return resVal;
971}
972
973OpValue FuncExprNode::generateEvalCode(CompileState* comp)
974{
975 comp->setNeedsClosures();
976
977 OpValue out;
978 OpValue nameV = OpValue::immIdent(&ident);
979 OpValue bodyV = OpValue::immNode(body.get());
980 CodeGen::emitOp(comp, Op_EvalFuncExpr, &out, &nameV, &bodyV);
981 return out;
982}
983
984void FuncDeclNode::generateExecCode(CompileState* comp)
985{
986 comp->setNeedsClosures();
987
988 // No executable content...
989}
990
991void SourceElementsNode::generateExecCode(CompileState* comp)
992{
993 node->generateExecCode(comp);
994
995 // ### FIXME: how do we do proper completion?
996 for (SourceElementsNode *n = next.get(); n; n = n->next.get()) {
997 n->node->generateExecCode(comp);
998 }
999}
1000
1001OpValue AssignNode::generateEvalCode(CompileState* comp)
1002{
1003 Node* cand = m_loc->nodeInsideAllParens();
1004 if (!cand->isLocation()) {
1005 emitReferenceError(comp, this, "Left side of assignment is not a reference.");
1006 return OpValue::immValue(jsUndefined());
1007 }
1008
1009 LocationNode* loc = static_cast<LocationNode*>(cand);
1010
1011 CompileReference* ref;
1012
1013 OpValue v;
1014 if (m_oper == OpEqual) {
1015 ref = loc->generateRefBind(comp);
1016 v = m_right->generateEvalCode(comp);
1017 } else {
1018 OpValue v1;
1019 ref = loc->generateRefRead(comp, &v1);
1020 OpValue v2 = m_right->generateEvalCode(comp);
1021
1022 OpName codeOp;
1023 switch (m_oper) {
1024 case OpMultEq:
1025 codeOp = Op_Mult;
1026 break;
1027 case OpDivEq:
1028 codeOp = Op_Div;
1029 break;
1030 case OpModEq:
1031 codeOp = Op_Mod;
1032 break;
1033 case OpPlusEq:
1034 codeOp = Op_Add;
1035 break;
1036 case OpMinusEq:
1037 codeOp = Op_Sub;
1038 break;
1039 case OpLShift:
1040 codeOp = Op_LShift;
1041 break;
1042 case OpRShift:
1043 codeOp = Op_RShift;
1044 break;
1045 case OpURShift:
1046 codeOp = Op_URShift;
1047 break;
1048 case OpAndEq:
1049 codeOp = Op_BitAnd;
1050 break;
1051 case OpXOrEq:
1052 codeOp = Op_BitXOr;
1053 break;
1054 case OpOrEq:
1055 codeOp = Op_BitOr;
1056 break;
1057 default:
1058 ASSERT(0);
1059 }
1060
1061 CodeGen::emitOp(comp, codeOp, &v, &v1, &v2);
1062 }
1063
1064 loc->generateRefWrite(comp, ref, v);
1065
1066 delete ref;
1067 return v;
1068}
1069
1070OpValue CommaNode::generateEvalCode(CompileState* comp)
1071{
1072 expr1->generateEvalCode(comp);
1073 return expr2->generateEvalCode(comp);
1074}
1075
1076OpValue AssignExprNode::generateEvalCode(CompileState* comp)
1077{
1078 return expr->generateEvalCode(comp);
1079}
1080
1081void VarDeclNode::generateCode(CompileState* comp)
1082{
1083 // We only care about things which have an initializer ---
1084 // everything else is a no-op at execution time,
1085 // and only makes a difference at processVarDecl time
1086 if (init) {
1087 if (comp->inNestedScope()) {
1088 // We need to do the full lookup mess, which includes doing split binding and store
1089 OpValue quiet = OpValue::immNode(0);
1090 OpValue varName = OpValue::immIdent(&ident);
1091 OpValue base;
1092 CodeGen::emitOp(comp, Op_ScopeLookup, &base, &varName, &quiet);
1093
1094 OpValue val = init->generateEvalCode(comp);
1095 CodeGen::emitOp(comp, Op_SymPutKnownObject, 0, &base, &varName, &val);
1096 return;
1097 }
1098
1099 OpValue val = init->generateEvalCode(comp);
1100 size_t localID = comp->functionBody()->lookupSymbolID(ident);
1101 if (localID == missingSymbolMarker()) {
1102 // Generate a symbolic assignment, always to local scope
1103 OpValue identV = OpValue::immIdent(&ident);
1104 CodeGen::emitOp(comp, Op_SymPutKnownObject, 0, comp->localScope(), &identV, &val);
1105 } else {
1106 // Store to the local..
1107 OpValue dest = comp->localWriteRef(comp->codeBlock(), localID);
1108 CodeGen::emitOp(comp, Op_RegPutValue, 0, &dest, &val);
1109 }
1110 } // if initializer..
1111}
1112
1113OpValue VarDeclListNode::generateEvalCode(CompileState* comp)
1114{
1115 for (VarDeclListNode *n = this; n; n = n->next.get())
1116 n->var->generateCode(comp);
1117
1118 return OpValue::immInt32(0); // unused..
1119}
1120
1121void VarStatementNode::generateExecCode(CompileState* comp)
1122{
1123 generateDebugInfoIfNeeded(comp);
1124 next->generateEvalCode(comp);
1125}
1126
1127void BlockNode::generateExecCode(CompileState* comp)
1128{
1129 if (source) {
1130 generateDebugInfoIfNeeded(comp);
1131 source->generateExecCode(comp);
1132 }
1133}
1134
1135void EmptyStatementNode::generateExecCode(CompileState*)
1136{}
1137
1138void ExprStatementNode::generateExecCode(CompileState* comp)
1139{
1140 generateDebugInfoIfNeeded(comp);
1141 OpValue val = expr->generateEvalCode(comp);
1142
1143 // Update the result for eval or global code
1144 if (comp->codeType() != FunctionCode)
1145 CodeGen::emitOp(comp, Op_RegPutValue, 0, comp->evalResultReg(), &val);
1146}
1147
1148void IfNode::generateExecCode(CompileState* comp)
1149{
1150 generateDebugInfoIfNeeded(comp);
1151
1152 // eval the condition
1153 OpValue cond = expr->generateEvalCode(comp);
1154
1155 // If condition is not true, jump to after or else..
1156 Addr afterTrueJmp = CodeGen::emitOp(comp, Op_IfNotJump, 0, &cond, OpValue::dummyAddr());
1157
1158 // Emit the body of true...
1159 statement1->generateExecCode(comp);
1160
1161 // If we have an else, add in a jump to skip over it.
1162 Addr afterAllJmp = 0;
1163 if (statement2)
1164 afterAllJmp = CodeGen::emitOp(comp, Op_Jump, 0, OpValue::dummyAddr());
1165
1166 // This is where we go if true fails --- else, or afterwards.
1167 CodeGen::patchJumpToNext(comp, afterTrueJmp, 1);
1168
1169 if (statement2) {
1170 // Body of else
1171 statement2->generateExecCode(comp);
1172
1173 // Fix up the jump-over code
1174 CodeGen::patchJumpToNext(comp, afterAllJmp, 0);
1175 }
1176}
1177
1178void DoWhileNode::generateExecCode(CompileState* comp)
1179{
1180 generateDebugInfoIfNeeded(comp);
1181 comp->enterLoop(this);
1182
1183 // Body
1184 OpValue beforeBody = OpValue::immAddr(CodeGen::nextPC(comp));
1185 statement->generateExecCode(comp);
1186
1187 // continues go to just before the test..
1188 comp->resolvePendingContinues(this, CodeGen::nextPC(comp));
1189
1190 // test
1191 OpValue cond = expr->generateEvalCode(comp);
1192 CodeGen::emitOp(comp, Op_IfJump, 0, &cond, &beforeBody);
1193
1194 comp->exitLoop(this);
1195}
1196
1197void WhileNode::generateExecCode(CompileState* comp)
1198{
1199 generateDebugInfoIfNeeded(comp);
1200 comp->enterLoop(this);
1201
1202 // Jump to test.
1203 Addr jumpToTest = CodeGen::emitOp(comp, Op_Jump, 0, OpValue::dummyAddr());
1204
1205 // Body
1206 OpValue beforeBody = OpValue::immAddr(CodeGen::nextPC(comp));
1207 statement->generateExecCode(comp);
1208
1209 // continues go to just before the test..
1210 comp->resolvePendingContinues(this, CodeGen::nextPC(comp));
1211
1212 // patch up the destination of the initial jump to test
1213 CodeGen::patchJumpToNext(comp, jumpToTest, 0);
1214
1215 // test
1216 OpValue cond = expr->generateEvalCode(comp);
1217 CodeGen::emitOp(comp, Op_IfJump, 0, &cond, &beforeBody);
1218
1219 comp->exitLoop(this);
1220}
1221
1222void ForNode::generateExecCode(CompileState* comp)
1223{
1224 generateDebugInfoIfNeeded(comp);
1225 comp->enterLoop(this);
1226
1227 // Initializer, if any..
1228 if (expr1)
1229 expr1->generateEvalCode(comp);
1230
1231 // Insert a jump to the loop test (address not yet known)
1232 Addr jumpToTest = CodeGen::emitOp(comp, Op_Jump, 0, OpValue::dummyAddr());
1233
1234 // Generate loop body..
1235 OpValue bodyAddr = OpValue::immAddr(CodeGen::nextPC(comp));
1236 statement->generateExecCode(comp);
1237
1238 // We're about to generate the increment... The continues should go here..
1239 comp->resolvePendingContinues(this, CodeGen::nextPC(comp));
1240
1241 // ### there is a CheckTimeout hook here in nodes.cpp...
1242
1243 // Generate increment...
1244 if (expr3)
1245 expr3->generateEvalCode(comp);
1246
1247 // The test goes here, so patch up the previous jump..
1248 CodeGen::patchJumpToNext(comp, jumpToTest, 0);
1249
1250 // Make the test itself --- if it exists..
1251 if (expr2) {
1252 OpValue cond = expr2->generateEvalCode(comp);
1253 CodeGen::emitOp(comp, Op_IfJump, 0, &cond, &bodyAddr);
1254 } else {
1255 // Just jump back to the body.
1256 CodeGen::emitOp(comp, Op_Jump, 0, &bodyAddr);
1257 }
1258
1259 comp->exitLoop(this);
1260}
1261
1262void ForInNode::generateExecCode(CompileState* comp)
1263{
1264 generateDebugInfoIfNeeded(comp);
1265 if (varDecl)
1266 varDecl->generateCode(comp);
1267
1268 OpValue val = expr->generateEvalCode(comp);
1269 OpValue obj; // version of val after toObject, returned by BeginForIn.
1270
1271 OpValue stateVal, stateReg;
1272 comp->requestTemporary(OpType_value, &stateVal, &stateReg);
1273
1274 // Fetch the property name array..
1275 CodeGen::emitOp(comp, Op_BeginForIn, &obj, &val, &stateReg);
1276
1277 comp->enterLoop(this);
1278
1279 // We put the test first here, since the test and the fetch are combined.
1280 OpValue sym;
1281 Addr fetchNext = CodeGen::emitOp(comp, Op_NextForInEntry, &sym, &obj,
1282 &stateVal, OpValue::dummyAddr());
1283
1284 // Write to the variable
1285 assert (lexpr->isLocation());
1286 LocationNode* loc = static_cast<LocationNode*>(lexpr.get());
1287
1288 CompileReference* ref = loc->generateRefBind(comp);
1289 loc->generateRefWrite (comp, ref, sym);
1290 delete ref;
1291
1292 // Run the body.
1293 statement->generateExecCode(comp);
1294
1295 // Can fix the continues to go back to the test...
1296 comp->resolvePendingContinues(this, fetchNext);
1297
1298 // Jump back..
1299 OpValue backVal = OpValue::immAddr(fetchNext);
1300 CodeGen::emitOp(comp, Op_Jump, 0, &backVal);
1301
1302 // The end address is here (3 argument + return val)
1303 CodeGen::patchJumpToNext(comp, fetchNext, 3);
1304
1305 comp->exitLoop(this);
1306}
1307
1308// Helper for continue/break -- emits stack cleanup call if needed,
1309// and a jump either to the or an ??? exception.
1310static void handleJumpOut(CompileState* comp, Node* dest, ComplType breakOrCont)
1311{
1312 // We scan up the nest stack until we get to the target or
1313 // a try-finally.
1314 int toUnwind = 0;
1315
1316 const WTF::Vector<CompileState::NestInfo>& nests = comp->nestStack();
1317
1318 for (int pos = nests.size() - 1; pos >= 0; --pos) {
1319 switch (nests[pos].type) {
1320 case CompileState::Scope:
1321 case CompileState::OtherCleanup:
1322 ++toUnwind;
1323 break;
1324 case CompileState::TryFinally: {
1325 // Uh-oh. We have to handle this via exception machinery, giving it the
1326 // original address
1327 Addr pc = CodeGen::nextPC(comp);
1328 CodeGen::emitOp(comp, Op_ContBreakInTryFinally, 0, OpValue::dummyAddr());
1329
1330 // Queue destination for resolution
1331 if (breakOrCont == Continue)
1332 comp->addPendingContinue(dest, pc);
1333 else
1334 comp->addPendingBreak(dest, pc);
1335
1336 return;
1337 }
1338
1339 case CompileState::ContBreakTarget:
1340 if (nests[pos].node == dest) {
1341 // Great. We found where we're going! Emit the unwind instr (if needed),
1342 // and the jump.
1343 if (toUnwind) {
1344 OpValue unwind = OpValue::immInt32(toUnwind);
1345 CodeGen::emitOp(comp, Op_UnwindStacks, 0, &unwind);
1346 }
1347
1348 // Emit a jump...
1349 Addr pc = CodeGen::nextPC(comp);
1350 CodeGen::emitOp(comp, Op_Jump, 0, 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 return;
1359 } // if matching destination..
1360 }
1361 }
1362
1363 assert (!"Huh? Unable to find continue/break target in the nest stack");
1364}
1365
1366void ContinueNode::generateExecCode(CompileState* comp)
1367{
1368 generateDebugInfoIfNeeded(comp);
1369 Node* dest = comp->resolveContinueLabel(ident);
1370 if (!dest) {
1371 if (ident.isEmpty())
1372 emitSyntaxError(comp, this, "Illegal continue without target outside a loop.");
1373 else
1374 emitSyntaxError(comp, this, "Invalid label in continue.");
1375 } else {
1376 // Continue can only be used for a loop
1377 if (dest->isIterationStatement()) {
1378 handleJumpOut(comp, dest, Continue);
1379 } else {
1380 emitSyntaxError(comp, this, "Invalid continue target; must be a loop.");
1381 }
1382 }
1383}
1384
1385void BreakNode::generateExecCode(CompileState* comp)
1386{
1387 generateDebugInfoIfNeeded(comp);
1388 Node* dest = comp->resolveBreakLabel(ident);
1389 if (!dest) {
1390 if (ident.isEmpty())
1391 emitSyntaxError(comp, this, "Illegal break without target outside a loop or switch.");
1392 else
1393 emitSyntaxError(comp, this, "Invalid label in break.");
1394 } else {
1395 handleJumpOut(comp, dest, Break);
1396 }
1397}
1398
1399void ReturnNode::generateExecCode(CompileState* comp)
1400{
1401 generateDebugInfoIfNeeded(comp);
1402 OpValue arg;
1403
1404 // Return is invalid in non-function..
1405 if (comp->codeType() != FunctionCode) {
1406 emitSyntaxError(comp, this, "Invalid return.");
1407 return;
1408 }
1409
1410 if (!value)
1411 arg = OpValue::immValue(jsUndefined());
1412 else
1413 arg = value->generateEvalCode(comp);
1414
1415 if (!comp->inTryFinally())
1416 generateExitContextIfNeeded(comp);
1417
1418 CodeGen::emitOp(comp, comp->inTryFinally() ? Op_ReturnInTryFinally : Op_Return, 0, &arg);
1419}
1420
1421void WithNode::generateExecCode(CompileState* comp)
1422{
1423 generateDebugInfoIfNeeded(comp);
1424 // ### this may be too conservative --- it only applies if there is
1425 // a function call within
1426 comp->setNeedsClosures();
1427
1428 OpValue scopeObj = expr->generateEvalCode(comp);
1429
1430 comp->pushNest(CompileState::Scope, this);
1431 CodeGen::emitOp(comp, Op_PushScope, 0, &scopeObj);
1432
1433 statement->generateExecCode(comp);
1434
1435 CodeGen::emitOp(comp, Op_PopScope, 0);
1436 comp->popNest();
1437}
1438
1439void LabelNode::generateExecCode(CompileState* comp)
1440{
1441 if (!comp->pushLabel(label)) {
1442 emitSyntaxError(comp, this, "Duplicated label found.");
1443 return;
1444 }
1445
1446 if (!statement->isLabelNode()) { // we're the last label..
1447 comp->pushNest(CompileState::ContBreakTarget, statement.get());
1448 comp->bindLabels(statement.get());
1449 }
1450
1451 // Generate code for stuff inside the label...
1452 statement->generateExecCode(comp);
1453
1454 // Fix up any breaks..
1455 if (!statement->isLabelNode()) {
1456 comp->popNest();
1457 comp->resolvePendingBreaks(statement.get(), CodeGen::nextPC(comp));
1458 }
1459
1460 comp->popLabel();
1461}
1462
1463void ThrowNode::generateExecCode(CompileState* comp)
1464{
1465 generateDebugInfoIfNeeded(comp);
1466 OpValue projectile = expr->generateEvalCode(comp);
1467 CodeGen::emitOp(comp, Op_Throw, 0, &projectile);
1468}
1469
1470void TryNode::generateExecCode(CompileState* comp)
1471{
1472 generateDebugInfoIfNeeded(comp);
1473 // ### this may be too conservative --- it only applies if there is
1474 // a function call within the catch
1475 comp->setNeedsClosures();
1476
1477 // Set the catch handler, run the try clause, pop the try handler..
1478 Addr setCatchHandler = CodeGen::emitOp(comp, Op_PushExceptionHandler, 0, OpValue::dummyAddr());
1479 comp->pushNest(finallyBlock ? CompileState::TryFinally : CompileState::OtherCleanup);
1480
1481 tryBlock->generateExecCode(comp);
1482
1483 CodeGen::emitOp(comp, Op_PopExceptionHandler);
1484 comp->popNest();
1485
1486 // Jump over the catch if try is OK
1487 Addr jumpOverCatch = 0;
1488 if (catchBlock)
1489 jumpOverCatch = CodeGen::emitOp(comp, Op_Jump, 0, OpValue::dummyAddr());
1490
1491 // Exceptions would go here --- either in a catch or a finally.
1492 CodeGen::patchJumpToNext(comp, setCatchHandler, 0);
1493
1494 Addr catchToFinallyEH = 0;
1495 if (catchBlock) {
1496 // If there is a finally block, that acts as an exception handler for the catch;
1497 // we need to set it before entering the catch scope, so the cleanup entries for that
1498 // are on top. Also, that's needed because if the inside raised a non-exception
1499 // continuation, EnterCatch will re-raise it.
1500 if (finallyBlock) {
1501 catchToFinallyEH = CodeGen::emitOp(comp, Op_PushExceptionHandler, 0, OpValue::dummyAddr());
1502 comp->pushNest(CompileState::TryFinally);
1503 }
1504
1505 // Emit the catch.. Note: the unwinder has already popped the catch handler entry,
1506 // but the exception object is still set, since we need to make a scope for it.
1507 // EnterCatch would do that for us, given the name
1508 OpValue catchVar = OpValue::immIdent(&exceptionIdent);
1509 CodeGen::emitOp(comp, Op_EnterCatch, 0, &catchVar);
1510 comp->pushNest(CompileState::Scope);
1511
1512 catchBlock->generateExecCode(comp);
1513
1514 // If needed, cleanup the binding to finally, and always cleans the catch scope
1515 CodeGen::emitOp(comp, Op_ExitCatch);
1516 comp->popNest();
1517
1518 if (finallyBlock) {
1519 CodeGen::emitOp(comp, Op_PopExceptionHandler);
1520 comp->popNest();
1521 }
1522
1523 // after an OK 'try', we always go to finally, if any, which needs an op if there is a catch block
1524 CodeGen::patchJumpToNext(comp, jumpOverCatch, 0);
1525 }
1526
1527
1528 if (finallyBlock) {
1529 if (catchBlock) // if a catch was using us an EH, patch that instruction to here
1530 CodeGen::patchJumpToNext(comp, catchToFinallyEH, 0);
1531
1532 CodeGen::emitOp(comp, Op_DeferCompletion);
1533 comp->pushNest(CompileState::OtherCleanup);
1534
1535 finallyBlock->generateExecCode(comp);
1536
1537 OpValue otherTryFinally = OpValue::immBool(comp->inTryFinally());
1538
1539 if (exitContextNeeded(comp)) {
1540 OpValue ourNode = OpValue::immNode(comp->functionBody());
1541 CodeGen::emitOp(comp, Op_ReactivateCompletionDebug, 0, &otherTryFinally, &ourNode);
1542 } else {
1543 CodeGen::emitOp(comp, Op_ReactivateCompletion, 0, &otherTryFinally);
1544 }
1545 comp->popNest();
1546 }
1547}
1548
1549void FunctionBodyNode::generateExecCode(CompileState* comp)
1550{
1551 // Load scope, global and 'this' pointers.
1552 OpValue scopeVal, scopeReg,
1553 globalVal, globalReg,
1554 thisVal, thisReg;
1555
1556 comp->requestTemporary(OpType_value, &scopeVal, &scopeReg);
1557 comp->requestTemporary(OpType_value, &globalVal, &globalReg);
1558 comp->requestTemporary(OpType_value, &thisVal, &thisReg);
1559
1560 CodeGen::emitOp(comp, Op_Preamble, 0, &scopeReg, &globalReg, &thisReg);
1561
1562 comp->setPreloadRegs(&scopeVal, &globalVal, &thisVal);
1563
1564 OpValue evalResReg, evalResVal;
1565 if (comp->codeType() != FunctionCode) {
1566 comp->requestTemporary(OpType_value, &evalResVal, &evalResReg);
1567 comp->setEvalResultRegister(&evalResReg);
1568
1569 // There is no need to initialize this as everything will be set to undefined anyway
1570 } else {
1571 if (comp->compileType() == Debug) {
1572 OpValue ourNode = OpValue::immNode(this);
1573 CodeGen::emitOp(comp, Op_EnterDebugContext, 0, &ourNode);
1574 }
1575 }
1576
1577 // Set unwind..
1578 Addr unwind = CodeGen::emitOp(comp, Op_PushExceptionHandler, 0, OpValue::dummyAddr());
1579
1580 // Generate body...
1581 BlockNode::generateExecCode(comp);
1582
1583 // Make sure we exit!
1584 if (comp->codeType() != FunctionCode) {
1585 CodeGen::emitOp(comp, Op_Return, 0, &evalResVal);
1586 } else {
1587 generateExitContextIfNeeded(comp);
1588 CodeGen::emitOp(comp, Op_Exit);
1589 }
1590
1591 // Unwind stuff..
1592 CodeGen::patchJumpToNext(comp, unwind, 0);
1593 generateExitContextIfNeeded(comp);
1594 CodeGen::emitOp(comp, Op_PropagateException);
1595}
1596
1597void SwitchNode::generateExecCode(CompileState* comp)
1598{
1599 generateDebugInfoIfNeeded(comp);
1600 CaseBlockNode* caseBlock = this->block.get();
1601
1602 // The code we produce has 2 stages: first, we emit all the conditionals, and pick
1603 // the label to jump to (with the jump to the default being last),
1604 // then we just emit all the clauses in the row. The breaks will be
1605 // resolved at the end --- for that, we bind ourselves for label'less break.
1606 comp->pushNest(CompileState::ContBreakTarget, this);
1607 comp->pushDefaultBreak(this);
1608
1609 // What we compare with
1610 OpValue switchOn = expr->generateEvalCode(comp);
1611
1612 WTF::Vector<Addr> list1jumps;
1613 WTF::Vector<Addr> list2jumps;
1614 Addr defJump;
1615
1616 // Jumps for list 1..
1617 for (ClauseListNode* iter = caseBlock->list1.get(); iter; iter = iter->next.get()) {
1618 OpValue ref = iter->clause->expr->generateEvalCode(comp);
1619 OpValue match;
1620 CodeGen::emitOp(comp, Op_StrEq, &match, &switchOn, &ref);
1621
1622 Addr jumpToClause = CodeGen::emitOp(comp, Op_IfJump, 0, &match, OpValue::dummyAddr());
1623 list1jumps.append(jumpToClause);
1624 }
1625
1626 // Jumps for list 2..
1627 for (ClauseListNode* iter = caseBlock->list2.get(); iter; iter = iter->next.get()) {
1628 OpValue ref = iter->clause->expr->generateEvalCode(comp);
1629 OpValue match;
1630 CodeGen::emitOp(comp, Op_StrEq, &match, &switchOn, &ref);
1631
1632 Addr jumpToClause = CodeGen::emitOp(comp, Op_IfJump, 0, &match, OpValue::dummyAddr());
1633 list2jumps.append(jumpToClause);
1634 }
1635
1636 // Jump to default (or after, if there is no default)
1637 defJump = CodeGen::emitOp(comp, Op_Jump, 0, OpValue::dummyAddr());
1638
1639 // Now, we can actually emit the bodies, fixing the addresses as we go
1640 int p = 0;
1641 for (ClauseListNode* iter = caseBlock->list1.get(); iter; iter = iter->next.get()) {
1642 CodeGen::patchJumpToNext(comp, list1jumps[p], 1);
1643 if (iter->clause->source)
1644 iter->clause->source->generateExecCode(comp);
1645 ++p;
1646 }
1647
1648 if (caseBlock->def) {
1649 CodeGen::patchJumpToNext(comp, defJump, 0);
1650 if (caseBlock->def->source)
1651 caseBlock->def->source->generateExecCode(comp);
1652 }
1653
1654 p = 0;
1655 for (ClauseListNode* iter = caseBlock->list2.get(); iter; iter = iter->next.get()) {
1656 CodeGen::patchJumpToNext(comp, list2jumps[p], 1);
1657 if (iter->clause->source)
1658 iter->clause->source->generateExecCode(comp);
1659 ++p;
1660 }
1661
1662 // If we didn't have a default, that jump is to here..
1663 if (!caseBlock->def)
1664 CodeGen::patchJumpToNext(comp, defJump, 0);
1665
1666 // Breaks should go after us..
1667 comp->popDefaultBreak();
1668 comp->popNest();
1669 comp->resolvePendingBreaks(this, CodeGen::nextPC(comp));
1670}
1671
1672void ImportStatement::generateExecCode(CompileState*)
1673{} // handled as a declaration..
1674
1675
1676}
1677
1678// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on; hl c++;
1679