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
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.
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 ***** */
50 using namespace ActionBlockConstants
;
52 static bool matchLabel(Ctx
* ctx
, Str
* label
)
58 Seq
<Str
*>* labels
= ((ContinueCtx
*)ctx
)->label_names
;
59 while (labels
!= NULL
) {
60 if (label
== labels
->hd
)
67 return label
== ((BreakCtx
*)ctx
)->label_name
;
73 void Cogen::unstructuredControlFlow(Ctx
* ctx
, bool (hit
)(Ctx
*,void*), void* package
, bool jump
, SyntaxError msg
, uint32_t pos
)
76 if (hit(ctx
, package
)) {
78 I_jump(((ControlFlowCtx
*)ctx
)->label
);
82 if(ctx
->tag
== CTX_With
|| ctx
->tag
== CTX_Catch
) {
83 ScopeCtx
* ctx1
= (ScopeCtx
*)ctx
;
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
));
94 I_setlocal(ctx2
->returnreg
);
95 I_jump(ctx2
->Lfinally
);
100 compiler
->syntaxError(pos
, msg
);
103 static void restoreScopes(Cogen
* cogen
, Ctx
* ctx
)
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
)
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();
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
));
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
*)
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
);
183 void ExprStmt::cogen(Cogen
* cogen
, Ctx
* ctx
)
185 cogen
->I_debugline(pos
);
186 expr
->cogen(cogen
, ctx
);
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
) {
192 cogen
->I_setlocal(((ProgramCtx
*)c
)->capture_reg
);
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();
209 alternate
->cogen(cogen
, ctx
);
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();
253 init
->cogen(cogen
, ctx
);
256 cogen
->I_label(Ltop
);
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
);
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();
299 init
->cogen(cogen
, ctx
);
302 obj
->cogen(cogen
, ctx
);
305 cogen
->I_setlocal(T_obj
);
306 cogen
->I_pushbyte(0);
308 cogen
->I_setlocal(T_idx
);
310 cogen
->I_label(Ltop
);
312 cogen
->I_getlocal(T_idx
);
314 cogen
->I_setlocal(T_idx2
);
315 cogen
->I_hasnext2(T_obj
, T_idx2
);
316 cogen
->I_getlocal(T_idx2
);
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
);
326 cogen
->I_nextvalue();
329 cogen
->I_setlocal(T_val
);
330 (ALLOC(AssignExpr
, (OPR_assign
, lhs
, ALLOC(RefLocalExpr
, (T_val
)))))->cogen(cogen
, ctx
);
333 BreakCtx
ctx1(Lbreak
, ctx
);
334 ContinueCtx
ctx2(Lcont
, labels
, &ctx1
);
335 body
->cogen(cogen
, &ctx2
);
337 cogen
->I_label(Lcont
);
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
,
357 (label
== NULL
? SYNTAXERR_ILLEGAL_BREAK
: SYNTAXERR_BREAK_LABEL_UNDEF
),
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
,
372 (label
== NULL
? SYNTAXERR_ILLEGAL_CONTINUE
: SYNTAXERR_CONTINUE_LABEL_UNDEF
),
376 void ThrowStmt::cogen(Cogen
* cogen
, Ctx
* ctx
)
378 cogen
->I_debugline(pos
);
379 expr
->cogen(cogen
, ctx
);
383 static bool hitFunction(Ctx
* ctx
, void*)
385 return ctx
->tag
== CTX_Function
;
388 void ReturnStmt::cogen(Cogen
* cogen
, Ctx
* ctx
)
393 cogen
->I_debugline(pos
);
394 expr
->cogen(cogen
, ctx
);
395 tmp
= cogen
->getTemp();
397 cogen
->I_setlocal(tmp
);
400 cogen
->unstructuredControlFlow(ctx
,
404 SYNTAXERR_RETURN_OUTSIDE_FN
);
407 cogen
->I_returnvoid();
409 cogen
->I_getlocal(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
);
422 cogen
->I_setlocal(scopereg
);
424 WithCtx
ctx1(scopereg
, ctx
);
425 body
->cogen(cogen
, &ctx1
);
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
437 void SwitchStmt::cogen(Cogen
* cogen
, Ctx
* ctx
)
440 if (analyze(&low
, &high
))
441 cogenFast(cogen
, ctx
, low
, high
);
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
)
456 *high
= (-0x7FFFFFFF - 1);
458 for ( Seq
<CaseClause
*>* cases
= this->cases
; cases
!= NULL
; cases
= cases
->tl
) {
459 Expr
* e
= cases
->hd
->expr
;
462 else if (e
->tag() == TAG_literalInt
) {
463 int32_t v
= ((LiteralInt
*)e
)->value
;
465 *high
= max(*high
, v
);
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;
487 #ifdef AVMC_STANDALONE
488 Lcase
= (Label
**)alloca(sizeof(Label
*) * ncases
);
490 MMgc::GC::AllocaAutoPtr _Lcase
;
491 Lcase
= (Label
**)VMPI_alloca(compiler
->context
->core
, _Lcase
, sizeof(Label
*) * ncases
);
493 Label
* Ldefault
= cogen
->newLabel();
494 Label
* Lbreak
= cogen
->newLabel();
495 BreakCtx
nctx(Lbreak
, ctx
);
497 for ( uint32_t i
=0 ; i
< ncases
; i
++ )
500 for ( Seq
<CaseClause
*>* cases
= this->cases
; cases
!= NULL
; cases
= cases
->tl
) {
501 Expr
* e
= cases
->hd
->expr
;
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
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.)
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
));
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
;
561 AvmAssert(Ldefault
!= NULL
);
562 cogen
->I_label(Ldefault
);
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
]);
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
);
587 void SwitchStmt::cogenSlow(Cogen
* cogen
, Ctx
* ctx
)
589 uint32_t tmp
= cogen
->getTemp();
591 Label
* Ldefault
= NULL
;
592 Label
* Lnext
= cogen
->newLabel();
594 Label
* Lbreak
= cogen
->newLabel();
596 cogen
->I_debugline(pos
);
597 expr
->cogen(cogen
, ctx
);
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
614 cogen
->I_label(Lnext
); // label next pos
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
);
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
638 cogen
->I_label(Lnext
);
639 if (Ldefault
!= NULL
)
640 cogen
->I_jump(Ldefault
);
642 cogen
->I_label(Lfall
);
643 cogen
->I_label(Lbreak
);
647 void TryStmt::cogen(Cogen
* cogen
, Ctx
* ctx
)
649 if (finallyblock
!= NULL
)
650 cogenWithFinally(cogen
, ctx
);
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
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
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
));
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
);
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.
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
));
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();
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
,
777 cogen
->getCodeLength(),
778 cogen
->emitTypeName(compiler
, catchClause
->type_name
),
779 cogen
->abc
->addQName(compiler
->NS_public
, cogen
->emitString(catchClause
->name
)));
783 uint32_t t
= cogen
->getTemp();
784 restoreScopes(cogen
, ctx
);
785 CatchCtx
ctx1(t
, ctx
);
787 cogen
->I_newcatch(catch_idx
);
789 cogen
->I_setlocal(t
); // Store catch scope in register so it can be restored later
791 cogen
->I_pushscope();
793 // Store the exception object in the catch scope.
795 cogen
->I_setproperty(cogen
->abc
->addQName(compiler
->NS_public
, cogen
->emitString(catchClause
->name
)));
798 for ( Seq
<Stmt
*>* stmts
= catchClause
->stmts
; stmts
!= NULL
; stmts
= stmts
->tl
)
799 stmts
->hd
->cogen(cogen
, &ctx1
);
807 void DefaultXmlNamespaceStmt::cogen(Cogen
* cogen
, Ctx
* ctx
)
809 expr
->cogen(cogen
, ctx
);
813 void SuperStmt::cogen(Cogen
* cogen
, Ctx
* ctx
)
816 Compiler
* compiler
= cogen
->compiler
;
817 compiler
->internalError(pos
, "Unimplemented: superStmt");