EjsArray *ejsCaptureStack(Ejs *ejs, int uplevels) { EjsFrame *fp; EjsState *state; EjsArray *stack; wchar *source; EjsObj *frame; char *filename; int index, lineNumber; assert(ejs); stack = ejsCreateArray(ejs, 0); index = 0; for (state = ejs->state; state; state = state->prev) { for (fp = state->fp; fp; fp = fp->caller) { if (uplevels-- <= 0) { frame = ejsCreateEmptyPot(ejs); if (ejsGetDebugInfo(ejs, (EjsFunction*) fp, fp->pc, &filename, &lineNumber, &source) >= 0) { ejsSetPropertyByName(ejs, frame, EN("filename"), ejsCreatePathFromAsc(ejs, filename)); ejsSetPropertyByName(ejs, frame, EN("lineno"), ejsCreateNumber(ejs, lineNumber)); ejsSetPropertyByName(ejs, frame, EN("code"), ejsCreateString(ejs, source, wlen(source))); } else { ejsSetPropertyByName(ejs, frame, EN("filename"), EST(undefined)); } ejsSetPropertyByName(ejs, frame, EN("func"), fp->function.name); ejsSetProperty(ejs, stack, index++, frame); } } } return stack; }
/* Interpret the code for a function */ static void interp(EjsMod *mp, EjsModule *module, EjsFunction *fun) { EjsOptable *optable, *opt; EjsCode *code; MprChar *currentLine; uchar *start; char argbuf[MPR_MAX_STRING], lineInfo[MPR_MAX_STRING], name[MPR_MAX_STRING]; char *currentFile, *src, *dest; int maxOp, opcode, lineNumber, stack, codeLen, address, stackEffect, nbytes, i, lastLine; mprAssert(mp); mprAssert(module); mprAssert(fun); /* Store so that getNum and getString can easily read instructions */ code = fun->body.code; mp->fun = fun; mp->module = module; mp->pc = code->byteCode; codeLen = code->codeLen; start = mp->pc; stack = 0; currentLine = 0; lineNumber = 0; currentFile = 0; lastLine = -1; optable = ejsGetOptable(mp); for (maxOp = 0, opt = optable; opt->name; opt++) { maxOp++; } while ((mp->pc - start) < codeLen) { address = (int) (mp->pc - start); opcode = *mp->pc++; argbuf[0] = '\0'; stackEffect = 0; if (opcode < 0 || opcode >= maxOp) { mprError("Bad opcode %x at address %d.\n", opcode, address); return; } opt = &optable[opcode]; if (mp->showAsm) { /* Output address [stack] opcode Format: "address: [stackDepth] opcode <args> ..." */ mprFprintf(mp->file, " %04d: [%d] %02x ", address, stack, opcode); } nbytes = decodeOperands(mp, opt, argbuf, (int) sizeof(argbuf), (int) (mp->pc - start), &stackEffect); if (mp->showAsm) { for (i = 24 - (nbytes * 3); i >= 0; i--) { mprFprintf(mp->file, "."); } for (dest = name, src = opt->name; *src; src++, dest++) { if (*src == '_') { *dest = *++src; } else { *dest = tolower((uchar) *src); } } *dest++ = '\0'; mprFprintf(mp->file, " %s %s\n", name, argbuf); } else { for (i = 24 - (nbytes * 3); i >= 0; i--) { mprFprintf(mp->file, " "); } mprFprintf(mp->file, " %s\n", argbuf); } stack += stackEffect; if (opcode == EJS_OP_RETURN_VALUE || opcode == EJS_OP_RETURN) { stack = 0; } if (stack < 0) { if (mp->warnOnError) { mprPrintfError("Instruction stack is negative %d\n", stack); } if (mp->exitOnError) { exit(255); } } ejsGetDebugInfo(mp->ejs, fun, mp->pc, ¤tFile, &lineNumber, ¤tLine); if (currentFile && currentLine && *currentLine && lineNumber != lastLine) { mprSprintf(lineInfo, sizeof(lineInfo), "%s:%d", currentFile, lineNumber); mprFprintf(mp->file, "\n # %-25s %w\n\n", lineInfo, currentLine); lastLine = lineNumber; } } }