Bug 623379: runtests: Check for java binary before asc invokes (r=fklockii)
[tamarin-stm.git] / eval / eval-cogen-stmt.cpp
blob7473e0243c9dbf22ce0e76c77bffad8f910be2be
1 /* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
2 /* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is [Open Source Virtual Machine.].
18 * The Initial Developer of the Original Code is
19 * Adobe System Incorporated.
20 * Portions created by the Initial Developer are Copyright (C) 2008
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
24 * Adobe AS3 Team
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
40 #include "avmplus.h"
42 #ifdef VMCFG_EVAL
44 #include "eval.h"
46 namespace avmplus
48 namespace RTC
50 using namespace ActionBlockConstants;
52 static bool matchLabel(Ctx* ctx, Str* label)
54 if (label == NULL)
55 return true;
56 switch (ctx->tag) {
57 case CTX_Continue: {
58 Seq<Str*>* labels = ((ContinueCtx*)ctx)->label_names;
59 while (labels != NULL) {
60 if (label == labels->hd)
61 return true;
62 labels = labels->tl;
64 return false;
66 case CTX_Break:
67 return label == ((BreakCtx*)ctx)->label_name;
68 default:
69 return false;
73 void Cogen::unstructuredControlFlow(Ctx* ctx, bool (hit)(Ctx*,void*), void* package, bool jump, SyntaxError msg, uint32_t pos)
75 while (ctx != NULL) {
76 if (hit(ctx, package)) {
77 if (jump)
78 I_jump(((ControlFlowCtx*)ctx)->label);
79 return;
82 if(ctx->tag == CTX_With || ctx->tag == CTX_Catch) {
83 ScopeCtx* ctx1 = (ScopeCtx*)ctx;
84 I_popscope();
85 I_kill(ctx1->scope_reg);
88 if (ctx->tag == CTX_Finally) {
89 FinallyCtx* ctx2 = (FinallyCtx*)ctx;
90 Label* Lreturn = newLabel();
91 uint32_t myReturnLabel = ctx2->addReturnLabel(Lreturn);
92 I_pushuint(emitUInt(myReturnLabel));
93 I_coerce_a();
94 I_setlocal(ctx2->returnreg);
95 I_jump(ctx2->Lfinally);
96 I_label(Lreturn);
98 ctx = ctx->next;
100 compiler->syntaxError(pos, msg);
103 static void restoreScopes(Cogen* cogen, Ctx* ctx)
105 if (ctx == NULL)
106 return;
107 if (ctx->tag != CTX_Function && ctx->tag != CTX_ClassMethod)
108 restoreScopes(cogen, ctx->next);
109 if (ctx->mustPushThis()) {
110 cogen->I_getlocal(0);
111 cogen->I_pushscope();
113 if (ctx->mustPushScopeReg()) {
114 ScopeCtx* ctx1 = (ScopeCtx*)ctx;
115 cogen->I_getlocal(ctx1->scope_reg);
116 if (ctx1->tag == CTX_With)
117 cogen->I_pushwith();
118 else
119 cogen->I_pushscope();
123 // Statement code generators
125 void Program::cogenBody(Cogen* cogen, Ctx* ctx, uint32_t activation_reg)
127 (void)activation_reg;
128 AvmAssert(activation_reg == 0); // Because programs don't have activation records
129 AvmAssert(ctx->tag == CTX_Program);
130 uint32_t capture_reg = ((ProgramCtx*)ctx)->capture_reg;
131 cogen->I_pushundefined();
132 cogen->I_coerce_a();
133 cogen->I_setlocal(capture_reg);
134 for ( Seq<Stmt*>* stmts = this->stmts ; stmts != NULL ; stmts = stmts->tl )
135 stmts->hd->cogen(cogen, ctx);
136 cogen->I_getlocal(capture_reg);
137 cogen->I_returnvalue();
140 void FunctionDefn::cogenBody(Cogen* cogen, Ctx* ctx, uint32_t activation_reg)
142 // Inherit open namespaces
143 VarScopeCtx* vs = ctx->findVarScope();
144 Seq<Namespace*>* openNamespaces = vs->openNamespaces;
145 uint32_t nsset = vs->nsset;
146 if (this->openNamespaces != NULL) {
147 Allocator* allocator = cogen->allocator;
148 Seq<Namespace*>* ons = this->openNamespaces;
149 while (ons != NULL) {
150 openNamespaces = ALLOC(Seq<Namespace*>, (ons->hd, openNamespaces));
151 ons = ons->tl;
153 nsset = cogen->buildNssetWithPublic(openNamespaces);
155 FunctionCtx ctx0(cogen->allocator, nsset, openNamespaces, ctx);
156 ActivationCtx ctx1(activation_reg, &ctx0);
157 Ctx* ctx2 = activation_reg == 0 ? (Ctx*)&ctx0 : (Ctx*)&ctx1;
159 for ( Seq<Stmt*>* stmts = this->stmts ; stmts != NULL ; stmts = stmts->tl )
160 stmts->hd->cogen(cogen, ctx2);
161 cogen->I_returnvoid();
164 void EmptyStmt::cogen(Cogen*, Ctx*)
166 // nothing
169 void BlockStmt::cogen(Cogen* cogen, Ctx* ctx)
171 for ( Seq<Stmt*>* ss = stmts ; ss != NULL ; ss = ss->tl )
172 ss->hd->cogen(cogen, ctx);
175 void LabeledStmt::cogen(Cogen* cogen, Ctx* ctx)
177 Label* L0 = cogen->newLabel();
178 BreakCtx ctx1(L0, ctx, label);
179 stmt->cogen(cogen, &ctx1);
180 cogen->I_label(L0);
183 void ExprStmt::cogen(Cogen* cogen, Ctx* ctx)
185 cogen->I_debugline(pos);
186 expr->cogen(cogen, ctx);
187 Ctx* c;
188 for ( c = ctx ; c->tag != CTX_Program && c->tag != CTX_Function && c->tag != CTX_ClassMethod ; c = c->next )
190 if (c->tag == CTX_Program) {
191 cogen->I_coerce_a();
192 cogen->I_setlocal(((ProgramCtx*)c)->capture_reg);
194 else
195 cogen->I_pop();
198 void IfStmt::cogen(Cogen* cogen, Ctx* ctx)
200 Label* L1 = cogen->newLabel();
201 cogen->I_debugline(pos);
202 expr->cogen(cogen, ctx);
203 cogen->I_iffalse(L1);
204 consequent->cogen(cogen, ctx);
205 if (alternate != NULL) {
206 Label* L2 = cogen->newLabel();
207 cogen->I_jump(L2);
208 cogen->I_label(L1);
209 alternate->cogen(cogen, ctx);
210 cogen->I_label(L2);
212 else
213 cogen->I_label(L1);
216 void WhileStmt::cogen(Cogen* cogen, Ctx* ctx)
218 Label* Lbreak = cogen->newLabel();
219 Label* Lcont = cogen->newLabel();
220 cogen->I_label(Lcont);
221 cogen->I_debugline(pos);
222 expr->cogen(cogen, ctx);
223 cogen->I_iffalse(Lbreak);
224 BreakCtx ctx1(Lbreak, ctx);
225 ContinueCtx ctx2(Lcont, labels, &ctx1);
226 body->cogen(cogen, &ctx2);
227 cogen->I_jump(Lcont);
228 cogen->I_label(Lbreak);
231 void DoWhileStmt::cogen(Cogen* cogen, Ctx* ctx)
233 Label* Lbreak = cogen->newLabel();
234 Label* Lcont = cogen->newLabel();
235 Label* Ltop = cogen->newLabel();
236 cogen->I_label(Ltop);
237 BreakCtx ctx1(Lbreak, ctx);
238 ContinueCtx ctx2(Lcont, labels, &ctx1);
239 body->cogen(cogen, &ctx2);
240 cogen->I_label(Lcont);
241 cogen->I_debugline(pos);
242 expr->cogen(cogen, ctx);
243 cogen->I_iftrue(Ltop);
244 cogen->I_label(Lbreak);
247 void ForStmt::cogen(Cogen* cogen, Ctx* ctx)
249 Label* Lbreak = cogen->newLabel();
250 Label* Lcont = cogen->newLabel();
251 Label* Ltop = cogen->newLabel();
252 if (init != NULL) {
253 init->cogen(cogen, ctx);
254 cogen->I_pop();
256 cogen->I_label(Ltop);
257 if (test != NULL) {
258 test->cogen(cogen, ctx);
259 cogen->I_iffalse(Lbreak);
261 BreakCtx ctx1(Lbreak, ctx);
262 ContinueCtx ctx2(Lcont, labels, &ctx1);
263 body->cogen(cogen, &ctx2);
264 cogen->I_label(Lcont);
265 if (update != NULL) {
266 update->cogen(cogen, ctx);
267 cogen->I_pop();
269 cogen->I_jump(Ltop);
270 cogen->I_label(Lbreak);
273 // Instruction set bug workaround.
275 // In hasnext2, the second argument reg must be known to be 'int', but this
276 // means that if we want to kill it below the loop then all paths past that
277 // kill (from statements enclosing this statement) must have a kill for the
278 // register too. This is just needless complexity. Yet if there is not a
279 // kill at the end of the loop, any enclosing loop will get into trouble
280 // with the verifier because the types along the backward edge to the top of
281 // the loop will not match the initial values into that loop.
283 // To work around this we use two index registers here, and one has a very short
284 // lifetime, just across the hasnext2 instruction, to keep the verifier happy.
286 void ForInStmt::cogen(Cogen* cogen, Ctx* ctx)
288 Allocator* allocator = cogen->allocator;
289 Label* Lbreak = cogen->newLabel();
290 Label* Lcont = cogen->newLabel();
291 Label* Ltop = cogen->newLabel();
293 uint32_t T_obj = cogen->getTemp();
294 uint32_t T_idx = cogen->getTemp();
295 uint32_t T_idx2 = cogen->getTemp();
296 uint32_t T_val = cogen->getTemp();
298 if (init != lhs) {
299 init->cogen(cogen, ctx);
300 cogen->I_pop();
302 obj->cogen(cogen, ctx);
304 cogen->I_coerce_a();
305 cogen->I_setlocal(T_obj);
306 cogen->I_pushbyte(0);
307 cogen->I_coerce_a();
308 cogen->I_setlocal(T_idx);
310 cogen->I_label(Ltop);
312 cogen->I_getlocal(T_idx);
313 cogen->I_coerce_i();
314 cogen->I_setlocal(T_idx2);
315 cogen->I_hasnext2(T_obj, T_idx2);
316 cogen->I_getlocal(T_idx2);
317 cogen->I_coerce_a();
318 cogen->I_setlocal(T_idx);
319 cogen->I_kill(T_idx2);
320 cogen->I_iffalse(Lbreak);
321 cogen->I_getlocal(T_obj);
322 cogen->I_getlocal(T_idx);
323 cogen->I_coerce_i();
325 if (is_each)
326 cogen->I_nextvalue();
327 else
328 cogen->I_nextname();
329 cogen->I_setlocal(T_val);
330 (ALLOC(AssignExpr, (OPR_assign, lhs, ALLOC(RefLocalExpr, (T_val)))))->cogen(cogen, ctx);
331 cogen->I_pop();
333 BreakCtx ctx1(Lbreak, ctx);
334 ContinueCtx ctx2(Lcont, labels, &ctx1);
335 body->cogen(cogen, &ctx2);
337 cogen->I_label(Lcont);
338 cogen->I_jump(Ltop);
340 cogen->I_label(Lbreak);
341 cogen->I_kill(T_val);
342 cogen->I_kill(T_idx);
343 cogen->I_kill(T_obj);
346 static bool hitBreak(Ctx* ctx, void* package)
348 return ctx->tag == CTX_Break && matchLabel(ctx, (Str*)package);
351 void BreakStmt::cogen(Cogen* cogen, Ctx* ctx)
353 cogen->unstructuredControlFlow(ctx,
354 hitBreak,
355 (void*)label,
356 true,
357 (label == NULL ? SYNTAXERR_ILLEGAL_BREAK : SYNTAXERR_BREAK_LABEL_UNDEF),
358 pos);
361 static bool hitContinue(Ctx* ctx, void* package)
363 return ctx->tag == CTX_Continue && matchLabel(ctx, (Str*)package);
366 void ContinueStmt::cogen(Cogen* cogen, Ctx* ctx)
368 cogen->unstructuredControlFlow(ctx,
369 hitContinue,
370 (void*)label,
371 true,
372 (label == NULL ? SYNTAXERR_ILLEGAL_CONTINUE : SYNTAXERR_CONTINUE_LABEL_UNDEF),
373 pos);
376 void ThrowStmt::cogen(Cogen* cogen, Ctx* ctx)
378 cogen->I_debugline(pos);
379 expr->cogen(cogen, ctx);
380 cogen->I_throw();
383 static bool hitFunction(Ctx* ctx, void*)
385 return ctx->tag == CTX_Function;
388 void ReturnStmt::cogen(Cogen* cogen, Ctx* ctx)
390 uint32_t tmp = 0;
392 if (expr != NULL) {
393 cogen->I_debugline(pos);
394 expr->cogen(cogen, ctx);
395 tmp = cogen->getTemp();
396 cogen->I_coerce_a();
397 cogen->I_setlocal(tmp);
400 cogen->unstructuredControlFlow(ctx,
401 hitFunction,
402 NULL,
403 false,
404 SYNTAXERR_RETURN_OUTSIDE_FN);
406 if (expr == NULL)
407 cogen->I_returnvoid();
408 else {
409 cogen->I_getlocal(tmp);
410 cogen->I_kill(tmp);
411 cogen->I_returnvalue();
415 void WithStmt::cogen(Cogen* cogen, Ctx* ctx)
417 uint32_t scopereg = cogen->getTemp();
419 cogen->I_debugline(pos);
420 expr->cogen(cogen, ctx);
421 cogen->I_dup();
422 cogen->I_setlocal(scopereg);
423 cogen->I_pushwith();
424 WithCtx ctx1(scopereg, ctx);
425 body->cogen(cogen, &ctx1);
426 cogen->I_popscope();
427 cogen->I_kill(scopereg);
430 // OPTIMIZEME: we can do better here for switches that are sparse overall (cover a large range)
431 // but which have significant dense segments. Consider a scanner that handles unicode: it may
432 // have a lot of cases for values in the ASCII range and then a few cases to handle unicode
433 // outliers, like unicode space characters. It will fail the 'fast' test but would benefit
434 // from being rewritten as a dense switch whose default case switches further on the outlying
435 // values.
437 void SwitchStmt::cogen(Cogen* cogen, Ctx* ctx)
439 int32_t low, high;
440 if (analyze(&low, &high))
441 cogenFast(cogen, ctx, low, high);
442 else
443 cogenSlow(cogen, ctx);
446 // Trigger lookupswitch if
447 // - all cases are integer constants
448 // - there are at least 4 cases
449 // - all cases in U30 range when biased by low
450 // - at least 1/3 of the values in the switch range are present
452 bool SwitchStmt::analyze(int32_t* low, int32_t* high)
454 uint32_t count = 0;
455 *low = 0x7FFFFFFF;
456 *high = (-0x7FFFFFFF - 1);
458 for ( Seq<CaseClause*>* cases = this->cases ; cases != NULL ; cases = cases->tl ) {
459 Expr* e = cases->hd->expr;
460 if (e == NULL)
462 else if (e->tag() == TAG_literalInt) {
463 int32_t v = ((LiteralInt*)e)->value;
464 *low = min(*low, v);
465 *high = max(*high, v);
466 count++;
468 else
469 return false;
471 const uint32_t ncases = uint32_t(*high - *low + 1);
472 return count >= 4 && ncases < (1<<30) && count * 3 >= ncases;
475 void SwitchStmt::cogenFast(Cogen* cogen, Ctx* ctx, int32_t low, int32_t high)
477 AvmAssert( high > low );
478 AvmAssert( high - low + 1 < (1 << 30) );
480 // Lcase[i] has the label for value (low+i)
481 // Ldefault is the default case (whether or not there is a default in the switch)
483 Compiler* compiler = cogen->compiler;
484 uint32_t tmp = cogen->getTemp();
485 const uint32_t ncases = high - low + 1;
486 Label** Lcase;
487 #ifdef AVMC_STANDALONE
488 Lcase = (Label**)alloca(sizeof(Label*) * ncases);
489 #else
490 MMgc::GC::AllocaAutoPtr _Lcase;
491 Lcase = (Label**)VMPI_alloca(compiler->context->core, _Lcase, sizeof(Label*) * ncases);
492 #endif
493 Label* Ldefault = cogen->newLabel();
494 Label* Lbreak = cogen->newLabel();
495 BreakCtx nctx(Lbreak, ctx);
497 for ( uint32_t i=0 ; i < ncases ; i++ )
498 Lcase[i] = Ldefault;
500 for ( Seq<CaseClause*>* cases = this->cases ; cases != NULL ; cases = cases->tl ) {
501 Expr* e = cases->hd->expr;
502 if (e != NULL) {
503 AvmAssert( e->tag() == TAG_literalInt);
504 int32_t v = ((LiteralInt*)e)->value - low;
505 // A value may be duplicated in the switch; generate only one label, and
506 // observe that the label is only emitted for the first (sequential case),
507 // the others are unreachable except by fallthrough.
508 if (Lcase[v] == Ldefault)
509 Lcase[v] = cogen->newLabel();
513 expr->cogen(cogen, ctx); // switch value
514 cogen->I_coerce_a();
515 cogen->I_setlocal(tmp);
517 // Case clauses are triggered by strict equality, so if the type of the
518 // dispatch value is not int then we definitely won't hit any of the
519 // clauses. Also, test for 'int' tests for integer values in the 'int'
520 // range that are represented as Number, which is what we want here.
522 // Test applicability of the dispatch value. In the absence of static type
523 // information this is fairly painful, we must not have observable side
524 // effects (eg valueOf conversion) or overflow & truncate. The rules are:
526 // if (low != 0) then
527 // if (value is not Number) then skip to default
528 // subtract low from value
529 // if (value is not int) then skip to default
531 // OPTIMIZEME: avoid type tests if the type is known and if we've verified that
532 // the JIT does not perform that optimization. (It might, but it would have to
533 // track the type from the original expression through tmp, and ignore all the
534 // coerce_a instructions, so it's unlikely that it's currently performing it.)
536 if (low != 0) {
537 cogen->I_getlocal(tmp);
538 cogen->I_istype(compiler->ID_Number);
539 cogen->I_iffalse(Ldefault);
541 cogen->I_getlocal(tmp);
542 cogen->I_pushint(cogen->emitInt(low));
543 cogen->I_subtract();
544 cogen->I_coerce_a();
545 cogen->I_setlocal(tmp);
548 cogen->I_getlocal(tmp);
549 cogen->I_istype(compiler->ID_int);
550 cogen->I_iffalse(Ldefault);
552 cogen->I_getlocal(tmp);
553 cogen->I_coerce_i(); // not redundant, the representation could have been Number
554 cogen->I_lookupswitch(Ldefault, Lcase, ncases);
556 for ( Seq<CaseClause*>* cases = this->cases ; cases != NULL ; cases = cases->tl ) {
557 CaseClause* c = cases->hd;
558 Expr* e = c->expr;
560 if (e == NULL) {
561 AvmAssert(Ldefault != NULL);
562 cogen->I_label(Ldefault);
563 Ldefault = NULL;
565 else {
566 AvmAssert(e->tag() == TAG_literalInt);
567 int32_t v = ((LiteralInt*)e)->value - low;
569 // There might be duplicate case selector values, but only the first one counts.
570 if (Lcase[v] != NULL) {
571 cogen->I_label(Lcase[v]);
572 Lcase[v] = NULL;
576 for ( Seq<Stmt*>* stmts = c->stmts ; stmts != NULL ; stmts = stmts->tl )
577 stmts->hd->cogen(cogen, &nctx);
580 if (Ldefault != NULL)
581 cogen->I_label(Ldefault);
583 cogen->I_label(Lbreak);
584 cogen->I_kill(tmp);
587 void SwitchStmt::cogenSlow(Cogen* cogen, Ctx* ctx)
589 uint32_t tmp = cogen->getTemp();
591 Label* Ldefault = NULL;
592 Label* Lnext = cogen->newLabel();
593 Label* Lfall = NULL;
594 Label* Lbreak = cogen->newLabel();
596 cogen->I_debugline(pos);
597 expr->cogen(cogen, ctx);
598 cogen->I_coerce_a();
599 cogen->I_setlocal(tmp);
600 cogen->I_jump(Lnext);
602 BreakCtx ctx1(Lbreak, ctx);
604 for ( Seq<CaseClause*>* cases=this->cases ; cases != NULL ; cases = cases->tl ) {
605 CaseClause* c = cases->hd;
607 if (c->expr == NULL) {
608 AvmAssert(Ldefault == NULL);
609 Ldefault = cogen->newLabel();
610 cogen->I_label(Ldefault); // label default pos
612 else {
613 if (Lnext != NULL) {
614 cogen->I_label(Lnext); // label next pos
615 Lnext = NULL;
617 cogen->I_debugline(c->pos);
618 c->expr->cogen(cogen, ctx); // check for match
619 cogen->I_getlocal(tmp);
620 cogen->I_strictequals();
621 Lnext = cogen->newLabel();
622 cogen->I_iffalse(Lnext);
625 if (Lfall != NULL) { // label fall through pos
626 cogen->I_label(Lfall);
627 Lfall = NULL;
630 for ( Seq<Stmt*>* stmts = c->stmts ; stmts != NULL ; stmts = stmts->tl )
631 stmts->hd->cogen(cogen, &ctx1);
633 Lfall = cogen->newLabel();
634 cogen->I_jump(Lfall); // fall through
637 if (Lnext != NULL)
638 cogen->I_label(Lnext);
639 if (Ldefault != NULL)
640 cogen->I_jump(Ldefault);
641 if (Lfall != NULL)
642 cogen->I_label(Lfall);
643 cogen->I_label(Lbreak);
644 cogen->I_kill(tmp);
647 void TryStmt::cogen(Cogen* cogen, Ctx* ctx)
649 if (finallyblock != NULL)
650 cogenWithFinally(cogen, ctx);
651 else
652 cogenNoFinally(cogen, ctx);
655 // If there's a finally block then:
657 // - there is a generated catch around the try-catch complex with a handler that
658 // handles any exception type
659 // - the handler in that block must visit the finally code and then re-throw if
660 // the finally code returns normally
661 // - code in the try block or the catch block(s) is compiled with a ctx that
662 // records the fact that there is a finally block, so that exits to the outside of
663 // the try/catch block by means of break/continue (labelled or not) must visit
664 // the finally block (in inside-out order if there are several)
665 // - break, continue, and return must look for finally blocks
667 // Visiting the finally block may thus be done from various places. To avoid
668 // code bloat it is generated out-of-line. Visiting is done by setting a register
669 // to the "return" address, then jumping to the finally code, which ends with a
670 // switch statement that jumps back to all the possible return points.
672 // Each finally block gets its own register, it's recorded in the ctx rib.
674 // The code for the finally block's "switch" can't be generated until we've seen
675 // all the code that can visit it (represented as a list of id/labels in the ctx rib).
677 // There is a counter in the ctx, and id's for the switch are generated from it.
678 // Its initial value is 0. lookupswitch can be used.
680 void TryStmt::cogenWithFinally(Cogen* cogen, Ctx* ctx)
682 uint32_t returnreg = cogen->getTemp(); // the local that records the index of the label this finally block should return to
683 Label* Lfinally = cogen->newLabel(); // the address of the finally block body
685 FinallyCtx fctx(cogen->allocator, Lfinally, returnreg, ctx);
687 // Lreturn is the address in this finally block that visited, outer finally blocks return to
688 // after executing to completion.
689 Label* Lreturn = cogen->newLabel();
690 uint32_t myreturn = fctx.addReturnLabel(Lreturn);
692 // Lend is the address to branch to to get out of the finally block after entering the
693 // finally block normally and executing it without throwing any exceptions.
694 Label* Lend = cogen->newLabel();
695 uint32_t myend = fctx.addReturnLabel(Lend);
697 uint32_t code_start = cogen->getCodeLength();
698 cogenNoFinally(cogen, &fctx);
699 uint32_t code_end = cogen->getCodeLength();
701 // Fallthrough from try-catch: visit the finally block. This code must not be in the
702 // scope of the generated exception handler.
704 cogen->I_pushuint(cogen->emitUInt(myend)); // return to Lend
705 cogen->I_coerce_a();
706 cogen->I_setlocal(returnreg);
707 cogen->I_jump(Lfinally); // control continues at Lend below
709 // Generated catch block to handle throws out of try-catch:
710 // capture the exception, visit the finally block with return
711 // to Lreturn, then re-throw the exception at Lreturn.
713 // Use a lightweight exception handler; always store the value
714 // in a register.
716 uint32_t savedExn = cogen->getTemp();
717 /*uint32_t catch_idx =*/ cogen->emitException(code_start, code_end, cogen->getCodeLength(), 0, 0);
719 cogen->startCatch(); // push 1 item
720 cogen->I_setlocal(savedExn); // pop and save it
722 restoreScopes(cogen, ctx); // finally block needs correct scopes
724 cogen->I_pushuint(cogen->emitUInt(myreturn));
725 cogen->I_coerce_a();
726 cogen->I_setlocal(returnreg);
727 cogen->I_jump(Lfinally); // control continues at Lreturn directly below
728 cogen->I_label(Lreturn);
729 cogen->I_getlocal(savedExn);
730 cogen->I_kill(savedExn);
731 cogen->I_throw();
733 // Finally block
735 cogen->I_label(Lfinally);
736 for ( Seq<Stmt*>* stmts = this->finallyblock ; stmts != NULL ; stmts = stmts->tl )
737 stmts->hd->cogen(cogen, ctx);
739 // The return-from-subroutine code at the end of the finally block
740 // From the above it may seem that there are at most two labels in the list,
741 // but this is not so: unstructuredControlFlow can place more labels into it.
743 Seq<Label*>* labels;
744 uint32_t i;
745 for ( i=0, labels = fctx.returnLabels.get() ; labels != NULL ; i++, labels = labels->tl ) {
746 cogen->I_getlocal(returnreg);
747 cogen->I_pushuint(cogen->emitUInt(i));
748 cogen->I_coerce_a();
749 cogen->I_ifeq(labels->hd);
752 cogen->I_label(Lend);
753 cogen->I_kill(returnreg);
756 void TryStmt::cogenNoFinally(Cogen* cogen, Ctx* ctx)
758 uint32_t code_start = cogen->getCodeLength();
759 for ( Seq<Stmt*>* stmts = this->tryblock ; stmts != NULL ; stmts = stmts->tl )
760 stmts->hd->cogen(cogen, ctx);
761 uint32_t code_end = cogen->getCodeLength();
763 Label* Lend = cogen->newLabel();
764 cogen->I_jump(Lend);
766 for( Seq<CatchClause*>* catches = this->catches ; catches != NULL ; catches = catches->tl )
767 cgCatch(cogen, ctx, code_start, code_end, Lend, catches->hd);
769 cogen->I_label(Lend);
772 void TryStmt::cgCatch(Cogen* cogen, Ctx* ctx, uint32_t code_start, uint32_t code_end, Label* Lend, CatchClause* catchClause)
774 Compiler* compiler = cogen->compiler;
775 uint32_t catch_idx = cogen->emitException(code_start,
776 code_end,
777 cogen->getCodeLength(),
778 cogen->emitTypeName(compiler, catchClause->type_name),
779 cogen->abc->addQName(compiler->NS_public, cogen->emitString(catchClause->name)));
781 cogen->startCatch();
783 uint32_t t = cogen->getTemp();
784 restoreScopes(cogen, ctx);
785 CatchCtx ctx1(t, ctx);
787 cogen->I_newcatch(catch_idx);
788 cogen->I_dup();
789 cogen->I_setlocal(t); // Store catch scope in register so it can be restored later
790 cogen->I_dup();
791 cogen->I_pushscope();
793 // Store the exception object in the catch scope.
794 cogen->I_swap();
795 cogen->I_setproperty(cogen->abc->addQName(compiler->NS_public, cogen->emitString(catchClause->name)));
797 // catch block body
798 for ( Seq<Stmt*>* stmts = catchClause->stmts ; stmts != NULL ; stmts = stmts->tl )
799 stmts->hd->cogen(cogen, &ctx1);
801 cogen->I_kill(t);
803 cogen->I_popscope();
804 cogen->I_jump(Lend);
807 void DefaultXmlNamespaceStmt::cogen(Cogen* cogen, Ctx* ctx)
809 expr->cogen(cogen, ctx);
810 cogen->I_dxnslate();
813 void SuperStmt::cogen(Cogen* cogen, Ctx* ctx)
815 (void)ctx;
816 Compiler* compiler = cogen->compiler;
817 compiler->internalError(pos, "Unimplemented: superStmt");
822 #endif // VMCFG_EVAL