aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/gopkg.in/olebedev/go-duktape.v3/duk_logging.c
diff options
context:
space:
mode:
authorPéter Szilágyi <peterke@gmail.com>2017-12-21 19:56:11 +0800
committerGitHub <noreply@github.com>2017-12-21 19:56:11 +0800
commit5258785c81959109138ebeca613f12c277188abc (patch)
treeb3d21fc2f38927841f44541a3717b69f5a3c5ec1 /vendor/gopkg.in/olebedev/go-duktape.v3/duk_logging.c
parent1a5425779b026587e36f5d21a6e50efe17cc6a9d (diff)
downloadgo-tangerine-5258785c81959109138ebeca613f12c277188abc.tar
go-tangerine-5258785c81959109138ebeca613f12c277188abc.tar.gz
go-tangerine-5258785c81959109138ebeca613f12c277188abc.tar.bz2
go-tangerine-5258785c81959109138ebeca613f12c277188abc.tar.lz
go-tangerine-5258785c81959109138ebeca613f12c277188abc.tar.xz
go-tangerine-5258785c81959109138ebeca613f12c277188abc.tar.zst
go-tangerine-5258785c81959109138ebeca613f12c277188abc.zip
cmd, core, eth/tracers: support fancier js tracing (#15516)
* cmd, core, eth/tracers: support fancier js tracing * eth, internal/web3ext: rework trace API, concurrency, chain tracing * eth/tracers: add three more JavaScript tracers * eth/tracers, vendor: swap ottovm to duktape for tracing * core, eth, internal: finalize call tracer and needed extras * eth, tests: prestate tracer, call test suite, rewinding * vendor: fix windows builds for tracer js engine * vendor: temporary duktape fix * eth/tracers: fix up 4byte and evmdis tracer * vendor: pull in latest duktape with my upstream fixes * eth: fix some review comments * eth: rename rewind to reexec to make it more obvious * core/vm: terminate tracing using defers
Diffstat (limited to 'vendor/gopkg.in/olebedev/go-duktape.v3/duk_logging.c')
-rwxr-xr-xvendor/gopkg.in/olebedev/go-duktape.v3/duk_logging.c380
1 files changed, 380 insertions, 0 deletions
diff --git a/vendor/gopkg.in/olebedev/go-duktape.v3/duk_logging.c b/vendor/gopkg.in/olebedev/go-duktape.v3/duk_logging.c
new file mode 100755
index 000000000..9be2c1c27
--- /dev/null
+++ b/vendor/gopkg.in/olebedev/go-duktape.v3/duk_logging.c
@@ -0,0 +1,380 @@
+/*
+ * Logging support
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include "duktape.h"
+#include "duk_logging.h"
+
+/* XXX: uses stderr always for now, configurable? */
+
+#define DUK_LOGGING_FLUSH /* Duktape 1.x: flush stderr */
+
+/* 3-letter log level strings. */
+static const char duk__log_level_strings[] = {
+ 'T', 'R', 'C', 'D', 'B', 'G', 'I', 'N', 'F',
+ 'W', 'R', 'N', 'E', 'R', 'R', 'F', 'T', 'L'
+};
+
+/* Log method names. */
+static const char *duk__log_method_names[] = {
+ "trace", "debug", "info", "warn", "error", "fatal"
+};
+
+/* Constructor. */
+static duk_ret_t duk__logger_constructor(duk_context *ctx) {
+ duk_idx_t nargs;
+
+ /* Calling as a non-constructor is not meaningful. */
+ if (!duk_is_constructor_call(ctx)) {
+ return DUK_RET_TYPE_ERROR;
+ }
+
+ nargs = duk_get_top(ctx);
+ duk_set_top(ctx, 1);
+
+ duk_push_this(ctx);
+
+ /* [ name this ] */
+
+ if (nargs == 0) {
+ /* Automatic defaulting of logger name from caller. This
+ * would work poorly with tail calls, but constructor calls
+ * are currently never tail calls, so tail calls are not an
+ * issue now.
+ */
+
+ duk_inspect_callstack_entry(ctx, -2);
+ if (duk_is_object(ctx, -1)) {
+ if (duk_get_prop_string(ctx, -1, "function")) {
+ if (duk_get_prop_string(ctx, -1, "fileName")) {
+ if (duk_is_string(ctx, -1)) {
+ duk_replace(ctx, 0);
+ }
+ }
+ }
+ }
+ /* Leave values on stack on purpose, ignored below. */
+
+ /* Stripping the filename might be a good idea
+ * ("/foo/bar/quux.js" -> logger name "quux"),
+ * but now used verbatim.
+ */
+ }
+ /* The stack is unbalanced here on purpose; we only rely on the
+ * initial two values: [ name this ].
+ */
+
+ if (duk_is_string(ctx, 0)) {
+ duk_dup(ctx, 0);
+ duk_put_prop_string(ctx, 1, "n");
+ } else {
+ /* don't set 'n' at all, inherited value is used as name */
+ }
+
+ duk_compact(ctx, 1);
+
+ return 0; /* keep default instance */
+}
+
+/* Default function to format objects. Tries to use toLogString() but falls
+ * back to toString(). Any errors are propagated out without catching.
+ */
+static duk_ret_t duk__logger_prototype_fmt(duk_context *ctx) {
+ if (duk_get_prop_string(ctx, 0, "toLogString")) {
+ /* [ arg toLogString ] */
+
+ duk_dup(ctx, 0);
+ duk_call_method(ctx, 0);
+
+ /* [ arg result ] */
+ return 1;
+ }
+
+ /* [ arg undefined ] */
+ duk_pop(ctx);
+ duk_to_string(ctx, 0);
+ return 1;
+}
+
+/* Default function to write a formatted log line. Writes to stderr,
+ * appending a newline to the log line.
+ *
+ * The argument is a buffer; avoid coercing the buffer to a string to
+ * avoid string table traffic.
+ */
+static duk_ret_t duk__logger_prototype_raw(duk_context *ctx) {
+ const char *data;
+ duk_size_t data_len;
+
+ data = (const char *) duk_require_buffer(ctx, 0, &data_len);
+ fwrite((const void *) data, 1, data_len, stderr);
+ fputc((int) '\n', stderr);
+#if defined(DUK_LOGGING_FLUSH)
+ fflush(stderr);
+#endif
+ return 0;
+}
+
+/* Log frontend shared helper, magic value indicates log level. Provides
+ * frontend functions: trace(), debug(), info(), warn(), error(), fatal().
+ * This needs to have small footprint, reasonable performance, minimal
+ * memory churn, etc.
+ */
+static duk_ret_t duk__logger_prototype_log_shared(duk_context *ctx) {
+ duk_double_t now;
+ duk_time_components comp;
+ duk_small_int_t entry_lev;
+ duk_small_int_t logger_lev;
+ duk_int_t nargs;
+ duk_int_t i;
+ duk_size_t tot_len;
+ const duk_uint8_t *arg_str;
+ duk_size_t arg_len;
+ duk_uint8_t *buf, *p;
+ const duk_uint8_t *q;
+ duk_uint8_t date_buf[32]; /* maximum format length is 24+1 (NUL), round up. */
+ duk_size_t date_len;
+ duk_small_int_t rc;
+
+ /* XXX: sanitize to printable (and maybe ASCII) */
+ /* XXX: better multiline */
+
+ /*
+ * Logger arguments are:
+ *
+ * magic: log level (0-5)
+ * this: logger
+ * stack: plain log args
+ *
+ * We want to minimize memory churn so a two-pass approach
+ * is used: first pass formats arguments and computes final
+ * string length, second pass copies strings into a buffer
+ * allocated directly with the correct size. If the backend
+ * function plays nice, it won't coerce the buffer to a string
+ * (and thus intern it).
+ */
+
+ entry_lev = duk_get_current_magic(ctx);
+ if (entry_lev < DUK_LOG_TRACE || entry_lev > DUK_LOG_FATAL) {
+ /* Should never happen, check just in case. */
+ return 0;
+ }
+ nargs = duk_get_top(ctx);
+
+ /* [ arg1 ... argN this ] */
+
+ /*
+ * Log level check
+ */
+
+ duk_push_this(ctx);
+
+ duk_get_prop_string(ctx, -1, "l");
+ logger_lev = (duk_small_int_t) duk_get_int(ctx, -1);
+ if (entry_lev < logger_lev) {
+ return 0;
+ }
+ /* log level could be popped but that's not necessary */
+
+ now = duk_get_now(ctx);
+ duk_time_to_components(ctx, now, &comp);
+ sprintf((char *) date_buf, "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ",
+ (int) comp.year, (int) comp.month + 1, (int) comp.day,
+ (int) comp.hours, (int) comp.minutes, (int) comp.seconds,
+ (int) comp.milliseconds);
+
+ date_len = strlen((const char *) date_buf);
+
+ duk_get_prop_string(ctx, -2, "n");
+ duk_to_string(ctx, -1);
+
+ /* [ arg1 ... argN this loggerLevel loggerName ] */
+
+ /*
+ * Pass 1
+ */
+
+ /* Line format: <time> <entryLev> <loggerName>: <msg> */
+
+ tot_len = 0;
+ tot_len += 3 + /* separators: space, space, colon */
+ 3 + /* level string */
+ date_len + /* time */
+ duk_get_length(ctx, -1); /* loggerName */
+
+ for (i = 0; i < nargs; i++) {
+ /* When formatting an argument to a string, errors may happen from multiple
+ * causes. In general we want to catch obvious errors like a toLogString()
+ * throwing an error, but we don't currently try to catch every possible
+ * error. In particular, internal errors (like out of memory or stack) are
+ * not caught. Also, we expect Error toString() to not throw an error.
+ */
+ if (duk_is_object(ctx, i)) {
+ /* duk_pcall_prop() may itself throw an error, but we're content
+ * in catching the obvious errors (like toLogString() throwing an
+ * error).
+ */
+ duk_push_string(ctx, "fmt");
+ duk_dup(ctx, i);
+ /* [ arg1 ... argN this loggerLevel loggerName 'fmt' arg ] */
+ /* call: this.fmt(arg) */
+ rc = duk_pcall_prop(ctx, -5 /*obj_index*/, 1 /*nargs*/);
+ if (rc) {
+ /* Keep the error as the result (coercing it might fail below,
+ * but we don't catch that now).
+ */
+ ;
+ }
+ duk_replace(ctx, i);
+ }
+ (void) duk_to_lstring(ctx, i, &arg_len);
+ tot_len++; /* sep (even before first one) */
+ tot_len += arg_len;
+ }
+
+ /*
+ * Pass 2
+ */
+
+ /* XXX: Here it'd be nice if we didn't need to allocate a new fixed
+ * buffer for every write. This would be possible if raw() took a
+ * buffer and a length. We could then use a preallocated buffer for
+ * most log writes and request raw() to write a partial buffer.
+ */
+
+ buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, tot_len);
+ p = buf;
+
+ memcpy((void *) p, (const void *) date_buf, (size_t) date_len);
+ p += date_len;
+ *p++ = (duk_uint8_t) ' ';
+
+ q = (const duk_uint8_t *) duk__log_level_strings + (entry_lev * 3);
+ memcpy((void *) p, (const void *) q, (size_t) 3);
+ p += 3;
+
+ *p++ = (duk_uint8_t) ' ';
+
+ arg_str = (const duk_uint8_t *) duk_get_lstring(ctx, -2, &arg_len);
+ memcpy((void *) p, (const void *) arg_str, (size_t) arg_len);
+ p += arg_len;
+
+ *p++ = (duk_uint8_t) ':';
+
+ for (i = 0; i < nargs; i++) {
+ *p++ = (duk_uint8_t) ' ';
+
+ arg_str = (const duk_uint8_t *) duk_get_lstring(ctx, i, &arg_len);
+ memcpy((void *) p, (const void *) arg_str, (size_t) arg_len);
+ p += arg_len;
+ }
+
+ /* [ arg1 ... argN this loggerLevel loggerName buffer ] */
+
+ /* Call this.raw(msg); look up through the instance allows user to override
+ * the raw() function in the instance or in the prototype for maximum
+ * flexibility.
+ */
+ duk_push_string(ctx, "raw");
+ duk_dup(ctx, -2);
+ /* [ arg1 ... argN this loggerLevel loggerName buffer 'raw' buffer ] */
+ duk_call_prop(ctx, -6, 1); /* this.raw(buffer) */
+
+ return 0;
+}
+
+void duk_log_va(duk_context *ctx, duk_int_t level, const char *fmt, va_list ap) {
+ if (level < 0) {
+ level = 0;
+ } else if (level > (int) (sizeof(duk__log_method_names) / sizeof(const char *)) - 1) {
+ level = (int) (sizeof(duk__log_method_names) / sizeof(const char *)) - 1;
+ }
+
+ duk_push_global_stash(ctx);
+ duk_get_prop_string(ctx, -1, "\xff" "logger:constructor"); /* fixed at init time */
+ duk_get_prop_string(ctx, -1, "clog");
+ duk_get_prop_string(ctx, -1, duk__log_method_names[level]);
+ duk_dup(ctx, -2);
+ duk_push_vsprintf(ctx, fmt, ap);
+
+ /* [ ... stash Logger clog logfunc clog(=this) msg ] */
+
+ duk_call_method(ctx, 1 /*nargs*/);
+
+ /* [ ... stash Logger clog res ] */
+
+ duk_pop_n(ctx, 4);
+}
+
+void duk_log(duk_context *ctx, duk_int_t level, const char *fmt, ...) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ duk_log_va(ctx, level, fmt, ap);
+ va_end(ap);
+}
+
+void duk_logging_init(duk_context *ctx, duk_uint_t flags) {
+ /* XXX: Add .name property for logger functions (useful for stack traces if they throw). */
+
+ (void) flags;
+
+ duk_eval_string(ctx,
+ "(function(cons,prot){"
+ "Object.defineProperty(Duktape,'Logger',{value:cons,writable:true,configurable:true});"
+ "Object.defineProperty(cons,'prototype',{value:prot});"
+ "Object.defineProperty(cons,'clog',{value:new Duktape.Logger('C'),writable:true,configurable:true});"
+ "});");
+
+ duk_push_c_function(ctx, duk__logger_constructor, DUK_VARARGS /*nargs*/); /* Duktape.Logger */
+ duk_push_object(ctx); /* Duktape.Logger.prototype */
+
+ /* [ ... func Duktape.Logger Duktape.Logger.prototype ] */
+
+ duk_push_string(ctx, "name");
+ duk_push_string(ctx, "Logger");
+ duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_FORCE);
+
+ duk_dup_top(ctx);
+ duk_put_prop_string(ctx, -2, "constructor");
+ duk_push_int(ctx, 2);
+ duk_put_prop_string(ctx, -2, "l");
+ duk_push_string(ctx, "anon");
+ duk_put_prop_string(ctx, -2, "n");
+ duk_push_c_function(ctx, duk__logger_prototype_fmt, 1 /*nargs*/);
+ duk_put_prop_string(ctx, -2, "fmt");
+ duk_push_c_function(ctx, duk__logger_prototype_raw, 1 /*nargs*/);
+ duk_put_prop_string(ctx, -2, "raw");
+ duk_push_c_function(ctx, duk__logger_prototype_log_shared, DUK_VARARGS /*nargs*/);
+ duk_set_magic(ctx, -1, 0); /* magic=0: trace */
+ duk_put_prop_string(ctx, -2, "trace");
+ duk_push_c_function(ctx, duk__logger_prototype_log_shared, DUK_VARARGS /*nargs*/);
+ duk_set_magic(ctx, -1, 1); /* magic=1: debug */
+ duk_put_prop_string(ctx, -2, "debug");
+ duk_push_c_function(ctx, duk__logger_prototype_log_shared, DUK_VARARGS /*nargs*/);
+ duk_set_magic(ctx, -1, 2); /* magic=2: info */
+ duk_put_prop_string(ctx, -2, "info");
+ duk_push_c_function(ctx, duk__logger_prototype_log_shared, DUK_VARARGS /*nargs*/);
+ duk_set_magic(ctx, -1, 3); /* magic=3: warn */
+ duk_put_prop_string(ctx, -2, "warn");
+ duk_push_c_function(ctx, duk__logger_prototype_log_shared, DUK_VARARGS /*nargs*/);
+ duk_set_magic(ctx, -1, 4); /* magic=4: error */
+ duk_put_prop_string(ctx, -2, "error");
+ duk_push_c_function(ctx, duk__logger_prototype_log_shared, DUK_VARARGS /*nargs*/);
+ duk_set_magic(ctx, -1, 5); /* magic=5: fatal */
+ duk_put_prop_string(ctx, -2, "fatal");
+
+ /* [ ... func Duktape.Logger Duktape.Logger.prototype ] */
+
+ /* XXX: when using ROM built-ins, "Duktape" is read-only by default so
+ * setting Duktape.Logger will now fail.
+ */
+
+ /* [ ... func Duktape.Logger Duktape.Logger.prototype ] */
+
+ duk_call(ctx, 2);
+ duk_pop(ctx);
+}