static void ctrycatchfinally(JF, js_Ast *trystm, js_Ast *catchvar, js_Ast *catchstm, js_Ast *finallystm) { int L1, L2, L3; L1 = emitjump(J, F, OP_TRY); { /* if we get here, we have caught an exception in the try block */ L2 = emitjump(J, F, OP_TRY); { /* if we get here, we have caught an exception in the catch block */ cstm(J, F, finallystm); /* inline finally block */ emit(J, F, OP_THROW); /* rethrow exception */ } label(J, F, L2); if (J->strict) { if (!strcmp(catchvar->string, "arguments")) jsC_error(J, catchvar, "redefining 'arguments' is not allowed in strict mode"); if (!strcmp(catchvar->string, "eval")) jsC_error(J, catchvar, "redefining 'eval' is not allowed in strict mode"); } emitstring(J, F, OP_CATCH, catchvar->string); cstm(J, F, catchstm); emit(J, F, OP_ENDCATCH); L3 = emitjump(J, F, OP_JUMP); /* skip past the try block to the finally block */ } label(J, F, L1); cstm(J, F, trystm); emit(J, F, OP_ENDTRY); label(J, F, L3); cstm(J, F, finallystm); }
static void ctrycatch(JF, js_Ast *trystm, js_Ast *catchvar, js_Ast *catchstm) { int L1, L2; L1 = emitjump(J, F, OP_TRY); { /* if we get here, we have caught an exception in the try block */ emitstring(J, F, OP_CATCH, catchvar->string); cstm(J, F, catchstm); emit(J, F, OP_ENDCATCH); L2 = emitjump(J, F, OP_JUMP); /* skip past the try block */ } label(J, F, L1); cstm(J, F, trystm); emit(J, F, OP_ENDTRY); label(J, F, L2); }
static void cswitch(JF, js_Ast *ref, js_Ast *head) { js_Ast *node, *clause, *def = NULL; int end; cexp(J, F, ref); /* emit an if-else chain of tests for the case clause expressions */ for (node = head; node; node = node->b) { clause = node->a; if (clause->type == STM_DEFAULT) { if (def) jsC_error(J, clause, "more than one default label in switch"); def = clause; } else { cexp(J, F, clause->a); clause->casejump = emitjump(J, F, OP_JCASE); } } emit(J, F, OP_POP); if (def) { def->casejump = emitjump(J, F, OP_JUMP); end = 0; } else { end = emitjump(J, F, OP_JUMP); } /* emit the casue clause bodies */ for (node = head; node; node = node->b) { clause = node->a; label(J, F, clause->casejump); if (clause->type == STM_DEFAULT) cstmlist(J, F, clause->a); else cstmlist(J, F, clause->b); } if (end) label(J, F, end); }
static void ctryfinally(JF, js_Ast *trystm, js_Ast *finallystm) { int L1; L1 = emitjump(J, F, OP_TRY); { /* if we get here, we have caught an exception in the try block */ cstm(J, F, finallystm); /* inline finally block */ emit(J, F, OP_THROW); /* rethrow exception */ } label(J, F, L1); cstm(J, F, trystm); emit(J, F, OP_ENDTRY); cstm(J, F, finallystm); }
static void ctrycatchfinally(JF, js_Ast *trystm, js_Ast *catchvar, js_Ast *catchstm, js_Ast *finallystm) { int L1, L2, L3; L1 = emitjump(J, F, OP_TRY); { /* if we get here, we have caught an exception in the try block */ L2 = emitjump(J, F, OP_TRY); { /* if we get here, we have caught an exception in the catch block */ cstm(J, F, finallystm); /* inline finally block */ emit(J, F, OP_THROW); /* rethrow exception */ } label(J, F, L2); emitstring(J, F, OP_CATCH, catchvar->string); cstm(J, F, catchstm); emit(J, F, OP_ENDCATCH); L3 = emitjump(J, F, OP_JUMP); /* skip past the try block to the finally block */ } label(J, F, L1); cstm(J, F, trystm); emit(J, F, OP_ENDTRY); label(J, F, L3); cstm(J, F, finallystm); }
static void cstm(JF, js_Ast *stm) { js_Ast *target; int loop, cont, then, end; emitline(J, F, stm); switch (stm->type) { case AST_FUNDEC: break; case STM_BLOCK: cstmlist(J, F, stm->a); break; case STM_EMPTY: if (F->script) { emit(J, F, OP_POP); emit(J, F, OP_UNDEF); } break; case STM_VAR: cvarinit(J, F, stm->a); break; case STM_IF: if (stm->c) { cexp(J, F, stm->a); then = emitjump(J, F, OP_JTRUE); cstm(J, F, stm->c); end = emitjump(J, F, OP_JUMP); label(J, F, then); cstm(J, F, stm->b); label(J, F, end); } else { cexp(J, F, stm->a); end = emitjump(J, F, OP_JFALSE); cstm(J, F, stm->b); label(J, F, end); } break; case STM_DO: loop = here(J, F); cstm(J, F, stm->a); cont = here(J, F); cexp(J, F, stm->b); emitjumpto(J, F, OP_JTRUE, loop); labeljumps(J, F, stm->jumps, here(J,F), cont); break; case STM_WHILE: loop = here(J, F); cexp(J, F, stm->a); end = emitjump(J, F, OP_JFALSE); cstm(J, F, stm->b); emitjumpto(J, F, OP_JUMP, loop); label(J, F, end); labeljumps(J, F, stm->jumps, here(J,F), loop); break; case STM_FOR: case STM_FOR_VAR: if (stm->type == STM_FOR_VAR) { cvarinit(J, F, stm->a); } else { if (stm->a) { cexp(J, F, stm->a); emit(J, F, OP_POP); } } loop = here(J, F); if (stm->b) { cexp(J, F, stm->b); end = emitjump(J, F, OP_JFALSE); } else { end = 0; } cstm(J, F, stm->d); cont = here(J, F); if (stm->c) { cexp(J, F, stm->c); emit(J, F, OP_POP); } emitjumpto(J, F, OP_JUMP, loop); if (end) label(J, F, end); labeljumps(J, F, stm->jumps, here(J,F), cont); break; case STM_FOR_IN: case STM_FOR_IN_VAR: cexp(J, F, stm->b); emit(J, F, OP_ITERATOR); loop = here(J, F); { emit(J, F, OP_NEXTITER); end = emitjump(J, F, OP_JFALSE); cassignforin(J, F, stm); if (F->script) { emit(J, F, OP_ROT2); cstm(J, F, stm->c); emit(J, F, OP_ROT2); } else { cstm(J, F, stm->c); } emitjumpto(J, F, OP_JUMP, loop); } label(J, F, end); labeljumps(J, F, stm->jumps, here(J,F), loop); break; case STM_SWITCH: cswitch(J, F, stm->a, stm->b); labeljumps(J, F, stm->jumps, here(J,F), 0); break; case STM_LABEL: cstm(J, F, stm->b); /* skip consecutive labels */ while (stm->type == STM_LABEL) stm = stm->b; /* loops and switches have already been labelled */ if (!isloop(stm->type) && stm->type != STM_SWITCH) labeljumps(J, F, stm->jumps, here(J,F), 0); break; case STM_BREAK: if (stm->a) { target = breaktarget(J, F, stm, stm->a->string); if (!target) jsC_error(J, stm, "break label '%s' not found", stm->a->string); } else { target = breaktarget(J, F, stm, NULL); if (!target) jsC_error(J, stm, "unlabelled break must be inside loop or switch"); } cexit(J, F, STM_BREAK, stm, target); addjump(J, F, STM_BREAK, target, emitjump(J, F, OP_JUMP)); break; case STM_CONTINUE: if (stm->a) { target = continuetarget(J, F, stm, stm->a->string); if (!target) jsC_error(J, stm, "continue label '%s' not found", stm->a->string); } else { target = continuetarget(J, F, stm, NULL); if (!target) jsC_error(J, stm, "continue must be inside loop"); } cexit(J, F, STM_CONTINUE, stm, target); addjump(J, F, STM_CONTINUE, target, emitjump(J, F, OP_JUMP)); break; case STM_RETURN: if (stm->a) cexp(J, F, stm->a); else emit(J, F, OP_UNDEF); target = returntarget(J, F, stm); if (!target) jsC_error(J, stm, "return not in function"); cexit(J, F, STM_RETURN, stm, target); emit(J, F, OP_RETURN); break; case STM_THROW: cexp(J, F, stm->a); emit(J, F, OP_THROW); break; case STM_WITH: cexp(J, F, stm->a); emit(J, F, OP_WITH); cstm(J, F, stm->b); emit(J, F, OP_ENDWITH); break; case STM_TRY: if (stm->b && stm->c) { if (stm->d) ctrycatchfinally(J, F, stm->a, stm->b, stm->c, stm->d); else ctrycatch(J, F, stm->a, stm->b, stm->c); } else { ctryfinally(J, F, stm->a, stm->d); } break; case STM_DEBUGGER: emit(J, F, OP_DEBUGGER); break; default: if (F->script) { emit(J, F, OP_POP); cexp(J, F, stm); } else { cexp(J, F, stm); emit(J, F, OP_POP); } break; } }
static void cexp(JF, js_Ast *exp) { int then, end; int n; switch (exp->type) { case EXP_STRING: emitstring(J, F, OP_STRING, exp->string); break; case EXP_NUMBER: emitnumber(J, F, exp->number); break; case EXP_UNDEF: emit(J, F, OP_UNDEF); break; case EXP_NULL: emit(J, F, OP_NULL); break; case EXP_TRUE: emit(J, F, OP_TRUE); break; case EXP_FALSE: emit(J, F, OP_FALSE); break; case EXP_THIS: emit(J, F, OP_THIS); break; case EXP_REGEXP: emit(J, F, OP_NEWREGEXP); emitraw(J, F, addstring(J, F, exp->string)); emitraw(J, F, exp->number); break; case EXP_OBJECT: emit(J, F, OP_NEWOBJECT); cobject(J, F, exp->a); break; case EXP_ARRAY: emit(J, F, OP_NEWARRAY); carray(J, F, exp->a); break; case EXP_FUN: emitfunction(J, F, newfun(J, exp->a, exp->b, exp->c, 0)); break; case EXP_IDENTIFIER: emitlocal(J, F, OP_GETLOCAL, OP_GETVAR, exp); break; case EXP_INDEX: cexp(J, F, exp->a); cexp(J, F, exp->b); emit(J, F, OP_GETPROP); break; case EXP_MEMBER: cexp(J, F, exp->a); emitstring(J, F, OP_GETPROP_S, exp->b->string); break; case EXP_CALL: ccall(J, F, exp->a, exp->b); break; case EXP_NEW: cexp(J, F, exp->a); n = cargs(J, F, exp->b); emit(J, F, OP_NEW); emitraw(J, F, n); break; case EXP_DELETE: cdelete(J, F, exp->a); break; case EXP_PREINC: cassignop1(J, F, exp->a); emit(J, F, OP_INC); cassignop2(J, F, exp->a, 0); break; case EXP_PREDEC: cassignop1(J, F, exp->a); emit(J, F, OP_DEC); cassignop2(J, F, exp->a, 0); break; case EXP_POSTINC: cassignop1(J, F, exp->a); emit(J, F, OP_POSTINC); cassignop2(J, F, exp->a, 1); emit(J, F, OP_POP); break; case EXP_POSTDEC: cassignop1(J, F, exp->a); emit(J, F, OP_POSTDEC); cassignop2(J, F, exp->a, 1); emit(J, F, OP_POP); break; case EXP_VOID: cexp(J, F, exp->a); emit(J, F, OP_POP); emit(J, F, OP_UNDEF); break; case EXP_TYPEOF: ctypeof(J, F, exp->a); break; case EXP_POS: cunary(J, F, exp, OP_POS); break; case EXP_NEG: cunary(J, F, exp, OP_NEG); break; case EXP_BITNOT: cunary(J, F, exp, OP_BITNOT); break; case EXP_LOGNOT: cunary(J, F, exp, OP_LOGNOT); break; case EXP_BITOR: cbinary(J, F, exp, OP_BITOR); break; case EXP_BITXOR: cbinary(J, F, exp, OP_BITXOR); break; case EXP_BITAND: cbinary(J, F, exp, OP_BITAND); break; case EXP_EQ: cbinary(J, F, exp, OP_EQ); break; case EXP_NE: cbinary(J, F, exp, OP_NE); break; case EXP_STRICTEQ: cbinary(J, F, exp, OP_STRICTEQ); break; case EXP_STRICTNE: cbinary(J, F, exp, OP_STRICTNE); break; case EXP_LT: cbinary(J, F, exp, OP_LT); break; case EXP_GT: cbinary(J, F, exp, OP_GT); break; case EXP_LE: cbinary(J, F, exp, OP_LE); break; case EXP_GE: cbinary(J, F, exp, OP_GE); break; case EXP_INSTANCEOF: cbinary(J, F, exp, OP_INSTANCEOF); break; case EXP_IN: cbinary(J, F, exp, OP_IN); break; case EXP_SHL: cbinary(J, F, exp, OP_SHL); break; case EXP_SHR: cbinary(J, F, exp, OP_SHR); break; case EXP_USHR: cbinary(J, F, exp, OP_USHR); break; case EXP_ADD: cbinary(J, F, exp, OP_ADD); break; case EXP_SUB: cbinary(J, F, exp, OP_SUB); break; case EXP_MUL: cbinary(J, F, exp, OP_MUL); break; case EXP_DIV: cbinary(J, F, exp, OP_DIV); break; case EXP_MOD: cbinary(J, F, exp, OP_MOD); break; case EXP_ASS: cassign(J, F, exp); break; case EXP_ASS_MUL: cassignop(J, F, exp, OP_MUL); break; case EXP_ASS_DIV: cassignop(J, F, exp, OP_DIV); break; case EXP_ASS_MOD: cassignop(J, F, exp, OP_MOD); break; case EXP_ASS_ADD: cassignop(J, F, exp, OP_ADD); break; case EXP_ASS_SUB: cassignop(J, F, exp, OP_SUB); break; case EXP_ASS_SHL: cassignop(J, F, exp, OP_SHL); break; case EXP_ASS_SHR: cassignop(J, F, exp, OP_SHR); break; case EXP_ASS_USHR: cassignop(J, F, exp, OP_USHR); break; case EXP_ASS_BITAND: cassignop(J, F, exp, OP_BITAND); break; case EXP_ASS_BITXOR: cassignop(J, F, exp, OP_BITXOR); break; case EXP_ASS_BITOR: cassignop(J, F, exp, OP_BITOR); break; case EXP_COMMA: cexp(J, F, exp->a); emit(J, F, OP_POP); cexp(J, F, exp->b); break; case EXP_LOGOR: cexp(J, F, exp->a); emit(J, F, OP_DUP); end = emitjump(J, F, OP_JTRUE); emit(J, F, OP_POP); cexp(J, F, exp->b); label(J, F, end); break; case EXP_LOGAND: cexp(J, F, exp->a); emit(J, F, OP_DUP); end = emitjump(J, F, OP_JFALSE); emit(J, F, OP_POP); cexp(J, F, exp->b); label(J, F, end); break; case EXP_COND: cexp(J, F, exp->a); then = emitjump(J, F, OP_JTRUE); cexp(J, F, exp->c); end = emitjump(J, F, OP_JUMP); label(J, F, then); cexp(J, F, exp->b); label(J, F, end); break; default: jsC_error(J, exp, "unknown expression: (%s)", jsP_aststring(exp->type)); } }